https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/88473
>From 84907542cecbe76b1971a50642d39ec4d1078687 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Fri, 12 Apr 2024 08:18:06 +0300 Subject: [PATCH 1/2] [clang] Implement `__is_pointer_interconvertible_base_of()` --- clang/include/clang/Basic/TokenKinds.def | 1 + clang/include/clang/Sema/Sema.h | 2 + clang/lib/Sema/SemaChecking.cpp | 21 ++++++ clang/lib/Sema/SemaExprCXX.cpp | 16 +++++ clang/test/SemaCXX/type-traits.cpp | 86 +++++++++++++++++++++++- 5 files changed, 125 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 800af0e6d04480..a27fbed358a60c 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -521,6 +521,7 @@ TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) TYPE_TRAIT_1(__has_unique_object_representations, HasUniqueObjectRepresentations, KEYCXX) TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX) +TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBaseOf, 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 0ee4f3c8e127f6..397c5ae8eee777 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1975,6 +1975,8 @@ class Sema final : public SemaBase { }; bool IsLayoutCompatible(QualType T1, QualType T2) const; + bool IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, + const TypeSourceInfo *Derived); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index abfd9a3031577b..bbe82672183508 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -19710,6 +19710,27 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const { return isLayoutCompatible(getASTContext(), T1, T2); } +//===-------------- Pointer interconvertibility ----------------------------// + +bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, + const TypeSourceInfo *Derived) { + QualType BaseT = Base->getType().getCanonicalType().getUnqualifiedType(); + QualType DerivedT = + Derived->getType().getCanonicalType().getUnqualifiedType(); + + if (!BaseT->isUnionType() && !DerivedT->isUnionType() && + getASTContext().hasSameType(BaseT, DerivedT)) + return true; + + if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT)) + return false; + + if (DerivedT->getAsCXXRecordDecl()->isStandardLayout()) + return true; + + return false; +} + //===--- 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 12f42f66e5e21b..1416dab9eb3a0e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6082,6 +6082,22 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) << 1 << tok::kw___is_layout_compatible; return Self.IsLayoutCompatible(LhsT, RhsT); + } + case BTT_IsPointerInterconvertibleBaseOf: { + if (!LhsT->isUnionType() && !RhsT->isUnionType() && + !Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) { + Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type); + } + + if (LhsT->isVariableArrayType()) + Self.Diag(Lhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) + << 1 << tok::kw___is_pointer_interconvertible_base_of; + if (RhsT->isVariableArrayType()) + Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) + << 1 << tok::kw___is_pointer_interconvertible_base_of; + + return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs); } default: llvm_unreachable("not a BTT"); } diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 421d3007d27ffe..7c22a7659de9e8 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -1740,7 +1740,7 @@ void is_layout_compatible(int n) static_assert(!__is_layout_compatible(void, int)); static_assert(__is_layout_compatible(void, const void)); static_assert(__is_layout_compatible(void, volatile void)); - static_assert(__is_layout_compatible(const int, volatile int)); + static_assert(__is_layout_compatible(const void, volatile void)); static_assert(__is_layout_compatible(int, int)); static_assert(__is_layout_compatible(int, const int)); static_assert(__is_layout_compatible(int, volatile int)); @@ -1839,6 +1839,90 @@ void is_layout_compatible(int n) static_assert(!__is_layout_compatible(EnumClassForward, int)); } +namespace IPIBO { +struct Base {}; +struct Base2 {}; +struct Base3 : Base {}; +struct Base3Virtual : virtual Base {}; +struct Derived : Base {}; +struct DerivedIndirect : Base3 {}; +struct DerivedMultiple : Base, Base2 {}; +struct DerivedAmbiguous : Base, Base3 {}; +/* expected-warning@-1 {{direct base 'Base' is inaccessible due to ambiguity: + struct IPIBO::DerivedAmbiguous -> Base + struct IPIBO::DerivedAmbiguous -> Base3 -> Base}} */ +struct DerivedPrivate : private Base {}; +struct DerivedVirtual : virtual Base {}; + +union Union {}; +union UnionIncomplete; +struct StructIncomplete; + +void is_pointer_interconvertible_base_of(int n) +{ + static_assert(__is_pointer_interconvertible_base_of(Base, Derived)); + static_assert(!__is_pointer_interconvertible_base_of(Base2, Derived)); + static_assert(__is_pointer_interconvertible_base_of(Base, DerivedIndirect)); + static_assert(__is_pointer_interconvertible_base_of(Base, DerivedMultiple)); + static_assert(!__is_pointer_interconvertible_base_of(Base3, DerivedMultiple)); + static_assert(!__is_pointer_interconvertible_base_of(Base, DerivedAmbiguous)); + static_assert(__is_pointer_interconvertible_base_of(Base, DerivedPrivate)); + static_assert(!__is_pointer_interconvertible_base_of(Base, DerivedVirtual)); + static_assert(!__is_pointer_interconvertible_base_of(Union, Union)); + static_assert(!__is_pointer_interconvertible_base_of(UnionIncomplete, UnionIncomplete)); + static_assert(__is_pointer_interconvertible_base_of(StructIncomplete, StructIncomplete)); + static_assert(__is_pointer_interconvertible_base_of(StructIncomplete, const StructIncomplete)); + static_assert(__is_pointer_interconvertible_base_of(StructIncomplete, volatile StructIncomplete)); + static_assert(__is_pointer_interconvertible_base_of(const StructIncomplete, volatile StructIncomplete)); + static_assert(!__is_pointer_interconvertible_base_of(CStruct2, CppStructNonStandardByBase2)); + static_assert(__is_pointer_interconvertible_base_of(void, void)); + static_assert(!__is_pointer_interconvertible_base_of(void, int)); + static_assert(__is_pointer_interconvertible_base_of(void, const void)); + static_assert(__is_pointer_interconvertible_base_of(void, volatile void)); + static_assert(__is_pointer_interconvertible_base_of(const void, volatile void)); + static_assert(__is_pointer_interconvertible_base_of(int, int)); + static_assert(__is_pointer_interconvertible_base_of(int, const int)); + static_assert(__is_pointer_interconvertible_base_of(int, volatile int)); + static_assert(__is_pointer_interconvertible_base_of(const int, volatile int)); + static_assert(__is_pointer_interconvertible_base_of(int *, int * __restrict)); + static_assert(!__is_pointer_interconvertible_base_of(int, _Atomic int)); + static_assert(__is_pointer_interconvertible_base_of(_Atomic(int), _Atomic int)); + static_assert(!__is_pointer_interconvertible_base_of(int, unsigned int)); + static_assert(!__is_pointer_interconvertible_base_of(char, unsigned char)); + static_assert(!__is_pointer_interconvertible_base_of(char, signed char)); + static_assert(!__is_pointer_interconvertible_base_of(unsigned char, signed char)); + using function_type = void(); + using function_type2 = void(char); + static_assert(__is_pointer_interconvertible_base_of(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_pointer_interconvertible_base_of(function_type, const function_type)); + // expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}} + static_assert(!__is_pointer_interconvertible_base_of(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_pointer_interconvertible_base_of(int CStruct2::*, int CStruct2::*)); + static_assert(!__is_pointer_interconvertible_base_of(int CStruct2::*, char CStruct2::*)); + static_assert(__is_pointer_interconvertible_base_of(void(CStruct2::*)(int), void(CStruct2::*)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(CStruct2::*)(int), void(CStruct2::*)(char))); + static_assert(__is_pointer_interconvertible_base_of(int[], int[])); + static_assert(__is_pointer_interconvertible_base_of(int[2], int[2])); + static_assert(!__is_pointer_interconvertible_base_of(int[n], int[2])); + // expected-error@-1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} + static_assert(!__is_pointer_interconvertible_base_of(int[n], int[n])); + // expected-error@-1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} + // expected-error@-2 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} + static_assert(__is_pointer_interconvertible_base_of(int&, int&)); + static_assert(!__is_pointer_interconvertible_base_of(int&, char&)); + static_assert(__is_pointer_interconvertible_base_of(void(int), void(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(int), void(char))); + static_assert(__is_pointer_interconvertible_base_of(void(&)(int), void(&)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(&)(int), void(&)(char))); + static_assert(__is_pointer_interconvertible_base_of(void(*)(int), void(*)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(*)(int), void(*)(char))); +} +} + void is_signed() { //static_assert(__is_signed(char)); >From 0f7b465f316c9db823cadba5ebdc6fc9a75cb764 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Fri, 12 Apr 2024 09:58:00 +0300 Subject: [PATCH 2/2] Yield `false` for non-class types --- clang/lib/Sema/SemaChecking.cpp | 2 +- clang/test/SemaCXX/type-traits.cpp | 40 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index bbe82672183508..c4525d660f902f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -19718,7 +19718,7 @@ bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, QualType DerivedT = Derived->getType().getCanonicalType().getUnqualifiedType(); - if (!BaseT->isUnionType() && !DerivedT->isUnionType() && + if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() && getASTContext().hasSameType(BaseT, DerivedT)) return true; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 7c22a7659de9e8..2dd00886e60074 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -1875,50 +1875,50 @@ void is_pointer_interconvertible_base_of(int n) static_assert(__is_pointer_interconvertible_base_of(StructIncomplete, volatile StructIncomplete)); static_assert(__is_pointer_interconvertible_base_of(const StructIncomplete, volatile StructIncomplete)); static_assert(!__is_pointer_interconvertible_base_of(CStruct2, CppStructNonStandardByBase2)); - static_assert(__is_pointer_interconvertible_base_of(void, void)); + static_assert(!__is_pointer_interconvertible_base_of(void, void)); static_assert(!__is_pointer_interconvertible_base_of(void, int)); - static_assert(__is_pointer_interconvertible_base_of(void, const void)); - static_assert(__is_pointer_interconvertible_base_of(void, volatile void)); - static_assert(__is_pointer_interconvertible_base_of(const void, volatile void)); - static_assert(__is_pointer_interconvertible_base_of(int, int)); - static_assert(__is_pointer_interconvertible_base_of(int, const int)); - static_assert(__is_pointer_interconvertible_base_of(int, volatile int)); - static_assert(__is_pointer_interconvertible_base_of(const int, volatile int)); - static_assert(__is_pointer_interconvertible_base_of(int *, int * __restrict)); + static_assert(!__is_pointer_interconvertible_base_of(void, const void)); + static_assert(!__is_pointer_interconvertible_base_of(void, volatile void)); + static_assert(!__is_pointer_interconvertible_base_of(const void, volatile void)); + static_assert(!__is_pointer_interconvertible_base_of(int, int)); + static_assert(!__is_pointer_interconvertible_base_of(int, const int)); + static_assert(!__is_pointer_interconvertible_base_of(int, volatile int)); + static_assert(!__is_pointer_interconvertible_base_of(const int, volatile int)); + static_assert(!__is_pointer_interconvertible_base_of(int *, int * __restrict)); static_assert(!__is_pointer_interconvertible_base_of(int, _Atomic int)); - static_assert(__is_pointer_interconvertible_base_of(_Atomic(int), _Atomic int)); + static_assert(!__is_pointer_interconvertible_base_of(_Atomic(int), _Atomic int)); static_assert(!__is_pointer_interconvertible_base_of(int, unsigned int)); static_assert(!__is_pointer_interconvertible_base_of(char, unsigned char)); static_assert(!__is_pointer_interconvertible_base_of(char, signed char)); static_assert(!__is_pointer_interconvertible_base_of(unsigned char, signed char)); using function_type = void(); using function_type2 = void(char); - static_assert(__is_pointer_interconvertible_base_of(const function_type, const function_type)); + static_assert(!__is_pointer_interconvertible_base_of(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_pointer_interconvertible_base_of(function_type, const function_type)); + static_assert(!__is_pointer_interconvertible_base_of(function_type, const function_type)); // expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}} static_assert(!__is_pointer_interconvertible_base_of(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_pointer_interconvertible_base_of(int CStruct2::*, int CStruct2::*)); + static_assert(!__is_pointer_interconvertible_base_of(int CStruct2::*, int CStruct2::*)); static_assert(!__is_pointer_interconvertible_base_of(int CStruct2::*, char CStruct2::*)); - static_assert(__is_pointer_interconvertible_base_of(void(CStruct2::*)(int), void(CStruct2::*)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(CStruct2::*)(int), void(CStruct2::*)(int))); static_assert(!__is_pointer_interconvertible_base_of(void(CStruct2::*)(int), void(CStruct2::*)(char))); - static_assert(__is_pointer_interconvertible_base_of(int[], int[])); - static_assert(__is_pointer_interconvertible_base_of(int[2], int[2])); + static_assert(!__is_pointer_interconvertible_base_of(int[], int[])); + static_assert(!__is_pointer_interconvertible_base_of(int[2], int[2])); static_assert(!__is_pointer_interconvertible_base_of(int[n], int[2])); // expected-error@-1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} static_assert(!__is_pointer_interconvertible_base_of(int[n], int[n])); // expected-error@-1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} // expected-error@-2 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}} - static_assert(__is_pointer_interconvertible_base_of(int&, int&)); + static_assert(!__is_pointer_interconvertible_base_of(int&, int&)); static_assert(!__is_pointer_interconvertible_base_of(int&, char&)); - static_assert(__is_pointer_interconvertible_base_of(void(int), void(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(int), void(int))); static_assert(!__is_pointer_interconvertible_base_of(void(int), void(char))); - static_assert(__is_pointer_interconvertible_base_of(void(&)(int), void(&)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(&)(int), void(&)(int))); static_assert(!__is_pointer_interconvertible_base_of(void(&)(int), void(&)(char))); - static_assert(__is_pointer_interconvertible_base_of(void(*)(int), void(*)(int))); + static_assert(!__is_pointer_interconvertible_base_of(void(*)(int), void(*)(int))); static_assert(!__is_pointer_interconvertible_base_of(void(*)(int), void(*)(char))); } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits