HomePhabricator

[MS ABI] Implement __declspec(empty_bases) and __declspec(layout_version)

Description

[MS ABI] Implement declspec(empty_bases) and declspec(layout_version)

The layout_version attribute is pretty straightforward: use the layout
rules from version XYZ of MSVC when used like
struct __declspec(layout_version(XYZ)) S {};

The empty_bases attribute is more interesting. It tries to get the C++
empty base optimization to fire more often by tweaking the MSVC ABI
rules in subtle ways:

  1. Disable the leading and trailing zero-sized object flags if a class is marked __declspec(empty_bases) and is empty.

    This means that given: struct declspec(empty_bases) A {}; struct declspec(empty_bases) B {}; struct C : A, B {};

    'C' will have size 1 and nvsize 0 despite not being annotated __declspec(empty_bases).
  1. When laying out virtual or non-virtual bases, disable the injection of padding between classes if the most derived class is marked __declspec(empty_bases).

    This means that given: struct A {}; struct B {}; struct __declspec(empty_bases) C : A, B {};

    'C' will have size 1 and nvsize 0.
  1. When calculating the offset of a non-virtual base, choose offset zero if the most derived class is marked __declspec(empty_bases) and the base is empty _and_ has an nvsize of 0.

    Because of the ABI rules, this does not mean that empty bases reliably get placed at offset 0!

    For example: struct A {}; struct B {}; struct __declspec(empty_bases) C : A, B { virtual ~C(); };

    'C' will be pointer sized to account for the vfptr at offset 0. 'A' and 'B' will _not_ be at offset 0 despite being empty! Instead, they will be located right after the vfptr.

    This occurs due to the interaction betweeen non-virtual base layout and virtual function pointer injection: injection occurs after the nv-bases and shifts them down by the size of a pointer.

Details

Committed
majnemerMay 23 2016, 10:16 AM
Branches
Unknown
Tags
Unknown