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

John McCall rjmccall at apple.com
Sun Apr 26 04:10:35 UTC 2015


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.

I propose the following changes:

1.  Add “or members of zero-length array type” to the ABI definition of "empty class”.
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).

John.


More information about the cxx-abi-dev mailing list