]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't try to evaluate MaterializeTemporaryExpr as a constant.
authorJordan Rose <jordan_rose@apple.com>
Thu, 2 May 2013 19:51:20 +0000 (19:51 +0000)
committerJordan Rose <jordan_rose@apple.com>
Thu, 2 May 2013 19:51:20 +0000 (19:51 +0000)
...and don't consider '0' to be a null pointer constant if it's the
initializer for a float!

Apparently null pointer constant evaluation looks through both
MaterializeTemporaryExpr and ImplicitCastExpr, so we have to be more
careful about types in the callers. For RegionStore this just means giving
up a little more; for ExprEngine this means handling the
MaterializeTemporaryExpr case explicitly.

Follow-up to r180894.

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

include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/SValBuilder.cpp
test/Analysis/inline.cpp

index 713a6d593302918e948e6fcae5708cc9569a3350..bbb56885af0416eaaf02fd7cbd134e278aee3b4b 100644 (file)
@@ -206,9 +206,6 @@ public:
   /// manner.
   ///
   /// If \p E is not a constant or cannot be modeled, returns \c None.
-  ///
-  /// Note that this function always treats \p E as a prvalue. Callers should
-  /// check to see if \p E is a glvalue and modify their behavior accordingly.
   Optional<SVal> getConstantVal(const Expr *E);
 
   NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) {
index 0d5fb1785b338af520971b5cb83fab6c564f40ef..bfe4e15a7156bc3e8c71925766237a4860ef80d3 100644 (file)
@@ -741,6 +741,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
       const Expr *ArgE = DefaultE->getExpr();
 
+      bool IsTemporary = false;
+      if (const MaterializeTemporaryExpr *MTE =
+            dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
+        ArgE = MTE->GetTemporaryExpr();
+        IsTemporary = true;
+      }
+
       Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
       if (!ConstantVal)
         ConstantVal = UnknownVal();
@@ -749,7 +756,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
            I != E; ++I) {
         ProgramStateRef State = (*I)->getState();
         State = State->BindExpr(DefaultE, LCtx, *ConstantVal);
-        if (DefaultE->isGLValue())
+        if (IsTemporary)
           State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
                                                 DefaultE);
         Bldr2.generateNode(S, *I, State);
index 652809777cfdc33a55d8409d6e4a742b0b5f8d0d..9d77a3ef58fb6f2a32790578bc9428eb82955e54 100644 (file)
@@ -268,13 +268,18 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
 
   // If we don't have a special case, fall back to the AST's constant evaluator.
   default: {
+    // Don't try to come up with a value for materialized temporaries.
+    if (E->isGLValue())
+      return None;
+
     ASTContext &Ctx = getContext();
     llvm::APSInt Result;
     if (E->EvaluateAsInt(Result, Ctx))
       return makeIntVal(Result);
 
-    if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
-      return makeNull();
+    if (Loc::isLocType(E->getType()))
+      if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+        return makeNull();
 
     return None;
   }
index 62bce284721b55621820304133ec2d13ad0de2e2..909e18017b34b9d0bebc3d154f7fabca693e1a8e 100644 (file)
@@ -262,12 +262,33 @@ namespace DefaultArgs {
   }
 
   int defaultReference(const int &input = 42) {
-    return input;
+    return -input;
+  }
+  int defaultReferenceZero(const int &input = 0) {
+    return -input;
   }
 
   void testReference() {
-    clang_analyzer_eval(defaultReference(1) == 1); // expected-warning{{TRUE}}
-    clang_analyzer_eval(defaultReference() == 42); // expected-warning{{TRUE}}
+    clang_analyzer_eval(defaultReference(1) == -1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(defaultReference() == -42); // expected-warning{{TRUE}}
+
+    clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}}
+}
+
+  double defaultFloatReference(const double &i = 42) {
+    return -i;
+  }
+  double defaultFloatReferenceZero(const double &i = 0) {
+    return -i;
+  }
+
+  void testFloatReference() {
+    clang_analyzer_eval(defaultFloatReference(1) == -1); // expected-warning{{UNKNOWN}}
+    clang_analyzer_eval(defaultFloatReference() == -42); // expected-warning{{UNKNOWN}}
+
+    clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}}
+    clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}}
   }
 }