xref: /llvm-project/clang/test/Analysis/use-after-move.cpp (revision 566363981bb9ff6a6081490f05aa6b19aefc16f0)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
2 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
3 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
4 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
5 // RUN:  -verify=expected,peaceful,non-aggressive
6 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
7 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
8 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
9 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
10 // RUN:  -verify=expected,peaceful,non-aggressive
11 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
12 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
13 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
14 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
15 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
16 // RUN:  -verify=expected,non-aggressive
17 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
18 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
19 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
20 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
21 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
22 // RUN:  -verify=expected,non-aggressive
23 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
24 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
25 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
26 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
27 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
28 // RUN:  -verify=expected,peaceful,aggressive
29 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
30 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
31 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
32 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
33 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
34 // RUN:  -verify=expected,peaceful,aggressive
35 
36 // RUN: not %clang_analyze_cc1 -verify %s \
37 // RUN:   -analyzer-checker=core \
38 // RUN:   -analyzer-checker=cplusplus.Move \
39 // RUN:   -analyzer-config cplusplus.Move:WarnOn="a bunch of things" \
40 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-MOVE-INVALID-VALUE
41 
42 // CHECK-MOVE-INVALID-VALUE: (frontend): invalid input for checker option
43 // CHECK-MOVE-INVALID-VALUE-SAME: 'cplusplus.Move:WarnOn', that expects either
44 // CHECK-MOVE-INVALID-VALUE-SAME: "KnownsOnly", "KnownsAndLocals" or "All"
45 // CHECK-MOVE-INVALID-VALUE-SAME: string value
46 
47 // Tests checker-messages printing.
48 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
49 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
50 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
51 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
52 // RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
53 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
54 
55 #include "Inputs/system-header-simulator-cxx.h"
56 
57 void clang_analyzer_warnIfReached();
58 void clang_analyzer_printState();
59 
60 class B {
61 public:
62   B() = default;
63   B(const B &) = default;
64   B(B &&) = default;
65   B& operator=(const B &q) = default;
66   void operator=(B &&b) {
67     return;
68   }
69   void foo() { return; }
70 };
71 
72 class A {
73   int i;
74   double d;
75 
76 public:
77   B b;
78   A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
79   void moveconstruct(A &&other) {
80     std::swap(b, other.b);
81     std::swap(d, other.d);
82     std::swap(i, other.i);
83     return;
84   }
85   static A get() {
86     A v(12, 13);
87     return v;
88   }
89   A(A *a) {
90     moveconstruct(std::move(*a));
91   }
92   A(const A &other) : i(other.i), d(other.d), b(other.b) {}
93   A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // aggressive-note{{Object 'b' is moved}}
94   }
95   A(A &&other, char *k) {
96     moveconstruct(std::move(other));
97   }
98   void operator=(const A &other) {
99     i = other.i;
100     d = other.d;
101     b = other.b;
102     return;
103   }
104   void operator=(A &&other) {
105     moveconstruct(std::move(other));
106     return;
107   }
108   int getI() { return i; }
109   int foo() const;
110   void bar() const;
111   void reset();
112   void destroy();
113   void clear();
114   void resize(std::size_t);
115   void assign(const A &);
116   bool empty() const;
117   bool isEmpty() const;
118   operator bool() const;
119 
120   void testUpdateField() {
121     A a;
122     A b = std::move(a);
123     a.i = 1;
124     a.foo(); // no-warning
125   }
126   void testUpdateFieldDouble() {
127     A a;
128     A b = std::move(a);
129     a.d = 1.0;
130     a.foo(); // no-warning
131   }
132 };
133 
134 int bignum();
135 
136 void moveInsideFunctionCall(A a) {
137   A b = std::move(a);
138 }
139 void leftRefCall(A &a) {
140   a.foo();
141 }
142 void rightRefCall(A &&a) {
143   a.foo();
144 }
145 void constCopyOrMoveCall(const A a) {
146   a.foo();
147 }
148 
149 void copyOrMoveCall(A a) {
150   a.foo();
151 }
152 
153 void simpleMoveCtorTest() {
154   {
155     A a;
156     A b = std::move(a); // peaceful-note {{Object 'a' is moved}}
157 
158 #ifdef AGGRESSIVE_DFS
159     clang_analyzer_printState();
160 
161 // CHECK:      "checker_messages": [
162 // CHECK-NEXT:   { "checker": "cplusplus.Move", "messages": [
163 // CHECK-NEXT:     "Moved-from objects :",
164 // CHECK:          "a: moved",
165 // CHECK:          ""
166 // CHECK-NEXT:   ]}
167 // CHECK-NEXT: ]
168 #endif
169 
170     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
171              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
172   }
173   {
174     A a;
175     A b = std::move(a); // peaceful-note {{Object 'a' is moved}}
176     b = a; // peaceful-warning {{Moved-from object 'a' is copied}}
177            // peaceful-note@-1 {{Moved-from object 'a' is copied}}
178   }
179   {
180     A a;
181     A b = std::move(a); // peaceful-note {{Object 'a' is moved}}
182     b = std::move(a); // peaceful-warning {{Moved-from object 'a' is moved}}
183                       // peaceful-note@-1 {{Moved-from object 'a' is moved}}
184   }
185 }
186 
187 void simpleMoveAssignementTest() {
188   {
189     A a;
190     A b;
191     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
192     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
193              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
194   }
195   {
196     A a;
197     A b;
198     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
199     A c(a); // peaceful-warning {{Moved-from object 'a' is copied}}
200             // peaceful-note@-1 {{Moved-from object 'a' is copied}}
201   }
202   {
203     A a;
204     A b;
205     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
206     A c(std::move(a)); // peaceful-warning {{Moved-from object 'a' is moved}}
207                        // peaceful-note@-1 {{Moved-from object 'a' is moved}}
208   }
209 }
210 
211 void moveInInitListTest() {
212   struct S {
213     A a;
214   };
215   A a;
216   S s{std::move(a)}; // peaceful-note {{Object 'a' is moved}}
217   a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
218            // peaceful-note@-1 {{Method called on moved-from object 'a'}}
219 }
220 
221 // Don't report a bug if the variable was assigned to in the meantime.
222 void reinitializationTest(int i) {
223   {
224     A a;
225     A b;
226     b = std::move(a);
227     a = A();
228     a.foo();
229   }
230   {
231     A a;
232     if (i == 1) { // peaceful-note 2 {{Assuming 'i' is not equal to 1}}
233                   // peaceful-note@-1 2 {{Taking false branch}}
234       A b;
235       b = std::move(a);
236       a = A();
237     }
238     if (i == 2) { // peaceful-note 2 {{Assuming 'i' is not equal to 2}}
239                   // peaceful-note@-1 2 {{Taking false branch}}
240       a.foo();    // no-warning
241     }
242   }
243   {
244     A a;
245     if (i == 1) { // peaceful-note 2 {{'i' is not equal to 1}}
246                   // peaceful-note@-1 2 {{Taking false branch}}
247       (void)std::move(a);
248     }
249     if (i == 2) { // peaceful-note 2 {{'i' is not equal to 2}}
250                   // peaceful-note@-1 2 {{Taking false branch}}
251       a = A();
252       a.foo();
253     }
254   }
255   // The built-in assignment operator should also be recognized as a
256   // reinitialization. (std::move() may be called on built-in types in template
257   // code.)
258   {
259     int a1 = 1, a2 = 2;
260     std::swap(a1, a2);
261   }
262   // A std::move() after the assignment makes the variable invalid again.
263   {
264     A a;
265     A b;
266     b = std::move(a);
267     a = A();
268     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
269     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
270              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
271   }
272   // If a path exist where we not reinitialize the variable we report a bug.
273   {
274     A a;
275     A b;
276     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
277     if (i < 10) { // peaceful-note {{Assuming 'i' is >= 10}}
278                   // peaceful-note@-1 {{Taking false branch}}
279       a = A();
280     }
281     if (i > 5) { // peaceful-note {{'i' is > 5}}
282                  // peaceful-note@-1 {{Taking true branch}}
283       a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
284                // peaceful-note@-1 {{Method called on moved-from object 'a'}}
285     }
286   }
287 }
288 
289 // Using decltype on an expression is not a use.
290 void decltypeIsNotUseTest() {
291   A a;
292   // A b(std::move(a));
293   decltype(a) other_a; // no-warning
294 }
295 
296 void loopTest() {
297   {
298     A a;
299     // FIXME: Execution doesn't jump to the end of the function yet.
300     for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
301       rightRefCall(std::move(a));        // no-warning
302     }
303   }
304   {
305     A a;
306     for (int i = 0; i < 2; i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
307                                   // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
308                                   // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
309       rightRefCall(std::move(a)); // no-warning
310     }
311   }
312   {
313     A a;
314     for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
315       leftRefCall(a);                    // no-warning
316     }
317   }
318   {
319     A a;
320     for (int i = 0; i < 2; i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
321                                   // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
322                                   // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
323       leftRefCall(a);             // no-warning
324     }
325   }
326   {
327     A a;
328     for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
329       constCopyOrMoveCall(a);            // no-warning
330     }
331   }
332   {
333     A a;
334     for (int i = 0; i < 2; i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
335                                   // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
336                                   // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
337       constCopyOrMoveCall(a);     // no-warning
338     }
339   }
340   {
341     A a;
342     for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
343       moveInsideFunctionCall(a);         // no-warning
344     }
345   }
346   {
347     A a;
348     for (int i = 0; i < 2; i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
349                                   // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
350                                   // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
351       moveInsideFunctionCall(a);  // no-warning
352     }
353   }
354   {
355     A a;
356     for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
357       copyOrMoveCall(a);                 // no-warning
358     }
359   }
360   {
361     A a;
362     for (int i = 0; i < 2; i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
363                                   // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
364                                   // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
365       copyOrMoveCall(a);          // no-warning
366     }
367   }
368   {
369     A a;
370     for (int i = 0; i < bignum(); i++) { // peaceful-note    {{Loop condition is true.  Entering loop body}}
371                                          // peaceful-note@-1 {{Loop condition is true.  Entering loop body}}
372       constCopyOrMoveCall(std::move(a)); // peaceful-note {{Object 'a' is moved}}
373                                          // peaceful-warning@-1 {{Moved-from object 'a' is moved}}
374                                          // peaceful-note@-2    {{Moved-from object 'a' is moved}}
375     }
376   }
377 
378   // Don't warn if we return after the move.
379   {
380     A a;
381     for (int i = 0; i < 3; ++i) {
382       a.bar();
383       if (a.foo() > 0) {
384         A b;
385         b = std::move(a); // no-warning
386         return;
387       }
388     }
389   }
390 }
391 
392 // Report a usage of a moved-from object only at the first use.
393 void uniqueTest(bool cond) {
394   A a(42, 42.0);
395   A b;
396   b = std::move(a); // peaceful-note {{Object 'a' is moved}}
397 
398   if (cond) { // peaceful-note {{Assuming 'cond' is true}}
399               // peaceful-note@-1 {{Taking true branch}}
400     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
401              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
402   }
403   if (cond) {
404     a.bar(); // no-warning
405   }
406 
407   a.bar(); // no-warning
408 }
409 
410 void uniqueTest2() {
411   A a;
412   A a1 = std::move(a); // peaceful-note {{Object 'a' is moved}}
413   a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
414            // peaceful-note@-1    {{Method called on moved-from object 'a'}}
415 
416   A a2 = std::move(a); // no-warning
417   a.foo();             // no-warning
418 }
419 
420 // There are exceptions where we assume in general that the method works fine
421 //even on moved-from objects.
422 void moveSafeFunctionsTest() {
423   A a;
424   A b = std::move(a); // peaceful-note {{Object 'a' is moved}}
425   a.empty();          // no-warning
426   a.isEmpty();        // no-warning
427   (void)a;            // no-warning
428   (bool)a;            // expected-warning {{expression result unused}}
429   a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
430            // peaceful-note@-1 {{Method called on moved-from object 'a'}}
431 }
432 
433 void moveStateResetFunctionsTest() {
434   {
435     A a;
436     A b = std::move(a);
437     a.reset(); // no-warning
438     a.foo();   // no-warning
439     // Test if resets the state of subregions as well.
440     a.b.foo(); // no-warning
441   }
442   {
443     A a;
444     A b = std::move(a);
445     a.destroy(); // no-warning
446     a.foo();     // no-warning
447   }
448   {
449     A a;
450     A b = std::move(a);
451     a.clear(); // no-warning
452     a.foo();   // no-warning
453     a.b.foo(); // no-warning
454   }
455   {
456     A a;
457     A b = std::move(a);
458     a.resize(0); // no-warning
459     a.foo();   // no-warning
460     a.b.foo(); // no-warning
461   }
462   {
463     A a;
464     A b = std::move(a);
465     a.assign(A()); // no-warning
466     a.foo();   // no-warning
467     a.b.foo(); // no-warning
468   }
469 }
470 
471 // Moves or uses that occur as part of template arguments.
472 template <int>
473 class ClassTemplate {
474 public:
475   void foo(A a);
476 };
477 
478 template <int>
479 void functionTemplate(A a);
480 
481 void templateArgIsNotUseTest() {
482   {
483     // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
484     // Google Test.
485     A a;
486     ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
487   }
488   {
489     A a;
490     functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
491   }
492 }
493 
494 // Moves of global variables are not reported.
495 A global_a;
496 void globalVariablesTest() {
497   (void)std::move(global_a);
498   global_a.foo(); // no-warning
499 }
500 
501 // Moves of member variables.
502 class memberVariablesTest {
503   A a;
504   static A static_a;
505 
506   void f() {
507     A b;
508     b = std::move(a); // aggressive-note {{Object 'a' is moved}}
509 
510     a.foo(); // aggressive-warning {{Method called on moved-from object 'a'}}
511              // aggressive-note@-1 {{Method called on moved-from object 'a'}}
512 
513     b = std::move(static_a); // aggressive-note {{Object 'static_a' is moved}}
514     static_a.foo(); // aggressive-warning {{Method called on moved-from object 'static_a'}}
515                     // aggressive-note@-1 {{Method called on moved-from object 'static_a'}}
516   }
517 };
518 
519 void PtrAndArrayTest() {
520   A *Ptr = new A(1, 1.5);
521   A Arr[10];
522   Arr[2] = std::move(*Ptr); // aggressive-note{{Object is moved}}
523   (*Ptr).foo(); // aggressive-warning{{Method called on moved-from object}}
524                 // aggressive-note@-1{{Method called on moved-from object}}
525 
526   Ptr = &Arr[1];
527   Arr[3] = std::move(Arr[1]); // aggressive-note {{Object is moved}}
528   Ptr->foo(); // aggressive-warning {{Method called on moved-from object}}
529               // aggressive-note@-1 {{Method called on moved-from object}}
530 
531   Arr[3] = std::move(Arr[2]); // aggressive-note{{Object is moved}}
532   Arr[2].foo(); // aggressive-warning{{Method called on moved-from object}}
533                 // aggressive-note@-1{{Method called on moved-from object}}
534 
535   Arr[2] = std::move(Arr[3]); // reinitialization
536   Arr[2].foo();               // no-warning
537 }
538 
539 void exclusiveConditionsTest(bool cond) {
540   A a;
541   if (cond) {
542     A b;
543     b = std::move(a);
544   }
545   if (!cond) {
546     a.bar(); // no-warning
547   }
548 }
549 
550 void differentBranchesTest(int i) {
551   // Don't warn if the use is in a different branch from the move.
552   {
553     A a;
554     if (i > 0) { // peaceful-note {{Assuming 'i' is > 0}}
555                  // peaceful-note@-1 {{Taking true branch}}
556       A b;
557       b = std::move(a);
558     } else {
559       a.foo(); // no-warning
560     }
561   }
562   // Same thing, but with a ternary operator.
563   {
564     A a, b;
565     i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning
566     // peaceful-note@-1 {{'i' is > 0}}
567     // peaceful-note@-2 {{'?' condition is true}}
568   }
569   // A variation on the theme above.
570   {
571     A a;
572     a.foo() > 0 ? a.foo() : A(std::move(a)).foo();
573     // peaceful-note@-1 {{Assuming the condition is true}}
574     // peaceful-note@-2 {{'?' condition is true}}
575   }
576   // Same thing, but with a switch statement.
577   {
578     A a, b;
579     switch (i) { // peaceful-note {{Control jumps to 'case 1:'}}
580     case 1:
581       b = std::move(a); // no-warning
582       // FIXME: Execution doesn't jump to the end of the function yet.
583       break; // peaceful-note {{Execution jumps to the end of the function}}
584     case 2:
585       a.foo(); // no-warning
586       break;
587     }
588   }
589   // However, if there's a fallthrough, we do warn.
590   {
591     A a, b;
592     switch (i) { // peaceful-note {{Control jumps to 'case 1:'}}
593     case 1:
594       b = std::move(a); // peaceful-note {{Object 'a' is moved}}
595     case 2:
596       a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
597                // peaceful-note@-1 {{Method called on moved-from object 'a'}}
598       break;
599     }
600   }
601 }
602 
603 void tempTest() {
604   A a = A::get();
605   A::get().foo(); // no-warning
606   for (int i = 0; i < bignum(); i++) {
607     A::get().foo(); // no-warning
608   }
609 }
610 
611 void lifeTimeExtendTest() {
612   A&& a = A{};
613   A b = std::move(a); // peaceful-note {{Object is moved}}
614 
615   a.foo(); // peaceful-warning {{Method called on moved-from object}}
616            // peaceful-note@-1 {{Method called on moved-from object}}
617 }
618 
619 void interFunTest1(A &a) {
620   a.bar(); // peaceful-warning {{Method called on moved-from object 'a'}}
621            // peaceful-note@-1 {{Method called on moved-from object 'a'}}
622 }
623 
624 void interFunTest2() {
625   A a;
626   A b;
627   b = std::move(a); // peaceful-note {{Object 'a' is moved}}
628   interFunTest1(a); // peaceful-note {{Calling 'interFunTest1'}}
629 }
630 
631 void foobar(A a, int i);
632 void foobar(int i, A a);
633 
634 void paramEvaluateOrderTest() {
635   A a;
636   foobar(std::move(a), a.getI()); // peaceful-note {{Object 'a' is moved}}
637                                   // peaceful-warning@-1 {{Method called on moved-from object 'a'}}
638                                   // peaceful-note@-2    {{Method called on moved-from object 'a'}}
639 
640   //FALSE NEGATIVE since parameters evaluate order is undefined
641   foobar(a.getI(), std::move(a)); //no-warning
642 }
643 
644 void not_known_pass_by_ref(A &a);
645 void not_known_pass_by_const_ref(const A &a);
646 void not_known_pass_by_rvalue_ref(A &&a);
647 void not_known_pass_by_ptr(A *a);
648 void not_known_pass_by_const_ptr(const A *a);
649 
650 void regionAndPointerEscapeTest() {
651   {
652     A a;
653     A b;
654     b = std::move(a);
655     not_known_pass_by_ref(a);
656     a.foo(); // no-warning
657   }
658   {
659     A a;
660     A b;
661     b = std::move(a); // peaceful-note{{Object 'a' is moved}}
662     not_known_pass_by_const_ref(a);
663     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
664              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
665   }
666   {
667     A a;
668     A b;
669     b = std::move(a);
670     not_known_pass_by_rvalue_ref(std::move(a));
671     a.foo(); // no-warning
672   }
673   {
674     A a;
675     A b;
676     b = std::move(a);
677     not_known_pass_by_ptr(&a);
678     a.foo(); // no-warning
679   }
680   {
681     A a;
682     A b;
683     b = std::move(a); // peaceful-note {{Object 'a' is moved}}
684     not_known_pass_by_const_ptr(&a);
685     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
686              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
687   }
688 }
689 
690 // A declaration statement containing multiple declarations sequences the
691 // initializer expressions.
692 void declarationSequenceTest() {
693   {
694     A a;
695     A a1 = a, a2 = std::move(a); // no-warning
696   }
697   {
698     A a;
699     A a1 = std::move(a), a2 = a; // peaceful-note {{Object 'a' is moved}}
700                                  // peaceful-warning@-1 {{Moved-from object 'a' is copied}}
701                                  // peaceful-note@-2    {{Moved-from object 'a' is copied}}
702   }
703 }
704 
705 // The logical operators && and || sequence their operands.
706 void logicalOperatorsSequenceTest() {
707   {
708     A a;
709     if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // peaceful-note    {{Assuming the condition is false}}
710                                                     // peaceful-note@-1 {{Left side of '&&' is false}}
711                                                     // peaceful-note@-2 {{Taking false branch}}
712                                                     // And the other report:
713                                                     // peaceful-note@-4 {{Assuming the condition is false}}
714                                                     // peaceful-note@-5 {{Left side of '&&' is false}}
715                                                     // peaceful-note@-6 {{Taking false branch}}
716       A().bar();
717     }
718   }
719   // A variation: Negate the result of the && (which pushes the && further down
720   // into the AST).
721   {
722     A a;
723     if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // peaceful-note    {{Assuming the condition is false}}
724                                                        // peaceful-note@-1 {{Left side of '&&' is false}}
725                                                        // peaceful-note@-2 {{Taking true branch}}
726                                                        // And the other report:
727                                                        // peaceful-note@-4 {{Assuming the condition is false}}
728                                                        // peaceful-note@-5 {{Left side of '&&' is false}}
729                                                        // peaceful-note@-6 {{Taking true branch}}
730       A().bar();
731     }
732   }
733   {
734     A a;
735     if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // peaceful-note    {{Object 'a' is moved}}
736                                                     // peaceful-note@-1 {{Assuming the condition is true}}
737                                                     // peaceful-note@-2 {{Left side of '&&' is true}}
738                                                     // peaceful-warning@-3 {{Method called on moved-from object 'a'}}
739                                                     // peaceful-note@-4    {{Method called on moved-from object 'a'}}
740                                                     // And the other report:
741                                                     // peaceful-note@-6 {{Assuming the condition is false}}
742                                                     // peaceful-note@-7 {{Left side of '&&' is false}}
743                                                     // peaceful-note@-8 {{Taking false branch}}
744       A().bar();
745     }
746   }
747   {
748     A a;
749     if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // peaceful-note    {{Assuming the condition is true}}
750                                                     // peaceful-note@-1 {{Left side of '||' is true}}
751                                                     // peaceful-note@-2 {{Taking true branch}}
752       A().bar();
753     }
754   }
755   {
756     A a;
757     if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // peaceful-note {{Object 'a' is moved}}
758                                                     // peaceful-note@-1 {{Assuming the condition is false}}
759                                                     // peaceful-note@-2 {{Left side of '||' is false}}
760                                                     // peaceful-warning@-3 {{Method called on moved-from object 'a'}}
761                                                     // peaceful-note@-4    {{Method called on moved-from object 'a'}}
762       A().bar();
763     }
764   }
765 }
766 
767 // A range-based for sequences the loop variable declaration before the body.
768 void forRangeSequencesTest() {
769   A v[2] = {A(), A()};
770   for (A &a : v) {
771     A b;
772     b = std::move(a); // no-warning
773   }
774 }
775 
776 // If a variable is declared in an if statement, the declaration of the variable
777 // (which is treated like a reinitialization by the check) is sequenced before
778 // the evaluation of the condition (which constitutes a use).
779 void ifStmtSequencesDeclAndConditionTest() {
780   for (int i = 0; i < 3; ++i) {
781     if (A a = A()) {
782       A b;
783       b = std::move(a); // no-warning
784     }
785   }
786 }
787 
788 struct C : public A {
789   [[clang::reinitializes]] void reinit();
790 };
791 
792 void subRegionMoveTest() {
793   {
794     A a;
795     B b = std::move(a.b); // aggressive-note {{Object 'b' is moved}}
796     a.b.foo(); // aggressive-warning {{Method called on moved-from object 'b'}}
797                // aggressive-note@-1 {{Method called on moved-from object 'b'}}
798   }
799   {
800     A a;
801     A a1 = std::move(a); // aggressive-note {{Calling move constructor for 'A'}}
802                          // aggressive-note@-1 {{Returning from move constructor for 'A'}}
803     a.b.foo(); // aggressive-warning{{Method called on moved-from object 'b'}}
804                // aggressive-note@-1{{Method called on moved-from object 'b'}}
805   }
806   // Don't report a misuse if any SuperRegion is already reported.
807   {
808     A a;
809     A a1 = std::move(a); // peaceful-note {{Object 'a' is moved}}
810     a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
811              // peaceful-note@-1 {{Method called on moved-from object 'a'}}
812     a.b.foo(); // no-warning
813   }
814   {
815     C c;
816     C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}}
817     c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}}
818              // peaceful-note@-1 {{Method called on moved-from object 'c'}}
819     c.b.foo(); // no-warning
820   }
821 }
822 
823 void resetSuperClass() {
824   C c;
825   C c1 = std::move(c);
826   c.clear();
827   C c2 = c; // no-warning
828 }
829 
830 void resetSuperClass2() {
831   C c;
832   C c1 = std::move(c);
833   c.reinit();
834   C c2 = c; // no-warning
835 }
836 
837 void reportSuperClass() {
838   C c;
839   C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}}
840   c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}}
841            // peaceful-note@-1 {{Method called on moved-from object 'c'}}
842   C c2 = c; // no-warning
843 }
844 
845 struct Empty {};
846 
847 Empty inlinedCall() {
848   // Used to warn because region 'e' failed to be cleaned up because no symbols
849   // have ever died during the analysis and the checkDeadSymbols callback
850   // was skipped entirely.
851   Empty e{};
852   return e; // no-warning
853 }
854 
855 void checkInlinedCallZombies() {
856   while (true)
857     inlinedCall();
858 }
859 
860 void checkLoopZombies() {
861   while (true) {
862     Empty e{};
863     Empty f = std::move(e); // no-warning
864   }
865 }
866 
867 void checkMoreLoopZombies1(bool flag) {
868   while (flag) {
869     Empty e{};
870     if (true)
871       e; // expected-warning {{expression result unused}}
872     Empty f = std::move(e); // no-warning
873   }
874 }
875 
876 bool coin();
877 
878 void checkMoreLoopZombies2(bool flag) {
879   while (flag) {
880     Empty e{};
881     while (coin())
882       e; // expected-warning {{expression result unused}}
883     Empty f = std::move(e); // no-warning
884   }
885 }
886 
887 void checkMoreLoopZombies3(bool flag) {
888   while (flag) {
889     Empty e{};
890     do
891       e; // expected-warning {{expression result unused}}
892     while (coin());
893     Empty f = std::move(e); // no-warning
894   }
895 }
896 
897 void checkMoreLoopZombies4(bool flag) {
898   while (flag) {
899     Empty e{};
900     for (; coin();)
901       e; // expected-warning {{expression result unused}}
902     Empty f = std::move(e); // no-warning
903   }
904 }
905 
906 void checkExplicitDestructorCalls() {
907   // The below code segments invoke the destructor twice (explicit and
908   // implicit). While this is not a desired code behavior, it is
909   // not the use-after-move checker's responsibility to issue such a warning.
910   {
911      B* b = new B;
912      B a = std::move(*b);
913      b->~B(); // no-warning
914      delete b;
915   }
916   {
917     B a, b;
918     new (&a) B(reinterpret_cast<B &&>(b));
919     (&b)->~B(); // no-warning
920   }
921   {
922     B b;
923     B a  = std::move(b);
924     b.~B(); // no-warning
925   }
926 }
927 
928 struct MoveOnlyWithDestructor {
929   MoveOnlyWithDestructor();
930   ~MoveOnlyWithDestructor();
931   MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete;
932   MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m);
933 };
934 
935 MoveOnlyWithDestructor foo() {
936   MoveOnlyWithDestructor m;
937   return m;
938 }
939 
940 class HasSTLField {
941   std::vector<int> V;
942   void testVector() {
943     // Warn even in non-aggressive mode when it comes to STL, because
944     // in STL the object is left in "valid but unspecified state" after move.
945     std::vector<int> W = std::move(V); // expected-note {{Object 'V' of type 'std::vector' is left in a valid but unspecified state after move}}
946     V.push_back(123); // expected-warning {{Method called on moved-from object 'V'}}
947                       // expected-note@-1 {{Method called on moved-from object 'V'}}
948   }
949 
950   std::unique_ptr<int> P;
951   void testUniquePtr() {
952     // unique_ptr remains in a well-defined state after move.
953     std::unique_ptr<int> Q = std::move(P); // aggressive-note {{Object 'P' is moved}}
954                                            // non-aggressive-note@-1 {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
955     P.get(); // aggressive-warning{{Method called on moved-from object 'P'}}
956              // aggressive-note@-1{{Method called on moved-from object 'P'}}
957 
958     // Because that well-defined state is null, dereference is still UB.
959     // Note that in aggressive mode we already warned about 'P',
960     // so no extra warning is generated.
961     *P += 1; // non-aggressive-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
962              // non-aggressive-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
963 
964     // The program should have crashed by now.
965     clang_analyzer_warnIfReached(); // no-warning
966   }
967 };
968 
969 void localRValueMove(A &&a) {
970   A b = std::move(a); // peaceful-note {{Object 'a' is moved}}
971   a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
972            // peaceful-note@-1 {{Method called on moved-from object 'a'}}
973 }
974 
975 void localUniquePtr(std::unique_ptr<int> P) {
976   // Even though unique_ptr is safe to use after move,
977   // reusing a local variable this way usually indicates a bug.
978   std::unique_ptr<int> Q = std::move(P); // peaceful-note {{Object 'P' is moved}}
979   P.get(); // peaceful-warning {{Method called on moved-from object 'P'}}
980            // peaceful-note@-1 {{Method called on moved-from object 'P'}}
981 }
982 
983 void localUniquePtrWithArrow(std::unique_ptr<A> P) {
984   std::unique_ptr<A> Q = std::move(P); // expected-note{{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
985   P->foo(); // expected-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
986             // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
987 }
988 
989 void getAfterMove(std::unique_ptr<A> P) {
990   std::unique_ptr<A> Q = std::move(P); // peaceful-note {{Object 'P' is moved}}
991 
992   // TODO: Explain why (bool)P is false.
993   if (P) // peaceful-note{{Taking false branch}}
994     clang_analyzer_warnIfReached(); // no-warning
995 
996   A *a = P.get(); // peaceful-warning {{Method called on moved-from object 'P'}}
997                   // peaceful-note@-1 {{Method called on moved-from object 'P'}}
998 
999   // TODO: Warn on a null dereference here.
1000   a->foo();
1001 }
1002 
1003 struct OtherMoveSafeClasses {
1004   std::packaged_task<int(void)> Task;
1005 
1006   void test() {
1007     // Test the suppression caused by use-after-move semantics of
1008     // std::package_task being different from other standard classes.
1009     // Only warn in aggressive mode. Don't say that the object
1010     // is left in unspecified state after move.
1011     std::packaged_task<int(void)> Task2 = std::move(Task);
1012     // aggressive-note@-1   {{Object 'Task' is moved}}
1013     std::packaged_task<int(void)> Task3 = std::move(Task);
1014     // aggressive-warning@-1{{Moved-from object 'Task' is moved}}
1015     // aggressive-note@-2   {{Moved-from object 'Task' is moved}}
1016   }
1017 };
1018