}
}
+/// \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())