]> granicus.if.org Git - clang/commitdiff
Extract a function to impose the completeness requirement on unary type
authorChandler Carruth <chandlerc@gmail.com>
Sat, 30 Apr 2011 10:07:32 +0000 (10:07 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 30 Apr 2011 10:07:32 +0000 (10:07 +0000)
trait arguments. Reflow the logic to use early exit instead of a complex
condition expression. Switch to a switch for acting on different type
traits and add a bunch of the recently implemented type traits here.
This fixes one of the regressions with the new __is_standard_layout
trait to again require a complete type. It also fixes some latent bugs
in other traits that never did impose this despite the standard
requiring it. However, all these bugs were hidden for non-borland
systems where the default is to require a complete type.

It's unclear to me what the best approach here is: providing an explicit
lists for the ones requiring complete types only w/ Borland and using
a default for the rest, or forcing this switch to enumerate the traits
and make it clear which way each one goes.

I'm still working on cleaning up the tests so that they actually catch
this, a much more comprehensive update to the tests will come once I've
worked through the bugs I'm finding via inspection.

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

lib/Sema/SemaExprCXX.cpp

index d87752081b3bbbb3295238b46e673e715abf7bfd..85a65a43a3817f57fa7b07c7a76e90b175cde6bf 100644 (file)
@@ -2628,34 +2628,87 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
   }
 }
 
+/// \brief Check the completeness of a type in a unary type trait.
+///
+/// If the particular type trait requires a complete type, tries to complete
+/// it. If completing the type fails, a diagnostic is emitted and false
+/// returned. If completing the type succeeds or no completion was required,
+/// returns true.
+static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
+                                                UnaryTypeTrait UTT,
+                                                SourceLocation Loc,
+                                                QualType ArgTy) {
+  // C++0x [meta.unary.prop]p3:
+  //   For all of the class templates X declared in this Clause, instantiating
+  //   that template with a template argument that is a class template
+  //   specialization may result in the implicit instantiation of the template
+  //   argument if and only if the semantics of X require that the argument
+  //   must be a complete type.
+  // We apply this rule to all the type trait expressions used to implement
+  // these class templates. We also try to follow any GCC documented behavior
+  // in these expressions to ensure portability of standard libraries.
+  switch (UTT) {
+    // is_complete_type somewhat obviously cannot require a complete type.
+  case UTT_IsCompleteType:
+    return true;
+
+    // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+    // all traits except __is_class, __is_enum and __is_union require a the type
+    // to be complete, an array of unknown bound, or void.
+  case UTT_IsClass:
+  case UTT_IsEnum:
+  case UTT_IsUnion:
+    return true;
+
+  default:
+    // Apprantely Borland only wants the explicitly listed traits to complete
+    // the type.
+    if (S.LangOpts.Borland) return true;
+
+    // C++0x [meta.unary.prop] Table 49 requires the following traits to be
+    // applied to a complete type, so we enumerate theme here even though the
+    // default for non-Borland compilers is to require completeness for any
+    // other traits than the ones specifically allowed to work on incomplete
+    // types.
+    // FIXME: C++0x: This list is incomplete, and the names don't always
+    // correspond clearly to entries in the standard's table.
+  case UTT_HasNothrowAssign:
+  case UTT_HasNothrowConstructor:
+  case UTT_HasNothrowCopy:
+  case UTT_HasTrivialAssign:
+  case UTT_HasTrivialConstructor:
+  case UTT_HasTrivialCopy:
+  case UTT_HasTrivialDestructor:
+  case UTT_HasVirtualDestructor:
+  case UTT_IsAbstract:
+  case UTT_IsEmpty:
+  case UTT_IsLiteral:
+  case UTT_IsPOD:
+  case UTT_IsPolymorphic:
+  case UTT_IsStandardLayout:
+  case UTT_IsTrivial:
+    // 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())
+      return true;
+
+    return !S.RequireCompleteType(
+      Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr);
+  }
+}
+
+
 ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT,
                                      SourceLocation KWLoc,
                                      TypeSourceInfo *TSInfo,
                                      SourceLocation RParen) {
   QualType T = TSInfo->getType();
-
-  // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
-  // all traits except __is_class, __is_enum and __is_union require a the type
-  // to be complete, an array of unknown bound, or void.
-  if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion &&
-      UTT != UTT_IsCompleteType) {
-    QualType E = T;
-    if (T->isIncompleteArrayType())
-      E = Context.getAsArrayType(T)->getElementType();
-    if (!T->isVoidType() &&
-        (! LangOpts.Borland ||
-         UTT == UTT_HasNothrowAssign ||
-         UTT == UTT_HasNothrowCopy ||
-         UTT == UTT_HasNothrowConstructor ||
-         UTT == UTT_HasTrivialAssign ||
-         UTT == UTT_HasTrivialCopy ||
-         UTT == UTT_HasTrivialConstructor ||
-         UTT == UTT_HasTrivialDestructor ||
-         UTT == UTT_HasVirtualDestructor) &&
-        RequireCompleteType(KWLoc, E,
-                            diag::err_incomplete_type_used_in_type_trait_expr))
-      return ExprError();
-  }
+  if (!CheckUnaryTypeTraitTypeCompleteness(*this, UTT, KWLoc, T))
+    return ExprError();
 
   bool Value = false;
   if (!T->isDependentType())