Split apart the state accumulated during constant expression evaluation and the
end result. Use this split to propagate state information and diagnostics
through more of constant expression evaluation.

llvm-svn: 142159
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index df75bc8..3c21dc4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -46,8 +46,8 @@
   struct EvalInfo {
     const ASTContext &Ctx;
 
-    /// EvalResult - Contains information about the evaluation.
-    Expr::EvalResult &EvalResult;
+    /// EvalStatus - Contains information about the evaluation.
+    Expr::EvalStatus &EvalStatus;
 
     typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
     MapTy OpaqueValues;
@@ -57,8 +57,8 @@
       return &i->second;
     }
 
-    EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult)
-      : Ctx(ctx), EvalResult(evalresult) {}
+    EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+      : Ctx(C), EvalStatus(S) {}
 
     const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
   };
@@ -121,7 +121,7 @@
   };
 }
 
-static bool Evaluate(EvalInfo &info, const Expr *E);
+static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
 static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluateInteger(const Expr *E, APSInt  &Result, EvalInfo &Info);
@@ -264,10 +264,10 @@
 namespace {
 class HasSideEffect
   : public ConstStmtVisitor<HasSideEffect, bool> {
-  EvalInfo &Info;
+  const ASTContext &Ctx;
 public:
 
-  HasSideEffect(EvalInfo &info) : Info(info) {}
+  HasSideEffect(const ASTContext &C) : Ctx(C) {}
 
   // Unhandled nodes conservatively default to having side effects.
   bool VisitStmt(const Stmt *S) {
@@ -279,17 +279,17 @@
     return Visit(E->getResultExpr());
   }
   bool VisitDeclRefExpr(const DeclRefExpr *E) {
-    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+    if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
       return true;
     return false;
   }
   bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) {
-    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+    if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
       return true;
     return false;
   }
   bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) {
-    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+    if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
       return true;
     return false;
   }
@@ -310,7 +310,7 @@
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E)
     { return Visit(E->getLHS()) || Visit(E->getRHS()); }
   bool VisitChooseExpr(const ChooseExpr *E)
-    { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+    { return Visit(E->getChosenSubExpr(Ctx)); }
   bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); }
   bool VisitBinAssign(const BinaryOperator *E) { return true; }
   bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; }
@@ -321,7 +321,7 @@
   bool VisitUnaryPreDec(const UnaryOperator *E) { return true; }
   bool VisitUnaryPostDec(const UnaryOperator *E) { return true; }
   bool VisitUnaryDeref(const UnaryOperator *E) {
-    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+    if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
       return true;
     return Visit(E->getSubExpr());
   }
@@ -349,16 +349,17 @@
     : info(info), opaqueValue(opaqueValue) {
 
     // If evaluation fails, fail immediately.
-    if (!Evaluate(info, value)) {
+    if (!Evaluate(info.OpaqueValues[opaqueValue], info, value)) {
       this->opaqueValue = 0;
       return;
     }
-    info.OpaqueValues[opaqueValue] = info.EvalResult.Val;
   }
 
   bool hasError() const { return opaqueValue == 0; }
 
   ~OpaqueValueEvaluation() {
+    // FIXME: This will not work for recursive constexpr functions using opaque
+    // values. Restore the former value.
     if (opaqueValue) info.OpaqueValues.erase(opaqueValue);
   }
 };
@@ -967,8 +968,9 @@
 }
 
 APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
-  if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
-    Info.EvalResult.HasSideEffects = true;
+  APValue Scratch;
+  if (!Evaluate(Scratch, Info, E->getSubExpr()))
+    Info.EvalStatus.HasSideEffects = true;
   return GetZeroVector(E->getType());
 }
 
@@ -1020,10 +1022,10 @@
 
   bool Error(SourceLocation L, diag::kind D, const Expr *E) {
     // Take the first error.
-    if (Info.EvalResult.Diag == 0) {
-      Info.EvalResult.DiagLoc = L;
-      Info.EvalResult.Diag = D;
-      Info.EvalResult.DiagExpr = E;
+    if (Info.EvalStatus.Diag == 0) {
+      Info.EvalStatus.DiagLoc = L;
+      Info.EvalStatus.Diag = D;
+      Info.EvalStatus.DiagExpr = E;
     }
     return false;
   }
@@ -1058,7 +1060,7 @@
   bool VisitMemberExpr(const MemberExpr *E) {
     if (CheckReferencedDecl(E, E->getMemberDecl())) {
       // Conservatively assume a MemberExpr will have side-effects
-      Info.EvalResult.HasSideEffects = true;
+      Info.EvalStatus.HasSideEffects = true;
       return true;
     }
 
@@ -1172,6 +1174,8 @@
         VD->setEvaluatingValue();
 
         Expr::EvalResult EResult;
+        // FIXME: Produce a diagnostic if the initializer isn't a constant
+        // expression.
         if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects &&
             EResult.Val.isInt()) {
           // Cache the evaluated value in the variable declaration.
@@ -1350,8 +1354,9 @@
 
     // If we can't evaluate the LHS, it might have side effects;
     // conservatively mark it.
-    if (!E->getLHS()->isEvaluatable(Info.Ctx))
-      Info.EvalResult.HasSideEffects = true;
+    APValue Scratch;
+    if (!Evaluate(Scratch, Info, E->getLHS()))
+      Info.EvalStatus.HasSideEffects = true;
 
     return true;
   }
@@ -1381,7 +1386,7 @@
             !rhsResult == (E->getOpcode() == BO_LAnd)) {
           // Since we weren't able to evaluate the left hand side, it
           // must have had side effects.
-          Info.EvalResult.HasSideEffects = true;
+          Info.EvalStatus.HasSideEffects = true;
 
           return Success(rhsResult, E);
         }
