[clang] [clang] Implement `__is_pointer_interconvertible_base_of()` (PR #88473)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 12 08:19:57 PDT 2024
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.vladislav at 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 at -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 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_pointer_interconvertible_base_of(function_type, const function_type));
+ // expected-warning at -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 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_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 at -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 at -1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}}
+ // expected-error at -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.vladislav at 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 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_pointer_interconvertible_base_of(function_type, const function_type));
+ static_assert(!__is_pointer_interconvertible_base_of(function_type, const function_type));
// expected-warning at -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 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_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 at -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 at -1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}}
// expected-error at -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.vladislav at 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.vladislav at 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 at -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 at -1 {{variable length arrays are not supported in '__is_pointer_interconvertible_base_of'}}
More information about the cfe-commits
mailing list