From eb65a108bd1eb613ed2a9ebfdbd73a9c872f0309 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sat, 30 Apr 2011 10:07:32 +0000 Subject: [PATCH] Extract a function to impose the completeness requirement on unary type 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 | 99 ++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d87752081b..85a65a43a3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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()) -- 2.50.1