C++1y constexpr extensions, round 1: Allow most forms of declaration and
statement in constexpr functions. Everything which doesn't require variable
mutation is also allowed as an extension in C++11. 'void' becomes a literal
type to support constexpr functions which return 'void'.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180022 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index ece8315..c2b7513 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -186,7 +186,7 @@
data().IsStandardLayout = false;
// Record if this base is the first non-literal field or base.
- if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType())
+ if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C))
data().HasNonLiteralTypeFieldsOrBases = true;
// Now go through all virtual bases of this base and add them.
@@ -676,7 +676,7 @@
}
// Record if this field is the first non-literal or volatile field or base.
- if (!T->isLiteralType() || T.isVolatileQualified())
+ if (!T->isLiteralType(Context) || T.isVolatileQualified())
data().HasNonLiteralTypeFieldsOrBases = true;
if (Field->hasInClassInitializer()) {
@@ -845,7 +845,7 @@
}
} else {
// Base element type of field is a non-class type.
- if (!T->isLiteralType() ||
+ if (!T->isLiteralType(Context) ||
(!Field->hasInClassInitializer() && !isUnion()))
data().DefaultedDefaultConstructorIsConstexpr = false;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1303fb0..cf7ddbc 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -289,7 +289,7 @@
// expression that is value-dependent [C++11]
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
if ((Ctx.getLangOpts().CPlusPlus11 ?
- Var->getType()->isLiteralType() :
+ Var->getType()->isLiteralType(Ctx) :
Var->getType()->isIntegralOrEnumerationType()) &&
(Var->getType().isConstQualified() ||
Var->getType()->isReferenceType())) {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c02df9a..2a7e8a7 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -290,7 +290,7 @@
// Note that we intentionally use std::map here so that references to
// values are stable.
- typedef std::map<const Expr*, APValue> MapTy;
+ typedef std::map<const void*, APValue> MapTy;
typedef MapTy::const_iterator temp_iterator;
/// Temporaries - Temporary lvalues materialized within this stack frame.
MapTy Temporaries;
@@ -913,6 +913,14 @@
// Misc utilities
//===----------------------------------------------------------------------===//
+/// Evaluate an expression to see if it had side-effects, and discard its
+/// result.
+static void EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
+ APValue Scratch;
+ if (!Evaluate(Scratch, Info, E))
+ Info.EvalStatus.HasSideEffects = true;
+}
+
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
unsigned Builtin = E->isBuiltinCall();
@@ -1046,7 +1054,7 @@
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
- if (!E->isRValue() || E->getType()->isLiteralType())
+ if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
// Prvalue constant expressions must be of literal types.
@@ -1461,6 +1469,15 @@
return true;
}
+ // If this is a local variable, dig out its value.
+ if (VD->hasLocalStorage() && Frame && Frame->Index > 1) {
+ Result = Frame->Temporaries[VD];
+ // If we've carried on past an unevaluatable local variable initializer,
+ // we can't go any further. This can happen during potential constant
+ // expression checking.
+ return !Result.isUninit();
+ }
+
// Dig out the initializer, and use the declaration which it's attached to.
const Expr *Init = VD->getAnyInitializer(VD);
if (!Init || Init->isValueDependent()) {
@@ -1803,7 +1820,9 @@
return false;
}
- if (!isa<ParmVarDecl>(VD)) {
+ // Unless we're looking at a local variable or argument in a constexpr call,
+ // the variable we're reading must be const.
+ if (LVal.CallIndex <= 1 || !VD->hasLocalStorage()) {
if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (VT->isIntegralOrEnumerationType()) {
@@ -1911,7 +1930,7 @@
if (Object->isGLValue())
return EvaluateLValue(Object, This, Info);
- if (Object->getType()->isLiteralType())
+ if (Object->getType()->isLiteralType(Info.Ctx))
return EvaluateTemporary(Object, This, Info);
return false;
@@ -2060,20 +2079,61 @@
};
}
+static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // We don't need to evaluate the initializer for a static local.
+ if (!VD->hasLocalStorage())
+ return true;
+
+ LValue Result;
+ Result.set(VD, Info.CurrentCall->Index);
+ APValue &Val = Info.CurrentCall->Temporaries[VD];
+
+ if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
+ // Wipe out any partially-computed value, to allow tracking that this
+ // evaluation failed.
+ Val = APValue();
+ return false;
+ }
+ }
+
+ return true;
+}
+
// Evaluate a statement.
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const Stmt *S) {
+ // FIXME: Mark all temporaries in the current frame as destroyed at
+ // the end of each full-expression.
switch (S->getStmtClass()) {
default:
+ if (const Expr *E = dyn_cast<Expr>(S)) {
+ EvaluateIgnoredValue(Info, E);
+ // Don't bother evaluating beyond an expression-statement which couldn't
+ // be evaluated.
+ if (Info.EvalStatus.HasSideEffects && !Info.keepEvaluatingAfterFailure())
+ return ESR_Failed;
+ return ESR_Succeeded;
+ }
+
+ Info.Diag(S->getLocStart());
return ESR_Failed;
case Stmt::NullStmtClass:
- case Stmt::DeclStmtClass:
return ESR_Succeeded;
+ case Stmt::DeclStmtClass: {
+ const DeclStmt *DS = cast<DeclStmt>(S);
+ for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt)
+ if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
+ return ESR_Failed;
+ return ESR_Succeeded;
+ }
+
case Stmt::ReturnStmtClass: {
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
- if (!Evaluate(Result, Info, RetExpr))
+ if (RetExpr && !Evaluate(Result, Info, RetExpr))
return ESR_Failed;
return ESR_Returned;
}
@@ -2088,6 +2148,28 @@
}
return ESR_Succeeded;
}
+
+ case Stmt::IfStmtClass: {
+ const IfStmt *IS = cast<IfStmt>(S);
+
+ // Evaluate the condition, as either a var decl or as an expression.
+ bool Cond;
+ if (VarDecl *CondDecl = IS->getConditionVariable()) {
+ if (!EvaluateDecl(Info, CondDecl))
+ return ESR_Failed;
+ if (!HandleConversionToBool(Info.CurrentCall->Temporaries[CondDecl],
+ Cond))
+ return ESR_Failed;
+ } else if (!EvaluateAsBooleanCondition(IS->getCond(), Cond, Info))
+ return ESR_Failed;
+
+ if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
+ return ESR_Succeeded;
+ }
}
}
@@ -2181,7 +2263,10 @@
return false;
CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
- return EvaluateStmt(Result, Info, Body) == ESR_Returned;
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
+ if (ESR == ESR_Succeeded)
+ Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return);
+ return ESR == ESR_Returned;
}
/// Evaluate a constructor call.
@@ -2207,7 +2292,9 @@
// If it's a delegating constructor, just delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
- return EvaluateInPlace(Result, Info, This, (*I)->getInit());
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ return false;
+ return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
}
// For a trivial copy or move constructor, perform an APValue copy. This is
@@ -2307,7 +2394,8 @@
}
}
- return Success;
+ return Success &&
+ EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
}
//===----------------------------------------------------------------------===//
@@ -2660,9 +2748,7 @@
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
- APValue Scratch;
- if (!Evaluate(Scratch, Info, E))
- Info.EvalStatus.HasSideEffects = true;
+ EvaluateIgnoredValue(Info, E);
}
};
@@ -2868,7 +2954,7 @@
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
if (!VD->getType()->isReferenceType()) {
- if (isa<ParmVarDecl>(VD)) {
+ if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
Result.set(VD, Info.CurrentCall->Index);
return true;
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0c5636d..7922c33 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1142,16 +1142,20 @@
-bool Type::isLiteralType() const {
+bool Type::isLiteralType(ASTContext &Ctx) const {
if (isDependentType())
return false;
- // C++0x [basic.types]p10:
+ // C++1y [basic.types]p10:
+ // A type is a literal type if it is:
+ // -- cv void; or
+ if (Ctx.getLangOpts().CPlusPlus1y && isVoidType())
+ return true;
+
+ // C++11 [basic.types]p10:
// A type is a literal type if it is:
// [...]
- // -- an array of literal type.
- // Extension: variable arrays cannot be literal types, since they're
- // runtime-sized.
+ // -- an array of literal type other than an array of runtime bound; or
if (isVariableArrayType())
return false;
const Type *BaseTy = getBaseElementTypeUnsafe();
@@ -1162,7 +1166,7 @@
if (BaseTy->isIncompleteType())
return false;
- // C++0x [basic.types]p10:
+ // C++11 [basic.types]p10:
// A type is a literal type if it is:
// -- a scalar type; or
// As an extension, Clang treats vector types and complex types as
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 6ecc84f..380b53f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -7626,7 +7626,7 @@
}
// Suggest adding 'constexpr' in C++11 for literal types.
- } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) {
+ } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
<< DclT << Init->getSourceRange()
<< FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b29ce23..d18b9d3 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -775,12 +775,13 @@
}
/// Check the given declaration statement is legal within a constexpr function
-/// body. C++0x [dcl.constexpr]p3,p4.
+/// body. C++11 [dcl.constexpr]p3,p4, and C++1y [dcl.constexpr]p3.
///
-/// \return true if the body is OK, false if we have diagnosed a problem.
+/// \return true if the body is OK (maybe only as an extension), false if we
+/// have diagnosed a problem.
static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
- DeclStmt *DS) {
- // C++0x [dcl.constexpr]p3 and p4:
+ DeclStmt *DS, SourceLocation &Cxx1yLoc) {
+ // C++11 [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(),
@@ -791,6 +792,7 @@
case Decl::UsingShadow:
case Decl::UsingDirective:
case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
// - static_assert-declarations
// - using-declarations,
// - using-directives,
@@ -814,20 +816,62 @@
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)
+ // C++1y allows types to be defined, not just declared.
+ if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition())
+ SemaRef.Diag(DS->getLocStart(),
+ SemaRef.getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_constexpr_type_definition
+ : diag::ext_constexpr_type_definition)
<< isa<CXXConstructorDecl>(Dcl);
- return false;
- }
continue;
- case Decl::Var:
- SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration)
+ case Decl::EnumConstant:
+ case Decl::IndirectField:
+ case Decl::ParmVar:
+ // These can only appear with other declarations which are banned in
+ // C++11 and permitted in C++1y, so ignore them.
+ continue;
+
+ case Decl::Var: {
+ // C++1y [dcl.constexpr]p3 allows anything except:
+ // a definition of a variable of non-literal type or of static or
+ // thread storage duration or for which no initialization is performed.
+ VarDecl *VD = cast<VarDecl>(*DclIt);
+ if (VD->isThisDeclarationADefinition()) {
+ if (VD->isStaticLocal()) {
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_constexpr_local_var_static)
+ << isa<CXXConstructorDecl>(Dcl)
+ << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ return false;
+ }
+ if (SemaRef.RequireLiteralType(
+ VD->getLocation(), VD->getType(),
+ diag::err_constexpr_local_var_non_literal_type,
+ isa<CXXConstructorDecl>(Dcl)))
+ return false;
+ if (!VD->hasInit()) {
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_constexpr_local_var_no_init)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+ }
+ }
+ SemaRef.Diag(VD->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_constexpr_local_var
+ : diag::ext_constexpr_local_var)
<< isa<CXXConstructorDecl>(Dcl);
- return false;
+ continue;
+ }
+
+ case Decl::NamespaceAlias:
+ case Decl::Function:
+ // These are disallowed in C++11 and permitted in C++1y. Allow them
+ // everywhere as an extension.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = DS->getLocStart();
+ continue;
default:
SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt)
@@ -876,6 +920,124 @@
}
}
+/// Check the provided statement is allowed in a constexpr function
+/// definition.
+static bool
+CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
+ llvm::SmallVectorImpl<SourceLocation> &ReturnStmts,
+ SourceLocation &Cxx1yLoc) {
+ // - its function-body shall be [...] a compound-statement that contains only
+ switch (S->getStmtClass()) {
+ case Stmt::NullStmtClass:
+ // - null statements,
+ return true;
+
+ case Stmt::DeclStmtClass:
+ // - static_assert-declarations
+ // - using-declarations,
+ // - using-directives,
+ // - typedef declarations and alias-declarations that do not define
+ // classes or enumerations,
+ if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc))
+ return false;
+ return true;
+
+ case Stmt::ReturnStmtClass:
+ // - and exactly one return statement;
+ if (isa<CXXConstructorDecl>(Dcl)) {
+ // C++1y allows return statements in constexpr constructors.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+ return true;
+ }
+
+ ReturnStmts.push_back(S->getLocStart());
+ return true;
+
+ case Stmt::CompoundStmtClass: {
+ // C++1y allows compound-statements.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+
+ CompoundStmt *CompStmt = cast<CompoundStmt>(S);
+ for (CompoundStmt::body_iterator BodyIt = CompStmt->body_begin(),
+ BodyEnd = CompStmt->body_end(); BodyIt != BodyEnd; ++BodyIt) {
+ if (!CheckConstexprFunctionStmt(SemaRef, Dcl, *BodyIt, ReturnStmts,
+ Cxx1yLoc))
+ return false;
+ }
+ return true;
+ }
+
+ case Stmt::AttributedStmtClass:
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+ return true;
+
+ case Stmt::IfStmtClass: {
+ // C++1y allows if-statements.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+
+ IfStmt *If = cast<IfStmt>(S);
+ if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
+ Cxx1yLoc))
+ return false;
+ if (If->getElse() &&
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
+ Cxx1yLoc))
+ return false;
+ return true;
+ }
+
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::ContinueStmtClass:
+ // C++1y allows all of these. We don't allow them as extensions in C++11,
+ // because they don't make sense without variable mutation.
+ if (!SemaRef.getLangOpts().CPlusPlus1y)
+ break;
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+ for (Stmt::child_range Children = S->children(); Children; ++Children)
+ if (*Children &&
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts,
+ Cxx1yLoc))
+ return false;
+ return true;
+
+ case Stmt::SwitchStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::BreakStmtClass:
+ // C++1y allows switch-statements, and since they don't need variable
+ // mutation, we can reasonably allow them in C++11 as an extension.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+ for (Stmt::child_range Children = S->children(); Children; ++Children)
+ if (*Children &&
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts,
+ Cxx1yLoc))
+ return false;
+ return true;
+
+ default:
+ if (!isa<Expr>(S))
+ break;
+
+ // C++1y allows expression-statements.
+ if (!Cxx1yLoc.isValid())
+ Cxx1yLoc = S->getLocStart();
+ return true;
+ }
+
+ SemaRef.Diag(S->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+ return false;
+}
+
/// Check the body for the given constexpr function declaration only contains
/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
///
@@ -896,44 +1058,25 @@
return false;
}
- // - its function-body shall be [...] a compound-statement that contains only
- CompoundStmt *CompBody = cast<CompoundStmt>(Body);
-
SmallVector<SourceLocation, 4> ReturnStmts;
+
+ // - its function-body shall be [...] a compound-statement that contains only
+ // [... list of cases ...]
+ CompoundStmt *CompBody = cast<CompoundStmt>(Body);
+ SourceLocation Cxx1yLoc;
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());
- continue;
-
- default:
- break;
- }
-
- Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl);
- return false;
+ if (!CheckConstexprFunctionStmt(*this, Dcl, *BodyIt, ReturnStmts, Cxx1yLoc))
+ return false;
}
+ if (Cxx1yLoc.isValid())
+ Diag(Cxx1yLoc,
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
+ : diag::ext_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl);
+
if (const CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Dcl)) {
const CXXRecordDecl *RD = Constructor->getParent();
@@ -988,14 +1131,23 @@
}
} else {
if (ReturnStmts.empty()) {
- Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
+ // C++1y doesn't require constexpr functions to contain a 'return'
+ // statement. We still do, unless the return type is void, because
+ // otherwise if there's no return statement, the function cannot
+ // be used in a core constant expression.
+ Diag(Dcl->getLocation(),
+ getLangOpts().CPlusPlus1y && Dcl->getResultType()->isVoidType()
+ ? diag::warn_cxx11_compat_constexpr_body_no_return
+ : diag::err_constexpr_body_no_return);
return false;
}
if (ReturnStmts.size() > 1) {
- Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return);
+ Diag(ReturnStmts.back(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_constexpr_body_multiple_return
+ : diag::ext_constexpr_body_multiple_return);
for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
- return false;
}
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 89c1bc5..ba2291e 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -3137,7 +3137,7 @@
case UTT_IsPOD:
return T.isPODType(Self.Context);
case UTT_IsLiteral:
- return T->isLiteralType();
+ return T->isLiteralType(Self.Context);
case UTT_IsEmpty:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return !RD->isUnion() && RD->isEmpty();
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 699265c..5289d15 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -4809,7 +4809,7 @@
QualType ElemType = Context.getBaseElementType(T);
RequireCompleteType(Loc, ElemType, 0);
- if (T->isLiteralType())
+ if (T->isLiteralType(Context))
return false;
if (Diagnoser.Suppressed)
@@ -4851,7 +4851,7 @@
} 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()) {
+ if (!I->getType()->isLiteralType(Context)) {
Diag(I->getLocStart(),
diag::note_non_literal_base_class)
<< RD << I->getType() << I->getSourceRange();
@@ -4860,7 +4860,7 @@
}
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
- if (!I->getType()->isLiteralType() ||
+ if (!I->getType()->isLiteralType(Context) ||
I->getType().isVolatileQualified()) {
Diag(I->getLocation(), diag::note_non_literal_field)
<< RD << *I << I->getType()