diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1228,6 +1228,12 @@ # define _LIBCPP_PACKED_BYTE_FOR_AIX_END /* empty */ # endif +# if __has_attribute(__packed__) +# define _LIBCPP_PACKED __attribute__((__packed__)) +# else +# define _LIBCPP_PACKED +# endif + #endif // __cplusplus #endif // _LIBCPP___CONFIG diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -723,8 +723,15 @@ struct __long { - size_type __is_long_ : 1; - size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; + // Attribute 'packed' is used to keep the layout compatible with the + // previous definition that did not use bit fields. This is because + // on some platforms bit fields have a default size rather than + // the actual size used, e.g., it is 4 bytes on AIX. See D128285 + // for details. + struct _LIBCPP_PACKED { + size_type __is_long_ : 1; + size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; + }; size_type __size_; pointer __data_; }; @@ -734,14 +741,22 @@ struct __short { - unsigned char __is_long_ : 1; - unsigned char __size_ : 7; + // Attribute 'packed' is used to keep the layout compatible with the + // previous definition that did not use bit fields. This is because + // on some platforms bit fields have a default size rather than + // the actual size used, e.g., it is 4 bytes on AIX. See D128285 + // for details. + struct _LIBCPP_PACKED { + unsigned char __is_long_ : 1; + unsigned char __size_ : 7; + }; char __padding_[sizeof(value_type) - 1]; value_type __data_[__min_cap]; }; #endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT + static_assert(sizeof(__long) == (sizeof(pointer) + sizeof(size_type) * 2), "__long has an unexpected size."); static_assert(sizeof(__short) == (sizeof(value_type) * (__min_cap + 1)), "__short has an unexpected size."); union __ulx{__long __lx; __short __lxx;};