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/ >> type-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