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

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 19 04:59:50 PST 2024


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

>From 52b239153b2fc4f52e889ad2044daa6ed5cbc836 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 12 Feb 2024 17:44:38 +0300
Subject: [PATCH 01/15] Initial implementation

---
 clang/include/clang/Basic/TokenKinds.def |  1 +
 clang/include/clang/Sema/Sema.h          |  2 +
 clang/lib/Parse/ParseDeclCXX.cpp         |  1 +
 clang/lib/Parse/ParseExpr.cpp            |  1 +
 clang/lib/Sema/SemaChecking.cpp          |  4 ++
 clang/lib/Sema/SemaExprCXX.cpp           |  3 +
 clang/test/SemaCXX/type-traits.cpp       | 77 ++++++++++++++++++++++++
 7 files changed, 89 insertions(+)

diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 23817cde7a9354..112bfe8b23c2c0 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -520,6 +520,7 @@ TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
 TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
 TYPE_TRAIT_1(__has_unique_object_representations,
              HasUniqueObjectRepresentations, KEYCXX)
+TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX)
 
 #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX)
 #include "clang/Basic/TransformTypeTraits.def"
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 851560f759f0e4..ddeba328749653 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14040,6 +14040,8 @@ class Sema final {
   bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);
 
 public:
+  bool SemaIsLayoutCompatible(QualType T1, QualType T2);
+  
   // Used by C++ template instantiation.
   ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
   ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 79928ddb5af599..c9360981c1c1e4 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1717,6 +1717,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
           tok::kw___is_fundamental,
           tok::kw___is_integral,
           tok::kw___is_interface_class,
+          tok::kw___is_layout_compatible,
           tok::kw___is_literal,
           tok::kw___is_lvalue_expr,
           tok::kw___is_lvalue_reference,
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 52cebdb6f64bac..db21a7f1e9e368 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1114,6 +1114,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
           REVERTIBLE_TYPE_TRAIT(__is_fundamental);
           REVERTIBLE_TYPE_TRAIT(__is_integral);
           REVERTIBLE_TYPE_TRAIT(__is_interface_class);
+          REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
           REVERTIBLE_TYPE_TRAIT(__is_literal);
           REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
           REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 71e6e7230fc455..8aa744873f3704 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19150,6 +19150,10 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
   return false;
 }
 
+bool Sema::SemaIsLayoutCompatible(QualType T1, QualType T2) {
+  return isLayoutCompatible(getASTContext(), T1, T2);
+}
+
 //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
 
 /// Given a type tag expression find the type tag itself.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 246d2313e089f3..b279c367342fce 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5922,6 +5922,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
 
     llvm_unreachable("unhandled type trait");
     return false;
+  }
+  case BTT_IsLayoutCompatible: {
+    return Self.SemaIsLayoutCompatible(LhsT, RhsT);
   }
     default: llvm_unreachable("not a BTT");
   }
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 5659594577111e..f50bedc275359b 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1558,6 +1558,83 @@ 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 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)), "");
+  static_assert(__is_layout_compatible(CStruct, CStructAlignment), "");
+  static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), "");
+  static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");
+}
+
 void is_signed()
 {
   //int t01[T(__is_signed(char))];

>From 5599465e3c3921571fd22d18a5854ced3a752d80 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 12 Feb 2024 20:51:49 +0300
Subject: [PATCH 02/15] `Add another test for [[no_unique_address]]`

---
 clang/test/SemaCXX/type-traits.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index f50bedc275359b..51592849e97edd 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1604,6 +1604,11 @@ struct CStructNoUniqueAddress {
   [[no_unique_address]] int two;
 };
 
+struct CStructNoUniqueAddress2 {
+  int one;
+  [[no_unique_address]] int two;
+};
+
 struct CStructAlignment {
   int one;
   alignas(16) int two;
@@ -1629,7 +1634,8 @@ void is_layout_compatible()
   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)), "");
+  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), "");