@@ -1943,8 +1948,9 @@
     return Success(LV.getComplexIntImag(), E);
   }
 
-  if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
-    Info.EvalResult.HasSideEffects = true;
+  APValue Scratch;
+  if (!Evaluate(Scratch, Info, E->getSubExpr()))
+    Info.EvalStatus.HasSideEffects = true;
   return Success(0, E);
 }
 
@@ -2145,8 +2151,9 @@
     return true;
   }
 
-  if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
-    Info.EvalResult.HasSideEffects = true;
+  APValue Scratch;
+  if (!Evaluate(Scratch, Info, E->getSubExpr()))
+    Info.EvalStatus.HasSideEffects = true;
   const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType());
   Result = llvm::APFloat::getZero(Sem);
   return true;
@@ -2176,8 +2183,9 @@
 
     // If we can't evaluate the LHS, it might have side effects;
     // conservatively mark it.
-    if (!E->getLHS()->isEvaluatable(Info.Ctx))
-      Info.EvalResult.HasSideEffects = true;
+    APValue Scratch;
+    if (!Evaluate(Scratch, Info, E->getLHS()))
+      Info.EvalStatus.HasSideEffects = true;
 
     return true;
   }
@@ -2460,8 +2468,9 @@
 
     // If we can't evaluate the LHS, it might have side effects;
     // conservatively mark it.
-    if (!E->getLHS()->isEvaluatable(Info.Ctx))
-      Info.EvalResult.HasSideEffects = true;
+    APValue Scratch;
+    if (!Evaluate(Scratch, Info, E->getLHS()))
+      Info.EvalStatus.HasSideEffects = true;
 
     return true;
   }
@@ -2616,15 +2625,15 @@
 // Top level Expr::Evaluate method.
 //===----------------------------------------------------------------------===//
 
-static bool Evaluate(EvalInfo &Info, const Expr *E) {
+static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
   if (E->getType()->isVectorType()) {
-    if (!EvaluateVector(E, Info.EvalResult.Val, Info))
+    if (!EvaluateVector(E, Result, Info))
       return false;
   } else if (E->getType()->isIntegralOrEnumerationType()) {
-    if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E))
+    if (!IntExprEvaluator(Info, Result).Visit(E))
       return false;
-    if (Info.EvalResult.Val.isLValue() &&
-        !IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
+    if (Result.isLValue() &&
+        !IsGlobalLValue(Result.getLValueBase()))
       return false;
   } else if (E->getType()->hasPointerRepresentation()) {
     LValue LV;
@@ -2632,18 +2641,18 @@
       return false;
     if (!IsGlobalLValue(LV.Base))
       return false;
-    LV.moveInto(Info.EvalResult.Val);
+    LV.moveInto(Result);
   } else if (E->getType()->isRealFloatingType()) {
     llvm::APFloat F(0.0);
     if (!EvaluateFloat(E, F, Info))
       return false;
 
-    Info.EvalResult.Val = APValue(F);
+    Result = APValue(F);
   } else if (E->getType()->isAnyComplexType()) {
     ComplexValue C;
     if (!EvaluateComplex(E, C, Info))
       return false;
-    C.moveInto(Info.EvalResult.Val);
+    C.moveInto(Result);
   } else
     return false;
 
@@ -2656,19 +2665,19 @@
 /// in Result.
 bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
   EvalInfo Info(Ctx, Result);
-  return ::Evaluate(Info, this);
+  return ::Evaluate(Result.Val, Info, this);
 }
 
 bool Expr::EvaluateAsBooleanCondition(bool &Result,
                                       const ASTContext &Ctx) const {
-  EvalResult Scratch;
+  EvalStatus Scratch;
   EvalInfo Info(Ctx, Scratch);
 
   return HandleConversionToBool(this, Result, Info);
 }
 
 bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
-  EvalResult Scratch;
+  EvalStatus Scratch;
   EvalInfo Info(Ctx, Scratch);
 
   return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects;
@@ -2707,9 +2716,7 @@
 }
 
 bool Expr::HasSideEffects(const ASTContext &Ctx) const {
-  Expr::EvalResult Result;
-  EvalInfo Info(Ctx, Result);
-  return HasSideEffect(Info).Visit(this);
+  return HasSideEffect(Ctx).Visit(this);
 }
 
 APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {