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/4] [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/4] 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))); } } >From cc1aca56480eb5d02580a15e949c5ae85bf44542 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Fri, 12 Apr 2024 10:01:56 +0300 Subject: [PATCH 3/4] Add a release note --- clang/docs/ReleaseNotes.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c4a4893aec5cd6..dd3a2d80dbcdce 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -98,7 +98,8 @@ C++20 Feature Support behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'. (#GH79240). -- Implemented the `__is_layout_compatible` intrinsic to support +- Implemented the `__is_layout_compatible` and `__is_pointer_interconvertible_base_of` + intrinsics to support `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits <https://wg21.link/P0466R5>`_. - Clang now implements [module.import]p7 fully. Clang now will import module >From 6b20e1b89f84ae2834d17493f5f32de89b97aed5 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Fri, 12 Apr 2024 18:19:41 +0300 Subject: [PATCH 4/4] Address reviewer feedback --- clang/lib/Sema/SemaChecking.cpp | 6 +++--- clang/lib/Sema/SemaExprCXX.cpp | 2 +- clang/test/SemaCXX/type-traits.cpp | 7 ++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c4525d660f902f..8e21811b67d900 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -19714,9 +19714,8 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const { bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, const TypeSourceInfo *Derived) { - QualType BaseT = Base->getType().getCanonicalType().getUnqualifiedType(); - QualType DerivedT = - Derived->getType().getCanonicalType().getUnqualifiedType(); + QualType BaseT = Base->getType()->getCanonicalTypeUnqualified(); + QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified(); if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() && getASTContext().hasSameType(BaseT, DerivedT)) @@ -19725,6 +19724,7 @@ bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT)) return false; + // Per [basic.compound]/4.3, containing object has to be standard-layout. if (DerivedT->getAsCXXRecordDecl()->isStandardLayout()) return true; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1416dab9eb3a0e..6c02647a88e795 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6084,7 +6084,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI return Self.IsLayoutCompatible(LhsT, RhsT); } case BTT_IsPointerInterconvertibleBaseOf: { - if (!LhsT->isUnionType() && !RhsT->isUnionType() && + if (!LhsT->isStructureOrClassType() && !RhsT->isStructureOrClassType() && !Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) { Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, diag::err_incomplete_type); diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 2dd00886e60074..d43701c3d976e0 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -1856,7 +1856,7 @@ struct DerivedVirtual : virtual Base {}; union Union {}; union UnionIncomplete; -struct StructIncomplete; +struct StructIncomplete; // #StructIncomplete void is_pointer_interconvertible_base_of(int n) { @@ -1874,6 +1874,10 @@ void is_pointer_interconvertible_base_of(int n) 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(StructIncomplete, Derived)); + static_assert(!__is_pointer_interconvertible_base_of(Base, StructIncomplete)); + // expected-error@-1 {{incomplete type 'StructIncomplete' where a complete type is required}} + // expected-note@#StructIncomplete {{forward declaration of 'IPIBO::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)); @@ -1906,6 +1910,7 @@ void is_pointer_interconvertible_base_of(int n) 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[], double[])); 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'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits