[clang] 988fd95 - [clang] Implement `__builtin_is_virtual_base_of()` intrinsic (#100393)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 26 00:09:57 PDT 2024
Author: Vlad Serebrennikov
Date: 2024-07-26T09:09:54+02:00
New Revision: 988fd956e776bad8057a8b7ee051a524308c097b
URL: https://github.com/llvm/llvm-project/commit/988fd956e776bad8057a8b7ee051a524308c097b
DIFF: https://github.com/llvm/llvm-project/commit/988fd956e776bad8057a8b7ee051a524308c097b.diff
LOG: [clang] Implement `__builtin_is_virtual_base_of()` intrinsic (#100393)
This patch adds compiler support for
[P2985R0](https://wg21.link/p2985r0) "A type trait for detecting virtual
base classes".
Like we recently did with `__is_layout_compatible()` and
`__is_pointer_interconvertible_base_of()`, we support it only in C++
mode, and reject VLAs.
Resolves #98310.
Added:
Modified:
clang/docs/LanguageExtensions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/TokenKinds.def
clang/lib/Sema/SemaExprCXX.cpp
clang/test/SemaCXX/type-traits.cpp
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 81784c75081ba..a747464582e77 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1546,6 +1546,7 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__array_extent(type, dim)`` (Embarcadero):
The ``dim``'th array bound in the type ``type``, or ``0`` if
``dim >= __array_rank(type)``.
+* ``__builtin_is_virtual_base_of`` (C++, GNU, Microsoft)
* ``__can_pass_in_regs`` (C++)
Returns whether a class can be passed in registers under the current
ABI. This type can only be applied to unqualified class types.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5dddd8f1c5af5..b165f6e65636d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -81,6 +81,9 @@ C++23 Feature Support
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- Add ``__builtin_is_virtual_base_of`` intrinsic, which supports
+ `P2985R0 A type trait for detecting virtual base classes <https://wg21.link/p2985r0>`_
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 8c54661e65cf4..7e638dc1ddcdb 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -501,6 +501,7 @@ TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
// GNU and MS Type Traits
+TYPE_TRAIT_2(__builtin_is_virtual_base_of, IsVirtualBaseOf, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 51c4a36808fce..029969c1722b7 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6030,6 +6030,32 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
return cast<CXXRecordDecl>(rhsRecord->getDecl())
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
}
+ case BTT_IsVirtualBaseOf: {
+ const RecordType *BaseRecord = LhsT->getAs<RecordType>();
+ const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
+
+ if (!BaseRecord || !DerivedRecord) {
+ DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+ tok::kw___builtin_is_virtual_base_of);
+ DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+ tok::kw___builtin_is_virtual_base_of);
+ return false;
+ }
+
+ if (BaseRecord->isUnionType() || DerivedRecord->isUnionType())
+ return false;
+
+ if (!BaseRecord->isStructureOrClassType() ||
+ !DerivedRecord->isStructureOrClassType())
+ return false;
+
+ if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type))
+ return false;
+
+ return cast<CXXRecordDecl>(DerivedRecord->getDecl())
+ ->isVirtuallyDerivedFrom(cast<CXXRecordDecl>(BaseRecord->getDecl()));
+ }
case BTT_IsSame:
return Self.Context.hasSameType(LhsT, RhsT);
case BTT_TypeCompatible: {
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 23b07cac13eaf..e131212bb1071 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2402,11 +2402,11 @@ template<typename T> struct DerivedB : BaseA<T> { };
template<typename T> struct CrazyDerived : T { };
-class class_forward; // expected-note 2 {{forward declaration of 'class_forward'}}
+class class_forward; // expected-note 4 {{forward declaration of 'class_forward'}}
template <class T> class DerivedTemp : Base {};
template <class T> class NonderivedTemp {};
-template <class T> class UndefinedTemp; // expected-note {{declared here}}
+template <class T> class UndefinedTemp; // expected-note 2 {{declared here}}
void is_base_of() {
static_assert(__is_base_of(Base, Derived));
@@ -2457,6 +2457,76 @@ void is_base_of() {
static_assert(!__is_base_of(DerivedB<int>, BaseA<int>));
}
+struct DerivedTransitiveViaNonVirtual : Derived3 {};
+struct DerivedTransitiveViaVirtual : virtual Derived3 {};
+
+template <typename T>
+struct CrazyDerivedVirtual : virtual T {};
+
+struct DerivedPrivate : private virtual Base {};
+struct DerivedProtected : protected virtual Base {};
+struct DerivedPrivatePrivate : private DerivedPrivate {};
+struct DerivedPrivateProtected : private DerivedProtected {};
+struct DerivedProtectedPrivate : protected DerivedProtected {};
+struct DerivedProtectedProtected : protected DerivedProtected {};
+
+void is_virtual_base_of(int n) {
+ static_assert(!__builtin_is_virtual_base_of(Base, Derived));
+ static_assert(!__builtin_is_virtual_base_of(const Base, Derived));
+ static_assert(!__builtin_is_virtual_base_of(Derived, Base));
+ static_assert(!__builtin_is_virtual_base_of(Derived, int));
+ static_assert(!__builtin_is_virtual_base_of(Base, Base));
+ static_assert(!__builtin_is_virtual_base_of(Base, Derived3));
+ static_assert(!__builtin_is_virtual_base_of(Derived, Derived3));
+ static_assert(__builtin_is_virtual_base_of(Derived2b, Derived3));
+ static_assert(__builtin_is_virtual_base_of(Derived2a, Derived3));
+ static_assert(!__builtin_is_virtual_base_of(BaseA<int>, DerivedB<int>));
+ static_assert(!__builtin_is_virtual_base_of(DerivedB<int>, BaseA<int>));
+ static_assert(!__builtin_is_virtual_base_of(Union, Union));
+ static_assert(!__builtin_is_virtual_base_of(Empty, Empty));
+ static_assert(!__builtin_is_virtual_base_of(class_forward, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}}
+ static_assert(!__builtin_is_virtual_base_of(Empty, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}}
+ static_assert(!__builtin_is_virtual_base_of(class_forward, Empty));
+ static_assert(!__builtin_is_virtual_base_of(Base&, Derived&));
+ static_assert(!__builtin_is_virtual_base_of(Base[10], Derived[10]));
+ static_assert(!__builtin_is_virtual_base_of(Base[n], Derived[n])); // expected-error 2 {{variable length arrays are not supported in '__builtin_is_virtual_base_of'}}
+ static_assert(!__builtin_is_virtual_base_of(int, int));
+ static_assert(!__builtin_is_virtual_base_of(int[], int[]));
+ static_assert(!__builtin_is_virtual_base_of(long, int));
+ static_assert(!__builtin_is_virtual_base_of(Base, DerivedTemp<int>));
+ static_assert(!__builtin_is_virtual_base_of(Base, NonderivedTemp<int>));
+ static_assert(!__builtin_is_virtual_base_of(Base, UndefinedTemp<int>)); // expected-error {{implicit instantiation of undefined template 'UndefinedTemp<int>'}}
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivate));
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedProtected));
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivatePrivate));
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivateProtected));
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedPrivate));
+ static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedProtected));
+ static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaNonVirtual));
+ static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaNonVirtual));
+ static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaVirtual));
+ static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaVirtual));
+ static_assert(!__builtin_is_virtual_base_of(Base, CrazyDerived<Base>));
+ static_assert(!__builtin_is_virtual_base_of(CrazyDerived<Base>, Base));
+ static_assert(__builtin_is_virtual_base_of(Base, CrazyDerivedVirtual<Base>));
+ static_assert(!__builtin_is_virtual_base_of(CrazyDerivedVirtual<Base>, Base));
+
+ static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteUnion));
+ static_assert(!__builtin_is_virtual_base_of(Union, IncompleteUnion));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Union));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteUnion));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteStruct));
+ static_assert(!__builtin_is_virtual_base_of(Empty, IncompleteUnion));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Empty));
+ static_assert(!__builtin_is_virtual_base_of(int, IncompleteUnion));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, int));
+ static_assert(!__builtin_is_virtual_base_of(Empty, Union));
+ static_assert(!__builtin_is_virtual_base_of(Union, Empty));
+ static_assert(!__builtin_is_virtual_base_of(int, Empty));
+ static_assert(!__builtin_is_virtual_base_of(Union, int));
+ static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteStruct[n])); // expected-error {{variable length arrays are not supported in '__builtin_is_virtual_base_of'}}
+}
+
template<class T, class U>
class TemplateClass {};
More information about the cfe-commits
mailing list