[analyzer] Don't strip CXXBaseObjectRegions when checking dynamic_casts.

...and /do/ strip CXXBaseObjectRegions when casting to a virtual base class.

This allows us to enforce the invariant that a CXXBaseObjectRegion can always
provide an offset for its base region if its base region has a known class
type, by only allowing virtual bases and direct non-virtual bases to form
CXXBaseObjectRegions.

This does mean some slight problems for our modeling of dynamic_cast, which
needs to be resolved by finding a path from the current region to the class
we're trying to cast to.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161797 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index f6c9beb..b065bc2 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+
+void clang_analyzer_eval(bool);
 
 class A {
 protected:
@@ -22,3 +24,64 @@
     x = 5;
   }
 };
+
+
+namespace VirtualBaseClasses {
+  class A {
+  protected:
+    int x;
+  };
+
+  class B : public virtual A {
+  public:
+    int getX() { return x; }
+  };
+
+  class C : public virtual A {
+  public:
+    void setX() { x = 42; }
+  };
+
+  class D : public B, public C {};
+  class DV : virtual public B, public C {};
+  class DV2 : public B, virtual public C {};
+
+  void test() {
+    D d;
+    d.setX();
+    clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
+
+    DV dv;
+    dv.setX();
+    clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
+
+    DV2 dv2;
+    dv2.setX();
+    clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
+  }
+
+
+  // Make sure we're consistent about the offset of the A subobject within an
+  // Intermediate virtual base class.
+  class Padding1 { int unused; };
+  class Padding2 { int unused; };
+  class Intermediate : public Padding1, public A, public Padding2 {};
+
+  class BI : public virtual Intermediate {
+  public:
+    int getX() { return x; }
+  };
+
+  class CI : public virtual Intermediate {
+  public:
+    void setX() { x = 42; }
+  };
+
+  class DI : public BI, public CI {};
+
+  void testIntermediate() {
+    DI d;
+    d.setX();
+    clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
+  }
+}
diff --git a/test/Analysis/dynamic-cast.cpp b/test/Analysis/dynamic-cast.cpp
index 215bc49..b1133ac 100644
--- a/test/Analysis/dynamic-cast.cpp
+++ b/test/Analysis/dynamic-cast.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core -analyzer-ipa=none -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=none -verify %s
+
+void clang_analyzer_eval(bool);
 
 class A {
 public:
@@ -208,7 +210,25 @@
   testDynCastMostLikelyWillFail(&m);
 }
 
+
+void testDynCastToMiddleClass () {
+  class BBB : public BB {};
+  BBB obj;
+  A &ref = obj;
+
+  // These didn't always correctly layer base regions.
+  B *ptr = dynamic_cast<B*>(&ref);
+  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
+
+  // This is actually statically resolved to be a DerivedToBase cast.
+  ptr = dynamic_cast<B*>(&obj);
+  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
+}
+
+
+// -----------------------------
 // False positives/negatives.
+// -----------------------------
 
 // Due to symbolic regions not being typed.
 int testDynCastFalsePositive(BB *c) {