diff options
-rw-r--r-- | clang/include/clang/AST/Decl.h | 70 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 17 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/eval-recursive-constant.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaCXX/i-c-e-cxx.cpp | 7 |
5 files changed, 88 insertions, 22 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index f7944771efc..647ad03f409 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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 Note that we now know whether the initializer is an + /// \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 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 setCheckingICE() const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->CheckingICE = true; + } + /// \brief Note that we now know whether the initializer is an + /// integral constant expression. + void setInitKnownICE(bool IsICE) const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->CheckingICE = false; Eval->CheckedICE = true; Eval->IsICE = IsICE; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 28f1bd92f3e..2aca0604444 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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; } } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a20e1cc6f56..15a9a06be86 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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; } } diff --git a/clang/test/CodeGenCXX/eval-recursive-constant.cpp b/clang/test/CodeGenCXX/eval-recursive-constant.cpp new file mode 100644 index 00000000000..b60070fa1f4 --- /dev/null +++ b/clang/test/CodeGenCXX/eval-recursive-constant.cpp @@ -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; } diff --git a/clang/test/SemaCXX/i-c-e-cxx.cpp b/clang/test/SemaCXX/i-c-e-cxx.cpp index 785ea0efa40..b7db907e221 100644 --- a/clang/test/SemaCXX/i-c-e-cxx.cpp +++ b/clang/test/SemaCXX/i-c-e-cxx.cpp @@ -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}} + } +} |