[cfe-commits] [PATCH] Handle evaluation and ICE-checking of self-referencing constant integers without crashing

Eli Friedman eli.friedman at gmail.com
Fri Nov 27 13:00:34 PST 2009


Examples of issues:

(C or C++):
int a() { const int t=t; switch(1) { case t:; } }

(C++)
extern const int a,b;
const int a=b,b=a;
int a() { if (a) return 1; return 0; }

Doug, since you were the last person to touch this code recently,
would you mind taking a look?  I somehow get the feeling I'm missing
something, but I'm not sure what.

-Eli
-------------- next part --------------
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h	(revision 89989)
+++ include/clang/AST/Decl.h	(working copy)
@@ -351,10 +351,17 @@
   /// \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;
@@ -502,9 +509,7 @@
 
   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(ASTContext &C) const {
     EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
     if (!Eval) {
       Stmt *S = Init.get<Stmt *>();
@@ -512,7 +517,29 @@
       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(ASTContext &C) const {
+    EvaluatedStmt *Eval = EnsureEvaluatedStmt(C);
+    Eval->IsEvaluating = true;
+  }
+
+  /// \brief Note that constant evaluation has computed the given
+  /// value for this variable's initializer.
+  void setEvaluatedValue(ASTContext &C, const APValue &Value) const {
+    EvaluatedStmt *Eval = EnsureEvaluatedStmt(C);
     Eval->WasEvaluated = true;
     Eval->Evaluated = Value;
   }
@@ -546,17 +573,27 @@
     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(ASTContext &C) const {
+    EvaluatedStmt *Eval = EnsureEvaluatedStmt(C);
+    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;
-    }
-
+    EvaluatedStmt *Eval = EnsureEvaluatedStmt(C);
+    Eval->CheckingICE = false;
     Eval->CheckedICE = true;
     Eval->IsICE = IsICE;
   }
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp	(revision 89989)
+++ lib/AST/ExprConstant.cpp	(working copy)
@@ -867,13 +867,17 @@
     if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
       const VarDecl *Def = 0;
       if (const Expr *Init = VD->getDefinition(Def)) {
-        if (APValue *V = VD->getEvaluatedValue())
+        if (APValue *V = VD->getEvaluatedValue()) {
           return Success(V->getInt(), E);
-          
-        if (Visit(const_cast<Expr*>(Init))) {
-          // Cache the evaluated value in the variable declaration.
-          VD->setEvaluatedValue(Info.Ctx, Result);
-          return true;
+        } else if (VD->isEvaluatingValue()) {
+          // Recursive loop; don't try to visit.
+        } else {
+          VD->setEvaluatingValue(Info.Ctx);
+          if (Visit(const_cast<Expr*>(Init))) {
+            // Cache the evaluated value in the variable declaration.
+            VD->setEvaluatedValue(Info.Ctx, Result);
+            return true;
+          }
         }
 
         return false;
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp	(revision 89989)
+++ lib/AST/Expr.cpp	(working copy)
@@ -1600,7 +1600,12 @@
             Dcl->setInitKnownICE(Ctx, false);
             return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
           }
-          
+
+          if (Dcl->isCheckingICE()) {
+            return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+          }
+
+          Dcl->setCheckingICE(Ctx);
           ICEDiag Result = CheckICE(Init, Ctx);
           // Cache the result of the ICE test.
           Dcl->setInitKnownICE(Ctx, Result.Val == 0);


More information about the cfe-commits mailing list