]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't look through casts when creating pointer temporaries.
authorJordan Rose <jordan_rose@apple.com>
Tue, 26 Feb 2013 01:21:27 +0000 (01:21 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 26 Feb 2013 01:21:27 +0000 (01:21 +0000)
Normally, we need to look through derived-to-base casts when creating
temporary object regions (added in r175854). However, if the temporary
is a pointer (rather than a struct/class instance), we need to /preserve/
the base casts that have been applied.

This also ensures that we really do create a new temporary region when
we need to: MaterializeTemporaryExpr and lvalue CXXDefaultArgExprs.

Fixes PR15342, although the test case doesn't include the crash because
I couldn't isolate it.

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
test/Analysis/temporaries.cpp

index 8b6de1324972400d665631e9dbcd4fc7c4baaff3..437af86ccfc213179a182ba5e99ca0c144380a80 100644 (file)
@@ -182,14 +182,16 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
   // bindings for a base type. Start by stripping and recording base casts.
   SmallVector<const CastExpr *, 4> Casts;
   const Expr *Inner = Ex->IgnoreParens();
-  while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
-    if (CE->getCastKind() == CK_DerivedToBase ||
-        CE->getCastKind() == CK_UncheckedDerivedToBase)
-      Casts.push_back(CE);
-    else if (CE->getCastKind() != CK_NoOp)
-      break;
+  if (V.getAs<NonLoc>()) {
+    while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
+      if (CE->getCastKind() == CK_DerivedToBase ||
+          CE->getCastKind() == CK_UncheckedDerivedToBase)
+        Casts.push_back(CE);
+      else if (CE->getCastKind() != CK_NoOp)
+        break;
 
-    Inner = CE->getSubExpr()->IgnoreParens();
+      Inner = CE->getSubExpr()->IgnoreParens();
+    }
   }
 
   // Create a temporary object region for the inner expression (which may have
@@ -703,7 +705,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
 
         State = State->BindExpr(DefaultE, LCtx, V);
         if (DefaultE->isGLValue())
-          State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE);
+          State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
+                                                DefaultE);
         Bldr2.generateNode(S, *I, State);
       }
 
index e7d59ebf576e2e7102be269c56598e23fe7208aa..32b522cbd5b3369403e64e8f83aa41f227a312a0 100644 (file)
@@ -34,12 +34,17 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
 
   // If the value is already a CXXTempObjectRegion, it is fine as it is.
   // Otherwise, create a new CXXTempObjectRegion, and copy the value into it.
+  // This is an optimization for when an rvalue is constructed and then
+  // immediately materialized.
   const MemRegion *MR = V.getAsRegion();
-  if (MR && isa<CXXTempObjectRegion>(MR))
-    state = state->BindExpr(ME, LCtx, V);
-  else
-    state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
+  if (const CXXTempObjectRegion *TR =
+        dyn_cast_or_null<CXXTempObjectRegion>(MR)) {
+    if (getContext().hasSameUnqualifiedType(TR->getValueType(), ME->getType()))
+      state = state->BindExpr(ME, LCtx, V);
+  }
 
+  if (state == Pred->getState())
+    state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
   Bldr.generateNode(ME, Pred, state);
 }
 
index 8c4e33b17935d746e273663ee8f54ebf2c11acbb..32a4d3bef46575eff765cd4b100b21d66c373852 100644 (file)
@@ -62,3 +62,17 @@ namespace rdar13265460 {
   }
 }
 
+namespace rdar13281951 {
+  struct Derived : public Trivial {
+    Derived(int value) : Trivial(value), value2(-value) {}
+    int value2;
+  };
+
+  void test() {
+    Derived obj(1);
+    obj.value = 42;
+    const Trivial * const &pointerRef = &obj;
+    clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}}
+  }
+}
+