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 /// which it was evaluated (if any), and whether or not the statement
/// is an integral constant expression (if known). /// is an integral constant expression (if known).
struct EvaluatedStmt { 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. /// \brief Whether this statement was already evaluated.
bool WasEvaluated : 1; bool WasEvaluated : 1;
/// \brief Whether this statement is being evaluated.
bool IsEvaluating : 1;
/// \brief Whether we already checked whether this statement was an /// \brief Whether we already checked whether this statement was an
/// integral constant expression. /// integral constant expression.
bool CheckedICE : 1; 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 /// \brief Whether this statement is an integral constant
/// expression. Only valid if CheckedICE is true. /// expression. Only valid if CheckedICE is true.
bool IsICE : 1; bool IsICE : 1;
@ -504,23 +512,45 @@ public:
void setInit(ASTContext &C, Expr *I); void setInit(ASTContext &C, Expr *I);
/// \brief Note that constant evaluation has computed the given EvaluatedStmt *EnsureEvaluatedStmt() const {
/// value for this variable's initializer.
void setEvaluatedValue(ASTContext &C, const APValue &Value) const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) { if (!Eval) {
Stmt *S = Init.get<Stmt *>(); Stmt *S = Init.get<Stmt *>();
Eval = new (C) EvaluatedStmt; Eval = new (getASTContext()) EvaluatedStmt;
Eval->Value = S; Eval->Value = S;
Init = Eval; 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->WasEvaluated = true;
Eval->Evaluated = Value; Eval->Evaluated = Value;
} }
/// \brief Return the already-evaluated value of this variable's /// \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 { APValue *getEvaluatedValue() const {
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
if (Eval->WasEvaluated) if (Eval->WasEvaluated)
@ -548,17 +578,27 @@ public:
return Init.get<EvaluatedStmt *>()->IsICE; 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 /// \brief Note that we now know whether the initializer is an
/// integral constant expression. /// integral constant expression.
void setInitKnownICE(ASTContext &C, bool IsICE) const { void setInitKnownICE(bool IsICE) const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); EvaluatedStmt *Eval = EnsureEvaluatedStmt();
if (!Eval) { Eval->CheckingICE = false;
Stmt *S = Init.get<Stmt *>();
Eval = new (C) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
}
Eval->CheckedICE = true; Eval->CheckedICE = true;
Eval->IsICE = IsICE; 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 // constant expression (5.19). In that case, the member can appear
// in integral constant expressions. // in integral constant expressions.
if (Def->isOutOfLine()) { if (Def->isOutOfLine()) {
Dcl->setInitKnownICE(Ctx, false); Dcl->setInitKnownICE(false);
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
} }
if (Dcl->isCheckingICE()) {
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
Dcl->setCheckingICE();
ICEDiag Result = CheckICE(Init, Ctx); ICEDiag Result = CheckICE(Init, Ctx);
// Cache the result of the ICE test. // Cache the result of the ICE test.
Dcl->setInitKnownICE(Ctx, Result.Val == 0); Dcl->setInitKnownICE(Result.Val == 0);
return Result; 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)) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const VarDecl *Def = 0; const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def)) { if (const Expr *Init = VD->getDefinition(Def)) {
if (APValue *V = VD->getEvaluatedValue()) if (APValue *V = VD->getEvaluatedValue()) {
return Success(V->getInt(), E); 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))) { if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration. // Cache the evaluated value in the variable declaration.
VD->setEvaluatedValue(Info.Ctx, Result); VD->setEvaluatedValue(Result);
return true; return true;
} }
VD->setEvaluatedValue(APValue());
return false; 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 array[value];
} }
} }
int a() {
const int t=t; // expected-note {{subexpression not valid}}
switch(1) {
case t:; // expected-error {{not an integer constant expression}}
}
}