xref: /minix3/external/bsd/llvm/dist/clang/test/Analysis/dtor.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -verify %s
2f4a2713aSLionel Sambuc 
3f4a2713aSLionel Sambuc void clang_analyzer_eval(bool);
4f4a2713aSLionel Sambuc void clang_analyzer_checkInlined(bool);
5f4a2713aSLionel Sambuc 
6f4a2713aSLionel Sambuc class A {
7f4a2713aSLionel Sambuc public:
~A()8f4a2713aSLionel Sambuc   ~A() {
9f4a2713aSLionel Sambuc     int *x = 0;
10f4a2713aSLionel Sambuc     *x = 3; // expected-warning{{Dereference of null pointer}}
11f4a2713aSLionel Sambuc   }
12f4a2713aSLionel Sambuc };
13f4a2713aSLionel Sambuc 
main()14f4a2713aSLionel Sambuc int main() {
15f4a2713aSLionel Sambuc   A a;
16f4a2713aSLionel Sambuc }
17f4a2713aSLionel Sambuc 
18f4a2713aSLionel Sambuc 
19f4a2713aSLionel Sambuc typedef __typeof(sizeof(int)) size_t;
20f4a2713aSLionel Sambuc void *malloc(size_t);
21f4a2713aSLionel Sambuc void free(void *);
22f4a2713aSLionel Sambuc 
23f4a2713aSLionel Sambuc class SmartPointer {
24f4a2713aSLionel Sambuc   void *X;
25f4a2713aSLionel Sambuc public:
SmartPointer(void * x)26f4a2713aSLionel Sambuc   SmartPointer(void *x) : X(x) {}
~SmartPointer()27f4a2713aSLionel Sambuc   ~SmartPointer() {
28f4a2713aSLionel Sambuc     free(X);
29f4a2713aSLionel Sambuc   }
30f4a2713aSLionel Sambuc };
31f4a2713aSLionel Sambuc 
testSmartPointer()32f4a2713aSLionel Sambuc void testSmartPointer() {
33f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
34f4a2713aSLionel Sambuc   {
35f4a2713aSLionel Sambuc     SmartPointer Deleter(mem);
36f4a2713aSLionel Sambuc     // destructor called here
37f4a2713aSLionel Sambuc   }
38f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
39f4a2713aSLionel Sambuc }
40f4a2713aSLionel Sambuc 
41f4a2713aSLionel Sambuc 
42f4a2713aSLionel Sambuc void doSomething();
testSmartPointer2()43f4a2713aSLionel Sambuc void testSmartPointer2() {
44f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
45f4a2713aSLionel Sambuc   {
46f4a2713aSLionel Sambuc     SmartPointer Deleter(mem);
47f4a2713aSLionel Sambuc     // Remove dead bindings...
48f4a2713aSLionel Sambuc     doSomething();
49f4a2713aSLionel Sambuc     // destructor called here
50f4a2713aSLionel Sambuc   }
51f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
52f4a2713aSLionel Sambuc }
53f4a2713aSLionel Sambuc 
54f4a2713aSLionel Sambuc 
55f4a2713aSLionel Sambuc class Subclass : public SmartPointer {
56f4a2713aSLionel Sambuc public:
Subclass(void * x)57f4a2713aSLionel Sambuc   Subclass(void *x) : SmartPointer(x) {}
58f4a2713aSLionel Sambuc };
59f4a2713aSLionel Sambuc 
testSubclassSmartPointer()60f4a2713aSLionel Sambuc void testSubclassSmartPointer() {
61f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
62f4a2713aSLionel Sambuc   {
63f4a2713aSLionel Sambuc     Subclass Deleter(mem);
64f4a2713aSLionel Sambuc     // Remove dead bindings...
65f4a2713aSLionel Sambuc     doSomething();
66f4a2713aSLionel Sambuc     // destructor called here
67f4a2713aSLionel Sambuc   }
68f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
69f4a2713aSLionel Sambuc }
70f4a2713aSLionel Sambuc 
71f4a2713aSLionel Sambuc 
72f4a2713aSLionel Sambuc class MultipleInheritance : public Subclass, public SmartPointer {
73f4a2713aSLionel Sambuc public:
MultipleInheritance(void * a,void * b)74f4a2713aSLionel Sambuc   MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
75f4a2713aSLionel Sambuc };
76f4a2713aSLionel Sambuc 
testMultipleInheritance1()77f4a2713aSLionel Sambuc void testMultipleInheritance1() {
78f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
79f4a2713aSLionel Sambuc   {
80f4a2713aSLionel Sambuc     MultipleInheritance Deleter(mem, 0);
81f4a2713aSLionel Sambuc     // Remove dead bindings...
82f4a2713aSLionel Sambuc     doSomething();
83f4a2713aSLionel Sambuc     // destructor called here
84f4a2713aSLionel Sambuc   }
85f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
86f4a2713aSLionel Sambuc }
87f4a2713aSLionel Sambuc 
testMultipleInheritance2()88f4a2713aSLionel Sambuc void testMultipleInheritance2() {
89f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
90f4a2713aSLionel Sambuc   {
91f4a2713aSLionel Sambuc     MultipleInheritance Deleter(0, mem);
92f4a2713aSLionel Sambuc     // Remove dead bindings...
93f4a2713aSLionel Sambuc     doSomething();
94f4a2713aSLionel Sambuc     // destructor called here
95f4a2713aSLionel Sambuc   }
96f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
97f4a2713aSLionel Sambuc }
98f4a2713aSLionel Sambuc 
testMultipleInheritance3()99f4a2713aSLionel Sambuc void testMultipleInheritance3() {
100f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
101f4a2713aSLionel Sambuc   {
102f4a2713aSLionel Sambuc     MultipleInheritance Deleter(mem, mem);
103f4a2713aSLionel Sambuc     // Remove dead bindings...
104f4a2713aSLionel Sambuc     doSomething();
105f4a2713aSLionel Sambuc     // destructor called here
106f4a2713aSLionel Sambuc     // expected-warning@28 {{Attempt to free released memory}}
107f4a2713aSLionel Sambuc   }
108f4a2713aSLionel Sambuc }
109f4a2713aSLionel Sambuc 
110f4a2713aSLionel Sambuc 
111f4a2713aSLionel Sambuc class SmartPointerMember {
112f4a2713aSLionel Sambuc   SmartPointer P;
113f4a2713aSLionel Sambuc public:
SmartPointerMember(void * x)114f4a2713aSLionel Sambuc   SmartPointerMember(void *x) : P(x) {}
115f4a2713aSLionel Sambuc };
116f4a2713aSLionel Sambuc 
testSmartPointerMember()117f4a2713aSLionel Sambuc void testSmartPointerMember() {
118f4a2713aSLionel Sambuc   char *mem = (char*)malloc(4);
119f4a2713aSLionel Sambuc   {
120f4a2713aSLionel Sambuc     SmartPointerMember Deleter(mem);
121f4a2713aSLionel Sambuc     // Remove dead bindings...
122f4a2713aSLionel Sambuc     doSomething();
123f4a2713aSLionel Sambuc     // destructor called here
124f4a2713aSLionel Sambuc   }
125f4a2713aSLionel Sambuc   *mem = 0; // expected-warning{{Use of memory after it is freed}}
126f4a2713aSLionel Sambuc }
127f4a2713aSLionel Sambuc 
128f4a2713aSLionel Sambuc 
129f4a2713aSLionel Sambuc struct IntWrapper {
IntWrapperIntWrapper130f4a2713aSLionel Sambuc   IntWrapper() : x(0) {}
131f4a2713aSLionel Sambuc   ~IntWrapper();
132f4a2713aSLionel Sambuc   int *x;
133f4a2713aSLionel Sambuc };
134f4a2713aSLionel Sambuc 
testArrayInvalidation()135f4a2713aSLionel Sambuc void testArrayInvalidation() {
136f4a2713aSLionel Sambuc   int i = 42;
137f4a2713aSLionel Sambuc   int j = 42;
138f4a2713aSLionel Sambuc 
139f4a2713aSLionel Sambuc   {
140f4a2713aSLionel Sambuc     IntWrapper arr[2];
141f4a2713aSLionel Sambuc 
142f4a2713aSLionel Sambuc     // There should be no undefined value warnings here.
143f4a2713aSLionel Sambuc     // Eventually these should be TRUE as well, but right now
144f4a2713aSLionel Sambuc     // we can't handle array constructors.
145f4a2713aSLionel Sambuc     clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
146f4a2713aSLionel Sambuc     clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
147f4a2713aSLionel Sambuc 
148f4a2713aSLionel Sambuc     arr[0].x = &i;
149f4a2713aSLionel Sambuc     arr[1].x = &j;
150f4a2713aSLionel Sambuc     clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
151f4a2713aSLionel Sambuc     clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
152f4a2713aSLionel Sambuc   }
153f4a2713aSLionel Sambuc 
154f4a2713aSLionel Sambuc   // The destructors should have invalidated i and j.
155f4a2713aSLionel Sambuc   clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
156f4a2713aSLionel Sambuc   clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
157f4a2713aSLionel Sambuc }
158f4a2713aSLionel Sambuc 
159f4a2713aSLionel Sambuc 
160f4a2713aSLionel Sambuc 
161f4a2713aSLionel Sambuc // Don't crash on a default argument inside an initializer.
162f4a2713aSLionel Sambuc struct DefaultArg {
DefaultArgDefaultArg163f4a2713aSLionel Sambuc   DefaultArg(int x = 0) {}
164f4a2713aSLionel Sambuc   ~DefaultArg();
165f4a2713aSLionel Sambuc };
166f4a2713aSLionel Sambuc 
167f4a2713aSLionel Sambuc struct InheritsDefaultArg : DefaultArg {
InheritsDefaultArgInheritsDefaultArg168f4a2713aSLionel Sambuc   InheritsDefaultArg() {}
169f4a2713aSLionel Sambuc   virtual ~InheritsDefaultArg();
170f4a2713aSLionel Sambuc };
171f4a2713aSLionel Sambuc 
testDefaultArg()172f4a2713aSLionel Sambuc void testDefaultArg() {
173f4a2713aSLionel Sambuc   InheritsDefaultArg a;
174f4a2713aSLionel Sambuc   // Force a bug to be emitted.
175f4a2713aSLionel Sambuc   *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
176f4a2713aSLionel Sambuc }
177f4a2713aSLionel Sambuc 
178f4a2713aSLionel Sambuc 
179f4a2713aSLionel Sambuc namespace DestructorVirtualCalls {
180f4a2713aSLionel Sambuc   class A {
181f4a2713aSLionel Sambuc   public:
182f4a2713aSLionel Sambuc     int *out1, *out2, *out3;
183f4a2713aSLionel Sambuc 
get()184f4a2713aSLionel Sambuc     virtual int get() { return 1; }
185f4a2713aSLionel Sambuc 
~A()186f4a2713aSLionel Sambuc     ~A() {
187f4a2713aSLionel Sambuc       *out1 = get();
188f4a2713aSLionel Sambuc     }
189f4a2713aSLionel Sambuc   };
190f4a2713aSLionel Sambuc 
191f4a2713aSLionel Sambuc   class B : public A {
192f4a2713aSLionel Sambuc   public:
get()193f4a2713aSLionel Sambuc     virtual int get() { return 2; }
194f4a2713aSLionel Sambuc 
~B()195f4a2713aSLionel Sambuc     ~B() {
196f4a2713aSLionel Sambuc       *out2 = get();
197f4a2713aSLionel Sambuc     }
198f4a2713aSLionel Sambuc   };
199f4a2713aSLionel Sambuc 
200f4a2713aSLionel Sambuc   class C : public B {
201f4a2713aSLionel Sambuc   public:
get()202f4a2713aSLionel Sambuc     virtual int get() { return 3; }
203f4a2713aSLionel Sambuc 
~C()204f4a2713aSLionel Sambuc     ~C() {
205f4a2713aSLionel Sambuc       *out3 = get();
206f4a2713aSLionel Sambuc     }
207f4a2713aSLionel Sambuc   };
208f4a2713aSLionel Sambuc 
test()209f4a2713aSLionel Sambuc   void test() {
210f4a2713aSLionel Sambuc     int a, b, c;
211f4a2713aSLionel Sambuc 
212f4a2713aSLionel Sambuc     // New scope for the C object.
213f4a2713aSLionel Sambuc     {
214f4a2713aSLionel Sambuc       C obj;
215f4a2713aSLionel Sambuc       clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
216f4a2713aSLionel Sambuc 
217f4a2713aSLionel Sambuc       // Sanity check for devirtualization.
218f4a2713aSLionel Sambuc       A *base = &obj;
219f4a2713aSLionel Sambuc       clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
220f4a2713aSLionel Sambuc 
221f4a2713aSLionel Sambuc       obj.out1 = &a;
222f4a2713aSLionel Sambuc       obj.out2 = &b;
223f4a2713aSLionel Sambuc       obj.out3 = &c;
224f4a2713aSLionel Sambuc     }
225f4a2713aSLionel Sambuc 
226f4a2713aSLionel Sambuc     clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
227f4a2713aSLionel Sambuc     clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
228f4a2713aSLionel Sambuc     clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
229f4a2713aSLionel Sambuc   }
230f4a2713aSLionel Sambuc }
231f4a2713aSLionel Sambuc 
232f4a2713aSLionel Sambuc 
233f4a2713aSLionel Sambuc namespace DestructorsShouldNotAffectReturnValues {
234f4a2713aSLionel Sambuc   class Dtor {
235f4a2713aSLionel Sambuc   public:
~Dtor()236f4a2713aSLionel Sambuc     ~Dtor() {
237f4a2713aSLionel Sambuc       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
238f4a2713aSLionel Sambuc     }
239f4a2713aSLionel Sambuc   };
240f4a2713aSLionel Sambuc 
allocate()241f4a2713aSLionel Sambuc   void *allocate() {
242f4a2713aSLionel Sambuc     Dtor d;
243f4a2713aSLionel Sambuc     return malloc(4); // no-warning
244f4a2713aSLionel Sambuc   }
245f4a2713aSLionel Sambuc 
test()246f4a2713aSLionel Sambuc   void test() {
247f4a2713aSLionel Sambuc     // At one point we had an issue where the statements inside an
248f4a2713aSLionel Sambuc     // inlined destructor kept us from finding the return statement,
249f4a2713aSLionel Sambuc     // leading the analyzer to believe that the malloc'd memory had leaked.
250f4a2713aSLionel Sambuc     void *p = allocate();
251f4a2713aSLionel Sambuc     free(p); // no-warning
252f4a2713aSLionel Sambuc   }
253f4a2713aSLionel Sambuc }
254f4a2713aSLionel Sambuc 
255f4a2713aSLionel Sambuc namespace MultipleInheritanceVirtualDtors {
256f4a2713aSLionel Sambuc   class VirtualDtor {
257f4a2713aSLionel Sambuc   protected:
~VirtualDtor()258f4a2713aSLionel Sambuc     virtual ~VirtualDtor() {
259f4a2713aSLionel Sambuc       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
260f4a2713aSLionel Sambuc     }
261f4a2713aSLionel Sambuc   };
262f4a2713aSLionel Sambuc 
263f4a2713aSLionel Sambuc   class NonVirtualDtor {
264f4a2713aSLionel Sambuc   protected:
~NonVirtualDtor()265f4a2713aSLionel Sambuc     ~NonVirtualDtor() {
266f4a2713aSLionel Sambuc       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
267f4a2713aSLionel Sambuc     }
268f4a2713aSLionel Sambuc   };
269f4a2713aSLionel Sambuc 
270f4a2713aSLionel Sambuc   class SubclassA : public VirtualDtor, public NonVirtualDtor {
271f4a2713aSLionel Sambuc   public:
~SubclassA()272f4a2713aSLionel Sambuc     virtual ~SubclassA() {}
273f4a2713aSLionel Sambuc   };
274f4a2713aSLionel Sambuc   class SubclassB : public NonVirtualDtor, public VirtualDtor {
275f4a2713aSLionel Sambuc   public:
~SubclassB()276f4a2713aSLionel Sambuc     virtual ~SubclassB() {}
277f4a2713aSLionel Sambuc   };
278f4a2713aSLionel Sambuc 
test()279f4a2713aSLionel Sambuc   void test() {
280f4a2713aSLionel Sambuc     SubclassA a;
281f4a2713aSLionel Sambuc     SubclassB b;
282f4a2713aSLionel Sambuc   }
283f4a2713aSLionel Sambuc }
284f4a2713aSLionel Sambuc 
285f4a2713aSLionel Sambuc namespace ExplicitDestructorCall {
286f4a2713aSLionel Sambuc   class VirtualDtor {
287f4a2713aSLionel Sambuc   public:
~VirtualDtor()288f4a2713aSLionel Sambuc     virtual ~VirtualDtor() {
289f4a2713aSLionel Sambuc       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
290f4a2713aSLionel Sambuc     }
291f4a2713aSLionel Sambuc   };
292f4a2713aSLionel Sambuc 
293f4a2713aSLionel Sambuc   class Subclass : public VirtualDtor {
294f4a2713aSLionel Sambuc   public:
~Subclass()295f4a2713aSLionel Sambuc     virtual ~Subclass() {
296f4a2713aSLionel Sambuc       clang_analyzer_checkInlined(false); // no-warning
297f4a2713aSLionel Sambuc     }
298f4a2713aSLionel Sambuc   };
299f4a2713aSLionel Sambuc 
destroy(Subclass * obj)300f4a2713aSLionel Sambuc   void destroy(Subclass *obj) {
301f4a2713aSLionel Sambuc     obj->VirtualDtor::~VirtualDtor();
302f4a2713aSLionel Sambuc   }
303f4a2713aSLionel Sambuc }
304f4a2713aSLionel Sambuc 
305f4a2713aSLionel Sambuc 
306f4a2713aSLionel Sambuc namespace MultidimensionalArrays {
testArrayInvalidation()307f4a2713aSLionel Sambuc   void testArrayInvalidation() {
308f4a2713aSLionel Sambuc     int i = 42;
309f4a2713aSLionel Sambuc     int j = 42;
310f4a2713aSLionel Sambuc 
311f4a2713aSLionel Sambuc     {
312f4a2713aSLionel Sambuc       IntWrapper arr[2][2];
313f4a2713aSLionel Sambuc 
314f4a2713aSLionel Sambuc       // There should be no undefined value warnings here.
315f4a2713aSLionel Sambuc       // Eventually these should be TRUE as well, but right now
316f4a2713aSLionel Sambuc       // we can't handle array constructors.
317f4a2713aSLionel Sambuc       clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}}
318f4a2713aSLionel Sambuc       clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}}
319f4a2713aSLionel Sambuc 
320f4a2713aSLionel Sambuc       arr[0][0].x = &i;
321f4a2713aSLionel Sambuc       arr[1][1].x = &j;
322f4a2713aSLionel Sambuc       clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
323f4a2713aSLionel Sambuc       clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
324f4a2713aSLionel Sambuc     }
325f4a2713aSLionel Sambuc 
326f4a2713aSLionel Sambuc     // The destructors should have invalidated i and j.
327f4a2713aSLionel Sambuc     clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
328f4a2713aSLionel Sambuc     clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
329f4a2713aSLionel Sambuc   }
330f4a2713aSLionel Sambuc }
331f4a2713aSLionel Sambuc 
332f4a2713aSLionel Sambuc namespace LifetimeExtension {
333f4a2713aSLionel Sambuc   struct IntWrapper {
334f4a2713aSLionel Sambuc 	int x;
IntWrapperLifetimeExtension::IntWrapper335f4a2713aSLionel Sambuc 	IntWrapper(int y) : x(y) {}
IntWrapperLifetimeExtension::IntWrapper336f4a2713aSLionel Sambuc 	IntWrapper() {
337f4a2713aSLionel Sambuc       extern void use(int);
338f4a2713aSLionel Sambuc       use(x); // no-warning
339f4a2713aSLionel Sambuc 	}
340f4a2713aSLionel Sambuc   };
341f4a2713aSLionel Sambuc 
342f4a2713aSLionel Sambuc   struct DerivedWrapper : public IntWrapper {
DerivedWrapperLifetimeExtension::DerivedWrapper343f4a2713aSLionel Sambuc 	DerivedWrapper(int y) : IntWrapper(y) {}
344f4a2713aSLionel Sambuc   };
345f4a2713aSLionel Sambuc 
get()346f4a2713aSLionel Sambuc   DerivedWrapper get() {
347f4a2713aSLionel Sambuc 	return DerivedWrapper(1);
348f4a2713aSLionel Sambuc   }
349f4a2713aSLionel Sambuc 
test()350f4a2713aSLionel Sambuc   void test() {
351f4a2713aSLionel Sambuc 	const DerivedWrapper &d = get(); // lifetime extended here
352f4a2713aSLionel Sambuc   }
353f4a2713aSLionel Sambuc 
354f4a2713aSLionel Sambuc 
355f4a2713aSLionel Sambuc   class SaveOnDestruct {
356f4a2713aSLionel Sambuc   public:
357f4a2713aSLionel Sambuc     static int lastOutput;
358f4a2713aSLionel Sambuc     int value;
359f4a2713aSLionel Sambuc 
360f4a2713aSLionel Sambuc     SaveOnDestruct();
~SaveOnDestruct()361f4a2713aSLionel Sambuc     ~SaveOnDestruct() {
362f4a2713aSLionel Sambuc       lastOutput = value;
363f4a2713aSLionel Sambuc     }
364f4a2713aSLionel Sambuc   };
365f4a2713aSLionel Sambuc 
testSimple()366f4a2713aSLionel Sambuc   void testSimple() {
367f4a2713aSLionel Sambuc     {
368f4a2713aSLionel Sambuc       const SaveOnDestruct &obj = SaveOnDestruct();
369f4a2713aSLionel Sambuc       if (obj.value != 42)
370f4a2713aSLionel Sambuc         return;
371f4a2713aSLionel Sambuc       // destructor called here
372f4a2713aSLionel Sambuc     }
373f4a2713aSLionel Sambuc 
374f4a2713aSLionel Sambuc     clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
375f4a2713aSLionel Sambuc   }
376f4a2713aSLionel Sambuc 
377*0a6a1f1dSLionel Sambuc   struct NRCheck {
378*0a6a1f1dSLionel Sambuc     bool bool_;
NRCheckLifetimeExtension::NRCheck379*0a6a1f1dSLionel Sambuc     NRCheck():bool_(true) {}
380*0a6a1f1dSLionel Sambuc     ~NRCheck() __attribute__((noreturn));
operator boolLifetimeExtension::NRCheck381*0a6a1f1dSLionel Sambuc     operator bool() const { return bool_; }
382*0a6a1f1dSLionel Sambuc   };
383*0a6a1f1dSLionel Sambuc 
384*0a6a1f1dSLionel Sambuc   struct CheckAutoDestructor {
385*0a6a1f1dSLionel Sambuc     bool bool_;
CheckAutoDestructorLifetimeExtension::CheckAutoDestructor386*0a6a1f1dSLionel Sambuc     CheckAutoDestructor():bool_(true) {}
operator boolLifetimeExtension::CheckAutoDestructor387*0a6a1f1dSLionel Sambuc     operator bool() const { return bool_; }
388*0a6a1f1dSLionel Sambuc   };
389*0a6a1f1dSLionel Sambuc 
390*0a6a1f1dSLionel Sambuc   struct CheckCustomDestructor {
391*0a6a1f1dSLionel Sambuc     bool bool_;
CheckCustomDestructorLifetimeExtension::CheckCustomDestructor392*0a6a1f1dSLionel Sambuc     CheckCustomDestructor():bool_(true) {}
393*0a6a1f1dSLionel Sambuc     ~CheckCustomDestructor();
operator boolLifetimeExtension::CheckCustomDestructor394*0a6a1f1dSLionel Sambuc     operator bool() const { return bool_; }
395*0a6a1f1dSLionel Sambuc   };
396*0a6a1f1dSLionel Sambuc 
testUnnamedNR()397*0a6a1f1dSLionel Sambuc   bool testUnnamedNR() {
398*0a6a1f1dSLionel Sambuc     if (NRCheck())
399*0a6a1f1dSLionel Sambuc       return true;
400*0a6a1f1dSLionel Sambuc     return false;
401*0a6a1f1dSLionel Sambuc   }
402*0a6a1f1dSLionel Sambuc 
testNamedNR()403*0a6a1f1dSLionel Sambuc   bool testNamedNR() {
404*0a6a1f1dSLionel Sambuc     if (NRCheck c = NRCheck())
405*0a6a1f1dSLionel Sambuc       return true;
406*0a6a1f1dSLionel Sambuc     return false;
407*0a6a1f1dSLionel Sambuc   }
408*0a6a1f1dSLionel Sambuc 
testUnnamedAutoDestructor()409*0a6a1f1dSLionel Sambuc   bool testUnnamedAutoDestructor() {
410*0a6a1f1dSLionel Sambuc     if (CheckAutoDestructor())
411*0a6a1f1dSLionel Sambuc       return true;
412*0a6a1f1dSLionel Sambuc     return false;
413*0a6a1f1dSLionel Sambuc   }
414*0a6a1f1dSLionel Sambuc 
testNamedAutoDestructor()415*0a6a1f1dSLionel Sambuc   bool testNamedAutoDestructor() {
416*0a6a1f1dSLionel Sambuc     if (CheckAutoDestructor c = CheckAutoDestructor())
417*0a6a1f1dSLionel Sambuc       return true;
418*0a6a1f1dSLionel Sambuc     return false;
419*0a6a1f1dSLionel Sambuc   }
420*0a6a1f1dSLionel Sambuc 
testUnnamedCustomDestructor()421*0a6a1f1dSLionel Sambuc   bool testUnnamedCustomDestructor() {
422*0a6a1f1dSLionel Sambuc     if (CheckCustomDestructor())
423*0a6a1f1dSLionel Sambuc       return true;
424*0a6a1f1dSLionel Sambuc     return false;
425*0a6a1f1dSLionel Sambuc   }
426*0a6a1f1dSLionel Sambuc 
427*0a6a1f1dSLionel Sambuc   // This case used to cause an unexpected "Undefined or garbage value returned
428*0a6a1f1dSLionel Sambuc   // to caller" warning
testNamedCustomDestructor()429*0a6a1f1dSLionel Sambuc   bool testNamedCustomDestructor() {
430*0a6a1f1dSLionel Sambuc     if (CheckCustomDestructor c = CheckCustomDestructor())
431*0a6a1f1dSLionel Sambuc       return true;
432*0a6a1f1dSLionel Sambuc     return false;
433*0a6a1f1dSLionel Sambuc   }
434*0a6a1f1dSLionel Sambuc 
testMultipleTemporariesCustomDestructor()435*0a6a1f1dSLionel Sambuc   bool testMultipleTemporariesCustomDestructor() {
436*0a6a1f1dSLionel Sambuc     if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
437*0a6a1f1dSLionel Sambuc       return true;
438*0a6a1f1dSLionel Sambuc     return false;
439*0a6a1f1dSLionel Sambuc   }
440*0a6a1f1dSLionel Sambuc 
441f4a2713aSLionel Sambuc   class VirtualDtorBase {
442f4a2713aSLionel Sambuc   public:
443f4a2713aSLionel Sambuc     int value;
~VirtualDtorBase()444f4a2713aSLionel Sambuc     virtual ~VirtualDtorBase() {}
445f4a2713aSLionel Sambuc   };
446f4a2713aSLionel Sambuc 
447f4a2713aSLionel Sambuc   class SaveOnVirtualDestruct : public VirtualDtorBase {
448f4a2713aSLionel Sambuc   public:
449f4a2713aSLionel Sambuc     static int lastOutput;
450f4a2713aSLionel Sambuc 
451f4a2713aSLionel Sambuc     SaveOnVirtualDestruct();
~SaveOnVirtualDestruct()452f4a2713aSLionel Sambuc     virtual ~SaveOnVirtualDestruct() {
453f4a2713aSLionel Sambuc       lastOutput = value;
454f4a2713aSLionel Sambuc     }
455f4a2713aSLionel Sambuc   };
456f4a2713aSLionel Sambuc 
testVirtual()457f4a2713aSLionel Sambuc   void testVirtual() {
458f4a2713aSLionel Sambuc     {
459f4a2713aSLionel Sambuc       const VirtualDtorBase &obj = SaveOnVirtualDestruct();
460f4a2713aSLionel Sambuc       if (obj.value != 42)
461f4a2713aSLionel Sambuc         return;
462f4a2713aSLionel Sambuc       // destructor called here
463f4a2713aSLionel Sambuc     }
464f4a2713aSLionel Sambuc 
465f4a2713aSLionel Sambuc     clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
466f4a2713aSLionel Sambuc   }
467f4a2713aSLionel Sambuc }
468f4a2713aSLionel Sambuc 
469f4a2713aSLionel Sambuc namespace NoReturn {
470f4a2713aSLionel Sambuc   struct NR {
471f4a2713aSLionel Sambuc     ~NR() __attribute__((noreturn));
472f4a2713aSLionel Sambuc   };
473f4a2713aSLionel Sambuc 
f(int ** x)474f4a2713aSLionel Sambuc   void f(int **x) {
475f4a2713aSLionel Sambuc     NR nr;
476f4a2713aSLionel Sambuc   }
477f4a2713aSLionel Sambuc 
g()478f4a2713aSLionel Sambuc   void g() {
479f4a2713aSLionel Sambuc     int *x;
480f4a2713aSLionel Sambuc     f(&x);
481f4a2713aSLionel Sambuc     *x = 47; // no warning
482f4a2713aSLionel Sambuc   }
483*0a6a1f1dSLionel Sambuc 
g2(int * x)484*0a6a1f1dSLionel Sambuc   void g2(int *x) {
485*0a6a1f1dSLionel Sambuc     if (! x) NR();
486*0a6a1f1dSLionel Sambuc     *x = 47; // no warning
487*0a6a1f1dSLionel Sambuc   }
488f4a2713aSLionel Sambuc }
489f4a2713aSLionel Sambuc 
490f4a2713aSLionel Sambuc namespace PseudoDtor {
491f4a2713aSLionel Sambuc   template <typename T>
destroy(T & obj)492f4a2713aSLionel Sambuc   void destroy(T &obj) {
493f4a2713aSLionel Sambuc     clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
494f4a2713aSLionel Sambuc     obj.~T();
495f4a2713aSLionel Sambuc   }
496f4a2713aSLionel Sambuc 
test()497f4a2713aSLionel Sambuc   void test() {
498f4a2713aSLionel Sambuc     int i;
499f4a2713aSLionel Sambuc     destroy(i);
500f4a2713aSLionel Sambuc     clang_analyzer_eval(true); // expected-warning{{TRUE}}
501f4a2713aSLionel Sambuc   }
502f4a2713aSLionel Sambuc }
503f4a2713aSLionel Sambuc 
504f4a2713aSLionel Sambuc namespace Incomplete {
505f4a2713aSLionel Sambuc   class Foo; // expected-note{{forward declaration}}
f(Foo * foo)506f4a2713aSLionel Sambuc   void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
507f4a2713aSLionel Sambuc }
508