[cxx-abi-dev] Do zero-length arrays make a class type non-empty?

Richard Smith richardsmith at googlers.com
Sun Apr 26 21:26:57 UTC 2015


On 25 April 2015 at 21:10, John McCall <rjmccall at apple.com> wrote:

> The standard says that std::is_empty<T>::value is true if:
>   - T is a class type, but not a union type, with no non-static data
> members other than bit-fields of length 0, no virtual member functions, no
> virtual base classes, and no base class B for which is_empty<B>::value is
> false.
>
> The standard also says that array bounds must be greater than zero, but
> there’s a common extension to permit zero-length array types (hereafter,
> ZLATs).
>
> In GCC and Clang, at least, a ZLAT conventionally has size 0, both
> formally (as a result of sizeof) and for struct layout (a ZLAT field takes
> up no direct space, although it does cause the next offset to be rounded up
> to the field’s alignment).  Moreover, a ZLAT field inhibits the general
> rule rounding a class's size up to at least 1, recursively.
>
> Oddly, though, GCC and Clang also say that a struct containing a ZLAT is
> not empty, at least as far as std::is_empty is concerned.  On the other
> hand, ICC says that a struct containing only one (or more) ZLATs is empty;
> as does MSVC, for what it’s worth.
>
> This touches on the ABI because:
>   - the results of these metaprogramming traits can affect the ABI in a
> number of ways,
>   - class sizes are also obviously ABI, and
>   - whether a base class is empty dramatically affects Itanium class
> layout.
>
> The current Itanium definition mirrors the std::is_empty definition:
>   [a] class with no non-static data members other than zero-width
> bitfields, no virtual functions, no virtual base classes, and no non-empty
> non-virtual proper base classes.
>
> Now, of course, this is an extension, and we don’t have to standardize
> behavior on it; but my preference is to specify this sort of common
> extension wherever possible.
>

The point of is_empty is to allow detection of EBO opportunities, so I
think it should return 'true' in all cases where EBO would apply. It seems
reasonable (if not very worthwhile) to ignore ZLATs when determining
whether we can apply EBO. And I think this is a common enough extension for
the ABI to specify how it should behave.


> I propose the following changes:
>
> 1.  Add “or members of zero-length array type” to the ABI definition of
> "empty class”.
>

Is it worth explicitly calling out that flexible array members and
zero-length array members are handled the same in this regard?


> 2.  Specify std::is_empty to behave as if the same clause were there.
> 3.  Change the ABI class layout rule (in IV. Finalization) to not require
> sizeof(C) to be non-zero if C contains a ZLAT subobject.  That is, replace
> this sentence:
>   Round sizeof(C) up to a non-zero multiple of align(C).
> with:
>   If C does not contain (recursively) a subobject of zero-length array
> type, and sizeof(C) is 0, set sizeof(C) to align(C); otherwise, round
> sizeof(C) up to a multiple of align(C).


Perhaps:

If sizeof(C) is 0 and C has no non-static data members and no base classes,
set sizeof(C) to align(C); otherwise, round sizeof(C) up to a multiple of
align(C).

I think that's equivalent, and it seems simpler and more general.

Another problem is in step 2 of the layout algorithm: "Place D at this
offset unless doing so would result in two components (direct or indirect)
of the same type having the same offset.". That does the wrong thing for:

  struct A { int n[0]; int m[0]; };

where sizeof(A) should be zero, but will be 4 with this algorithm because
putting m at offset 0 gives two components of type 'int[0]' at the same
offset. Perhaps replace "components (direct or indirect)" with "non-array
subobjects"?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20150426/32b791d0/attachment.html>


More information about the cxx-abi-dev mailing list