llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Vlad Serebrennikov (Endilll) <details> <summary>Changes</summary> This intrinsic supports [P2647R1](https://wg21.link/p2674r1) "A trait for implicit lifetime types". --- Full diff: https://github.com/llvm/llvm-project/pull/101807.diff 5 Files Affected: - (modified) clang/docs/LanguageExtensions.rst (+1) - (modified) clang/docs/ReleaseNotes.rst (+3) - (modified) clang/include/clang/Basic/TokenKinds.def (+1) - (modified) clang/lib/Sema/SemaExprCXX.cpp (+22) - (modified) clang/test/SemaCXX/type-traits.cpp (+80-1) ``````````diff diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index a747464582e77..f04e6b0057b51 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_implicit_lifetime`` (C++, GNU, Microsoft) * ``__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 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 25f5bd37bbe94..6854a321e1720 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -86,6 +86,9 @@ C++23 Feature Support C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ +- Add ``__builtin_is_implicit_lifetime`` intrinsic, which supports + `P2647R1 A trait for implicit lifetime types <https://wg21.link/p2674r1>`_ + - Add ``__builtin_is_virtual_base_of`` intrinsic, which supports `P2985R0 A type trait for detecting virtual base classes <https://wg21.link/p2985r0>`_ diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 7e638dc1ddcdb..7505c5a1a1f27 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_1(__builtin_is_implicit_lifetime, IsImplicitLifetime, KEYCXX) 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) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c5003d9ac0254..504dc93316db5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5039,6 +5039,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, // LWG3823: T shall be an array type, a complete type, or cv void. case UTT_IsAggregate: + case UTT_IsImplicitLifetime: if (ArgTy->isArrayType() || ArgTy->isVoidType()) return true; @@ -5637,6 +5638,27 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return false; case UTT_IsTriviallyEqualityComparable: return isTriviallyEqualityComparableType(Self, T, KeyLoc); + case UTT_IsImplicitLifetime: { + DiagnoseVLAInCXXTypeTrait(Self, TInfo, + tok::kw___builtin_is_implicit_lifetime); + QualType UnqualT = T->getCanonicalTypeUnqualified(); + if (UnqualT->isScalarType()) + return true; + if (UnqualT->isArrayType()) + return true; + + CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl(); + if (!RD) + return false; + if (UnqualT->isAggregateType()) + if (!RD->getDestructor()->isUserProvided()) + return true; + if (RD->hasTrivialDestructor()) + if (RD->hasTrivialDefaultConstructor() || + RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor()) + return true; + return false; + } } } diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 4acb3d6c9eebe..11041414c1bba 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -18,7 +18,7 @@ enum class SignedEnumClass : signed int {}; enum class UnsignedEnumClass : unsigned int {}; struct POD { Enum e; int i; float f; NonPOD* p; }; struct Empty {}; -struct IncompleteStruct; +struct IncompleteStruct; // expected-note {{forward declaration of 'IncompleteStruct'}} typedef Empty EmptyAr[10]; typedef Empty EmptyArNB[]; typedef Empty EmptyArMB[1][2]; @@ -1944,6 +1944,85 @@ void is_pointer_interconvertible_base_of(int n) } } +struct NoEligibleTrivialContructor { + NoEligibleTrivialContructor() {}; + NoEligibleTrivialContructor(const NoEligibleTrivialContructor&) {} + NoEligibleTrivialContructor(NoEligibleTrivialContructor&&) {} +}; + +struct OnlyDefaultConstructorIsTrivial { + OnlyDefaultConstructorIsTrivial() = default; + OnlyDefaultConstructorIsTrivial(const OnlyDefaultConstructorIsTrivial&) {} + OnlyDefaultConstructorIsTrivial(OnlyDefaultConstructorIsTrivial&&) {} +}; + +struct AllContstructorsAreTrivial { + AllContstructorsAreTrivial() = default; + AllContstructorsAreTrivial(const AllContstructorsAreTrivial&) = default; + AllContstructorsAreTrivial(AllContstructorsAreTrivial&&) = default; +}; + +struct InheritedNoEligibleTrivialConstructor : NoEligibleTrivialContructor { + using NoEligibleTrivialContructor::NoEligibleTrivialContructor; +}; + +struct InheritedOnlyDefaultConstructorIsTrivial : OnlyDefaultConstructorIsTrivial { + using OnlyDefaultConstructorIsTrivial::OnlyDefaultConstructorIsTrivial; +}; + +struct InheritedAllContstructorsAreTrivial : AllContstructorsAreTrivial { + using AllContstructorsAreTrivial::AllContstructorsAreTrivial; +}; + +struct UserDeclaredDestructor { + ~UserDeclaredDestructor() = default; +}; + +struct UserProvidedDestructor { + ~UserProvidedDestructor() {} +}; + +void is_implicit_lifetime(int n) { + static_assert(!__builtin_is_implicit_lifetime(void)); + static_assert(!__builtin_is_implicit_lifetime(const void)); + static_assert(!__builtin_is_implicit_lifetime(volatile void)); + static_assert(__builtin_is_implicit_lifetime(int)); + static_assert(!__builtin_is_implicit_lifetime(int&)); + static_assert(!__builtin_is_implicit_lifetime(int&&)); + static_assert(__builtin_is_implicit_lifetime(int*)); + static_assert(__builtin_is_implicit_lifetime(int[])); + static_assert(__builtin_is_implicit_lifetime(int[5])); + static_assert(__builtin_is_implicit_lifetime(int[n])); + // expected-error@-1 {{variable length arrays are not supported in '__builtin_is_implicit_lifetime'}} + static_assert(__builtin_is_implicit_lifetime(Enum)); + static_assert(__builtin_is_implicit_lifetime(EnumClass)); + static_assert(!__builtin_is_implicit_lifetime(void())); + static_assert(!__builtin_is_implicit_lifetime(void() &)); + static_assert(!__builtin_is_implicit_lifetime(void() const)); + static_assert(!__builtin_is_implicit_lifetime(void(&)())); + static_assert(__builtin_is_implicit_lifetime(void(*)())); + static_assert(__builtin_is_implicit_lifetime(decltype(nullptr))); + static_assert(__builtin_is_implicit_lifetime(int UserDeclaredDestructor::*)); + static_assert(__builtin_is_implicit_lifetime(int (UserDeclaredDestructor::*)())); + static_assert(__builtin_is_implicit_lifetime(int (UserDeclaredDestructor::*)() const)); + static_assert(__builtin_is_implicit_lifetime(int (UserDeclaredDestructor::*)() &)); + static_assert(__builtin_is_implicit_lifetime(int (UserDeclaredDestructor::*)() &&)); + static_assert(!__builtin_is_implicit_lifetime(IncompleteStruct)); + // expected-error@-1 {{incomplete type 'IncompleteStruct' used in type trait expression}} + static_assert(__builtin_is_implicit_lifetime(IncompleteStruct[])); + static_assert(__builtin_is_implicit_lifetime(IncompleteStruct[5])); + static_assert(__builtin_is_implicit_lifetime(UserDeclaredDestructor)); + static_assert(__builtin_is_implicit_lifetime(const UserDeclaredDestructor)); + static_assert(__builtin_is_implicit_lifetime(volatile UserDeclaredDestructor)); + static_assert(!__builtin_is_implicit_lifetime(UserProvidedDestructor)); + static_assert(!__builtin_is_implicit_lifetime(NoEligibleTrivialContructor)); + static_assert(__builtin_is_implicit_lifetime(OnlyDefaultConstructorIsTrivial)); + static_assert(__builtin_is_implicit_lifetime(AllContstructorsAreTrivial)); + static_assert(!__builtin_is_implicit_lifetime(InheritedNoEligibleTrivialConstructor)); + static_assert(__builtin_is_implicit_lifetime(InheritedOnlyDefaultConstructorIsTrivial)); + static_assert(__builtin_is_implicit_lifetime(InheritedAllContstructorsAreTrivial)); +} + void is_signed() { //static_assert(__is_signed(char)); `````````` </details> https://github.com/llvm/llvm-project/pull/101807 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits