Skip to content

Commit 988fd95

Browse files
authored
[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.
1 parent 1079d9c commit 988fd95

File tree

5 files changed

+103
-2
lines changed

5 files changed

+103
-2
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,7 @@ The following type trait primitives are supported by Clang. Those traits marked
15461546
* ``__array_extent(type, dim)`` (Embarcadero):
15471547
The ``dim``'th array bound in the type ``type``, or ``0`` if
15481548
``dim >= __array_rank(type)``.
1549+
* ``__builtin_is_virtual_base_of`` (C++, GNU, Microsoft)
15491550
* ``__can_pass_in_regs`` (C++)
15501551
Returns whether a class can be passed in registers under the current
15511552
ABI. This type can only be applied to unqualified class types.

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ C++23 Feature Support
8181
C++2c Feature Support
8282
^^^^^^^^^^^^^^^^^^^^^
8383

84+
- Add ``__builtin_is_virtual_base_of`` intrinsic, which supports
85+
`P2985R0 A type trait for detecting virtual base classes <https://wg21.link/p2985r0>`_
86+
8487
Resolutions to C++ Defect Reports
8588
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8689

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
501501
TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
502502

503503
// GNU and MS Type Traits
504+
TYPE_TRAIT_2(__builtin_is_virtual_base_of, IsVirtualBaseOf, KEYCXX)
504505
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
505506
TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX)
506507
TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX)

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6030,6 +6030,32 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
60306030
return cast<CXXRecordDecl>(rhsRecord->getDecl())
60316031
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
60326032
}
6033+
case BTT_IsVirtualBaseOf: {
6034+
const RecordType *BaseRecord = LhsT->getAs<RecordType>();
6035+
const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
6036+
6037+
if (!BaseRecord || !DerivedRecord) {
6038+
DiagnoseVLAInCXXTypeTrait(Self, Lhs,
6039+
tok::kw___builtin_is_virtual_base_of);
6040+
DiagnoseVLAInCXXTypeTrait(Self, Rhs,
6041+
tok::kw___builtin_is_virtual_base_of);
6042+
return false;
6043+
}
6044+
6045+
if (BaseRecord->isUnionType() || DerivedRecord->isUnionType())
6046+
return false;
6047+
6048+
if (!BaseRecord->isStructureOrClassType() ||
6049+
!DerivedRecord->isStructureOrClassType())
6050+
return false;
6051+
6052+
if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
6053+
diag::err_incomplete_type))
6054+
return false;
6055+
6056+
return cast<CXXRecordDecl>(DerivedRecord->getDecl())
6057+
->isVirtuallyDerivedFrom(cast<CXXRecordDecl>(BaseRecord->getDecl()));
6058+
}
60336059
case BTT_IsSame:
60346060
return Self.Context.hasSameType(LhsT, RhsT);
60356061
case BTT_TypeCompatible: {

clang/test/SemaCXX/type-traits.cpp

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,11 +2402,11 @@ template<typename T> struct DerivedB : BaseA<T> { };
24022402
template<typename T> struct CrazyDerived : T { };
24032403

24042404

2405-
class class_forward; // expected-note 2 {{forward declaration of 'class_forward'}}
2405+
class class_forward; // expected-note 4 {{forward declaration of 'class_forward'}}
24062406

24072407
template <class T> class DerivedTemp : Base {};
24082408
template <class T> class NonderivedTemp {};
2409-
template <class T> class UndefinedTemp; // expected-note {{declared here}}
2409+
template <class T> class UndefinedTemp; // expected-note 2 {{declared here}}
24102410

24112411
void is_base_of() {
24122412
static_assert(__is_base_of(Base, Derived));
@@ -2457,6 +2457,76 @@ void is_base_of() {
24572457
static_assert(!__is_base_of(DerivedB<int>, BaseA<int>));
24582458
}
24592459

2460+
struct DerivedTransitiveViaNonVirtual : Derived3 {};
2461+
struct DerivedTransitiveViaVirtual : virtual Derived3 {};
2462+
2463+
template <typename T>
2464+
struct CrazyDerivedVirtual : virtual T {};
2465+
2466+
struct DerivedPrivate : private virtual Base {};
2467+
struct DerivedProtected : protected virtual Base {};
2468+
struct DerivedPrivatePrivate : private DerivedPrivate {};
2469+
struct DerivedPrivateProtected : private DerivedProtected {};
2470+
struct DerivedProtectedPrivate : protected DerivedProtected {};
2471+
struct DerivedProtectedProtected : protected DerivedProtected {};
2472+
2473+
void is_virtual_base_of(int n) {
2474+
static_assert(!__builtin_is_virtual_base_of(Base, Derived));
2475+
static_assert(!__builtin_is_virtual_base_of(const Base, Derived));
2476+
static_assert(!__builtin_is_virtual_base_of(Derived, Base));
2477+
static_assert(!__builtin_is_virtual_base_of(Derived, int));
2478+
static_assert(!__builtin_is_virtual_base_of(Base, Base));
2479+
static_assert(!__builtin_is_virtual_base_of(Base, Derived3));
2480+
static_assert(!__builtin_is_virtual_base_of(Derived, Derived3));
2481+
static_assert(__builtin_is_virtual_base_of(Derived2b, Derived3));
2482+
static_assert(__builtin_is_virtual_base_of(Derived2a, Derived3));
2483+
static_assert(!__builtin_is_virtual_base_of(BaseA<int>, DerivedB<int>));
2484+
static_assert(!__builtin_is_virtual_base_of(DerivedB<int>, BaseA<int>));
2485+
static_assert(!__builtin_is_virtual_base_of(Union, Union));
2486+
static_assert(!__builtin_is_virtual_base_of(Empty, Empty));
2487+
static_assert(!__builtin_is_virtual_base_of(class_forward, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}}
2488+
static_assert(!__builtin_is_virtual_base_of(Empty, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}}
2489+
static_assert(!__builtin_is_virtual_base_of(class_forward, Empty));
2490+
static_assert(!__builtin_is_virtual_base_of(Base&, Derived&));
2491+
static_assert(!__builtin_is_virtual_base_of(Base[10], Derived[10]));
2492+
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'}}
2493+
static_assert(!__builtin_is_virtual_base_of(int, int));
2494+
static_assert(!__builtin_is_virtual_base_of(int[], int[]));
2495+
static_assert(!__builtin_is_virtual_base_of(long, int));
2496+
static_assert(!__builtin_is_virtual_base_of(Base, DerivedTemp<int>));
2497+
static_assert(!__builtin_is_virtual_base_of(Base, NonderivedTemp<int>));
2498+
static_assert(!__builtin_is_virtual_base_of(Base, UndefinedTemp<int>)); // expected-error {{implicit instantiation of undefined template 'UndefinedTemp<int>'}}
2499+
static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivate));
2500+
static_assert(__builtin_is_virtual_base_of(Base, DerivedProtected));
2501+
static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivatePrivate));
2502+
static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivateProtected));
2503+
static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedPrivate));
2504+
static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedProtected));
2505+
static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaNonVirtual));
2506+
static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaNonVirtual));
2507+
static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaVirtual));
2508+
static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaVirtual));
2509+
static_assert(!__builtin_is_virtual_base_of(Base, CrazyDerived<Base>));
2510+
static_assert(!__builtin_is_virtual_base_of(CrazyDerived<Base>, Base));
2511+
static_assert(__builtin_is_virtual_base_of(Base, CrazyDerivedVirtual<Base>));
2512+
static_assert(!__builtin_is_virtual_base_of(CrazyDerivedVirtual<Base>, Base));
2513+
2514+
static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteUnion));
2515+
static_assert(!__builtin_is_virtual_base_of(Union, IncompleteUnion));
2516+
static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Union));
2517+
static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteUnion));
2518+
static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteStruct));
2519+
static_assert(!__builtin_is_virtual_base_of(Empty, IncompleteUnion));
2520+
static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Empty));
2521+
static_assert(!__builtin_is_virtual_base_of(int, IncompleteUnion));
2522+
static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, int));
2523+
static_assert(!__builtin_is_virtual_base_of(Empty, Union));
2524+
static_assert(!__builtin_is_virtual_base_of(Union, Empty));
2525+
static_assert(!__builtin_is_virtual_base_of(int, Empty));
2526+
static_assert(!__builtin_is_virtual_base_of(Union, int));
2527+
static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteStruct[n])); // expected-error {{variable length arrays are not supported in '__builtin_is_virtual_base_of'}}
2528+
}
2529+
24602530
template<class T, class U>
24612531
class TemplateClass {};
24622532

0 commit comments

Comments
 (0)