[AMDGPU][AsmParser][NFC] Get rid of custom default operand handlers.
[llvm-project.git] / clang / test / Analysis / copy-elision.cpp
blob991f325c05853d4dcf79e6ba50a321bc0cd285b0
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \
2 // RUN: -analyzer-config eagerly-assume=false -verify %s
3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \
4 // RUN: -analyzer-config eagerly-assume=false -verify %s
5 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \
6 // RUN: -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG \
7 // RUN: -analyzer-config eagerly-assume=false -verify=expected,no-elide %s
8 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \
9 // RUN: -analyzer-config elide-constructors=false \
10 // RUN: -analyzer-config eagerly-assume=false -verify %s
12 // Copy elision always occurs in C++17, otherwise it's under
13 // an on-by-default flag.
14 #if __cplusplus >= 201703L
15 #define ELIDE 1
16 #else
17 #ifndef NO_ELIDE_FLAG
18 #define ELIDE 1
19 #endif
20 #endif
22 void clang_analyzer_eval(bool);
23 void clang_analyzer_dump(int);
25 namespace variable_functional_cast_crash {
27 struct A {
28 A(int) {}
31 void foo() {
32 A a = A(0);
35 struct B {
36 A a;
37 B(): a(A(0)) {}
40 } // namespace variable_functional_cast_crash
43 namespace ctor_initializer {
45 struct S {
46 int x, y, z;
49 struct T {
50 S s;
51 int w;
52 T(int w): s(), w(w) {}
55 class C {
56 T t;
57 public:
58 C() : t(T(4)) {
59 S s = {1, 2, 3};
60 t.s = s;
61 // FIXME: Should be TRUE regardless of copy elision.
62 clang_analyzer_eval(t.w == 4);
63 #ifdef ELIDE
64 // expected-warning@-2{{TRUE}}
65 #else
66 // expected-warning@-4{{UNKNOWN}}
67 #endif
72 struct A {
73 int x;
74 A(): x(0) {}
75 ~A() {}
78 struct B {
79 A a;
80 B() : a(A()) {}
83 void foo() {
84 B b;
85 clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}}
88 } // namespace ctor_initializer
91 namespace elision_on_ternary_op_branches {
92 class C1 {
93 int x;
94 public:
95 C1(int x): x(x) {}
96 int getX() const { return x; }
97 ~C1();
100 class C2 {
101 int x;
102 int y;
103 public:
104 C2(int x, int y): x(x), y(y) {}
105 int getX() const { return x; }
106 int getY() const { return y; }
107 ~C2();
110 void foo(int coin) {
111 C1 c1 = coin ? C1(1) : C1(2);
112 if (coin) {
113 clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}}
114 } else {
115 clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}}
117 C2 c2 = coin ? C2(3, 4) : C2(5, 6);
118 if (coin) {
119 clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}}
120 clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}}
121 } else {
122 clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}}
123 clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}}
126 } // namespace elision_on_ternary_op_branches
129 namespace address_vector_tests {
131 template <typename T> struct AddressVector {
132 T *buf[20];
133 int len;
135 AddressVector() : len(0) {}
137 void push(T *t) {
138 buf[len] = t;
139 ++len;
143 class ClassWithoutDestructor {
144 AddressVector<ClassWithoutDestructor> &v;
146 public:
147 ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
148 push();
151 ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { push(); }
152 ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { push(); }
154 void push() { v.push(this); }
157 ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
158 return ClassWithoutDestructor(v);
159 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
160 object of type 'ClassWithoutDestructor' is still \
161 referred to by the stack variable 'v' upon returning to the caller}}
163 ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
164 return make1(v);
165 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
166 object of type 'ClassWithoutDestructor' is still \
167 referred to by the stack variable 'v' upon returning to the caller}}
169 ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
170 return make2(v);
171 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
172 object of type 'ClassWithoutDestructor' is still \
173 referred to by the stack variable 'v' upon returning to the caller}}
176 void testMultipleReturns() {
177 AddressVector<ClassWithoutDestructor> v;
178 ClassWithoutDestructor c = make3(v);
180 #if ELIDE
181 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
182 clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}}
183 #else
184 clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}}
185 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
186 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
187 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
188 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
189 clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}}
190 #endif
193 void consume(ClassWithoutDestructor c) {
194 c.push();
195 // expected-warning@-1 {{Address of stack memory associated with local \
196 variable 'c' is still referred to by the stack variable 'v' upon returning \
197 to the caller}}
200 void testArgumentConstructorWithoutDestructor() {
201 AddressVector<ClassWithoutDestructor> v;
203 consume(make3(v));
205 #if ELIDE
206 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
207 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
208 #else
209 clang_analyzer_eval(v.len == 6); // expected-warning{{TRUE}}
210 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
211 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
212 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
213 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
214 // We forced a push() in consume(), let's see if the address here matches
215 // the address during construction.
216 clang_analyzer_eval(v.buf[4] == v.buf[5]); // expected-warning{{TRUE}}
217 #endif
220 class ClassWithDestructor {
221 AddressVector<ClassWithDestructor> &v;
223 public:
224 ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
225 push();
228 ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); }
229 ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); }
231 ~ClassWithDestructor() { push(); }
233 void push() { v.push(this); }
236 void testVariable() {
237 AddressVector<ClassWithDestructor> v;
239 ClassWithDestructor c = ClassWithDestructor(v);
240 // Check if the last destructor is an automatic destructor.
241 // A temporary destructor would have fired by now.
242 #if ELIDE
243 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
244 #else
245 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
246 #endif
248 #if ELIDE
249 // 0. Construct the variable.
250 // 1. Destroy the variable.
251 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
252 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
253 #else
254 // 0. Construct the temporary.
255 // 1. Construct the variable.
256 // 2. Destroy the temporary.
257 // 3. Destroy the variable.
258 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
259 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
260 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
261 #endif
264 struct TestCtorInitializer {
265 ClassWithDestructor c;
266 TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
267 : c(ClassWithDestructor(v)) {}
268 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
269 object of type 'ClassWithDestructor' is still referred \
270 to by the stack variable 'v' upon returning to the caller}}
273 void testCtorInitializer() {
274 AddressVector<ClassWithDestructor> v;
276 TestCtorInitializer t(v);
277 // Check if the last destructor is an automatic destructor.
278 // A temporary destructor would have fired by now.
279 #if ELIDE
280 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
281 #else
282 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
283 #endif
285 #if ELIDE
286 // 0. Construct the member variable.
287 // 1. Destroy the member variable.
288 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
289 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
290 #else
291 // 0. Construct the temporary.
292 // 1. Construct the member variable.
293 // 2. Destroy the temporary.
294 // 3. Destroy the member variable.
295 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
296 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
297 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
298 #endif
302 ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
303 return ClassWithDestructor(v);
304 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
305 object of type 'ClassWithDestructor' is still referred \
306 to by the stack variable 'v' upon returning to the caller}}
308 ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
309 return make1(v);
310 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
311 object of type 'ClassWithDestructor' is still referred \
312 to by the stack variable 'v' upon returning to the caller}}
314 ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
315 return make2(v);
316 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
317 object of type 'ClassWithDestructor' is still referred \
318 to by the stack variable 'v' upon returning to the caller}}
321 void testMultipleReturnsWithDestructors() {
322 AddressVector<ClassWithDestructor> v;
324 ClassWithDestructor c = make3(v);
325 // Check if the last destructor is an automatic destructor.
326 // A temporary destructor would have fired by now.
327 #if ELIDE
328 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
329 #else
330 clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}}
331 #endif
334 #if ELIDE
335 // 0. Construct the variable. Yes, constructor in make1() constructs
336 // the variable 'c'.
337 // 1. Destroy the variable.
338 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
339 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
340 #else
341 // 0. Construct the temporary in make1().
342 // 1. Construct the temporary in make2().
343 // 2. Destroy the temporary in make1().
344 // 3. Construct the temporary in make3().
345 // 4. Destroy the temporary in make2().
346 // 5. Construct the temporary here.
347 // 6. Destroy the temporary in make3().
348 // 7. Construct the variable.
349 // 8. Destroy the temporary here.
350 // 9. Destroy the variable.
351 clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}}
352 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
353 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
354 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
355 clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}}
356 clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}}
357 #endif
360 void consume(ClassWithDestructor c) {
361 c.push();
362 // expected-warning@-1 {{Address of stack memory associated with local \
363 variable 'c' is still referred to by the stack variable 'v' upon returning \
364 to the caller}}
367 void testArgumentConstructorWithDestructor() {
368 AddressVector<ClassWithDestructor> v;
370 consume(make3(v));
372 #if ELIDE
373 // 0. Construct the argument.
374 // 1. Forced push() in consume().
375 // 2. Destroy the argument.
376 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
377 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
378 clang_analyzer_eval(v.buf[1] == v.buf[2]); // expected-warning{{TRUE}}
379 #else
380 // 0. Construct the temporary in make1().
381 // 1. Construct the temporary in make2().
382 // 2. Destroy the temporary in make1().
383 // 3. Construct the temporary in make3().
384 // 4. Destroy the temporary in make2().
385 // 5. Construct the temporary here.
386 // 6. Destroy the temporary in make3().
387 // 7. Construct the argument.
388 // 8. Forced push() in consume().
389 // 9. Destroy the argument. Notice the reverse order!
390 // 10. Destroy the temporary here.
391 clang_analyzer_eval(v.len == 11); // expected-warning{{TRUE}}
392 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
393 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
394 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
395 clang_analyzer_eval(v.buf[5] == v.buf[10]); // expected-warning{{TRUE}}
396 clang_analyzer_eval(v.buf[7] == v.buf[8]); // expected-warning{{TRUE}}
397 clang_analyzer_eval(v.buf[8] == v.buf[9]); // expected-warning{{TRUE}}
398 #endif
401 struct Foo {
402 Foo(Foo **q) {
403 *q = this;
407 Foo make1(Foo **r) {
408 return Foo(r);
409 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
410 object of type 'Foo' is still referred to by the stack \
411 variable 'z' upon returning to the caller}}
414 void test_copy_elision() {
415 Foo *z;
416 // If the copy elided, 'z' points to 'tmp', otherwise it's a dangling pointer.
417 Foo tmp = make1(&z);
418 (void)tmp;
421 } // namespace address_vector_tests
423 namespace arg_directly_from_return_in_loop {
425 struct Result {
426 int value;
429 Result create() {
430 return Result{10};
433 int accessValue(Result r) {
434 return r.value;
437 void test() {
438 for (int i = 0; i < 3; ++i) {
439 int v = accessValue(create());
440 if (i == 0) {
441 clang_analyzer_dump(v); // expected-warning {{10 S32b}}
442 } else {
443 clang_analyzer_dump(v); // expected-warning {{10 S32b}}
444 // was {{reg_${{[0-9]+}}<int r.value> }} for C++11
449 } // namespace arg_directly_from_return_in_loop