blob: eb91a3c71b0bdebfb58e7fee5aec53cd71c8b258 [file] [log] [blame]
Artem Dergachev9d3a7d82018-03-30 19:21:18 +00001// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -verify %s
2// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s
Artem Dergachev9a209ad2018-06-28 00:30:18 +00003// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %s
4// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %s
5
6// Copy elision always occurs in C++17, otherwise it's under
7// an on-by-default flag.
8#if __cplusplus >= 201703L
9 #define ELIDE 1
10#else
11 #ifndef NO_ELIDE_FLAG
12 #define ELIDE 1
13 #endif
14#endif
Artem Dergachev9d3a7d82018-03-30 19:21:18 +000015
16void clang_analyzer_eval(bool);
17
Artem Dergachev1fe52472018-06-14 01:32:46 +000018namespace variable_functional_cast_crash {
19
20struct A {
21 A(int) {}
22};
23
24void foo() {
25 A a = A(0);
26}
27
28struct B {
29 A a;
30 B(): a(A(0)) {}
31};
32
33} // namespace variable_functional_cast_crash
34
35
Artem Dergacheva84374d2018-06-14 01:40:49 +000036namespace ctor_initializer {
37
38struct S {
39 int x, y, z;
40};
41
42struct T {
43 S s;
44 int w;
45 T(int w): s(), w(w) {}
46};
47
48class C {
49 T t;
50public:
51 C() : t(T(4)) {
52 S s = {1, 2, 3};
53 t.s = s;
Artem Dergachev9a209ad2018-06-28 00:30:18 +000054 // FIXME: Should be TRUE regardless of copy elision.
Artem Dergacheva84374d2018-06-14 01:40:49 +000055 clang_analyzer_eval(t.w == 4);
Artem Dergachev9a209ad2018-06-28 00:30:18 +000056#ifdef ELIDE
Artem Dergacheva84374d2018-06-14 01:40:49 +000057 // expected-warning@-2{{TRUE}}
58#else
59 // expected-warning@-4{{UNKNOWN}}
60#endif
61 }
62};
63
Artem Dergachev53b8ce02018-06-14 01:54:21 +000064
65struct A {
66 int x;
67 A(): x(0) {}
68 ~A() {}
69};
70
71struct B {
72 A a;
73 B() : a(A()) {}
74};
75
76void foo() {
77 B b;
78 clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}}
79}
80
Artem Dergacheva84374d2018-06-14 01:40:49 +000081} // namespace ctor_initializer
82
83
Artem Dergachev53b8ce02018-06-14 01:54:21 +000084namespace elision_on_ternary_op_branches {
85class C1 {
86 int x;
87public:
88 C1(int x): x(x) {}
89 int getX() const { return x; }
90 ~C1();
91};
92
93class C2 {
94 int x;
95 int y;
96public:
97 C2(int x, int y): x(x), y(y) {}
98 int getX() const { return x; }
99 int getY() const { return y; }
100 ~C2();
101};
102
103void foo(int coin) {
104 C1 c1 = coin ? C1(1) : C1(2);
105 if (coin) {
106 clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}}
107 } else {
108 clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}}
109 }
110 C2 c2 = coin ? C2(3, 4) : C2(5, 6);
111 if (coin) {
112 clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}}
113 clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}}
114 } else {
115 clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}}
116 clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}}
117 }
118}
119} // namespace elision_on_ternary_op_branches
120
121
Artem Dergachev1fe52472018-06-14 01:32:46 +0000122namespace address_vector_tests {
123
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000124template <typename T> struct AddressVector {
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000125 T *buf[20];
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000126 int len;
127
128 AddressVector() : len(0) {}
129
130 void push(T *t) {
131 buf[len] = t;
132 ++len;
133 }
134};
135
136class ClassWithoutDestructor {
137 AddressVector<ClassWithoutDestructor> &v;
138
139public:
140 ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000141 push();
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000142 }
143
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000144 ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { push(); }
145 ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { push(); }
146
147 void push() { v.push(this); }
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000148};
149
150ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
151 return ClassWithoutDestructor(v);
152}
153ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
154 return make1(v);
155}
156ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
157 return make2(v);
158}
159
160void testMultipleReturns() {
161 AddressVector<ClassWithoutDestructor> v;
162 ClassWithoutDestructor c = make3(v);
163
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000164#if ELIDE
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000165 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000166 clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}}
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000167#else
168 clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}}
169 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
170 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
171 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
172 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
173 clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}}
174#endif
175}
Artem Dergachev1fe52472018-06-14 01:32:46 +0000176
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000177void consume(ClassWithoutDestructor c) {
178 c.push();
179}
180
181void testArgumentConstructorWithoutDestructor() {
182 AddressVector<ClassWithoutDestructor> v;
183
184 consume(make3(v));
185
186#if ELIDE
187 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
188 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
189#else
190 clang_analyzer_eval(v.len == 6); // expected-warning{{TRUE}}
191 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
192 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
193 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
194 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
195 // We forced a push() in consume(), let's see if the address here matches
196 // the address during construction.
197 clang_analyzer_eval(v.buf[4] == v.buf[5]); // expected-warning{{TRUE}}
198#endif
199}
200
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000201class ClassWithDestructor {
202 AddressVector<ClassWithDestructor> &v;
203
204public:
205 ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000206 push();
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000207 }
208
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000209 ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); }
210 ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); }
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000211
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000212 ~ClassWithDestructor() { push(); }
213
214 void push() { v.push(this); }
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000215};
216
217void testVariable() {
218 AddressVector<ClassWithDestructor> v;
219 {
220 ClassWithDestructor c = ClassWithDestructor(v);
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000221 // Check if the last destructor is an automatic destructor.
222 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000223#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000224 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
225#else
226 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
227#endif
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000228 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000229#if ELIDE
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000230 // 0. Construct the variable.
231 // 1. Destroy the variable.
232 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
233 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
234#else
235 // 0. Construct the temporary.
236 // 1. Construct the variable.
237 // 2. Destroy the temporary.
238 // 3. Destroy the variable.
239 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
240 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
241 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
242#endif
243}
244
245struct TestCtorInitializer {
246 ClassWithDestructor c;
247 TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
248 : c(ClassWithDestructor(v)) {}
249};
250
251void testCtorInitializer() {
252 AddressVector<ClassWithDestructor> v;
253 {
254 TestCtorInitializer t(v);
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000255 // Check if the last destructor is an automatic destructor.
256 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000257#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000258 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
259#else
260 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
261#endif
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000262 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000263#if ELIDE
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000264 // 0. Construct the member variable.
265 // 1. Destroy the member variable.
266 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
267 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
268#else
269 // 0. Construct the temporary.
270 // 1. Construct the member variable.
271 // 2. Destroy the temporary.
272 // 3. Destroy the member variable.
273 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
274 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
275 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
276#endif
277}
278
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000279
280ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
281 return ClassWithDestructor(v);
282}
283ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
284 return make1(v);
285}
286ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
287 return make2(v);
288}
289
290void testMultipleReturnsWithDestructors() {
291 AddressVector<ClassWithDestructor> v;
292 {
293 ClassWithDestructor c = make3(v);
294 // Check if the last destructor is an automatic destructor.
295 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000296#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000297 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
298#else
299 clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}}
300#endif
301 }
302
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000303#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000304 // 0. Construct the variable. Yes, constructor in make1() constructs
305 // the variable 'c'.
306 // 1. Destroy the variable.
307 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
308 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
309#else
310 // 0. Construct the temporary in make1().
311 // 1. Construct the temporary in make2().
312 // 2. Destroy the temporary in make1().
313 // 3. Construct the temporary in make3().
314 // 4. Destroy the temporary in make2().
315 // 5. Construct the temporary here.
316 // 6. Destroy the temporary in make3().
317 // 7. Construct the variable.
318 // 8. Destroy the temporary here.
319 // 9. Destroy the variable.
320 clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}}
321 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
322 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
323 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
324 clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}}
325 clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}}
326#endif
327}
Artem Dergachev3ccf14e2018-08-15 00:33:55 +0000328
329void consume(ClassWithDestructor c) {
330 c.push();
331}
332
333void testArgumentConstructorWithDestructor() {
334 AddressVector<ClassWithDestructor> v;
335
336 consume(make3(v));
337
338#if ELIDE
339 // 0. Construct the argument.
340 // 1. Forced push() in consume().
341 // 2. Destroy the argument.
342 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
343 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
344 clang_analyzer_eval(v.buf[1] == v.buf[2]); // expected-warning{{TRUE}}
345#else
346 // 0. Construct the temporary in make1().
347 // 1. Construct the temporary in make2().
348 // 2. Destroy the temporary in make1().
349 // 3. Construct the temporary in make3().
350 // 4. Destroy the temporary in make2().
351 // 5. Construct the temporary here.
352 // 6. Destroy the temporary in make3().
353 // 7. Construct the argument.
354 // 8. Forced push() in consume().
355 // 9. Destroy the argument. Notice the reverse order!
356 // 10. Destroy the temporary here.
357 clang_analyzer_eval(v.len == 11); // expected-warning{{TRUE}}
358 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
359 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
360 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
361 clang_analyzer_eval(v.buf[5] == v.buf[10]); // expected-warning{{TRUE}}
362 clang_analyzer_eval(v.buf[7] == v.buf[8]); // expected-warning{{TRUE}}
363 clang_analyzer_eval(v.buf[8] == v.buf[9]); // expected-warning{{TRUE}}
364#endif
365}
366
Artem Dergachev1fe52472018-06-14 01:32:46 +0000367} // namespace address_vector_tests