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 {}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits