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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed May 31 17:28:17 PDT 2017


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/SemaExprCXX.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))]; }
 }




More information about the cfe-commits mailing list