xref: /aosp_15_r20/external/clang/test/Analysis/derived-to-base.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
2*67e74705SXin Li // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
3*67e74705SXin Li 
4*67e74705SXin Li void clang_analyzer_eval(bool);
5*67e74705SXin Li void clang_analyzer_checkInlined(bool);
6*67e74705SXin Li 
7*67e74705SXin Li class A {
8*67e74705SXin Li protected:
9*67e74705SXin Li   int x;
10*67e74705SXin Li };
11*67e74705SXin Li 
12*67e74705SXin Li class B : public A {
13*67e74705SXin Li public:
14*67e74705SXin Li   void f();
15*67e74705SXin Li };
16*67e74705SXin Li 
f()17*67e74705SXin Li void B::f() {
18*67e74705SXin Li   x = 3;
19*67e74705SXin Li }
20*67e74705SXin Li 
21*67e74705SXin Li 
22*67e74705SXin Li class C : public B {
23*67e74705SXin Li public:
g()24*67e74705SXin Li   void g() {
25*67e74705SXin Li     // This used to crash because we are upcasting through two bases.
26*67e74705SXin Li     x = 5;
27*67e74705SXin Li   }
28*67e74705SXin Li };
29*67e74705SXin Li 
30*67e74705SXin Li 
31*67e74705SXin Li namespace VirtualBaseClasses {
32*67e74705SXin Li   class A {
33*67e74705SXin Li   protected:
34*67e74705SXin Li     int x;
35*67e74705SXin Li   };
36*67e74705SXin Li 
37*67e74705SXin Li   class B : public virtual A {
38*67e74705SXin Li   public:
getX()39*67e74705SXin Li     int getX() { return x; }
40*67e74705SXin Li   };
41*67e74705SXin Li 
42*67e74705SXin Li   class C : public virtual A {
43*67e74705SXin Li   public:
setX()44*67e74705SXin Li     void setX() { x = 42; }
45*67e74705SXin Li   };
46*67e74705SXin Li 
47*67e74705SXin Li   class D : public B, public C {};
48*67e74705SXin Li   class DV : virtual public B, public C {};
49*67e74705SXin Li   class DV2 : public B, virtual public C {};
50*67e74705SXin Li 
test()51*67e74705SXin Li   void test() {
52*67e74705SXin Li     D d;
53*67e74705SXin Li     d.setX();
54*67e74705SXin Li     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
55*67e74705SXin Li 
56*67e74705SXin Li     DV dv;
57*67e74705SXin Li     dv.setX();
58*67e74705SXin Li     clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
59*67e74705SXin Li 
60*67e74705SXin Li     DV2 dv2;
61*67e74705SXin Li     dv2.setX();
62*67e74705SXin Li     clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
63*67e74705SXin Li   }
64*67e74705SXin Li 
65*67e74705SXin Li 
66*67e74705SXin Li   // Make sure we're consistent about the offset of the A subobject within an
67*67e74705SXin Li   // Intermediate virtual base class.
68*67e74705SXin Li   class Padding1 { int unused; };
69*67e74705SXin Li   class Padding2 { int unused; };
70*67e74705SXin Li   class Intermediate : public Padding1, public A, public Padding2 {};
71*67e74705SXin Li 
72*67e74705SXin Li   class BI : public virtual Intermediate {
73*67e74705SXin Li   public:
getX()74*67e74705SXin Li     int getX() { return x; }
75*67e74705SXin Li   };
76*67e74705SXin Li 
77*67e74705SXin Li   class CI : public virtual Intermediate {
78*67e74705SXin Li   public:
setX()79*67e74705SXin Li     void setX() { x = 42; }
80*67e74705SXin Li   };
81*67e74705SXin Li 
82*67e74705SXin Li   class DI : public BI, public CI {};
83*67e74705SXin Li 
testIntermediate()84*67e74705SXin Li   void testIntermediate() {
85*67e74705SXin Li     DI d;
86*67e74705SXin Li     d.setX();
87*67e74705SXin Li     clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
88*67e74705SXin Li   }
89*67e74705SXin Li }
90*67e74705SXin Li 
91*67e74705SXin Li 
92*67e74705SXin Li namespace DynamicVirtualUpcast {
93*67e74705SXin Li   class A {
94*67e74705SXin Li   public:
95*67e74705SXin Li     virtual ~A();
96*67e74705SXin Li   };
97*67e74705SXin Li 
98*67e74705SXin Li   class B : virtual public A {};
99*67e74705SXin Li   class C : virtual public B {};
100*67e74705SXin Li   class D : virtual public C {};
101*67e74705SXin Li 
testCast(A * a)102*67e74705SXin Li   bool testCast(A *a) {
103*67e74705SXin Li     return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
104*67e74705SXin Li   }
105*67e74705SXin Li 
test()106*67e74705SXin Li   void test() {
107*67e74705SXin Li     D d;
108*67e74705SXin Li     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
109*67e74705SXin Li   }
110*67e74705SXin Li }
111*67e74705SXin Li 
112*67e74705SXin Li namespace DynamicMultipleInheritanceUpcast {
113*67e74705SXin Li   class B {
114*67e74705SXin Li   public:
115*67e74705SXin Li     virtual ~B();
116*67e74705SXin Li   };
117*67e74705SXin Li   class C {
118*67e74705SXin Li   public:
119*67e74705SXin Li     virtual ~C();
120*67e74705SXin Li   };
121*67e74705SXin Li   class D : public B, public C {};
122*67e74705SXin Li 
testCast(B * a)123*67e74705SXin Li   bool testCast(B *a) {
124*67e74705SXin Li     return dynamic_cast<C*>(a);
125*67e74705SXin Li   }
126*67e74705SXin Li 
test()127*67e74705SXin Li   void test() {
128*67e74705SXin Li     D d;
129*67e74705SXin Li     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
130*67e74705SXin Li   }
131*67e74705SXin Li 
132*67e74705SXin Li 
133*67e74705SXin Li   class DV : virtual public B, virtual public C {};
134*67e74705SXin Li 
testVirtual()135*67e74705SXin Li   void testVirtual() {
136*67e74705SXin Li     DV d;
137*67e74705SXin Li     clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
138*67e74705SXin Li   }
139*67e74705SXin Li }
140*67e74705SXin Li 
141*67e74705SXin Li namespace LazyBindings {
142*67e74705SXin Li   struct Base {
143*67e74705SXin Li     int x;
144*67e74705SXin Li   };
145*67e74705SXin Li 
146*67e74705SXin Li   struct Derived : public Base {
147*67e74705SXin Li     int y;
148*67e74705SXin Li   };
149*67e74705SXin Li 
150*67e74705SXin Li   struct DoubleDerived : public Derived {
151*67e74705SXin Li     int z;
152*67e74705SXin Li   };
153*67e74705SXin Li 
getX(const Base & obj)154*67e74705SXin Li   int getX(const Base &obj) {
155*67e74705SXin Li     return obj.x;
156*67e74705SXin Li   }
157*67e74705SXin Li 
getY(const Derived & obj)158*67e74705SXin Li   int getY(const Derived &obj) {
159*67e74705SXin Li     return obj.y;
160*67e74705SXin Li   }
161*67e74705SXin Li 
testDerived()162*67e74705SXin Li   void testDerived() {
163*67e74705SXin Li     Derived d;
164*67e74705SXin Li     d.x = 1;
165*67e74705SXin Li     d.y = 2;
166*67e74705SXin Li     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
167*67e74705SXin Li     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
168*67e74705SXin Li 
169*67e74705SXin Li     Base b(d);
170*67e74705SXin Li     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
171*67e74705SXin Li 
172*67e74705SXin Li     Derived d2(d);
173*67e74705SXin Li     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
174*67e74705SXin Li     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
175*67e74705SXin Li   }
176*67e74705SXin Li 
testDoubleDerived()177*67e74705SXin Li   void testDoubleDerived() {
178*67e74705SXin Li     DoubleDerived d;
179*67e74705SXin Li     d.x = 1;
180*67e74705SXin Li     d.y = 2;
181*67e74705SXin Li     clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
182*67e74705SXin Li     clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
183*67e74705SXin Li 
184*67e74705SXin Li     Base b(d);
185*67e74705SXin Li     clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
186*67e74705SXin Li 
187*67e74705SXin Li     Derived d2(d);
188*67e74705SXin Li     clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
189*67e74705SXin Li     clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
190*67e74705SXin Li 
191*67e74705SXin Li     DoubleDerived d3(d);
192*67e74705SXin Li     clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
193*67e74705SXin Li     clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
194*67e74705SXin Li   }
195*67e74705SXin Li 
196*67e74705SXin Li   namespace WithOffset {
197*67e74705SXin Li     struct Offset {
198*67e74705SXin Li       int padding;
199*67e74705SXin Li     };
200*67e74705SXin Li 
201*67e74705SXin Li     struct OffsetDerived : private Offset, public Base {
202*67e74705SXin Li       int y;
203*67e74705SXin Li     };
204*67e74705SXin Li 
205*67e74705SXin Li     struct DoubleOffsetDerived : public OffsetDerived {
206*67e74705SXin Li       int z;
207*67e74705SXin Li     };
208*67e74705SXin Li 
getY(const OffsetDerived & obj)209*67e74705SXin Li     int getY(const OffsetDerived &obj) {
210*67e74705SXin Li       return obj.y;
211*67e74705SXin Li     }
212*67e74705SXin Li 
testDerived()213*67e74705SXin Li     void testDerived() {
214*67e74705SXin Li       OffsetDerived d;
215*67e74705SXin Li       d.x = 1;
216*67e74705SXin Li       d.y = 2;
217*67e74705SXin Li       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
218*67e74705SXin Li       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
219*67e74705SXin Li 
220*67e74705SXin Li       Base b(d);
221*67e74705SXin Li       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
222*67e74705SXin Li 
223*67e74705SXin Li       OffsetDerived d2(d);
224*67e74705SXin Li       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
225*67e74705SXin Li       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
226*67e74705SXin Li     }
227*67e74705SXin Li 
testDoubleDerived()228*67e74705SXin Li     void testDoubleDerived() {
229*67e74705SXin Li       DoubleOffsetDerived d;
230*67e74705SXin Li       d.x = 1;
231*67e74705SXin Li       d.y = 2;
232*67e74705SXin Li       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
233*67e74705SXin Li       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
234*67e74705SXin Li 
235*67e74705SXin Li       Base b(d);
236*67e74705SXin Li       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
237*67e74705SXin Li 
238*67e74705SXin Li       OffsetDerived d2(d);
239*67e74705SXin Li       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
240*67e74705SXin Li       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
241*67e74705SXin Li 
242*67e74705SXin Li       DoubleOffsetDerived d3(d);
243*67e74705SXin Li       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
244*67e74705SXin Li       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
245*67e74705SXin Li     }
246*67e74705SXin Li   }
247*67e74705SXin Li 
248*67e74705SXin Li   namespace WithVTable {
249*67e74705SXin Li     struct DerivedVTBL : public Base {
250*67e74705SXin Li       int y;
251*67e74705SXin Li       virtual void method();
252*67e74705SXin Li     };
253*67e74705SXin Li 
254*67e74705SXin Li     struct DoubleDerivedVTBL : public DerivedVTBL {
255*67e74705SXin Li       int z;
256*67e74705SXin Li     };
257*67e74705SXin Li 
getY(const DerivedVTBL & obj)258*67e74705SXin Li     int getY(const DerivedVTBL &obj) {
259*67e74705SXin Li       return obj.y;
260*67e74705SXin Li     }
261*67e74705SXin Li 
getZ(const DoubleDerivedVTBL & obj)262*67e74705SXin Li     int getZ(const DoubleDerivedVTBL &obj) {
263*67e74705SXin Li       return obj.z;
264*67e74705SXin Li     }
265*67e74705SXin Li 
testDerived()266*67e74705SXin Li     void testDerived() {
267*67e74705SXin Li       DerivedVTBL d;
268*67e74705SXin Li       d.x = 1;
269*67e74705SXin Li       d.y = 2;
270*67e74705SXin Li       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
271*67e74705SXin Li       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
272*67e74705SXin Li 
273*67e74705SXin Li       Base b(d);
274*67e74705SXin Li       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
275*67e74705SXin Li 
276*67e74705SXin Li #if CONSTRUCTORS
277*67e74705SXin Li       DerivedVTBL d2(d);
278*67e74705SXin Li       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
279*67e74705SXin Li       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
280*67e74705SXin Li #endif
281*67e74705SXin Li     }
282*67e74705SXin Li 
283*67e74705SXin Li #if CONSTRUCTORS
testDoubleDerived()284*67e74705SXin Li     void testDoubleDerived() {
285*67e74705SXin Li       DoubleDerivedVTBL d;
286*67e74705SXin Li       d.x = 1;
287*67e74705SXin Li       d.y = 2;
288*67e74705SXin Li       d.z = 3;
289*67e74705SXin Li       clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
290*67e74705SXin Li       clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
291*67e74705SXin Li       clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
292*67e74705SXin Li 
293*67e74705SXin Li       Base b(d);
294*67e74705SXin Li       clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
295*67e74705SXin Li 
296*67e74705SXin Li       DerivedVTBL d2(d);
297*67e74705SXin Li       clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
298*67e74705SXin Li       clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
299*67e74705SXin Li 
300*67e74705SXin Li       DoubleDerivedVTBL d3(d);
301*67e74705SXin Li       clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
302*67e74705SXin Li       clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
303*67e74705SXin Li       clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
304*67e74705SXin Li     }
305*67e74705SXin Li #endif
306*67e74705SXin Li   }
307*67e74705SXin Li 
308*67e74705SXin Li #if CONSTRUCTORS
309*67e74705SXin Li   namespace Nested {
310*67e74705SXin Li     struct NonTrivialCopy {
311*67e74705SXin Li       int padding;
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy312*67e74705SXin Li       NonTrivialCopy() {}
NonTrivialCopyLazyBindings::Nested::NonTrivialCopy313*67e74705SXin Li       NonTrivialCopy(const NonTrivialCopy &) {}
314*67e74705SXin Li     };
315*67e74705SXin Li 
316*67e74705SXin Li     struct FullyDerived : private NonTrivialCopy, public Derived {
317*67e74705SXin Li       int z;
318*67e74705SXin Li     };
319*67e74705SXin Li 
320*67e74705SXin Li     struct Wrapper {
321*67e74705SXin Li       FullyDerived d;
322*67e74705SXin Li       int zz;
323*67e74705SXin Li 
WrapperLazyBindings::Nested::Wrapper324*67e74705SXin Li       Wrapper(const FullyDerived &d) : d(d), zz(0) {}
325*67e74705SXin Li     };
326*67e74705SXin Li 
test5()327*67e74705SXin Li     void test5() {
328*67e74705SXin Li       Wrapper w((FullyDerived()));
329*67e74705SXin Li       w.d.x = 1;
330*67e74705SXin Li 
331*67e74705SXin Li       Wrapper w2(w);
332*67e74705SXin Li       clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
333*67e74705SXin Li     }
334*67e74705SXin Li   }
335*67e74705SXin Li #endif
336*67e74705SXin Li }
337*67e74705SXin Li 
338*67e74705SXin Li namespace Redeclaration {
339*67e74705SXin Li   class Base;
340*67e74705SXin Li 
341*67e74705SXin Li   class Base {
342*67e74705SXin Li   public:
343*67e74705SXin Li     virtual int foo();
get()344*67e74705SXin Li     int get() { return value; }
345*67e74705SXin Li 
346*67e74705SXin Li     int value;
347*67e74705SXin Li   };
348*67e74705SXin Li 
349*67e74705SXin Li   class Derived : public Base {
350*67e74705SXin Li   public:
351*67e74705SXin Li     virtual int bar();
352*67e74705SXin Li   };
353*67e74705SXin Li 
test(Derived d)354*67e74705SXin Li   void test(Derived d) {
355*67e74705SXin Li     d.foo(); // don't crash
356*67e74705SXin Li     d.bar(); // sanity check
357*67e74705SXin Li 
358*67e74705SXin Li     Base &b = d;
359*67e74705SXin Li     b.foo(); // don't crash
360*67e74705SXin Li 
361*67e74705SXin Li     d.value = 42; // don't crash
362*67e74705SXin Li     clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
363*67e74705SXin Li     clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
364*67e74705SXin Li   }
365*67e74705SXin Li };
366*67e74705SXin Li 
367*67e74705SXin Li namespace PR15394 {
368*67e74705SXin Li   namespace Original {
369*67e74705SXin Li     class Base {
370*67e74705SXin Li     public:
371*67e74705SXin Li       virtual int f() = 0;
372*67e74705SXin Li       int i;
373*67e74705SXin Li     };
374*67e74705SXin Li 
375*67e74705SXin Li     class Derived1 : public Base {
376*67e74705SXin Li     public:
377*67e74705SXin Li       int j;
378*67e74705SXin Li     };
379*67e74705SXin Li 
380*67e74705SXin Li     class Derived2 : public Derived1 {
381*67e74705SXin Li     public:
f()382*67e74705SXin Li       virtual int f() {
383*67e74705SXin Li         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
384*67e74705SXin Li         return i + j;
385*67e74705SXin Li       }
386*67e74705SXin Li     };
387*67e74705SXin Li 
testXXX()388*67e74705SXin Li     void testXXX() {
389*67e74705SXin Li       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
390*67e74705SXin Li       d1p->i = 1;
391*67e74705SXin Li       d1p->j = 2;
392*67e74705SXin Li       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
393*67e74705SXin Li     }
394*67e74705SXin Li   }
395*67e74705SXin Li 
396*67e74705SXin Li   namespace VirtualInDerived {
397*67e74705SXin Li     class Base {
398*67e74705SXin Li     public:
399*67e74705SXin Li       int i;
400*67e74705SXin Li     };
401*67e74705SXin Li 
402*67e74705SXin Li     class Derived1 : public Base {
403*67e74705SXin Li     public:
404*67e74705SXin Li       virtual int f() = 0;
405*67e74705SXin Li       int j;
406*67e74705SXin Li     };
407*67e74705SXin Li 
408*67e74705SXin Li     class Derived2 : public Derived1 {
409*67e74705SXin Li     public:
f()410*67e74705SXin Li       virtual int f() {
411*67e74705SXin Li         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
412*67e74705SXin Li         return i + j;
413*67e74705SXin Li       }
414*67e74705SXin Li     };
415*67e74705SXin Li 
test()416*67e74705SXin Li     void test() {
417*67e74705SXin Li       Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2);
418*67e74705SXin Li       d1p->i = 1;
419*67e74705SXin Li       d1p->j = 2;
420*67e74705SXin Li       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
421*67e74705SXin Li     }
422*67e74705SXin Li   }
423*67e74705SXin Li 
424*67e74705SXin Li   namespace NoCast {
425*67e74705SXin Li     class Base {
426*67e74705SXin Li     public:
427*67e74705SXin Li       int i;
428*67e74705SXin Li     };
429*67e74705SXin Li 
430*67e74705SXin Li     class Derived1 : public Base {
431*67e74705SXin Li     public:
432*67e74705SXin Li       virtual int f() = 0;
433*67e74705SXin Li       int j;
434*67e74705SXin Li     };
435*67e74705SXin Li 
436*67e74705SXin Li     class Derived2 : public Derived1 {
437*67e74705SXin Li     public:
f()438*67e74705SXin Li       virtual int f() {
439*67e74705SXin Li         clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
440*67e74705SXin Li         return i + j;
441*67e74705SXin Li       }
442*67e74705SXin Li     };
443*67e74705SXin Li 
test()444*67e74705SXin Li     void test() {
445*67e74705SXin Li       Derived1 *d1p = new Derived2;
446*67e74705SXin Li       d1p->i = 1;
447*67e74705SXin Li       d1p->j = 2;
448*67e74705SXin Li       clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}}
449*67e74705SXin Li     }
450*67e74705SXin Li   }
451*67e74705SXin Li };
452*67e74705SXin Li 
453*67e74705SXin Li namespace Bug16309 {
454*67e74705SXin Li   struct Incomplete;
455*67e74705SXin Li 
456*67e74705SXin Li   struct Base { virtual ~Base(); };
457*67e74705SXin Li 
458*67e74705SXin Li   struct Derived : public Base { int x; };
459*67e74705SXin Li 
f(Incomplete * i)460*67e74705SXin Li   void* f(Incomplete *i) {
461*67e74705SXin Li     Base *b = reinterpret_cast<Base *>(i);
462*67e74705SXin Li     // This used to crash because of the reinterpret_cast above.
463*67e74705SXin Li     Derived *d = dynamic_cast<Derived *>(b);
464*67e74705SXin Li     return d;
465*67e74705SXin Li   }
466*67e74705SXin Li 
467*67e74705SXin Li   // And check that reinterpret+dynamic casts work correctly after the fix.
g()468*67e74705SXin Li   void g() {
469*67e74705SXin Li     Derived d;
470*67e74705SXin Li     d.x = 47;
471*67e74705SXin Li     Base *b = &d;
472*67e74705SXin Li     Incomplete *i = reinterpret_cast<Incomplete *>(b);
473*67e74705SXin Li     Base *b2 = reinterpret_cast<Base *>(i);
474*67e74705SXin Li     Derived *d2 = dynamic_cast<Derived *>(b2);
475*67e74705SXin Li     clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}}
476*67e74705SXin Li   }
477*67e74705SXin Li }
478