>From f0efbcc391366575f1aa2969c0c4f8ff51bc28b5 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 12 Feb 2024 21:12:05 +0300
Subject: [PATCH 03/15] Run clang-format

---
 clang/include/clang/Sema/Sema.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ddeba328749653..cd7d3c2ac1a254 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14041,7 +14041,7 @@ class Sema final {
 
 public:
   bool SemaIsLayoutCompatible(QualType T1, QualType T2);
-  
+
   // Used by C++ template instantiation.
   ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
   ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,

>From fcd987d5be209a4f27c2e14a87833bd70b4d93b0 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 13 Feb 2024 10:45:37 +0300
Subject: [PATCH 04/15] Drop "Sema" prefix on a function name

---
 clang/include/clang/Sema/Sema.h | 2 +-
 clang/lib/Sema/SemaChecking.cpp | 2 +-
 clang/lib/Sema/SemaExprCXX.cpp  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index cd7d3c2ac1a254..95f80d7f2fd4e1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14040,7 +14040,7 @@ class Sema final {
   bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);
 
 public:
-  bool SemaIsLayoutCompatible(QualType T1, QualType T2);
+  bool IsLayoutCompatible(QualType T1, QualType T2);
 
   // Used by C++ template instantiation.
   ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8aa744873f3704..31ca80d4022d4b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19150,7 +19150,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
   return false;
 }
 
-bool Sema::SemaIsLayoutCompatible(QualType T1, QualType T2) {
+bool Sema::IsLayoutCompatible(QualType T1, QualType T2) {
   return isLayoutCompatible(getASTContext(), T1, T2);
 }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b279c367342fce..8dd881b2a443ce 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5924,7 +5924,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
     return false;
   }
   case BTT_IsLayoutCompatible: {
-    return Self.SemaIsLayoutCompatible(LhsT, RhsT);
+    return Self.IsLayoutCompatible(LhsT, RhsT);
   }
     default: llvm_unreachable("not a BTT");
   }

>From 7edd1fb34590c20cf063cde219eb0600ce52dbde Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 13 Feb 2024 11:10:34 +0300
Subject: [PATCH 05/15] Add `const` qualifier to `Sema::IsLayoutCompatible()`

---
 clang/include/clang/Sema/Sema.h | 2 +-
 clang/lib/Sema/SemaChecking.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 95f80d7f2fd4e1..59c530f4342c61 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14040,7 +14040,7 @@ class Sema final {
   bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);
 
 public:
-  bool IsLayoutCompatible(QualType T1, QualType T2);
+  bool IsLayoutCompatible(QualType T1, QualType T2) const;
 
   // Used by C++ template instantiation.
   ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 31ca80d4022d4b..c10ce353142660 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19150,7 +19150,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
   return false;
 }
 
-bool Sema::IsLayoutCompatible(QualType T1, QualType T2) {
+bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const {
   return isLayoutCompatible(getASTContext(), T1, T2);
 }
 

>From 1e71746f3c70d05fb88278ab269e9fe41865a56d Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 13 Feb 2024 11:43:38 +0300
Subject: [PATCH 06/15] Remove changes to `ParseClassSpecifier()`

---
 clang/lib/Parse/ParseDeclCXX.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index c9360981c1c1e4..79928ddb5af599 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1717,7 +1717,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
           tok::kw___is_fundamental,
           tok::kw___is_integral,
           tok::kw___is_interface_class,
-          tok::kw___is_layout_compatible,
           tok::kw___is_literal,
           tok::kw___is_lvalue_expr,
           tok::kw___is_lvalue_reference,

>From 3b42854a51f0b5ef0edb2acf8dcc6b724f20827d Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 16 Feb 2024 14:49:54 +0300
Subject: [PATCH 07/15] Double the number of SemaCXX tests, add DR tests

---
 clang/test/CXX/drs/dr13xx.cpp      |  2 ++
 clang/test/CXX/drs/dr17xx.cpp      | 28 ++++++++++++++++++++++++++++
 clang/test/SemaCXX/type-traits.cpp | 29 +++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+)

