r304376 - PR33232: implement support for MSVC's __is_trivially_destructible trait.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 2 13:44:45 PDT 2017


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 <richard at metafoo.co.uk> wrote:

> On 31 May 2017 at 17:41, Eric Fiselier <eric at 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 at 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 at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170602/edb42c26/attachment-0001.html>


More information about the cfe-commits mailing list