derived-to-base.cpp revision ae7396c3891748762d01431e16541b3eb9125c4d
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
2// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
3
4void clang_analyzer_eval(bool);
5
6class A {
7protected:
8  int x;
9};
10
11class B : public A {
12public:
13  void f();
14};
15
16void B::f() {
17  x = 3;
18}
19
20
21class C : public B {
22public:
23  void g() {
24    // This used to crash because we are upcasting through two bases.
25    x = 5;
26  }
27};
28
29
30namespace VirtualBaseClasses {
31  class A {
32  protected:
33    int x;
34  };
35
36  class B : public virtual A {
37  public:
38    int getX() { return x; }
39  };
40
41  class C : public virtual A {
42  public:
43    void setX() { x = 42; }
44  };
45
46  class D : public B, public C {};
47  class DV : virtual public B, public C {};
48  class DV2 : public B, virtual public C {};
49
50  void test() {
51    D d;
52    d.setX();
53    clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
54
55    DV dv;
56    dv.setX();
57    clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}}
58
59    DV2 dv2;
60    dv2.setX();
61    clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}}
62  }
63
64
65  // Make sure we're consistent about the offset of the A subobject within an
66  // Intermediate virtual base class.
67  class Padding1 { int unused; };
68  class Padding2 { int unused; };
69  class Intermediate : public Padding1, public A, public Padding2 {};
70
71  class BI : public virtual Intermediate {
72  public:
73    int getX() { return x; }
74  };
75
76  class CI : public virtual Intermediate {
77  public:
78    void setX() { x = 42; }
79  };
80
81  class DI : public BI, public CI {};
82
83  void testIntermediate() {
84    DI d;
85    d.setX();
86    clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}}
87  }
88}
89
90
91namespace DynamicVirtualUpcast {
92  class A {
93  public:
94    virtual ~A();
95  };
96
97  class B : virtual public A {};
98  class C : virtual public B {};
99  class D : virtual public C {};
100
101  bool testCast(A *a) {
102    return dynamic_cast<B*>(a) && dynamic_cast<C*>(a);
103  }
104
105  void test() {
106    D d;
107    clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
108  }
109}
110
111namespace DynamicMultipleInheritanceUpcast {
112  class B {
113  public:
114    virtual ~B();
115  };
116  class C {
117  public:
118    virtual ~C();
119  };
120  class D : public B, public C {};
121
122  bool testCast(B *a) {
123    return dynamic_cast<C*>(a);
124  }
125
126  void test() {
127    D d;
128    clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
129  }
130
131
132  class DV : virtual public B, virtual public C {};
133
134  void testVirtual() {
135    DV d;
136    clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
137  }
138}
139
140namespace LazyBindings {
141  struct Base {
142    int x;
143  };
144
145  struct Derived : public Base {
146    int y;
147  };
148
149  struct DoubleDerived : public Derived {
150    int z;
151  };
152
153  int getX(const Base &obj) {
154    return obj.x;
155  }
156
157  int getY(const Derived &obj) {
158    return obj.y;
159  }
160
161  void testDerived() {
162    Derived d;
163    d.x = 1;
164    d.y = 2;
165    clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
166    clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
167
168    Base b(d);
169    clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
170
171    Derived d2(d);
172    clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
173    clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
174  }
175
176  void testDoubleDerived() {
177    DoubleDerived d;
178    d.x = 1;
179    d.y = 2;
180    clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
181    clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
182
183    Base b(d);
184    clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
185
186    Derived d2(d);
187    clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
188    clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
189
190    DoubleDerived d3(d);
191    clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
192    clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
193  }
194
195  namespace WithOffset {
196    struct Offset {
197      int padding;
198    };
199
200    struct OffsetDerived : private Offset, public Base {
201      int y;
202    };
203
204    struct DoubleOffsetDerived : public OffsetDerived {
205      int z;
206    };
207
208    int getY(const OffsetDerived &obj) {
209      return obj.y;
210    }
211
212    void testDerived() {
213      OffsetDerived d;
214      d.x = 1;
215      d.y = 2;
216      clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
217      clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
218
219      Base b(d);
220      clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
221
222      OffsetDerived d2(d);
223      clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
224      clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
225    }
226
227    void testDoubleDerived() {
228      DoubleOffsetDerived d;
229      d.x = 1;
230      d.y = 2;
231      clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
232      clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
233
234      Base b(d);
235      clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
236
237      OffsetDerived d2(d);
238      clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
239      clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
240
241      DoubleOffsetDerived d3(d);
242      clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
243      clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
244    }
245  }
246
247  namespace WithVTable {
248    struct DerivedVTBL : public Base {
249      int y;
250      virtual void method();
251    };
252
253    struct DoubleDerivedVTBL : public DerivedVTBL {
254      int z;
255    };
256
257    int getY(const DerivedVTBL &obj) {
258      return obj.y;
259    }
260
261    int getZ(const DoubleDerivedVTBL &obj) {
262      return obj.z;
263    }
264
265    void testDerived() {
266      DerivedVTBL d;
267      d.x = 1;
268      d.y = 2;
269      clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
270      clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
271
272      Base b(d);
273      clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
274
275#if CONSTRUCTORS
276      DerivedVTBL d2(d);
277      clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
278      clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
279#endif
280    }
281
282#if CONSTRUCTORS
283    void testDoubleDerived() {
284      DoubleDerivedVTBL d;
285      d.x = 1;
286      d.y = 2;
287      d.z = 3;
288      clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
289      clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
290      clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
291
292      Base b(d);
293      clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
294
295      DerivedVTBL d2(d);
296      clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
297      clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
298
299      DoubleDerivedVTBL d3(d);
300      clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
301      clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
302      clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
303    }
304#endif
305  }
306
307#if CONSTRUCTORS
308  namespace Nested {
309    struct NonTrivialCopy {
310      int padding;
311      NonTrivialCopy() {}
312      NonTrivialCopy(const NonTrivialCopy &) {}
313    };
314
315    struct FullyDerived : private NonTrivialCopy, public Derived {
316      int z;
317    };
318
319    struct Wrapper {
320      FullyDerived d;
321      int zz;
322
323      Wrapper(const FullyDerived &d) : d(d), zz(0) {}
324    };
325
326    void test5() {
327      Wrapper w((FullyDerived()));
328      w.d.x = 1;
329
330      Wrapper w2(w);
331      clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
332    }
333  }
334#endif
335}
336
337namespace Redeclaration {
338  class Base;
339
340  class Base {
341  public:
342    virtual int foo();
343    int get() { return value; }
344
345    int value;
346  };
347
348  class Derived : public Base {
349  public:
350    virtual int bar();
351  };
352
353  void test(Derived d) {
354    d.foo(); // don't crash
355    d.bar(); // sanity check
356
357    Base &b = d;
358    b.foo(); // don't crash
359
360    d.value = 42; // don't crash
361    clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
362    clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
363  }
364};
365
366