diff --git a/clang/test/CXX/drs/dr13xx.cpp b/clang/test/CXX/drs/dr13xx.cpp
index 0ff44ebbc95591..effdc53040d0b0 100644
--- a/clang/test/CXX/drs/dr13xx.cpp
+++ b/clang/test/CXX/drs/dr13xx.cpp
@@ -307,6 +307,8 @@ namespace dr1330 { // dr1330: 4 c++11
   E e; // #dr1330-e
 }
 
+// dr1334: sup 1719
+
 namespace dr1341 { // dr1341: sup P0683R1
 #if __cplusplus >= 202002L
 int a;
diff --git a/clang/test/CXX/drs/dr17xx.cpp b/clang/test/CXX/drs/dr17xx.cpp
index 2f7e62da7bb60b..e5cee19337ebd4 100644
--- a/clang/test/CXX/drs/dr17xx.cpp
+++ b/clang/test/CXX/drs/dr17xx.cpp
@@ -46,6 +46,34 @@ namespace dr1715 { // dr1715: 3.9
 #endif
 }
 
+namespace dr1719 { // dr1719: no
+#if __cplusplus >= 201103L
+struct CStruct {
+  int one;
+  int two;
+};
+
+struct CStruct2 {
+  int one;
+  int two;
+};
+
+struct CStructWithQualifiers {
+  const int one;
+  volatile int two;
+};
+
+static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
+static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");
+static_assert(__is_layout_compatible(const CStruct, volatile CStruct2), "");
+// FIXME: all of the following pairs of types are layout-compatible
+static_assert(!__is_layout_compatible(int, const int), "");
+static_assert(!__is_layout_compatible(int, volatile int), "");
+static_assert(!__is_layout_compatible(const int, volatile int), "");
+static_assert(!__is_layout_compatible(CStruct, CStructWithQualifiers), "");
+#endif
+} // namespace dr1719
+
 namespace dr1722 { // dr1722: 9
 #if __cplusplus >= 201103L
 void f() {
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 51592849e97edd..c9b6226275aa63 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1616,13 +1616,38 @@ struct CStructAlignment {
 
 struct CStructIncomplete;
 
+enum EnumLayout : int {};
+enum class EnumClassLayout {};
+
 void is_layout_compatible()
 {
   static_assert(__is_layout_compatible(void, void), "");
+  static_assert(!__is_layout_compatible(void, int), "");
   static_assert(__is_layout_compatible(int, int), "");
+  static_assert(!__is_layout_compatible(int, const int), ""); // FIXME: this is CWG1719
+  static_assert(!__is_layout_compatible(int, volatile int), ""); // FIXME: this is CWG1719
+  static_assert(!__is_layout_compatible(const int, volatile int), ""); // FIXME: this is CWG1719
+  static_assert(!__is_layout_compatible(int, unsigned int), "");
+  static_assert(!__is_layout_compatible(char, unsigned char), "");
+  static_assert(!__is_layout_compatible(char, signed char), "");
+  static_assert(!__is_layout_compatible(unsigned char, signed char), "");
   static_assert(__is_layout_compatible(int[], int[]), "");
   static_assert(__is_layout_compatible(int[2], int[2]), "");
+  static_assert(__is_layout_compatible(int&, int&), "");
+  static_assert(!__is_layout_compatible(int&, char&), "");
+  static_assert(__is_layout_compatible(void(int), void(int)), "");
+  static_assert(!__is_layout_compatible(void(int), void(char)), "");
+  static_assert(__is_layout_compatible(void(&)(int), void(&)(int)), "");
+  static_assert(!__is_layout_compatible(void(&)(int), void(&)(char)), "");
+  static_assert(__is_layout_compatible(void(*)(int), void(*)(int)), "");
+  static_assert(!__is_layout_compatible(void(*)(int), void(*)(char)), "");
+  static_assert(!__is_layout_compatible(EnumLayout, int), "");
+  static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
+  static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
   static_assert(__is_layout_compatible(CStruct, CStruct2), "");
+  static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
+  static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");
+  static_assert(__is_layout_compatible(const CStruct, volatile CStruct2), "");
   static_assert(__is_layout_compatible(CEmptyStruct, CEmptyStruct2), "");
   static_assert(__is_layout_compatible(CppEmptyStruct, CppEmptyStruct2), "");
   static_assert(__is_layout_compatible(CppStructStandard, CppStructStandard2), "");
@@ -1639,6 +1664,10 @@ void is_layout_compatible()
   static_assert(__is_layout_compatible(CStruct, CStructAlignment), "");
   static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), "");
   static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");
+  static_assert(__is_layout_compatible(int CStruct2::*, int CStruct2::*), "");
+  static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*), "");
+  static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)), "");
+  static_assert(!__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(char)), "");
 }
 
 void is_signed()

