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.vladis...@gmail.com> Date: Mon, 12 Feb 2024 17:44:38 +0300 Subject: [PATCH 01/11] 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.vladis...@gmail.com> Date: Mon, 12 Feb 2024 20:51:49 +0300 Subject: [PATCH 02/11] `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.vladis...@gmail.com> Date: Mon, 12 Feb 2024 21:12:05 +0300 Subject: [PATCH 03/11] 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.vladis...@gmail.com> Date: Tue, 13 Feb 2024 10:45:37 +0300 Subject: [PATCH 04/11] 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.vladis...@gmail.com> Date: Tue, 13 Feb 2024 11:10:34 +0300 Subject: [PATCH 05/11] 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.vladis...@gmail.com> Date: Tue, 13 Feb 2024 11:43:38 +0300 Subject: [PATCH 06/11] 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.vladis...@gmail.com> Date: Fri, 16 Feb 2024 14:49:54 +0300 Subject: [PATCH 07/11] 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.vladis...@gmail.com> Date: Fri, 16 Feb 2024 15:08:05 +0300 Subject: [PATCH 08/11] 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.vladis...@gmail.com> Date: Fri, 16 Feb 2024 21:09:37 +0300 Subject: [PATCH 09/11] 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.vladis...@gmail.com> Date: Sat, 17 Feb 2024 14:42:52 +0300 Subject: [PATCH 10/11] 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@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}} + // expected-warning@-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@-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@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}} + // expected-warning@-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.vladis...@gmail.com> Date: Sat, 17 Feb 2024 14:52:02 +0300 Subject: [PATCH 11/11] 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 ^^^^^^^^^^^^^^^^^^^^^ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits