[clang] [clang] Implement `__builtin_is_implicit_lifetime()` (PR #101807)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 13 03:42:19 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/6] [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 a747464582e77d..f04e6b0057b512 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 25f5bd37bbe94f..6854a321e17206 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 7e638dc1ddcdba..7505c5a1a1f27c 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 c5003d9ac02549..504dc93316db50 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 4acb3d6c9eebea..11041414c1bbab 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/6] 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 504dc93316db50..6f7e4203a17142 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())
>From 49de16a0126a3fe3284f017ee4a4969d41bb4094 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 11 Aug 2024 21:46:58 +0300
Subject: [PATCH 3/6] Address feedback
---
clang/lib/Sema/SemaExprCXX.cpp | 17 ++++++++++++---
clang/test/SemaCXX/type-traits.cpp | 34 ++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 6f7e4203a17142..5fb735600fac5a 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5641,19 +5641,30 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
case UTT_IsImplicitLifetime: {
DiagnoseVLAInCXXTypeTrait(Self, TInfo,
tok::kw___builtin_is_implicit_lifetime);
+
+ // [basic.types.general] p9
+ // Scalar types, implicit-lifetime class types ([class.prop]),
+ // array types, and cv-qualified versions of these types
+ // are collectively called implicit-lifetime types.
QualType UnqualT = T->getCanonicalTypeUnqualified();
if (UnqualT->isScalarType())
return true;
if (UnqualT->isArrayType())
return true;
-
const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
if (!RD)
return false;
+
+ // [class.prop] p9
+ // A class S is an implicit-lifetime class if
+ // - it is an aggregate whose destructor is not user-provided or
+ // - it has at least one trivial eligible constructor and a trivial,
+ // non-deleted destructor.
+ const CXXDestructorDecl *Dtor = RD->getDestructor();
if (UnqualT->isAggregateType())
- if (!RD->getDestructor()->isUserProvided())
+ if (Dtor && !Dtor->isUserProvided())
return true;
- if (RD->hasTrivialDestructor())
+ if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))
if (RD->hasTrivialDefaultConstructor() ||
RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor())
return true;
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 11041414c1bbab..fea6bec7476783 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1982,6 +1982,31 @@ struct UserProvidedDestructor {
~UserProvidedDestructor() {}
};
+struct UserDeletedDestructorInAggregate {
+ ~UserDeletedDestructorInAggregate() = delete;
+};
+
+struct UserDeletedDestructorInNonAggregate {
+ virtual void NonAggregate();
+ ~UserDeletedDestructorInNonAggregate() = delete;
+};
+
+struct DeletedDestructorViaBaseInAggregate : UserDeletedDestructorInAggregate {};
+struct DeletedDestructorViaBaseInNonAggregate : UserDeletedDestructorInNonAggregate {};
+
+#if __cplusplus >= 202002L
+template<bool B>
+struct ConstrainedUserDeclaredDefaultConstructor{
+ ConstrainedUserDeclaredDefaultConstructor() requires B = default;
+ ConstrainedUserDeclaredDefaultConstructor(const ConstrainedUserDeclaredDefaultConstructor&) {}
+};
+
+template<bool B>
+struct ConstrainedUserProvidedDestructor {
+ ~ConstrainedUserProvidedDestructor() requires B {}
+};
+#endif
+
void is_implicit_lifetime(int n) {
static_assert(!__builtin_is_implicit_lifetime(void));
static_assert(!__builtin_is_implicit_lifetime(const void));
@@ -2021,6 +2046,15 @@ void is_implicit_lifetime(int n) {
static_assert(!__builtin_is_implicit_lifetime(InheritedNoEligibleTrivialConstructor));
static_assert(__builtin_is_implicit_lifetime(InheritedOnlyDefaultConstructorIsTrivial));
static_assert(__builtin_is_implicit_lifetime(InheritedAllContstructorsAreTrivial));
+ static_assert(__builtin_is_implicit_lifetime(UserDeletedDestructorInAggregate));
+ static_assert(!__builtin_is_implicit_lifetime(UserDeletedDestructorInNonAggregate));
+ static_assert(__builtin_is_implicit_lifetime(DeletedDestructorViaBaseInAggregate) == __cplusplus >= 201703L);
+ static_assert(!__builtin_is_implicit_lifetime(DeletedDestructorViaBaseInNonAggregate));
+#if __cplusplus >= 202002L
+ static_assert(__builtin_is_implicit_lifetime(ConstrainedUserDeclaredDefaultConstructor<true>));
+ static_assert(!__builtin_is_implicit_lifetime(ConstrainedUserDeclaredDefaultConstructor<false>));
+ static_assert(!__builtin_is_implicit_lifetime(ConstrainedUserProvidedDestructor<true>));
+#endif
}
void is_signed()
>From 5dbfdf514503c45c7071348125c809b6ef13bcce Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 11 Aug 2024 21:55:03 +0300
Subject: [PATCH 4/6] Remove whitespaces
---
clang/lib/Sema/SemaExprCXX.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5fb735600fac5a..17f21f1e650732 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5641,7 +5641,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
case UTT_IsImplicitLifetime: {
DiagnoseVLAInCXXTypeTrait(Self, TInfo,
tok::kw___builtin_is_implicit_lifetime);
-
+
// [basic.types.general] p9
// Scalar types, implicit-lifetime class types ([class.prop]),
// array types, and cv-qualified versions of these types
@@ -5654,7 +5654,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
if (!RD)
return false;
-
+
// [class.prop] p9
// A class S is an implicit-lifetime class if
// - it is an aggregate whose destructor is not user-provided or
>From 5221a00354b294289323151c462c83b585e80656 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 13 Aug 2024 11:54:41 +0300
Subject: [PATCH 5/6] Handle vector types, add tests for various extensions
---
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/test/SemaCXX/type-traits.cpp | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 17f21f1e650732..d8bca391173749 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5649,7 +5649,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
QualType UnqualT = T->getCanonicalTypeUnqualified();
if (UnqualT->isScalarType())
return true;
- if (UnqualT->isArrayType())
+ if (UnqualT->isArrayType() || UnqualT->isVectorType())
return true;
const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
if (!RD)
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index fea6bec7476783..1cd34c263d495e 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2007,6 +2007,17 @@ struct ConstrainedUserProvidedDestructor {
};
#endif
+struct StructWithFAM {
+ int a[];
+};
+
+struct StructWithZeroSizedArray {
+ int a[0];
+};
+
+typedef float float4 __attribute__((vector_type(4)));
+typedef float ext_float4 __attribute__((ext_vector_type(4)));
+
void is_implicit_lifetime(int n) {
static_assert(!__builtin_is_implicit_lifetime(void));
static_assert(!__builtin_is_implicit_lifetime(const void));
@@ -2014,6 +2025,9 @@ void is_implicit_lifetime(int n) {
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(float));
+ static_assert(__builtin_is_implicit_lifetime(double));
+ static_assert(__builtin_is_implicit_lifetime(long double));
static_assert(__builtin_is_implicit_lifetime(int*));
static_assert(__builtin_is_implicit_lifetime(int[]));
static_assert(__builtin_is_implicit_lifetime(int[5]));
@@ -2055,6 +2069,18 @@ void is_implicit_lifetime(int n) {
static_assert(!__builtin_is_implicit_lifetime(ConstrainedUserDeclaredDefaultConstructor<false>));
static_assert(!__builtin_is_implicit_lifetime(ConstrainedUserProvidedDestructor<true>));
#endif
+
+ static_assert(__builtin_is_implicit_lifetime(__int128));
+ static_assert(__builtin_is_implicit_lifetime(_BitInt(8)));
+ static_assert(__builtin_is_implicit_lifetime(_BitInt(128)));
+ static_assert(__builtin_is_implicit_lifetime(int[0]));
+ static_assert(__builtin_is_implicit_lifetime(StructWithFAM));
+ static_assert(__builtin_is_implicit_lifetime(StructWithZeroSizedArray));
+ static_assert(__builtin_is_implicit_lifetime(__fp16));
+ static_assert(__builtin_is_implicit_lifetime(__bf16));
+ static_assert(__builtin_is_implicit_lifetime(_Complex double));
+ static_assert(__builtin_is_implicit_lifetime(float4));
+ static_assert(__builtin_is_implicit_lifetime(ext_float4));
}
void is_signed()
>From 318cc3bd41f3cbf022805874edaacd421dc4de5a Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 13 Aug 2024 13:40:31 +0300
Subject: [PATCH 6/6] So `vector_type` is not a thing
---
clang/test/SemaCXX/type-traits.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 1cd34c263d495e..22a4e3f02e764c 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2015,8 +2015,7 @@ struct StructWithZeroSizedArray {
int a[0];
};
-typedef float float4 __attribute__((vector_type(4)));
-typedef float ext_float4 __attribute__((ext_vector_type(4)));
+typedef float float4 __attribute__((ext_vector_type(4)));
void is_implicit_lifetime(int n) {
static_assert(!__builtin_is_implicit_lifetime(void));
@@ -2080,7 +2079,6 @@ void is_implicit_lifetime(int n) {
static_assert(__builtin_is_implicit_lifetime(__bf16));
static_assert(__builtin_is_implicit_lifetime(_Complex double));
static_assert(__builtin_is_implicit_lifetime(float4));
- static_assert(__builtin_is_implicit_lifetime(ext_float4));
}
void is_signed()
More information about the cfe-commits
mailing list