>From 58c1636aad18c86ed97737b7842060aa0650fabc Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 16 Feb 2024 15:08:05 +0300
Subject: [PATCH 08/15] Add test with nested class type

---
 clang/test/SemaCXX/type-traits.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index c9b6226275aa63..805f62981ca42b 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1616,6 +1616,18 @@ struct CStructAlignment {
 
 struct CStructIncomplete;
 
+struct CStructNested {
+  int a;
+  CStruct s;
+  int b;
+};
+
+struct CStructNested2 {
+  int a2;
+  CStruct s2;
+  int b2;
+};
+
 enum EnumLayout : int {};
 enum class EnumClassLayout {};
 
@@ -1668,6 +1680,7 @@ void is_layout_compatible()
   static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*), "");
   static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)), "");
   static_assert(!__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(char)), "");
+  static_assert(__is_layout_compatible(CStructNested, CStructNested2), "");
 }
 
 void is_signed()

>From 69243d43f1bce8fa4a80855857d3bcfedf09ba80 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 16 Feb 2024 21:09:37 +0300
Subject: [PATCH 09/15] Add test for forward declarations of enums

---
 clang/test/SemaCXX/type-traits.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 805f62981ca42b..191dee68c3641a 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1630,6 +1630,8 @@ struct CStructNested2 {
 
 enum EnumLayout : int {};
 enum class EnumClassLayout {};
+enum EnumForward : int;
+enum class EnumClassForward;
 
 void is_layout_compatible()
 {
@@ -1656,6 +1658,10 @@ void is_layout_compatible()
   static_assert(!__is_layout_compatible(EnumLayout, int), "");
   static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
   static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
+  static_assert(__is_layout_compatible(EnumForward, EnumForward), "");
+  static_assert(!__is_layout_compatible(EnumForward, int), "");
+  static_assert(!__is_layout_compatible(EnumClassForward, int), "");
+  static_assert(__is_layout_compatible(EnumForward, EnumClassForward), "");
   static_assert(__is_layout_compatible(CStruct, CStruct2), "");
   static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
   static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");

>From ec6d122c9dc87ad2ebb2afdd5b928e3fc891fbbf Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 17 Feb 2024 14:42:52 +0300
Subject: [PATCH 10/15] Add tests for VLAs, unions, incomplete, and abominable
 function types

---
 clang/test/SemaCXX/type-traits.cpp | 67 ++++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 191dee68c3641a..5befd1036a269e 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1628,15 +1628,56 @@ struct CStructNested2 {
   int b2;
 };
 
+struct CStructWithBitfelds {
+  int a : 5;
+  int : 0;
+};
+
+struct CStructWithBitfelds2 {
+  int a : 5;
+  int : 0;
+};
+
+struct CStructWithBitfelds3 {
+  int : 0;
+  int b : 5;
+};
+
 enum EnumLayout : int {};
 enum class EnumClassLayout {};
 enum EnumForward : int;
 enum class EnumClassForward;
 
-void is_layout_compatible()
+union UnionLayout {
+  int a;
+  double b;
+  CStruct c;
+  [[no_unique_address]] CEmptyStruct d;
+  [[no_unique_address]] CEmptyStruct2 e;
+};
+
+union UnionLayout2 {
+  CStruct c;
+  int a;
+  CEmptyStruct2 e;
+  double b;
+  [[no_unique_address]] CEmptyStruct d;
+};
+
+union UnionLayout3 {
+  CStruct c;
+  int a;
+  double b;
+  [[no_unique_address]] CEmptyStruct d;
+};
+
+void is_layout_compatible(int n)
 {
   static_assert(__is_layout_compatible(void, void), "");
   static_assert(!__is_layout_compatible(void, int), "");
+  static_assert(!__is_layout_compatible(void, const void), ""); // FIXME: this is CWG1719
+  static_assert(!__is_layout_compatible(void, volatile void), ""); // FIXME: this is CWG1719
+  static_assert(!__is_layout_compatible(const int, volatile int), ""); // FIXME: this is CWG1719
   static_assert(__is_layout_compatible(int, int), "");
   static_assert(!__is_layout_compatible(int, const int), ""); // FIXME: this is CWG1719
   static_assert(!__is_layout_compatible(int, volatile int), ""); // FIXME: this is CWG1719
@@ -1647,6 +1688,8 @@ void is_layout_compatible()
   static_assert(!__is_layout_compatible(unsigned char, signed char), "");
   static_assert(__is_layout_compatible(int[], int[]), "");
   static_assert(__is_layout_compatible(int[2], int[2]), "");
+  static_assert(!__is_layout_compatible(int[n], int[2]), ""); // FIXME: VLAs should be rejected
+  static_assert(!__is_layout_compatible(int[n], int[n]), ""); // FIXME: VLAs should be rejected
   static_assert(__is_layout_compatible(int&, int&), "");
   static_assert(!__is_layout_compatible(int&, char&), "");
   static_assert(__is_layout_compatible(void(int), void(int)), "");
@@ -1655,6 +1698,16 @@ void is_layout_compatible()
   static_assert(!__is_layout_compatible(void(&)(int), void(&)(char)), "");
   static_assert(__is_layout_compatible(void(*)(int), void(*)(int)), "");
   static_assert(!__is_layout_compatible(void(*)(int), void(*)(char)), "");
+  using function_type = void();
+  using function_type2 = void(char);
+  static_assert(__is_layout_compatible(const function_type, const function_type), "");
+  // expected-warning at -1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
+  // expected-warning at -2 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
+  static_assert(__is_layout_compatible(function_type, const function_type), "");
+  // expected-warning at -1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
+  static_assert(!__is_layout_compatible(const function_type, const function_type2), "");
+  // expected-warning at -1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
+  // expected-warning at -2 {{'const' qualifier on function type 'function_type2' (aka 'void (char)') has no effect}}
   static_assert(!__is_layout_compatible(EnumLayout, int), "");
   static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
   static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
@@ -1680,13 +1733,21 @@ void is_layout_compatible()
   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), "");
+  static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds), "");
+  static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds2), "");
+  static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds3), "");
   static_assert(__is_layout_compatible(int CStruct2::*, int CStruct2::*), "");
   static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*), "");
   static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)), "");
   static_assert(!__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(char)), "");
   static_assert(__is_layout_compatible(CStructNested, CStructNested2), "");
