I've been using !__is_identifier to test for things like that. It seems to be the most consistent way. Is there some problem with this?
/Eric On Thu, Jun 1, 2017 at 6:46 PM, Richard Smith <rich...@metafoo.co.uk> wrote: > On 31 May 2017 at 17:41, Eric Fiselier <e...@efcs.ca> wrote: > >> I'm assuming libc++ should move to this trait instead? >> > > Yes, that'd be a good idea. Though now that you mention it, I'm not sure > we have a good feature detection story for these builtins. Looks like a > bunch of the existing ones are (oddly) covered by __has_feature, and they > can all be discovered through !__is_identifier, but __has_extension or > __has_builtin seem like the right detection mechanism and neither of them > works here. ;-( > > Thoughts? > > >> /Eric >> >> On Wed, May 31, 2017 at 6:28 PM, Richard Smith via cfe-commits < >> cfe-commits@lists.llvm.org> wrote: >> >>> Author: rsmith >>> Date: Wed May 31 19:28:16 2017 >>> New Revision: 304376 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=304376&view=rev >>> Log: >>> PR33232: implement support for MSVC's __is_trivially_destructible trait. >>> >>> Unlike the GCC-compatible __has_trivial_destructor trait, this one >>> computes the >>> right answer rather than performing the quirky set of checks described >>> in GCC's >>> documentation (https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html). >>> >>> MSVC also has a __has_trivial_destructor trait which is the same as its >>> (and >>> now Clang's) __is_trivially_destructible trait; we might want to consider >>> changing the behavior of __has_trivial_destructor if we're targeting an >>> MSVC >>> platform, but I'm not doing so for now. >>> >>> While implementing this I found that we were incorrectly rejecting >>> __is_destructible queries on arrays of unknown bound of incomplete >>> types; that >>> too is fixed, and I've added similar tests for other traits for good >>> measure. >>> >>> Modified: >>> cfe/trunk/include/clang/Basic/TokenKinds.def >>> cfe/trunk/include/clang/Basic/TypeTraits.h >>> cfe/trunk/lib/Sema/SemaExprCXX.cpp >>> cfe/trunk/test/SemaCXX/type-traits.cpp >>> >>> Modified: cfe/trunk/include/clang/Basic/TokenKinds.def >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Basic/TokenKinds.def?rev=304376&r1=304375&r2=304376&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Basic/TokenKinds.def (original) >>> +++ cfe/trunk/include/clang/Basic/TokenKinds.def Wed May 31 19:28:16 >>> 2017 >>> @@ -411,6 +411,7 @@ TYPE_TRAIT_1(__is_sealed, IsSealed, KEYM >>> >>> // MSVC12.0 / VS2013 Type Traits >>> TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) >>> +TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, >>> KEYCXX) >>> TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS) >>> TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX) >>> TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX) >>> @@ -439,7 +440,6 @@ TYPE_TRAIT_2(__is_convertible_to, IsConv >>> TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX) >>> TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX) >>> TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX) >>> -// Tentative name - there's no implementation of std::is_literal_type >>> yet. >>> TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX) >>> // Name for GCC 4.6 compatibility - people have already written >>> libraries using >>> // this name unfortunately. >>> >>> Modified: cfe/trunk/include/clang/Basic/TypeTraits.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Basic/TypeTraits.h?rev=304376&r1=304375&r2=304376&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Basic/TypeTraits.h (original) >>> +++ cfe/trunk/include/clang/Basic/TypeTraits.h Wed May 31 19:28:16 2017 >>> @@ -65,6 +65,7 @@ namespace clang { >>> UTT_IsStandardLayout, >>> UTT_IsTrivial, >>> UTT_IsTriviallyCopyable, >>> + UTT_IsTriviallyDestructible, >>> UTT_IsUnion, >>> UTT_IsUnsigned, >>> UTT_IsVoid, >>> >>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaE >>> xprCXX.cpp?rev=304376&r1=304375&r2=304376&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) >>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed May 31 19:28:16 2017 >>> @@ -4080,24 +4080,23 @@ static bool CheckUnaryTypeTraitTypeCompl >>> Loc, ArgTy, diag::err_incomplete_type_used >>> _in_type_trait_expr); >>> return true; >>> >>> - // C++0x [meta.unary.prop] Table 49 requires the following traits to >>> be >>> - // applied to a complete type. >>> + // C++1z [meta.unary.prop]: >>> + // remove_all_extents_t<T> shall be a complete type or cv void. >>> case UTT_IsAggregate: >>> case UTT_IsTrivial: >>> case UTT_IsTriviallyCopyable: >>> case UTT_IsStandardLayout: >>> case UTT_IsPOD: >>> case UTT_IsLiteral: >>> + ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); >>> + LLVM_FALLTHROUGH; >>> >>> + // C++1z [meta.unary.prop]: >>> + // T shall be a complete type, cv void, or an array of unknown >>> bound. >>> case UTT_IsDestructible: >>> case UTT_IsNothrowDestructible: >>> - // Fall-through >>> - >>> - // These trait expressions are designed to help implement >>> predicates in >>> - // [meta.unary.prop] despite not being named the same. They are >>> specified >>> - // by both GCC and the Embarcadero C++ compiler, and require the >>> complete >>> - // type due to the overarching C++0x type predicates being >>> implemented >>> - // requiring the complete type. >>> + case UTT_IsTriviallyDestructible: >>> + // Per the GCC type traits documentation, the same constraints apply >>> to these. >>> case UTT_HasNothrowAssign: >>> case UTT_HasNothrowMoveAssign: >>> case UTT_HasNothrowConstructor: >>> @@ -4109,17 +4108,11 @@ static bool CheckUnaryTypeTraitTypeCompl >>> case UTT_HasTrivialCopy: >>> case UTT_HasTrivialDestructor: >>> case UTT_HasVirtualDestructor: >>> - // Arrays of unknown bound are expressly allowed. >>> - QualType ElTy = ArgTy; >>> - if (ArgTy->isIncompleteArrayType()) >>> - ElTy = S.Context.getAsArrayType(ArgTy)->getElementType(); >>> - >>> - // The void type is expressly allowed. >>> - if (ElTy->isVoidType()) >>> + if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) >>> return true; >>> >>> return !S.RequireCompleteType( >>> - Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr); >>> + Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); >>> } >>> } >>> >>> @@ -4356,6 +4349,7 @@ static bool EvaluateUnaryTypeTrait(Sema >>> !RD->hasNonTrivialCopyAssignment(); >>> return false; >>> case UTT_IsDestructible: >>> + case UTT_IsTriviallyDestructible: >>> case UTT_IsNothrowDestructible: >>> // C++14 [meta.unary.prop]: >>> // For reference types, is_destructible<T>::value is true. >>> @@ -4373,6 +4367,11 @@ static bool EvaluateUnaryTypeTrait(Sema >>> if (T->isIncompleteType() || T->isFunctionType()) >>> return false; >>> >>> + // A type that requires destruction (via a non-trivial destructor >>> or ARC >>> + // lifetime semantics) is not trivially-destructible. >>> + if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType()) >>> + return false; >>> + >>> // C++14 [meta.unary.prop]: >>> // For object types and given U equal to remove_all_extents_t<T>, >>> if the >>> // expression std::declval<U&>().~U() is well-formed when treated >>> as an >>> >>> Modified: cfe/trunk/test/SemaCXX/type-traits.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/t >>> ype-traits.cpp?rev=304376&r1=304375&r2=304376&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) >>> +++ cfe/trunk/test/SemaCXX/type-traits.cpp Wed May 31 19:28:16 2017 >>> @@ -252,6 +252,11 @@ void is_pod() >>> { int arr[F(__is_pod(void))]; } >>> { int arr[F(__is_pod(cvoid))]; } >>> // { int arr[F(__is_pod(NonPODUnion))]; } >>> + >>> + { int arr[T(__is_pod(ACompleteType))]; } >>> + { int arr[F(__is_pod(AnIncompleteType))]; } // expected-error >>> {{incomplete type}} >>> + { int arr[F(__is_pod(AnIncompleteType[]))]; } // expected-error >>> {{incomplete type}} >>> + { int arr[F(__is_pod(AnIncompleteType[1]))]; } // expected-error >>> {{incomplete type}} >>> } >>> >>> typedef Empty EmptyAr[10]; >>> @@ -287,6 +292,11 @@ void is_empty() >>> { int arr[F(__is_empty(IntArNB))]; } >>> { int arr[F(__is_empty(HasAnonymousUnion))]; } >>> // { int arr[F(__is_empty(DerivesVirt))]; } >>> + >>> + { int arr[T(__is_empty(ACompleteType))]; } >>> + { int arr[F(__is_empty(AnIncompleteType))]; } // expected-error >>> {{incomplete type}} >>> + { int arr[F(__is_empty(AnIncompleteType[]))]; } >>> + { int arr[F(__is_empty(AnIncompleteType[1]))]; } >>> } >>> >>> typedef Derives ClassType; >>> @@ -511,6 +521,8 @@ void is_aggregate() >>> constexpr bool TrueAfterCpp14 = __cplusplus > 201402L; >>> >>> __is_aggregate(AnIncompleteType); // expected-error {{incomplete >>> type}} >>> + __is_aggregate(AnIncompleteType[]); // expected-error {{incomplete >>> type}} >>> + __is_aggregate(AnIncompleteType[1]); // expected-error {{incomplete >>> type}} >>> __is_aggregate(AnIncompleteTypeAr); // expected-error {{incomplete >>> type}} >>> __is_aggregate(AnIncompleteTypeArNB); // expected-error {{incomplete >>> type}} >>> __is_aggregate(AnIncompleteTypeArMB); // expected-error {{incomplete >>> type}} >>> @@ -1220,6 +1232,13 @@ void is_trivial2() >>> int t32[F(__is_trivial(SuperNonTrivialStruct))]; >>> int t33[F(__is_trivial(NonTCStruct))]; >>> int t34[F(__is_trivial(ExtDefaulted))]; >>> + >>> + int t40[T(__is_trivial(ACompleteType))]; >>> + int t41[F(__is_trivial(AnIncompleteType))]; // expected-error >>> {{incomplete type}} >>> + int t42[F(__is_trivial(AnIncompleteType[]))]; // expected-error >>> {{incomplete type}} >>> + int t43[F(__is_trivial(AnIncompleteType[1]))]; // expected-error >>> {{incomplete type}} >>> + int t44[F(__is_trivial(void))]; >>> + int t45[F(__is_trivial(const volatile void))]; >>> } >>> >>> void is_trivially_copyable2() >>> @@ -1257,6 +1276,13 @@ void is_trivially_copyable2() >>> >>> int t34[T(__is_trivially_copyable(const int))]; >>> int t35[T(__is_trivially_copyable(volatile int))]; >>> + >>> + int t40[T(__is_trivially_copyable(ACompleteType))]; >>> + int t41[F(__is_trivially_copyable(AnIncompleteType))]; // >>> expected-error {{incomplete type}} >>> + int t42[F(__is_trivially_copyable(AnIncompleteType[]))]; // >>> expected-error {{incomplete type}} >>> + int t43[F(__is_trivially_copyable(AnIncompleteType[1]))]; // >>> expected-error {{incomplete type}} >>> + int t44[F(__is_trivially_copyable(void))]; >>> + int t45[F(__is_trivially_copyable(const volatile void))]; >>> } >>> >>> struct CStruct { >>> @@ -1320,6 +1346,13 @@ void is_standard_layout() >>> int t15[F(__is_standard_layout(CppStructNonStandardByBaseAr))]; >>> int t16[F(__is_standard_layout(CppStructNonStandardBySameBase))]; >>> int t17[F(__is_standard_layout(CppStructNonStandardBy2ndVirtBase))]; >>> + >>> + int t40[T(__is_standard_layout(ACompleteType))]; >>> + int t41[F(__is_standard_layout(AnIncompleteType))]; // >>> expected-error {{incomplete type}} >>> + int t42[F(__is_standard_layout(AnIncompleteType[]))]; // >>> expected-error {{incomplete type}} >>> + int t43[F(__is_standard_layout(AnIncompleteType[1]))]; // >>> expected-error {{incomplete type}} >>> + int t44[F(__is_standard_layout(void))]; >>> + int t45[F(__is_standard_layout(const volatile void))]; >>> } >>> >>> void is_signed() >>> @@ -2133,6 +2166,13 @@ void trivial_checks() >>> TrivialMoveButNotCopy)))]; } >>> { int arr[T((__is_assignable(TrivialMoveButNotCopy &, >>> TrivialMoveButNotCopy &&)))]; } >>> + >>> + { int arr[T(__is_assignable(ACompleteType, ACompleteType))]; } >>> + { int arr[F(__is_assignable(AnIncompleteType, AnIncompleteType))]; } >>> // expected-error {{incomplete type}} >>> + { int arr[F(__is_assignable(AnIncompleteType[], >>> AnIncompleteType[]))]; } >>> + { int arr[F(__is_assignable(AnIncompleteType[1], >>> AnIncompleteType[1]))]; } // expected-error {{incomplete type}} >>> + { int arr[F(__is_assignable(void, void))]; } >>> + { int arr[F(__is_assignable(const volatile void, const volatile >>> void))]; } >>> } >>> >>> void constructible_checks() { >>> @@ -2164,6 +2204,19 @@ void constructible_checks() { >>> >>> // PR25513 >>> { int arr[F(__is_constructible(int(int)))]; } >>> + >>> + { int arr[T(__is_constructible(ACompleteType))]; } >>> + { int arr[T(__is_nothrow_constructible(ACompleteType))]; } >>> + { int arr[F(__is_constructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_nothrow_constructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_constructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_nothrow_constructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_constructible(AnIncompleteType[1]))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_nothrow_constructible(AnIncompleteType[1]))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_constructible(void))]; } >>> + { int arr[F(__is_nothrow_constructible(void))]; } >>> + { int arr[F(__is_constructible(const volatile void))]; } >>> + { int arr[F(__is_nothrow_constructible(const volatile void))]; } >>> } >>> >>> // Instantiation of __is_trivially_constructible >>> @@ -2192,6 +2245,13 @@ void is_trivially_constructible_test() { >>> { int arr[F((is_trivially_constructible<NonTrivialDefault>::value))]; >>> } >>> { int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, >>> int&>::value))]; } >>> { int arr[F((is_trivially_constructible<Abstract>::value))]; } // >>> PR19178 >>> + >>> + { int arr[T(__is_trivially_constructible(ACompleteType))]; } >>> + { int arr[F(__is_trivially_constructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_trivially_constructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_trivially_constructible(AnIncompleteType[1]))]; } >>> // expected-error {{incomplete type}} >>> + { int arr[F(__is_trivially_constructible(void))]; } >>> + { int arr[F(__is_trivially_constructible(const volatile void))]; } >>> } >>> >>> void array_rank() { >>> @@ -2218,6 +2278,13 @@ void is_destructible_test() { >>> { int arr[F(__is_destructible(AllDeleted))]; } >>> { int arr[T(__is_destructible(ThrowingDtor))]; } >>> { int arr[T(__is_destructible(NoThrowDtor))]; } >>> + >>> + { int arr[T(__is_destructible(ACompleteType))]; } >>> + { int arr[F(__is_destructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_destructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_destructible(AnIncompleteType[1]))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_destructible(void))]; } >>> + { int arr[F(__is_destructible(const volatile void))]; } >>> } >>> >>> void is_nothrow_destructible_test() { >>> @@ -2234,4 +2301,33 @@ void is_nothrow_destructible_test() { >>> { int arr[F(__is_nothrow_destructible(ThrowingDtor))]; } >>> { int arr[T(__is_nothrow_destructible(NoExceptDtor))]; } >>> { int arr[T(__is_nothrow_destructible(NoThrowDtor))]; } >>> + >>> + { int arr[T(__is_nothrow_destructible(ACompleteType))]; } >>> + { int arr[F(__is_nothrow_destructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_nothrow_destructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_nothrow_destructible(AnIncompleteType[1]))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_nothrow_destructible(void))]; } >>> + { int arr[F(__is_nothrow_destructible(const volatile void))]; } >>> +} >>> + >>> +void is_trivially_destructible_test() { >>> + { int arr[T(__is_trivially_destructible(int))]; } >>> + { int arr[T(__is_trivially_destructible(int[2]))]; } >>> + { int arr[F(__is_trivially_destructible(int[]))]; } >>> + { int arr[F(__is_trivially_destructible(void))]; } >>> + { int arr[T(__is_trivially_destructible(int &))]; } >>> + { int arr[F(__is_trivially_destructible(HasDest))]; } >>> + { int arr[F(__is_trivially_destructible(AllPrivate))]; } >>> + { int arr[F(__is_trivially_destructible(SuperNonTrivialStruct))]; } >>> + { int arr[T(__is_trivially_destructible(AllDefaulted))]; } >>> + { int arr[F(__is_trivially_destructible(AllDeleted))]; } >>> + { int arr[F(__is_trivially_destructible(ThrowingDtor))]; } >>> + { int arr[F(__is_trivially_destructible(NoThrowDtor))]; } >>> + >>> + { int arr[T(__is_trivially_destructible(ACompleteType))]; } >>> + { int arr[F(__is_trivially_destructible(AnIncompleteType))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_trivially_destructible(AnIncompleteType[]))]; } >>> + { int arr[F(__is_trivially_destructible(AnIncompleteType[1]))]; } // >>> expected-error {{incomplete type}} >>> + { int arr[F(__is_trivially_destructible(void))]; } >>> + { int arr[F(__is_trivially_destructible(const volatile void))]; } >>> } >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >> >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits