[MSVC Compat] Implement __is_destructible, __is_nothrow_destructible

Our implementations of these type trait intrinsics simply mapped them to
__has_trivial_destructor.  Instead, flesh these intrinsics out with a
full implementation which matches the standard's description.

llvm-svn: 244564
This commit is contained in:
David Majnemer 2015-08-11 03:03:28 +00:00
parent 85a549dbc8
commit ac73de9502
2 changed files with 84 additions and 2 deletions

View File

@ -3814,8 +3814,47 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return false;
case UTT_IsDestructible:
case UTT_IsNothrowDestructible:
// FIXME: Implement UTT_IsDestructible and UTT_IsNothrowDestructible.
// For now, let's fall through.
// C++14 [meta.unary.prop]:
// For reference types, is_destructible<T>::value is true.
if (T->isReferenceType())
return true;
// Objective-C++ ARC: autorelease types don't require destruction.
if (T->isObjCLifetimeType() &&
T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
// C++14 [meta.unary.prop]:
// For incomplete types and function types, is_destructible<T>::value is
// false.
if (T->isIncompleteType() || T->isFunctionType())
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
// unevaluated operand (Clause 5), then is_destructible<T>::value is true
if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
CXXDestructorDecl *Destructor = Self.LookupDestructor(RD);
if (!Destructor)
return false;
// C++14 [dcl.fct.def.delete]p2:
// A program that refers to a deleted function implicitly or
// explicitly, other than to declare it, is ill-formed.
if (Destructor->isDeleted())
return false;
if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public)
return false;
if (UTT == UTT_IsNothrowDestructible) {
const FunctionProtoType *CPT =
Destructor->getType()->getAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT || !CPT->isNothrow(C))
return false;
}
}
return true;
case UTT_HasTrivialDestructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
// If __is_pod (type) is true or type is a reference type

View File

@ -150,6 +150,18 @@ struct VariadicCtor {
template<typename...T> VariadicCtor(T...);
};
struct ThrowingDtor {
~ThrowingDtor() throw(int);
};
struct NoExceptDtor {
~NoExceptDtor() noexcept(true);
};
struct NoThrowDtor {
~NoThrowDtor() throw();
};
void is_pod()
{
{ int arr[T(__is_pod(int))]; }
@ -2019,3 +2031,34 @@ void array_extent() {
int t02[T(__array_extent(ConstIntArAr, 0) == 4)];
int t03[T(__array_extent(ConstIntArAr, 1) == 10)];
}
void is_destructible_test() {
{ int arr[T(__is_destructible(int))]; }
{ int arr[T(__is_destructible(int[2]))]; }
{ int arr[F(__is_destructible(int[]))]; }
{ int arr[F(__is_destructible(void))]; }
{ int arr[T(__is_destructible(int &))]; }
{ int arr[T(__is_destructible(HasDest))]; }
{ int arr[F(__is_destructible(AllPrivate))]; }
{ int arr[T(__is_destructible(SuperNonTrivialStruct))]; }
{ int arr[T(__is_destructible(AllDefaulted))]; }
{ int arr[F(__is_destructible(AllDeleted))]; }
{ int arr[T(__is_destructible(ThrowingDtor))]; }
{ int arr[T(__is_destructible(NoThrowDtor))]; }
}
void is_nothrow_destructible_test() {
{ int arr[T(__is_nothrow_destructible(int))]; }
{ int arr[T(__is_nothrow_destructible(int[2]))]; }
{ int arr[F(__is_nothrow_destructible(int[]))]; }
{ int arr[F(__is_nothrow_destructible(void))]; }
{ int arr[T(__is_nothrow_destructible(int &))]; }
{ int arr[T(__is_nothrow_destructible(HasDest))]; }
{ int arr[F(__is_nothrow_destructible(AllPrivate))]; }
{ int arr[T(__is_nothrow_destructible(SuperNonTrivialStruct))]; }
{ int arr[T(__is_nothrow_destructible(AllDefaulted))]; }
{ int arr[F(__is_nothrow_destructible(AllDeleted))]; }
{ int arr[F(__is_nothrow_destructible(ThrowingDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoExceptDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoThrowDtor))]; }
}