Add recursion guards to ice-checking and evaluation for declrefs, so we

don't infinitely recurse for cases we can't evaluate.

llvm-svn: 90480
This commit is contained in:
Eli Friedman 2009-12-03 20:31:57 +00:00
parent a3536e23c8
commit 1d6fb1669c
5 changed files with 88 additions and 22 deletions

View File

@ -348,15 +348,23 @@ public:
/// which it was evaluated (if any), and whether or not the statement
/// is an integral constant expression (if known).
struct EvaluatedStmt {
EvaluatedStmt() : WasEvaluated(false), CheckedICE(false), IsICE(false) { }
EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false),
CheckingICE(false), IsICE(false) { }
/// \brief Whether this statement was already evaluated.
bool WasEvaluated : 1;
/// \brief Whether this statement is being evaluated.
bool IsEvaluating : 1;
/// \brief Whether we already checked whether this statement was an
/// integral constant expression.
bool CheckedICE : 1;
/// \brief Whether we are checking whether this statement is an
/// integral constant expression.
bool CheckingICE : 1;
/// \brief Whether this statement is an integral constant
/// expression. Only valid if CheckedICE is true.
bool IsICE : 1;
@ -504,23 +512,45 @@ public:
void setInit(ASTContext &C, Expr *I);
/// \brief Note that constant evaluation has computed the given
/// value for this variable's initializer.
void setEvaluatedValue(ASTContext &C, const APValue &Value) const {
EvaluatedStmt *EnsureEvaluatedStmt() const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
Stmt *S = Init.get<Stmt *>();
Eval = new (C) EvaluatedStmt;
Eval = new (getASTContext()) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
}
return Eval;
}
/// \brief Check whether we are in the process of checking whether the
/// initializer can be evaluated.
bool isEvaluatingValue() const {
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
return Eval->IsEvaluating;
return false;
}
/// \brief Note that we now are checking whether the initializer can be
/// evaluated.
void setEvaluatingValue() const {
EvaluatedStmt *Eval = EnsureEvaluatedStmt();
Eval->IsEvaluating = true;
}
/// \brief Note that constant evaluation has computed the given
/// value for this variable's initializer.
void setEvaluatedValue(const APValue &Value) const {
EvaluatedStmt *Eval = EnsureEvaluatedStmt();
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
Eval->Evaluated = Value;
}
/// \brief Return the already-evaluated value of this variable's
/// initializer, or NULL if the value is not yet known.
/// initializer, or NULL if the value is not yet known. Returns pointer
/// to untyped APValue if the value could not be evaluated.
APValue *getEvaluatedValue() const {
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
if (Eval->WasEvaluated)
@ -548,17 +578,27 @@ public:
return Init.get<EvaluatedStmt *>()->IsICE;
}
/// \brief Check whether we are in the process of checking the initializer
/// is an integral constant expression.
bool isCheckingICE() const {
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
return Eval->CheckingICE;
return false;
}
/// \brief Note that we now are checking whether the initializer is an
/// integral constant expression.
void setCheckingICE() const {
EvaluatedStmt *Eval = EnsureEvaluatedStmt();
Eval->CheckingICE = true;
}
/// \brief Note that we now know whether the initializer is an
/// integral constant expression.
void setInitKnownICE(ASTContext &C, bool IsICE) const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
Stmt *S = Init.get<Stmt *>();
Eval = new (C) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
}
void setInitKnownICE(bool IsICE) const {
EvaluatedStmt *Eval = EnsureEvaluatedStmt();
Eval->CheckingICE = false;
Eval->CheckedICE = true;
Eval->IsICE = IsICE;
}

View File

@ -1596,13 +1596,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// constant expression (5.19). In that case, the member can appear
// in integral constant expressions.
if (Def->isOutOfLine()) {
Dcl->setInitKnownICE(Ctx, false);
Dcl->setInitKnownICE(false);
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
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(Ctx, Result.Val == 0);
Dcl->setInitKnownICE(Result.Val == 0);
return Result;
}
}

View File

@ -866,15 +866,24 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def)) {
if (APValue *V = VD->getEvaluatedValue())
return Success(V->getInt(), E);
if (APValue *V = VD->getEvaluatedValue()) {
if (V->isInt())
return Success(V->getInt(), E);
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
}
if (VD->isEvaluatingValue())
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
VD->setEvaluatingValue();
if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration.
VD->setEvaluatedValue(Info.Ctx, Result);
VD->setEvaluatedValue(Result);
return true;
}
VD->setEvaluatedValue(APValue());
return false;
}
}

View File

@ -0,0 +1,5 @@
// RUN: clang-cc %s -emit-llvm-only
extern const int a,b;
const int a=b,b=a;
int c() { if (a) return 1; return 0; }

View File

@ -14,3 +14,10 @@ void f() {
int array[value];
}
}
int a() {
const int t=t; // expected-note {{subexpression not valid}}
switch(1) {
case t:; // expected-error {{not an integer constant expression}}
}
}