+  static_assert(__is_layout_compatible(UnionLayout, UnionLayout), "");
+  static_assert(__is_layout_compatible(UnionLayout, UnionLayout2), "");
+  static_assert(!__is_layout_compatible(UnionLayout, UnionLayout3), "");
+  // FIXME: the following should be rejected (array of unknown bound and void are the only allowed incomplete types)
+  static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), ""); 
+  static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");
+  static_assert(__is_layout_compatible(CStructIncomplete[2], CStructIncomplete[2]), "");
 }
 
 void is_signed()

>From c5a9c613720520f2c8f65082b79bc3e0362324c8 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 17 Feb 2024 14:52:02 +0300
Subject: [PATCH 11/15] Add documentation bits

---
 clang/docs/LanguageExtensions.rst | 1 +
 clang/docs/ReleaseNotes.rst       | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index e91156837290f7..a1f7c4696af884 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1582,6 +1582,7 @@ The following type trait primitives are supported by Clang. Those traits marked
 * ``__is_integral`` (C++, Embarcadero)
 * ``__is_interface_class`` (Microsoft):
   Returns ``false``, even for types defined with ``__interface``.
+* ``__is_layout_compatible`` (C++, GNU, Microsoft)
 * ``__is_literal`` (Clang):
   Synonym for ``__is_literal_type``.
 * ``__is_literal_type`` (C++, GNU, Microsoft):
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ece6013f672621..b3ba8aeb327ea6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -90,6 +90,12 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
 
