]> granicus.if.org Git - clang/commitdiff
[Sema] Implement several unary type traits more accurately
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 16 Nov 2015 06:58:51 +0000 (06:58 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 16 Nov 2015 06:58:51 +0000 (06:58 +0000)
is_empty, is_polymorphic, and is_abstract didn't handle incomplete types
correctly.  Only non-union class types must be complete for these
traits.

is_final and is_sealed don't care about the particular spelling of the
FinalAttr.

is_interface_class should always return false regardless of its input.
The type trait can only be satisfied in a mode we do not support (/CLR).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@253184 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExprCXX.cpp
test/SemaCXX/abstract.cpp
test/SemaCXX/ms-interface.cpp
test/SemaCXX/type-traits.cpp

index 4b7db59444b23ebdfc24b9d09557ca9714f67d83..da34791395be172f6f950f5d88560031525081a0 100644 (file)
@@ -3550,27 +3550,43 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   case UTT_IsVolatile:
   case UTT_IsSigned:
   case UTT_IsUnsigned:
+
+  // This type trait always returns false, checking the type is moot.
+  case UTT_IsInterfaceClass:
+    return true;
+
+  // C++14 [meta.unary.prop]:
+  //   If T is a non-union class type, T shall be a complete type.
+  case UTT_IsEmpty:
+  case UTT_IsPolymorphic:
+  case UTT_IsAbstract:
+    if (const auto *RD = ArgTy->getAsCXXRecordDecl())
+      if (!RD->isUnion())
+        return !S.RequireCompleteType(
+            Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+    return true;
+
+  // C++14 [meta.unary.prop]:
+  //   If T is a class type, T shall be a complete type.
+  case UTT_IsFinal:
+  case UTT_IsSealed:
+    if (ArgTy->getAsCXXRecordDecl())
+      return !S.RequireCompleteType(
+          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++0x [meta.unary.prop] Table 49 requires the following traits to be
+  // applied to a complete type.
   case UTT_IsTrivial:
   case UTT_IsTriviallyCopyable:
   case UTT_IsStandardLayout:
   case UTT_IsPOD:
   case UTT_IsLiteral:
-  case UTT_IsEmpty:
-  case UTT_IsPolymorphic:
-  case UTT_IsAbstract:
-  case UTT_IsInterfaceClass:
+
   case UTT_IsDestructible:
   case UTT_IsNothrowDestructible:
     // Fall-through
 
-  // These traits require a complete type.
-  case UTT_IsFinal:
-  case UTT_IsSealed:
-
     // 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
@@ -3729,24 +3745,21 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     return false;
   case UTT_IsPolymorphic:
     if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->isPolymorphic();
+      return !RD->isUnion() && RD->isPolymorphic();
     return false;
   case UTT_IsAbstract:
     if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->isAbstract();
+      return !RD->isUnion() && RD->isAbstract();
     return false;
+  // __is_interface_class only returns true when CL is invoked in /CLR mode and
+  // even then only when it is used with the 'interface struct ...' syntax
+  // Clang doesn't support /CLR which makes this type trait moot.
   case UTT_IsInterfaceClass:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->isInterface();
     return false;
   case UTT_IsFinal:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->hasAttr<FinalAttr>();
-    return false;
   case UTT_IsSealed:
     if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      if (FinalAttr *FA = RD->getAttr<FinalAttr>())
-        return FA->isSpelledAsSealed();
+      return RD->hasAttr<FinalAttr>();
     return false;
   case UTT_IsSigned:
     return T->isSignedIntegerType();
index b521196c23b652368b6073403a115823767f87d5..ffd36be5b7970c52dc894339f7757f6508b283eb 100644 (file)
@@ -8,6 +8,10 @@
   typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
 #endif
 
+union IncompleteUnion;
+
+static_assert(!__is_abstract(IncompleteUnion), "unions are never abstract");
+
 class C {
   virtual void f() = 0; // expected-note {{unimplemented pure virtual method 'f'}}
 };
index e7386ce5b8e7b1751552caa09082fb2f728dd99e..4a1c13ddcbbae5d34cdf5b23efe71939051e9b42 100644 (file)
@@ -58,10 +58,12 @@ __interface I6 : X {
 struct S { };
 class C { };
 __interface I { };
+union U;
 
 static_assert(!__is_interface_class(S), "oops");
 static_assert(!__is_interface_class(C), "oops");
-static_assert(__is_interface_class(I), "oops");
+static_assert(!__is_interface_class(I), "oops");
+static_assert(!__is_interface_class(U), "oops");
 
 // expected-error@55 {{interface type cannot inherit from 'struct S'}}
 // expected-note@+1 {{in instantiation of template class 'I6<S>' requested here}}
index 7c64aec9cb4f8789fa992905e13788fefc474551..69760fd6bd068762e46a63f3545e6a593909f9ed 100644 (file)
@@ -14,6 +14,7 @@ typedef Int IntAr[10];
 typedef Int IntArNB[];
 class Statics { static int priv; static NonPOD np; };
 union EmptyUnion {};
+union IncompleteUnion;
 union Union { int i; float f; };
 struct HasFunc { void f (); };
 struct HasOp { void operator *(); };
@@ -235,6 +236,7 @@ void is_empty()
   { int arr[F(__is_empty(Int))]; }
   { int arr[F(__is_empty(POD))]; }
   { int arr[F(__is_empty(EmptyUnion))]; }
+  { int arr[F(__is_empty(IncompleteUnion))]; }
   { int arr[F(__is_empty(EmptyAr))]; }
   { int arr[F(__is_empty(HasRef))]; }
   { int arr[F(__is_empty(HasVirt))]; }
@@ -313,8 +315,23 @@ struct PotentiallyFinal<T*> final { };
 template<>
 struct PotentiallyFinal<int> final { };
 
+struct SealedClass sealed {
+};
+
+template<typename T>
+struct PotentiallySealed { };
+
+template<typename T>
+struct PotentiallySealed<T*> sealed { };
+
+template<>
+struct PotentiallySealed<int> sealed { };
+
 void is_final()
 {
+       { int arr[T(__is_final(SealedClass))]; }
+       { int arr[T(__is_final(PotentiallySealed<float*>))]; }
+       { int arr[T(__is_final(PotentiallySealed<int>))]; }
        { int arr[T(__is_final(FinalClass))]; }
        { int arr[T(__is_final(PotentiallyFinal<float*>))]; }
        { int arr[T(__is_final(PotentiallyFinal<int>))]; }
@@ -330,25 +347,17 @@ void is_final()
        { int arr[F(__is_final(IntArNB))]; }
        { int arr[F(__is_final(HasAnonymousUnion))]; }
        { int arr[F(__is_final(PotentiallyFinal<float>))]; }
+       { int arr[F(__is_final(PotentiallySealed<float>))]; }
 }
 
-struct SealedClass sealed {
-};
-
-template<typename T>
-struct PotentiallySealed { };
-
-template<typename T>
-struct PotentiallySealed<T*> sealed { };
-
-template<>
-struct PotentiallySealed<int> sealed { };
-
 void is_sealed()
 {
        { int arr[T(__is_sealed(SealedClass))]; }
        { int arr[T(__is_sealed(PotentiallySealed<float*>))]; }
        { int arr[T(__is_sealed(PotentiallySealed<int>))]; }
+       { int arr[T(__is_sealed(FinalClass))]; }
+       { int arr[T(__is_sealed(PotentiallyFinal<float*>))]; }
+       { int arr[T(__is_sealed(PotentiallyFinal<int>))]; }
 
        { int arr[F(__is_sealed(int))]; }
        { int arr[F(__is_sealed(Union))]; }
@@ -361,6 +370,7 @@ void is_sealed()
        { int arr[F(__is_sealed(IntArNB))]; }
        { int arr[F(__is_sealed(HasAnonymousUnion))]; }
        { int arr[F(__is_sealed(PotentiallyFinal<float>))]; }
+       { int arr[F(__is_sealed(PotentiallySealed<float>))]; }
 }
 
 typedef HasVirt Polymorph;
@@ -373,6 +383,7 @@ void is_polymorphic()
 
   { int arr[F(__is_polymorphic(int))]; }
   { int arr[F(__is_polymorphic(Union))]; }
+  { int arr[F(__is_polymorphic(IncompleteUnion))]; }
   { int arr[F(__is_polymorphic(Int))]; }
   { int arr[F(__is_polymorphic(IntAr))]; }
   { int arr[F(__is_polymorphic(UnionAr))]; }