]> granicus.if.org Git - clang/commitdiff
More constant evaluation cleanup, and fix an issue where we'd override an
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 6 Nov 2013 02:19:10 +0000 (02:19 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 6 Nov 2013 02:19:10 +0000 (02:19 +0000)
earlier 'non-constant' diagnostic with a later one if the earlier one was from
a side-effect we thought we could evaluate past.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194117 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx1y.cpp

index cd22ff048b37f99c32ded0e56a5a8ad2ae74bec8..835938ab57907b05baac869c96ec8b998e6af434 100644 (file)
@@ -564,15 +564,17 @@ namespace {
         // EM_ConstantFold mode.
         if (!EvalStatus.Diag->empty()) {
           switch (EvalMode) {
+          case EM_ConstantFold:
+          case EM_IgnoreSideEffects:
+          case EM_EvaluateForOverflow:
+            if (!EvalStatus.HasSideEffects)
+              break;
+            // We've had side-effects; we want the diagnostic from them, not
+            // some later problem.
           case EM_ConstantExpression:
           case EM_PotentialConstantExpression:
             HasActiveDiagnostic = false;
             return OptionalDiagnostic();
-
-          case EM_ConstantFold:
-          case EM_IgnoreSideEffects:
-          case EM_EvaluateForOverflow:
-            break;
           }
         }
 
@@ -641,11 +643,11 @@ namespace {
     /// couldn't model?
     bool keepEvaluatingAfterSideEffect() {
       switch (EvalMode) {
+      case EM_PotentialConstantExpression:
       case EM_EvaluateForOverflow:
       case EM_IgnoreSideEffects:
         return true;
 
-      case EM_PotentialConstantExpression:
       case EM_ConstantExpression:
       case EM_ConstantFold:
         return false;
@@ -1122,11 +1124,9 @@ static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
 /// \return \c true if the caller should keep evaluating.
 static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
   APValue Scratch;
-  if (!Evaluate(Scratch, Info, E)) {
-    Info.EvalStatus.HasSideEffects = true;
-    return Info.keepEvaluatingAfterFailure();
-    // FIXME: return Info.noteSideEffect();
-  }
+  if (!Evaluate(Scratch, Info, E))
+    // We don't need the value, but we might have skipped a side effect here.
+    return Info.noteSideEffect();
   return true;
 }
 
@@ -6336,36 +6336,39 @@ bool DataRecursiveIntBinOpEvaluator::
   if (E->getOpcode() == BO_Comma) {
     // Ignore LHS but note if we could not evaluate it.
     if (LHSResult.Failed)
-      Info.EvalStatus.HasSideEffects = true;
+      return Info.noteSideEffect();
     return true;
   }
-  
+
   if (E->isLogicalOp()) {
-    bool lhsResult;
-    if (HandleConversionToBool(LHSResult.Val, lhsResult)) {
+    bool LHSAsBool;
+    if (!LHSResult.Failed && HandleConversionToBool(LHSResult.Val, LHSAsBool)) {
       // We were able to evaluate the LHS, see if we can get away with not
       // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
-      if (lhsResult == (E->getOpcode() == BO_LOr)) {
-        Success(lhsResult, E, LHSResult.Val);
+      if (LHSAsBool == (E->getOpcode() == BO_LOr)) {
+        Success(LHSAsBool, E, LHSResult.Val);
         return false; // Ignore RHS
       }
     } else {
+      LHSResult.Failed = true;
+
       // Since we weren't able to evaluate the left hand side, it
       // must have had side effects.
-      Info.EvalStatus.HasSideEffects = true;
-      
+      if (!Info.noteSideEffect())
+        return false;
+
       // We can't evaluate the LHS; however, sometimes the result
       // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
       // Don't ignore RHS and suppress diagnostics from this arm.
       SuppressRHSDiags = true;
     }
-    
+
     return true;
   }
-  
+
   assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
          E->getRHS()->getType()->isIntegralOrEnumerationType());
-  
+
   if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure())
     return false; // Ignore RHS;
 
index ebe8e989a83805764b8b9e0e32294e2592b32d08..7a2fa44c21716410089cd89593381ec85f8e4135 100644 (file)
@@ -128,10 +128,10 @@ constexpr int namespace_alias() {
 namespace assign {
   constexpr int a = 0;
   const int b = 0;
-  int c = 0; // expected-note 2{{here}}
+  int c = 0; // expected-note {{here}}
 
   constexpr void set(const int &a, int b) {
-    const_cast<int&>(a) = b; // expected-note 2{{constant expression cannot modify an object that is visible outside that expression}}
+    const_cast<int&>(a) = b; // expected-note 3{{constant expression cannot modify an object that is visible outside that expression}}
   }
   constexpr int wrap(int a, int b) {
     set(a, b);
@@ -140,7 +140,7 @@ namespace assign {
 
   static_assert((set(a, 1), a) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(a, 1)'}}
   static_assert((set(b, 1), b) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(b, 1)'}}
-  static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{read of non-const variable 'c'}}
+  static_assert((set(c, 1), c) == 1, ""); // expected-error {{constant expression}} expected-note {{in call to 'set(c, 1)'}}
 
   static_assert(wrap(a, 1) == 1, "");
   static_assert(wrap(b, 1) == 1, "");