+- Implemented `__is_layout_compatible` intrinsic, which backs up
+  `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.
+  `CWG1719: Layout compatibility and cv-qualification revisited  <https://cplusplus.github.io/CWG/issues/1719.html>`_
+  and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_
+  are not yet implemented.
+
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 

>From 4fcf3a343c2a2101d768eea1da4b70c37ec9b004 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 19 Feb 2024 13:17:49 +0300
Subject: [PATCH 12/15] Add tests for anonymous union

---
 clang/test/SemaCXX/type-traits.cpp | 47 +++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 5befd1036a269e..ac2fd15efff991 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1614,6 +1614,11 @@ struct CStructAlignment {
   alignas(16) int two;
 };
 
+enum EnumLayout : int {};
+enum class EnumClassLayout {};
+enum EnumForward : int;
+enum class EnumClassForward;
+
 struct CStructIncomplete;
 
 struct CStructNested {
@@ -1643,10 +1648,10 @@ struct CStructWithBitfelds3 {
   int b : 5;
 };
 
-enum EnumLayout : int {};
-enum class EnumClassLayout {};
-enum EnumForward : int;
-enum class EnumClassForward;
+struct CStructWithBitfelds4 {
+  EnumLayout a : 5;
+  int : 0;
+};
 
 union UnionLayout {
   int a;
@@ -1671,6 +1676,37 @@ union UnionLayout3 {
   [[no_unique_address]] CEmptyStruct d;
 };
 
+struct StructWithAnonUnion {
+  union {
+    int a;
+    double b;
+    CStruct c;
+    [[no_unique_address]] CEmptyStruct d;
+    [[no_unique_address]] CEmptyStruct2 e;
+  };
+};
+
+struct StructWithAnonUnion2 {
+  union {
+    CStruct c;
+    int a;
+    CEmptyStruct2 e;
+    double b;
+    [[no_unique_address]] CEmptyStruct d;
+  };
+};
+
+struct StructWithAnonUnion3 {
+  union {
+    CStruct c;
+    int a;
+    CEmptyStruct2 e;
+    double b;
+    [[no_unique_address]] CEmptyStruct d;
+  } u;
+};
+
+
 void is_layout_compatible(int n)
 {
   static_assert(__is_layout_compatible(void, void), "");
@@ -1736,6 +1772,7 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds), "");
   static_assert(__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds2), "");
   static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds3), "");
+  static_assert(!__is_layout_compatible(CStructWithBitfelds, CStructWithBitfelds4), "");
   static_assert(__is_layout_compatible(int CStruct2::*, int CStruct2::*), "");
   static_assert(!__is_layout_compatible(int CStruct2::*, char CStruct2::*), "");
   static_assert(__is_layout_compatible(void(CStruct2::*)(int), void(CStruct2::*)(int)), "");
@@ -1744,6 +1781,8 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(UnionLayout, UnionLayout), "");
   static_assert(__is_layout_compatible(UnionLayout, UnionLayout2), "");
   static_assert(!__is_layout_compatible(UnionLayout, UnionLayout3), "");
+  static_assert(__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion2), "");
+  static_assert(__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3), "");
   // FIXME: the following should be rejected (array of unknown bound and void are the only allowed incomplete types)
   static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), ""); 
   static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");

>From d4e15ed2677a95b065b606033bc0d52d12186103 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 19 Feb 2024 15:19:08 +0300
Subject: [PATCH 13/15] Mention Jens' comment in enum tests

