[clang] [clang] Implement `__is_layout_compatible` (PR #81506)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 12 10:09:27 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Vlad Serebrennikov (Endilll)
<details>
<summary>Changes</summary>
This patch implements `__is_layout_compatible`, which backs up `std::is_layout_compatible` type trait introduced in C++20 ([P0466R5](https://wg21.link/p0466r5) "Layout-compatibility and Pointer-interconvertibility Traits"). Name matched GCC and MSVC intrinsics.
Basically, this patch exposes our existing machinery for checking for layout compatibility and figuring out common initial sequences. Said machinery is a bit outdated, as it doesn't implement [CWG1719](https://cplusplus.github.io/CWG/issues/1719.html) "Layout compatibility and cv-qualification revisited" and [CWG2759](https://cplusplus.github.io/CWG/issues/2759.html) "`[[no_unique_address]` and common initial sequence". Those defect reports are considered out of scope of of this PR, but will be implemented in subsequent PRs.
Partially addresses #<!-- -->48204
---
Full diff: https://github.com/llvm/llvm-project/pull/81506.diff
7 Files Affected:
- (modified) clang/include/clang/Basic/TokenKinds.def (+1)
- (modified) clang/include/clang/Sema/Sema.h (+2)
- (modified) clang/lib/Parse/ParseDeclCXX.cpp (+1)
- (modified) clang/lib/Parse/ParseExpr.cpp (+1)
- (modified) clang/lib/Sema/SemaChecking.cpp (+4)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+3)
- (modified) clang/test/SemaCXX/type-traits.cpp (+83)
``````````diff
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..51592849e97edd 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -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), "");
+}
+
void is_signed()
{
//int t01[T(__is_signed(char))];
``````````
</details>
https://github.com/llvm/llvm-project/pull/81506
More information about the cfe-commits
mailing list