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.

llvm-svn: 304376
This commit is contained in:
Richard Smith 2017-06-01 00:28:16 +00:00
parent 32c5e809be
commit f03e9084c1
4 changed files with 114 additions and 18 deletions

View File

@ -411,6 +411,7 @@ TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
// MSVC12.0 / VS2013 Type Traits // MSVC12.0 / VS2013 Type Traits
TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS) 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_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS)
TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX) TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX) TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
@ -439,7 +440,6 @@ TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX)
TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX) TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX)
TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX) TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX)
TYPE_TRAIT_1(__is_final, IsFinal, 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) TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using // Name for GCC 4.6 compatibility - people have already written libraries using
// this name unfortunately. // this name unfortunately.

View File

@ -65,6 +65,7 @@ namespace clang {
UTT_IsStandardLayout, UTT_IsStandardLayout,
UTT_IsTrivial, UTT_IsTrivial,
UTT_IsTriviallyCopyable, UTT_IsTriviallyCopyable,
UTT_IsTriviallyDestructible,
UTT_IsUnion, UTT_IsUnion,
UTT_IsUnsigned, UTT_IsUnsigned,
UTT_IsVoid, UTT_IsVoid,

View File

@ -4080,24 +4080,23 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
return true; return true;
// C++0x [meta.unary.prop] Table 49 requires the following traits to be // C++1z [meta.unary.prop]:
// applied to a complete type. // remove_all_extents_t<T> shall be a complete type or cv void.
case UTT_IsAggregate: case UTT_IsAggregate:
case UTT_IsTrivial: case UTT_IsTrivial:
case UTT_IsTriviallyCopyable: case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout: case UTT_IsStandardLayout:
case UTT_IsPOD: case UTT_IsPOD:
case UTT_IsLiteral: 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_IsDestructible:
case UTT_IsNothrowDestructible: case UTT_IsNothrowDestructible:
// Fall-through case UTT_IsTriviallyDestructible:
// Per the GCC type traits documentation, the same constraints apply to these.
// 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_HasNothrowAssign: case UTT_HasNothrowAssign:
case UTT_HasNothrowMoveAssign: case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor: case UTT_HasNothrowConstructor:
@ -4109,17 +4108,11 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialCopy: case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor: case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor: case UTT_HasVirtualDestructor:
// Arrays of unknown bound are expressly allowed. if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
QualType ElTy = ArgTy;
if (ArgTy->isIncompleteArrayType())
ElTy = S.Context.getAsArrayType(ArgTy)->getElementType();
// The void type is expressly allowed.
if (ElTy->isVoidType())
return true; return true;
return !S.RequireCompleteType( 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 &Self, TypeTrait UTT,
!RD->hasNonTrivialCopyAssignment(); !RD->hasNonTrivialCopyAssignment();
return false; return false;
case UTT_IsDestructible: case UTT_IsDestructible:
case UTT_IsTriviallyDestructible:
case UTT_IsNothrowDestructible: case UTT_IsNothrowDestructible:
// C++14 [meta.unary.prop]: // C++14 [meta.unary.prop]:
// For reference types, is_destructible<T>::value is true. // For reference types, is_destructible<T>::value is true.
@ -4373,6 +4367,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (T->isIncompleteType() || T->isFunctionType()) if (T->isIncompleteType() || T->isFunctionType())
return false; 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]: // C++14 [meta.unary.prop]:
// For object types and given U equal to remove_all_extents_t<T>, if the // 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 // expression std::declval<U&>().~U() is well-formed when treated as an

View File

@ -252,6 +252,11 @@ void is_pod()
{ int arr[F(__is_pod(void))]; } { int arr[F(__is_pod(void))]; }
{ int arr[F(__is_pod(cvoid))]; } { int arr[F(__is_pod(cvoid))]; }
// { int arr[F(__is_pod(NonPODUnion))]; } // { 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]; typedef Empty EmptyAr[10];
@ -287,6 +292,11 @@ void is_empty()
{ int arr[F(__is_empty(IntArNB))]; } { int arr[F(__is_empty(IntArNB))]; }
{ int arr[F(__is_empty(HasAnonymousUnion))]; } { int arr[F(__is_empty(HasAnonymousUnion))]; }
// { int arr[F(__is_empty(DerivesVirt))]; } // { 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; typedef Derives ClassType;
@ -511,6 +521,8 @@ void is_aggregate()
constexpr bool TrueAfterCpp14 = __cplusplus > 201402L; constexpr bool TrueAfterCpp14 = __cplusplus > 201402L;
__is_aggregate(AnIncompleteType); // expected-error {{incomplete type}} __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(AnIncompleteTypeAr); // expected-error {{incomplete type}}
__is_aggregate(AnIncompleteTypeArNB); // expected-error {{incomplete type}} __is_aggregate(AnIncompleteTypeArNB); // expected-error {{incomplete type}}
__is_aggregate(AnIncompleteTypeArMB); // 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 t32[F(__is_trivial(SuperNonTrivialStruct))];
int t33[F(__is_trivial(NonTCStruct))]; int t33[F(__is_trivial(NonTCStruct))];
int t34[F(__is_trivial(ExtDefaulted))]; 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() void is_trivially_copyable2()
@ -1257,6 +1276,13 @@ void is_trivially_copyable2()
int t34[T(__is_trivially_copyable(const int))]; int t34[T(__is_trivially_copyable(const int))];
int t35[T(__is_trivially_copyable(volatile 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 { struct CStruct {
@ -1320,6 +1346,13 @@ void is_standard_layout()
int t15[F(__is_standard_layout(CppStructNonStandardByBaseAr))]; int t15[F(__is_standard_layout(CppStructNonStandardByBaseAr))];
int t16[F(__is_standard_layout(CppStructNonStandardBySameBase))]; int t16[F(__is_standard_layout(CppStructNonStandardBySameBase))];
int t17[F(__is_standard_layout(CppStructNonStandardBy2ndVirtBase))]; 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() void is_signed()
@ -2133,6 +2166,13 @@ void trivial_checks()
TrivialMoveButNotCopy)))]; } TrivialMoveButNotCopy)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &, { int arr[T((__is_assignable(TrivialMoveButNotCopy &,
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() { void constructible_checks() {
@ -2164,6 +2204,19 @@ void constructible_checks() {
// PR25513 // PR25513
{ int arr[F(__is_constructible(int(int)))]; } { 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 // 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<NonTrivialDefault>::value))]; }
{ int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; } { int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; }
{ int arr[F((is_trivially_constructible<Abstract>::value))]; } // PR19178 { 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() { void array_rank() {
@ -2218,6 +2278,13 @@ void is_destructible_test() {
{ int arr[F(__is_destructible(AllDeleted))]; } { int arr[F(__is_destructible(AllDeleted))]; }
{ int arr[T(__is_destructible(ThrowingDtor))]; } { int arr[T(__is_destructible(ThrowingDtor))]; }
{ int arr[T(__is_destructible(NoThrowDtor))]; } { 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() { void is_nothrow_destructible_test() {
@ -2234,4 +2301,33 @@ void is_nothrow_destructible_test() {
{ int arr[F(__is_nothrow_destructible(ThrowingDtor))]; } { int arr[F(__is_nothrow_destructible(ThrowingDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoExceptDtor))]; } { int arr[T(__is_nothrow_destructible(NoExceptDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoThrowDtor))]; } { 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))]; }
} }