---
 clang/test/SemaCXX/type-traits.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index ac2fd15efff991..6ff04b6c8c7223 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1744,13 +1744,6 @@ void is_layout_compatible(int n)
   static_assert(!__is_layout_compatible(const function_type, const function_type2), "");
   // expected-warning at -1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
   // expected-warning at -2 {{'const' qualifier on function type 'function_type2' (aka 'void (char)') has no effect}}
-  static_assert(!__is_layout_compatible(EnumLayout, int), "");
-  static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
-  static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
-  static_assert(__is_layout_compatible(EnumForward, EnumForward), "");
-  static_assert(!__is_layout_compatible(EnumForward, int), "");
-  static_assert(!__is_layout_compatible(EnumClassForward, int), "");
-  static_assert(__is_layout_compatible(EnumForward, EnumClassForward), "");
   static_assert(__is_layout_compatible(CStruct, CStruct2), "");
   static_assert(__is_layout_compatible(CStruct, const CStruct2), "");
   static_assert(__is_layout_compatible(CStruct, volatile CStruct2), "");
@@ -1783,6 +1776,14 @@ void is_layout_compatible(int n)
   static_assert(!__is_layout_compatible(UnionLayout, UnionLayout3), "");
   static_assert(__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion2), "");
   static_assert(__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3), "");
+  static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout), "");
+  static_assert(__is_layout_compatible(EnumForward, EnumForward), "");
+  static_assert(__is_layout_compatible(EnumForward, EnumClassForward), "");
+  // Layout compatibility for enums might be relaxed in the future. See https://github.com/cplusplus/CWG/issues/39#issuecomment-1184791364
+  static_assert(!__is_layout_compatible(EnumLayout, int), "");
+  static_assert(!__is_layout_compatible(EnumClassLayout, int), "");
+  static_assert(!__is_layout_compatible(EnumForward, int), "");
+  static_assert(!__is_layout_compatible(EnumClassForward, int), "");
   // FIXME: the following should be rejected (array of unknown bound and void are the only allowed incomplete types)
   static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete), ""); 
   static_assert(!__is_layout_compatible(CStruct, CStructIncomplete), "");

>From b33d3cae62f991fdcd87ec2ec7984644e92a2b57 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 19 Feb 2024 15:26:33 +0300
Subject: [PATCH 14/15] Accept Corentin's changes to release notes

---
 clang/docs/ReleaseNotes.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b3ba8aeb327ea6..8a35d582a044d9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -90,10 +90,10 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
 
-- Implemented `__is_layout_compatible` intrinsic, which backs up
-  `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.
-  `CWG1719: Layout compatibility and cv-qualification revisited  <https://cplusplus.github.io/CWG/issues/1719.html>`_
-  and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_
+- Implemented the `__is_layout_compatible` intrinsic to support  
+  `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.  
+  Note: `CWG1719: Layout compatibility and cv-qualification revisited  <https://cplusplus.github.io/CWG/issues/1719.html>`_  
+  and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_  
   are not yet implemented.
 
 C++23 Feature Support

>From 42ad118807e0d7429d51eaa8988a269bb222e03f Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 19 Feb 2024 15:59:30 +0300
Subject: [PATCH 15/15] Remove trailing whitespaces

---
 clang/docs/ReleaseNotes.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8a35d582a044d9..203d6e880ed2b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -90,10 +90,10 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
 
-- Implemented the `__is_layout_compatible` intrinsic to support  
-  `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.  
-  Note: `CWG1719: Layout compatibility and cv-qualification revisited  <https://cplusplus.github.io/CWG/issues/1719.html>`_  
-  and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_  
+- Implemented the `__is_layout_compatible` intrinsic to support
+  `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_.
+  Note: `CWG1719: Layout compatibility and cv-qualification revisited  <https://cplusplus.github.io/CWG/issues/1719.html>`_
+  and `CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_
   are not yet implemented.
 
 C++23 Feature Support



More information about the cfe-commits mailing list