[clang] [clang] Implement `__is_layout_compatible` (PR #81506)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 16 03:59:48 PST 2024


================
@@ -1558,6 +1558,89 @@ void is_standard_layout()
   int t71[F(__is_standard_layout(HasEmptyIndirectBaseAsSecondUnionMember))];
 }
 
+struct CStruct2 {
+  int one;
+  int two;
+};
+
+struct CEmptyStruct2 {};
+
+struct CppEmptyStruct2 : CStruct2 {};
+struct CppStructStandard2 : CEmptyStruct2 {
+  int three;
+  int four;
+};
+struct CppStructNonStandardByBase2 : CStruct2 {
+  int three;
+  int four;
+};
+struct CppStructNonStandardByVirt2 : CStruct2 {
+  virtual void method() {}
+};
+struct CppStructNonStandardByMemb2 : CStruct2 {
+  CppStructNonStandardByVirt member;
+};
+struct CppStructNonStandardByProt2 : CStruct2 {
+  int five;
+protected:
+  int six;
+};
+struct CppStructNonStandardByVirtBase2 : virtual CStruct2 {
+};
+struct CppStructNonStandardBySameBase2 : CEmptyStruct2 {
+  CEmptyStruct member;
+};
+struct CppStructNonStandardBy2ndVirtBase2 : CEmptyStruct2 {
+  CEmptyStruct member;
+};
+
+struct CStructWithQualifiers {
+  const int one;
+  volatile int two;
+};
+
+struct CStructNoUniqueAddress {
+  int one;
+  [[no_unique_address]] int two;
+};
+
+struct CStructNoUniqueAddress2 {
+  int one;
+  [[no_unique_address]] int two;
+};
+
+struct CStructAlignment {
+  int one;
+  alignas(16) int two;
+};
+
+struct CStructIncomplete;
+
+void is_layout_compatible()
+{
+  static_assert(__is_layout_compatible(void, void), "");
+  static_assert(__is_layout_compatible(int, int), "");
+  static_assert(__is_layout_compatible(int[], int[]), "");
+  static_assert(__is_layout_compatible(int[2], int[2]), "");
+  static_assert(__is_layout_compatible(CStruct, CStruct2), "");
+  static_assert(__is_layout_compatible(CEmptyStruct, CEmptyStruct2), "");
+  static_assert(__is_layout_compatible(CppEmptyStruct, CppEmptyStruct2), "");
+  static_assert(__is_layout_compatible(CppStructStandard, CppStructStandard2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardByBase, CppStructNonStandardByBase2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardByVirt, CppStructNonStandardByVirt2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardByMemb, CppStructNonStandardByMemb2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardByProt, CppStructNonStandardByProt2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardByVirtBase, CppStructNonStandardByVirtBase2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardBySameBase, CppStructNonStandardBySameBase2), "");
+  static_assert(!__is_layout_compatible(CppStructNonStandardBy2ndVirtBase, CppStructNonStandardBy2ndVirtBase2), "");
+  static_assert(!__is_layout_compatible(CStruct, CStructWithQualifiers), ""); // FIXME: this is CWG1719
+  static_assert(__is_layout_compatible(CStruct, CStructNoUniqueAddress) == bool(__has_cpp_attribute(no_unique_address)), ""); // FIXME: this is CWG2759
+  static_assert(__is_layout_compatible(CStructNoUniqueAddress, CStructNoUniqueAddress2) == bool(__has_cpp_attribute(no_unique_address)), ""); // FIXME: this is CWG2759
+  static_assert(__is_layout_compatible(CStruct, CStructAlignment), "");
+  static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), "");
+  static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");
+}
----------------
Endilll wrote:

> A type is layout compatible with its qualified version. e.g., SomeStruct and const SomeStruct

Done. It even works correctly for class types.

> Layout compatibility of function types (not function pointer types), e.g., void(int) and void(int)

Done. I added tests for function types, reference to functions, pointers to function, pointers to data members, pointers to member functions.

> Diagnostics when given an incomplete type for either operand

We don't issue any, as far as I can see. And I don't think we can when the types are the same, ignoring cv qualifiers:
> Two types cv1 T1 and cv2 T2 are [layout-compatible types](http://eel.is/c++draft/basic.types.general#def:type,layout-compatible) if T1 and T2 are the same type, [layout-compatible enumerations](http://eel.is/c++draft/dcl.enum#def:layout-compatible,enumeration), or [layout-compatible standard-layout class types](http://eel.is/c++draft/class.mem#def:layout-compatible,class)[.](http://eel.is/c++draft/basic.types.general#11.sentence-1)

> That int and unsigned int are not layout compatible
> That char and signed char/unsigned char are not layout compatible
> That an enumeration type and its underlying type are not layout compatible

Done.

> I think we should add those tests somewhere (either here or in dr1xxx.cpp) so 1) we know we don't crash on them, 2) we're alerted to behavioral changes in this area, and 3) better documentation of existing behavior.

Agreed. I marked 1334 as superseded as 1719, and added a test for 1719.

https://github.com/llvm/llvm-project/pull/81506


More information about the cfe-commits mailing list