aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Type.cpp34
-rw-r--r--lib/Sema/SemaDecl.cpp14
-rw-r--r--lib/Sema/SemaDeclCXX.cpp408
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp22
-rw-r--r--lib/Sema/SemaType.cpp112
5 files changed, 553 insertions, 37 deletions
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7471a3da5d..a2c6954d75 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1134,29 +1134,19 @@ bool Type::isLiteralType() const {
return true;
// -- a class type that has all of the following properties:
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ // -- a trivial destructor,
+ // -- every constructor call and full-expression in the
+ // brace-or-equal-initializers for non-static data members (if any)
+ // is a constant expression,
+ // -- it is an aggregate type or has at least one constexpr
+ // constructor or constructor template that is not a copy or move
+ // constructor, and
+ // -- all non-static data members and base classes of literal types
+ //
+ // We resolve DR1361 by ignoring the second bullet.
if (const CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // -- a trivial destructor,
- if (!ClassDecl->hasTrivialDestructor())
- return false;
-
- // -- every constructor call and full-expression in the
- // brace-or-equal-initializers for non-static data members (if any)
- // is a constant expression,
- // We deliberately do not implement this restriction. It isn't necessary
- // and doesn't make any sense.
-
- // -- it is an aggregate type or has at least one constexpr
- // constructor or constructor template that is not a copy or move
- // constructor, and
- if (!ClassDecl->isAggregate() &&
- !ClassDecl->hasConstexprNonCopyMoveConstructor())
- return false;
-
- // -- all non-static data members and base classes of literal types
- if (ClassDecl->hasNonLiteralTypeFieldsOrBases())
- return false;
- }
+ dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ return ClassDecl->isLiteral();
return true;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 942c1bc5c2..f4b6ce92e5 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4770,15 +4770,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// are implicitly inline.
NewFD->setImplicitlyInline();
- // FIXME: If this is a redeclaration, check the original declaration was
- // marked constepr.
-
// C++0x [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
if (isa<CXXDestructorDecl>(NewFD))
- Diag(D.getDeclSpec().getConstexprSpecLoc(),
- diag::err_constexpr_dtor);
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
}
// If __module_private__ was specified, mark the function accordingly.
@@ -5050,6 +5046,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
+ !CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
+ NewFD->setInvalidDecl();
+
NamedDecl *PrincipalDecl = (FunctionTemplate
? cast<NamedDecl>(FunctionTemplate)
: NewFD);
@@ -6963,6 +6963,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
ActivePolicy = &WP;
}
+ if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+ !CheckConstexprFunctionBody(FD, Body))
+ FD->setInvalidDecl();
+
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ae31e61c43..73fd18889e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -502,6 +502,20 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
+ // C++0x [dcl.constexpr]p1: If any declaration of a function or function
+ // template has a constexpr specifier then all its declarations shall
+ // contain the constexpr specifier. [Note: An explicit specialization can
+ // differ from the template declaration with respect to the constexpr
+ // specifier. -- end note]
+ //
+ // FIXME: Don't reject changes in constexpr in explicit specializations.
+ if (New->isConstexpr() != Old->isConstexpr()) {
+ Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+ << New << New->isConstexpr();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ Invalid = true;
+ }
+
if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
@@ -602,6 +616,359 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
}
}
+// CheckConstexprParameterTypes - Check whether a function's parameter types
+// are all literal types. If so, return true. If not, produce a suitable
+// diagnostic depending on @p CCK and return false.
+static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
+ Sema::CheckConstexprKind CCK) {
+ unsigned ArgIndex = 0;
+ const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
+ for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
+ e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) {
+ const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
+ SourceLocation ParamLoc = PD->getLocation();
+ if (!(*i)->isDependentType() &&
+ SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
+ SemaRef.PDiag(diag::err_constexpr_non_literal_param)
+ << ArgIndex+1 << PD->getSourceRange()
+ << isa<CXXConstructorDecl>(FD) :
+ SemaRef.PDiag(),
+ /*AllowIncompleteType*/ true)) {
+ if (CCK == Sema::CCK_NoteNonConstexprInstantiation)
+ SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param)
+ << ArgIndex+1 << PD->getSourceRange()
+ << isa<CXXConstructorDecl>(FD) << *i;
+ return false;
+ }
+ }
+ return true;
+}
+
+// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
+// the requirements of a constexpr function declaration or a constexpr
+// constructor declaration. Return true if it does, false if not.
+//
+// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308.
+//
+// \param CCK Specifies whether to produce diagnostics if the function does not
+// satisfy the requirements.
+bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
+ CheckConstexprKind CCK) {
+ assert((CCK != CCK_NoteNonConstexprInstantiation ||
+ (NewFD->getTemplateInstantiationPattern() &&
+ NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
+ "only constexpr templates can be instantiated non-constexpr");
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ // C++0x [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor, each of the parameter
+ // types shall be a literal type.
+ if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ return false;
+
+ // In addition, either its function-body shall be = delete or = default or
+ // it shall satisfy the following constraints:
+ // - the class shall not have any virtual base classes;
+ const CXXRecordDecl *RD = CD->getParent();
+ if (RD->getNumVBases()) {
+ // Note, this is still illegal if the body is = default, since the
+ // implicit body does not satisfy the requirements of a constexpr
+ // constructor. We also reject cases where the body is = delete, as
+ // required by N3308.
+ if (CCK != CCK_Instantiation) {
+ Diag(NewFD->getLocation(),
+ CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
+ : diag::note_constexpr_tmpl_virtual_base)
+ << RD->isStruct() << RD->getNumVBases();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I)
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ }
+ return false;
+ }
+ } else {
+ // C++0x [dcl.constexpr]p3:
+ // The definition of a constexpr function shall satisfy the following
+ // constraints:
+ // - it shall not be virtual;
+ const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
+ if (Method && Method->isVirtual()) {
+ if (CCK != CCK_Instantiation) {
+ Diag(NewFD->getLocation(),
+ CCK == CCK_Declaration ? diag::err_constexpr_virtual
+ : diag::note_constexpr_tmpl_virtual);
+
+ // If it's not obvious why this function is virtual, find an overridden
+ // function which uses the 'virtual' keyword.
+ const CXXMethodDecl *WrittenVirtual = Method;
+ while (!WrittenVirtual->isVirtualAsWritten())
+ WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
+ if (WrittenVirtual != Method)
+ Diag(WrittenVirtual->getLocation(),
+ diag::note_overridden_virtual_function);
+ }
+ return false;
+ }
+
+ // - its return type shall be a literal type;
+ QualType RT = NewFD->getResultType();
+ if (!RT->isDependentType() &&
+ RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ?
+ PDiag(diag::err_constexpr_non_literal_return) :
+ PDiag(),
+ /*AllowIncompleteType*/ true)) {
+ if (CCK == CCK_NoteNonConstexprInstantiation)
+ Diag(NewFD->getLocation(),
+ diag::note_constexpr_tmpl_non_literal_return) << RT;
+ return false;
+ }
+
+ // - each of its parameter types shall be a literal type;
+ if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ return false;
+ }
+
+ return true;
+}
+
+/// Check the given declaration statement is legal within a constexpr function
+/// body. C++0x [dcl.constexpr]p3,p4.
+///
+/// \return true if the body is OK, false if we have diagnosed a problem.
+static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
+ DeclStmt *DS) {
+ // C++0x [dcl.constexpr]p3 and p4:
+ // The definition of a constexpr function(p3) or constructor(p4) [...] shall
+ // contain only
+ for (DeclStmt::decl_iterator DclIt = DS->decl_begin(),
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ switch ((*DclIt)->getKind()) {
+ case Decl::StaticAssert:
+ case Decl::Using:
+ case Decl::UsingShadow:
+ case Decl::UsingDirective:
+ case Decl::UnresolvedUsingTypename:
+ // - static_assert-declarations
+ // - using-declarations,
+ // - using-directives,
+ continue;
+
+ case Decl::Typedef:
+ case Decl::TypeAlias: {
+ // - typedef declarations and alias-declarations that do not define
+ // classes or enumerations,
+ TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt);
+ if (TN->getUnderlyingType()->isVariablyModifiedType()) {
+ // Don't allow variably-modified types in constexpr functions.
+ TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
+ << TL.getSourceRange() << TL.getType()
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ continue;
+ }
+
+ case Decl::Enum:
+ case Decl::CXXRecord:
+ // As an extension, we allow the declaration (but not the definition) of
+ // classes and enumerations in all declarations, not just in typedef and
+ // alias declarations.
+ if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) {
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ continue;
+
+ case Decl::Var:
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+
+ default:
+ SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/// Check that the given field is initialized within a constexpr constructor.
+///
+/// \param Dcl The constexpr constructor being checked.
+/// \param Field The field being checked. This may be a member of an anonymous
+/// struct or union nested within the class being checked.
+/// \param Inits All declarations, including anonymous struct/union members and
+/// indirect members, for which any initialization was provided.
+/// \param Diagnosed Set to true if an error is produced.
+static void CheckConstexprCtorInitializer(Sema &SemaRef,
+ const FunctionDecl *Dcl,
+ FieldDecl *Field,
+ llvm::SmallSet<Decl*, 16> &Inits,
+ bool &Diagnosed) {
+ if (!Inits.count(Field)) {
+ if (!Diagnosed) {
+ SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
+ Diagnosed = true;
+ }
+ SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
+ } else if (Field->isAnonymousStructOrUnion()) {
+ const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I)
+ // If an anonymous union contains an anonymous struct of which any member
+ // is initialized, all members must be initialized.
+ if (!RD->isUnion() || Inits.count(*I))
+ CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed);
+ }
+}
+
+/// Check the body for the given constexpr function declaration only contains
+/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
+///
+/// \return true if the body is OK, false if we have diagnosed a problem.
+bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
+ if (isa<CXXTryStmt>(Body)) {
+ // C++0x [dcl.constexpr]p3:
+ // The definition of a constexpr function shall satisfy the following
+ // constraints: [...]
+ // - its function-body shall be = delete, = default, or a
+ // compound-statement
+ //
+ // C++0x [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor, [...]
+ // - its function-body shall not be a function-try-block;
+ Diag(Body->getLocStart(), diag::err_constexpr_function_try_block)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+
+ // - its function-body shall be [...] a compound-statement that contains only
+ CompoundStmt *CompBody = cast<CompoundStmt>(Body);
+
+ llvm::SmallVector<SourceLocation, 4> ReturnStmts;
+ for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
+ BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
+ switch ((*BodyIt)->getStmtClass()) {
+ case Stmt::NullStmtClass:
+ // - null statements,
+ continue;
+
+ case Stmt::DeclStmtClass:
+ // - static_assert-declarations
+ // - using-declarations,
+ // - using-directives,
+ // - typedef declarations and alias-declarations that do not define
+ // classes or enumerations,
+ if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt)))
+ return false;
+ continue;
+
+ case Stmt::ReturnStmtClass:
+ // - and exactly one return statement;
+ if (isa<CXXConstructorDecl>(Dcl))
+ break;
+
+ ReturnStmts.push_back((*BodyIt)->getLocStart());
+ // FIXME
+ // - every constructor call and implicit conversion used in initializing
+ // the return value shall be one of those allowed in a constant
+ // expression.
+ // Deal with this as part of a general check that the function can produce
+ // a constant expression (for [dcl.constexpr]p5).
+ continue;
+
+ default:
+ break;
+ }
+
+ Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+
+ if (const CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(Dcl)) {
+ const CXXRecordDecl *RD = Constructor->getParent();
+ // - every non-static data member and base class sub-object shall be
+ // initialized;
+ if (RD->isUnion()) {
+ // DR1359: Exactly one member of a union shall be initialized.
+ if (Constructor->getNumCtorInitializers() == 0) {
+ Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
+ return false;
+ }
+ } else if (!Constructor->isDelegatingConstructor()) {
+ assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases");
+
+ // Skip detailed checking if we have enough initializers, and we would
+ // allow at most one initializer per member.
+ bool AnyAnonStructUnionMembers = false;
+ unsigned Fields = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++Fields) {
+ if ((*I)->isAnonymousStructOrUnion()) {
+ AnyAnonStructUnionMembers = true;
+ break;
+ }
+ }
+ if (AnyAnonStructUnionMembers ||
+ Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) {
+ // Check initialization of non-static data members. Base classes are
+ // always initialized so do not need to be checked. Dependent bases
+ // might not have initializers in the member initializer list.
+ llvm::SmallSet<Decl*, 16> Inits;
+ for (CXXConstructorDecl::init_const_iterator
+ I = Constructor->init_begin(), E = Constructor->init_end();
+ I != E; ++I) {
+ if (FieldDecl *FD = (*I)->getMember())
+ Inits.insert(FD);
+ else if (IndirectFieldDecl *ID = (*I)->getIndirectMember())
+ Inits.insert(ID->chain_begin(), ID->chain_end());
+ }
+
+ bool Diagnosed = false;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I)
+ CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed);
+ if (Diagnosed)
+ return false;
+ }
+ }
+
+ // FIXME
+ // - every constructor involved in initializing non-static data members
+ // and base class sub-objects shall be a constexpr constructor;
+ // - every assignment-expression that is an initializer-clause appearing
+ // directly or indirectly within a brace-or-equal-initializer for
+ // a non-static data member that is not named by a mem-initializer-id
+ // shall be a constant expression; and
+ // - every implicit conversion used in converting a constructor argument
+ // to the corresponding parameter type and converting
+ // a full-expression to the corresponding member type shall be one of
+ // those allowed in a constant expression.
+ // Deal with these as part of a general check that the function can produce
+ // a constant expression (for [dcl.constexpr]p5).
+ } else {
+ if (ReturnStmts.empty()) {
+ Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
+ return false;
+ }
+ if (ReturnStmts.size() > 1) {
+ Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return);
+ for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
+ Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
+ return false;
+ }
+ }
+
+ return true;
+}
+
/// isCurrentClassName - Determine whether the identifier II is the
/// name of the class type currently being defined. In the case of
/// nested classes, this will only return true if II is the name of
@@ -3226,6 +3593,47 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
+ // function that is not a constructor declares that member function to be
+ // const. [...] The class of which that function is a member shall be
+ // a literal type.
+ //
+ // It's fine to diagnose constructors here too: such constructors cannot
+ // produce a constant expression, so are ill-formed (no diagnostic required).
+ //
+ // If the class has virtual bases, any constexpr members will already have
+ // been diagnosed by the checks performed on the member declaration, so
+ // suppress this (less useful) diagnostic.
+ if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
+ !Record->isLiteral() && !Record->getNumVBases()) {
+ for (CXXRecordDecl::method_iterator M = Record->method_begin(),
+ MEnd = Record->method_end();
+ M != MEnd; ++M) {
+ if ((*M)->isConstexpr()) {
+ switch (Record->getTemplateSpecializationKind()) {
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // If a template instantiates to a non-literal type, but its members
+ // instantiate to constexpr functions, the template is technically
+ // ill-formed, but we allow it for sanity. Such members are treated as
+ // non-constexpr.
+ (*M)->setConstexpr(false);
+ continue;
+
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record),
+ PDiag(diag::err_constexpr_method_non_literal));
+ break;
+ }
+
+ // Only produce one error per class.
+ break;
+ }
+ }
+ }
+
// Declare inherited constructors. We do this eagerly here because:
// - The standard requires an eager diagnostic for conflicting inherited
// constructors from different classes.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e29b75a2c2..694d94432f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1067,15 +1067,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgs);
}
- bool isConstexpr = D->isConstexpr();
- // FIXME: check whether the instantiation produces a constexpr function.
-
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getLocation(), D->getDeclName(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
- isConstexpr);
+ /*isConstexpr*/ false);
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -1388,9 +1385,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (!DC) return 0;
}
- bool isConstexpr = D->isConstexpr();
- // FIXME: check whether the instantiation produces a constexpr function.
-
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = 0;
@@ -1403,7 +1397,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
- false, isConstexpr);
+ false, /*isConstexpr*/ false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@@ -1414,14 +1408,15 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(),
Conversion->isExplicit(),
- isConstexpr, Conversion->getLocEnd());
+ /*isConstexpr*/ false,
+ Conversion->getLocEnd());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
D->isStatic(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
- isConstexpr, D->getLocEnd());
+ /*isConstexpr*/ false, D->getLocEnd());
}
if (QualifierLoc)
@@ -2312,6 +2307,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
+ // C++0x [dcl.constexpr]p6: If the instantiated template specialization of
+ // a constexpr function template satisfies the requirements for a constexpr
+ // function, then it is a constexpr function.
+ if (Tmpl->isConstexpr() &&
+ SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
+ New->setConstexpr(true);
+
const FunctionDecl* Definition = Tmpl;
// Get the definition. Leaves the variable unchanged if undefined.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 480dd3b85a..25ec0b1477 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -3992,6 +3992,118 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
std::make_pair(SourceLocation(), PDiag(0)));
}
+/// @brief Ensure that the type T is a literal type.
+///
+/// This routine checks whether the type @p T is a literal type. If @p T is an
+/// incomplete type, an attempt is made to complete it. If @p T is a literal
+/// type, or @p AllowIncompleteType is true and @p T is an incomplete type,
+/// returns false. Otherwise, this routine issues the diagnostic @p PD (giving
+/// it the type @p T), along with notes explaining why the type is not a
+/// literal type, and returns true.
+///
+/// @param Loc The location in the source that the non-literal type
+/// diagnostic should refer to.
+///
+/// @param T The type that this routine is examining for literalness.
+///
+/// @param PD The partial diagnostic that will be printed out if T is not a
+/// literal type.
+///
+/// @param AllowIncompleteType If true, an incomplete type will be considered
+/// acceptable.
+///
+/// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
+/// @c false otherwise.
+bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD,
+ bool AllowIncompleteType) {
+ assert(!T->isDependentType() && "type should not be dependent");
+
+ bool Incomplete = RequireCompleteType(Loc, T, 0);
+ if (T->isLiteralType() || (AllowIncompleteType && Incomplete))
+ return false;
+
+ if (PD.getDiagID() == 0)
+ return true;
+
+ Diag(Loc, PD) << T;
+
+ if (T->isVariableArrayType())
+ return true;
+
+ const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ if (!RT)
+ return true;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // If the class has virtual base classes, then it's not an aggregate, and
+ // cannot have any constexpr constructors, so is non-literal. This is better
+ // to diagnose than the resulting absence of constexpr constructors.
+ if (RD->getNumVBases()) {
+ Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
+ << RD->isStruct() << RD->getNumVBases();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I)
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
+ Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ break;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // If the base template had constexpr constructors which were
+ // instantiated as non-constexpr constructors, explain why.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
+ E = RD->ctor_end(); I != E; ++I) {
+ if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor())
+ continue;
+
+ FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction();
+ if (Base && Base->isConstexpr())
+ CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation);
+ }
+ }
+ } else if (RD->hasNonLiteralTypeFieldsOrBases()) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (!I->getType()->isLiteralType()) {
+ Diag(I->getSourceRange().getBegin(),
+ diag::note_non_literal_base_class)
+ << RD << I->getType() << I->getSourceRange();
+ return true;
+ }
+ }
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ if (!(*I)->getType()->isLiteralType()) {
+ Diag((*I)->getLocation(), diag::note_non_literal_field)
+ << RD << (*I) << (*I)->getType();
+ return true;
+ }
+ }
+ } else if (!RD->hasTrivialDestructor()) {
+ // All fields and bases are of literal types, so have trivial destructors.
+ // If this class's destructor is non-trivial it must be user-declared.
+ CXXDestructorDecl *Dtor = RD->getDestructor();
+ assert(Dtor && "class has literal fields and bases but no dtor?");
+ if (!Dtor)
+ return true;
+
+ Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
+ diag::note_non_literal_user_provided_dtor :
+ diag::note_non_literal_nontrivial_dtor) << RD;
+ }
+
+ return true;
+}
+
/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
/// and qualified by the nested-name-specifier contained in SS.
QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,