forked from OSchip/llvm-project
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:
parent
a3536e23c8
commit
1d6fb1669c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
|
@ -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}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue