[MSVC Compat] Implement __is_destructible, __is_nothrow_destructible
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 11 Aug 2015 03:03:28 +0000 (03:03 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 11 Aug 2015 03:03:28 +0000 (03:03 +0000)
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

clang/lib/Sema/SemaExprCXX.cpp
clang/test/SemaCXX/type-traits.cpp

index 9dce817..f7103c8 100644 (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
index 2265c28..d8b40e3 100644 (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))]; }
+}