summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/ASTImporter.cpp5
-rw-r--r--clang/lib/AST/Decl.cpp89
-rw-r--r--clang/lib/AST/ExprConstant.cpp119
3 files changed, 147 insertions, 66 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 963643e542a..a95c941e02e 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2802,6 +2802,11 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
} else {
Expr *Init = Importer.Import(DDef->getInit());
MergeWithVar->setInit(Init);
+ if (DDef->isInitKnownICE()) {
+ EvaluatedStmt *Eval = MergeWithVar->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = DDef->isInitICE();
+ }
}
}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 34eefc0dcc9..305c41c51c4 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1337,6 +1337,94 @@ void VarDecl::setInit(Expr *I) {
Init = I;
}
+/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
+/// form, which contains extra information on the evaluated value of the
+/// initializer.
+EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
+ EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
+ if (!Eval) {
+ Stmt *S = Init.get<Stmt *>();
+ Eval = new (getASTContext()) EvaluatedStmt;
+ Eval->Value = S;
+ Init = Eval;
+ }
+ return Eval;
+}
+
+bool VarDecl::evaluateValue(
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ EvaluatedStmt *Eval = ensureEvaluatedStmt();
+
+ // We only produce notes indicating why an initializer is non-constant the
+ // first time it is evaluated. FIXME: The notes won't always be emitted the
+ // first time we try evaluation, so might not be produced at all.
+ if (Eval->WasEvaluated)
+ return !Eval->Evaluated.isUninit();
+
+ const Expr *Init = cast<Expr>(Eval->Value);
+ assert(!Init->isValueDependent());
+
+ if (Eval->IsEvaluating) {
+ // FIXME: Produce a diagnostic for self-initialization.
+ Eval->CheckedICE = true;
+ Eval->IsICE = false;
+ return false;
+ }
+
+ Eval->IsEvaluating = true;
+
+ bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
+ this, Notes);
+
+ // Ensure the result is an uninitialized APValue if evaluation fails.
+ if (!Result)
+ Eval->Evaluated = APValue();
+
+ Eval->IsEvaluating = false;
+ Eval->WasEvaluated = true;
+
+ // In C++11, we have determined whether the initializer was a constant
+ // expression as a side-effect.
+ if (getASTContext().getLangOptions().CPlusPlus0x && !Eval->CheckedICE) {
+ Eval->CheckedICE = true;
+ Eval->IsICE = Notes.empty();
+ }
+
+ return Result;
+}
+
+bool VarDecl::checkInitIsICE() const {
+ EvaluatedStmt *Eval = ensureEvaluatedStmt();
+ if (Eval->CheckedICE)
+ // We have already checked whether this subexpression is an
+ // integral constant expression.
+ return Eval->IsICE;
+
+ const Expr *Init = cast<Expr>(Eval->Value);
+ assert(!Init->isValueDependent());
+
+ // In C++11, evaluate the initializer to check whether it's a constant
+ // expression.
+ if (getASTContext().getLangOptions().CPlusPlus0x) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ evaluateValue(Notes);
+ return Eval->IsICE;
+ }
+
+ // It's an ICE whether or not the definition we found is
+ // out-of-line. See DR 721 and the discussion in Clang PR
+ // 6206 for details.
+
+ if (Eval->CheckingICE)
+ return false;
+ Eval->CheckingICE = true;
+
+ Eval->IsICE = Init->isIntegerConstantExpr(getASTContext());
+ Eval->CheckingICE = false;
+ Eval->CheckedICE = true;
+ return Eval->IsICE;
+}
+
bool VarDecl::extendsLifetimeOfTemporary() const {
assert(getType()->isReferenceType() &&"Non-references never extend lifetime");
@@ -2687,4 +2775,3 @@ SourceRange ImportDecl::getSourceRange() const {
return SourceRange(getLocation(), getIdentifierLocs().back());
}
-
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 88a033151a8..ff556c30944 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -382,6 +382,14 @@ namespace {
return OptionalDiagnostic();
return OptionalDiagnostic(&addDiag(Loc, DiagId));
}
+
+ /// Add a stack of notes to a prior diagnostic.
+ void addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
+ if (HasActiveDiagnostic) {
+ EvalStatus.Diag->insert(EvalStatus.Diag->end(),
+ Diags.begin(), Diags.end());
+ }
+ }
};
}
@@ -1069,6 +1077,13 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
return true;
}
+ // Dig out the initializer, and use the declaration which it's attached to.
+ const Expr *Init = VD->getAnyInitializer(VD);
+ if (!Init || Init->isValueDependent()) {
+ Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
// If we're currently evaluating the initializer of this declaration, use that
// in-flight value.
if (Info.EvaluatingDecl == VD) {
@@ -1083,47 +1098,23 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
return false;
}
- const Expr *Init = VD->getAnyInitializer();
- if (!Init || Init->isValueDependent()) {
- Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
- return false;
- }
-
- if (APValue *V = VD->getEvaluatedValue()) {
- Result = CCValue(*V, CCValue::GlobalValue());
- return !Result.isUninit();
- }
-
- if (VD->isEvaluatingValue()) {
- Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
- return false;
- }
-
- VD->setEvaluatingValue();
-
- Expr::EvalStatus EStatus;
- EvalInfo InitInfo(Info.Ctx, EStatus);
- APValue EvalResult;
- InitInfo.setEvaluatingDecl(VD, EvalResult);
- LValue LVal;
- LVal.set(VD);
- // FIXME: The caller will need to know whether the value was a constant
- // expression. If not, we should propagate up a diagnostic.
- if (!EvaluateConstantExpression(EvalResult, InitInfo, LVal, Init)) {
- // FIXME: If the evaluation failure was not permanent (for instance, if we
- // hit a variable with no declaration yet, or a constexpr function with no
- // definition yet), the standard is unclear as to how we should behave.
- //
- // Either the initializer should be evaluated when the variable is defined,
- // or a failed evaluation of the initializer should be reattempted each time
- // it is used.
- VD->setEvaluatedValue(APValue());
- Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ // Check that we can fold the initializer. In C++, we will have already done
+ // this in the cases where it matters for conformance.
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!VD->evaluateValue(Notes)) {
+ Info.Diag(E->getExprLoc(), diag::note_constexpr_var_init_non_constant,
+ Notes.size() + 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ Info.addNotes(Notes);
return false;
+ } else if (!VD->checkInitIsICE()) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_var_init_non_constant,
+ Notes.size() + 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ Info.addNotes(Notes);
}
- VD->setEvaluatedValue(EvalResult);
- Result = CCValue(EvalResult, CCValue::GlobalValue());
+ Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue());
return true;
}
@@ -1523,6 +1514,8 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
if (Info.getLangOpts().CPlusPlus0x) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+ // FIXME: If DiagDecl is an implicitly-declared special member function, we
+ // should be much more explicit about why it's not constexpr.
Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
<< DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
<< DiagDecl;
@@ -4887,6 +4880,22 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
CCEK_Constant);
}
+bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
+ const VarDecl *VD,
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ Expr::EvalStatus EStatus;
+ EStatus.Diag = &Notes;
+
+ EvalInfo InitInfo(Ctx, EStatus);
+ InitInfo.setEvaluatingDecl(VD, Value);
+
+ LValue LVal;
+ LVal.set(VD);
+
+ return EvaluateConstantExpression(Value, InitInfo, LVal, this) &&
+ !EStatus.HasSideEffects;
+}
+
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded, but discard the result.
bool Expr::isEvaluatable(const ASTContext &Ctx) const {
@@ -5083,33 +5092,13 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (!Dcl->getType()->isIntegralOrEnumerationType())
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- // Look for a declaration of this variable that has an initializer.
- const VarDecl *ID = 0;
- const Expr *Init = Dcl->getAnyInitializer(ID);
- if (Init) {
- if (ID->isInitKnownICE()) {
- // We have already checked whether this subexpression is an
- // integral constant expression.
- if (ID->isInitICE())
- return NoDiag();
- else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
-
- // It's an ICE whether or not the definition we found is
- // out-of-line. See DR 721 and the discussion in Clang PR
- // 6206 for details.
-
- if (Dcl->isCheckingICE()) {
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
-
- Dcl->setCheckingICE();
- ICEDiag Result = CheckICE(Init, Ctx);
- // Cache the result of the ICE test.
- Dcl->setInitKnownICE(Result.Val == 0);
- return Result;
- }
+ const VarDecl *VD;
+ // Look for a declaration of this variable that has an initializer, and
+ // check whether it is an ICE.
+ if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
+ return NoDiag();
+ else
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
}
return ICEDiag(2, E->getLocStart());
OpenPOWER on IntegriCloud