[clang] [clang] Implement `__builtin_is_implicit_lifetime()` (PR #101807)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 3 05:38:15 PDT 2024
https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/101807
>From 9c4e7ccf47d5ede2b6169effb2a09668f512a182 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 3 Aug 2024 13:05:21 +0300
Subject: [PATCH 1/2] [clang] Implement `__builtin_is_implicit_lifetime()`
This intrinsic supports [P2647R1](https://wg21.link/p2674r1) "A trait for implicit lifetime types".
---
clang/docs/LanguageExtensions.rst | 1 +
clang/docs/ReleaseNotes.rst | 3 +
clang/include/clang/Basic/TokenKinds.def | 1 +
clang/lib/Sema/SemaExprCXX.cpp | 22 +++++++
clang/test/SemaCXX/type-traits.cpp | 81 +++++++++++++++++++++++-
5 files changed, 107 insertions(+), 1 deletion(-)
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 at -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 at -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));
>From ad0abb5ae0332c4de83723a96e3f765891993dc5 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 3 Aug 2024 16:38:08 +0400
Subject: [PATCH 2/2] Apply Timm's suggestion
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 504dc93316db5..6f7e4203a1714 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5647,7 +5647,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (UnqualT->isArrayType())
return true;
- CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
+ const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
if (!RD)
return false;
if (UnqualT->isAggregateType())
More information about the cfe-commits
mailing list