[analyzer] Make sure a temporary object region matches its initial bindings.

When creating a temporary region (say, when a struct rvalue is used as
the base of a member expr), make sure we account for any derived-to-base
casts. We don't actually record these in the LazyCompoundVal that
represents the rvalue, but we need to make sure that the temporary region
we're creating (a) matches the bindings, and (b) matches its expression.

Most of the time this will do exactly the same thing as before, but it
fixes spurious "garbage value" warnings introduced in r175234 by the use
of lazy bindings to model trivial copy constructors.

<rdar://problem/13265460>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175830 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 06b1db5..60fd8d0 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -173,10 +173,37 @@
   SVal V = State->getSVal(E, LC);
 
   if (V.getAs<NonLoc>()) {
-    MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
-    const MemRegion *R  = MRMgr.getCXXTempObjectRegion(E, LC);
-    State = State->bindLoc(loc::MemRegionVal(R), V);
-    State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+    ProgramStateManager &StateMgr = State->getStateManager();
+    MemRegionManager &MRMgr = StateMgr.getRegionManager();
+    StoreManager &StoreMgr = StateMgr.getStoreManager();
+
+    // We need to be careful about treating a derived type's value as
+    // bindings for a base type. Start by stripping and recording base casts.
+    SmallVector<const CastExpr *, 4> Casts;
+    const Expr *Inner = E->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;
+
+      Inner = CE->getSubExpr()->IgnoreParens();
+    }
+
+    // Create a temporary object region for the inner expression (which may have
+    // a more derived type) and bind the NonLoc value into it.
+    SVal Reg = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(Inner, LC));
+    State = State->bindLoc(Reg, V);
+
+    // Re-apply the casts (from innermost to outermost) for type sanity.
+    for (SmallVectorImpl<const CastExpr *>::reverse_iterator I = Casts.rbegin(),
+                                                             E = Casts.rend();
+         I != E; ++I) {
+      Reg = StoreMgr.evalDerivedToBase(Reg, *I);
+    }
+
+    State = State->BindExpr(E, LC, Reg);
   }
 
   return State;
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index e885878..8d0dd6e 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w %s
 
+extern bool clang_analyzer_eval(bool);
+
 struct Trivial {
   Trivial(int x) : value(x) {}
   int value;
@@ -28,3 +30,27 @@
   return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'const struct NonTrivial' returned to caller}}
 }
 
+namespace rdar13265460 {
+  struct TrivialSubclass : public Trivial {
+    TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
+    int anotherValue;
+  };
+
+  TrivialSubclass getTrivialSub() {
+    TrivialSubclass obj(1);
+    obj.value = 42;
+    obj.anotherValue = -42;
+    return obj;
+  }
+
+  void test() {
+    TrivialSubclass obj = getTrivialSub();
+
+    clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
+    clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
+
+    clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
+    clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
+  }
+}
+