[analyzer] Treat reinterpret_cast like a base cast in certain cases.

The analyzer represents all pointer-to-pointer bitcasts the same way, but
this can be problematic if an implicit base cast gets layered on top of a
manual base cast (performed with reinterpret_cast instead of static_cast).
Fix this (and avoid a valid assertion) by looking through cast regions.

Using reinterpret_cast this way is only valid if the base class is at the
same offset as the derived class; this is checked by -Wreinterpret-base-class.
In the interest of performance, the analyzer doesn't repeat this check
anywhere; it will just silently do the wrong thing (use the wrong offsets
for fields of the base class) if the user code is wrong.

PR15394

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180052 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index b846d2c..0664189 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
 
 void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
 
 class A {
 protected:
@@ -363,3 +364,89 @@
   }
 };
 
+namespace PR15394 {
+  namespace Original {
+    class Base {
+    public:
+      virtual int f() = 0;
+      int i;
+    };
+
+    class Derived1 : public Base {
+    public:
+      int j;
+    };
+
+    class Derived2 : public Derived1 {
+    public:
+      virtual int f() {
+        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+        return i + j;
+      }
+    };
+
+    void testXXX() {
+      Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
+      d1p->i = 1;
+      d1p->j = 2;
+      clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
+    }
+  }
+
+  namespace VirtualInDerived {
+    class Base {
+    public:
+      int i;
+    };
+
+    class Derived1 : public Base {
+    public:
+      virtual int f() = 0;
+      int j;
+    };
+
+    class Derived2 : public Derived1 {
+    public:
+      virtual int f() {
+        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+        return i + j;
+      }
+    };
+
+    void test() {
+      Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
+      d1p->i = 1;
+      d1p->j = 2;
+      clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
+    }
+  }
+
+  namespace NoCast {
+    class Base {
+    public:
+      int i;
+    };
+
+    class Derived1 : public Base {
+    public:
+      virtual int f() = 0;
+      int j;
+    };
+
+    class Derived2 : public Derived1 {
+    public:
+      virtual int f() {
+        clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+        return i + j;
+      }
+    };
+
+    void test() {
+      Derived1 *d1p = new Derived2;
+      d1p->i = 1;
+      d1p->j = 2;
+      clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
+    }
+  }
+};
+