1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %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: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\
5 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
6 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS=1
7 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\
8 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
9 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
10 // RUN:  -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE
11 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\
12 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
13 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS=1\
14 // RUN:  -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE
15 
16 namespace std {
17 
18 typedef __typeof(sizeof(int)) size_t;
19 
20 template <typename>
21 struct remove_reference;
22 
23 template <typename _Tp>
24 struct remove_reference { typedef _Tp type; };
25 
26 template <typename _Tp>
27 struct remove_reference<_Tp &> { typedef _Tp type; };
28 
29 template <typename _Tp>
30 struct remove_reference<_Tp &&> { typedef _Tp type; };
31 
32 template <typename _Tp>
33 typename remove_reference<_Tp>::type &&move(_Tp &&__t) {
34   return static_cast<typename remove_reference<_Tp>::type &&>(__t);
35 }
36 
37 template <typename _Tp>
38 _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
39   return static_cast<_Tp &&>(__t);
40 }
41 
42 template <class T>
43 void swap(T &a, T &b) {
44   T c(std::move(a));
45   a = std::move(b);
46   b = std::move(c);
47 }
48 
49 template <typename T>
50 class vector {
51 public:
52   vector();
53   void push_back(const T &t);
54 };
55 
56 } // namespace std
57 
58 class B {
59 public:
60   B() = default;
61   B(const B &) = default;
62   B(B &&) = default;
63   B& operator=(const B &q) = default;
64   void operator=(B &&b) {
65     return;
66   }
67   void foo() { return; }
68 };
69 
70 class A {
71   int i;
72   double d;
73 
74 public:
75   B b;
76   A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
77   void moveconstruct(A &&other) {
78     std::swap(b, other.b);
79     std::swap(d, other.d);
80     std::swap(i, other.i);
81     return;
82   }
83   static A get() {
84     A v(12, 13);
85     return v;
86   }
87   A(A *a) {
88     moveconstruct(std::move(*a));
89   }
90   A(const A &other) : i(other.i), d(other.d), b(other.b) {}
91   A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) {
92 #ifdef AGGRESSIVE
93     // expected-note@-2{{Object 'b' is moved}}
94 #endif
95   }
96   A(A &&other, char *k) {
97     moveconstruct(std::move(other));
98   }
99   void operator=(const A &other) {
100     i = other.i;
101     d = other.d;
102     b = other.b;
103     return;
104   }
105   void operator=(A &&other) {
106     moveconstruct(std::move(other));
107     return;
108   }
109   int getI() { return i; }
110   int foo() const;
111   void bar() const;
112   void reset();
113   void destroy();
114   void clear();
115   void resize(std::size_t);
116   bool empty() const;
117   bool isEmpty() const;
118   operator bool() const;
119 };
120 
121 int bignum();
122 
123 void moveInsideFunctionCall(A a) {
124   A b = std::move(a);
125 }
126 void leftRefCall(A &a) {
127   a.foo();
128 }
129 void rightRefCall(A &&a) {
130   a.foo();
131 }
132 void constCopyOrMoveCall(const A a) {
133   a.foo();
134 }
135 
136 void copyOrMoveCall(A a) {
137   a.foo();
138 }
139 
140 void simpleMoveCtorTest() {
141   {
142     A a;
143     A b = std::move(a); // expected-note {{Object 'a' is moved}}
144     a.foo();            // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
145   }
146   {
147     A a;
148     A b = std::move(a); // expected-note {{Object 'a' is moved}}
149     b = a;              // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}}
150   }
151   {
152     A a;
153     A b = std::move(a); // expected-note {{Object 'a' is moved}}
154     b = std::move(a);   // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}}
155   }
156 }
157 
158 void simpleMoveAssignementTest() {
159   {
160     A a;
161     A b;
162     b = std::move(a); // expected-note {{Object 'a' is moved}}
163     a.foo();          // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
164   }
165   {
166     A a;
167     A b;
168     b = std::move(a); // expected-note {{Object 'a' is moved}}
169     A c(a);           // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}}
170   }
171   {
172     A a;
173     A b;
174     b = std::move(a);  // expected-note {{Object 'a' is moved}}
175     A c(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}}
176   }
177 }
178 
179 void moveInInitListTest() {
180   struct S {
181     A a;
182   };
183   A a;
184   S s{std::move(a)}; // expected-note {{Object 'a' is moved}}
185   a.foo();           // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
186 }
187 
188 // Don't report a bug if the variable was assigned to in the meantime.
189 void reinitializationTest(int i) {
190   {
191     A a;
192     A b;
193     b = std::move(a);
194     a = A();
195     a.foo();
196   }
197   {
198     A a;
199     if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}}
200       // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}}
201       A b;
202       b = std::move(a);
203       a = A();
204     }
205     if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}}
206       //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}}
207       a.foo();    // no-warning
208     }
209   }
210   {
211     A a;
212     if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
213       std::move(a);
214     }
215     if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
216       a = A();
217       a.foo();
218     }
219   }
220   // The built-in assignment operator should also be recognized as a
221   // reinitialization. (std::move() may be called on built-in types in template
222   // code.)
223   {
224     int a1 = 1, a2 = 2;
225     std::swap(a1, a2);
226   }
227   // A std::move() after the assignment makes the variable invalid again.
228   {
229     A a;
230     A b;
231     b = std::move(a);
232     a = A();
233     b = std::move(a); // expected-note {{Object 'a' is moved}}
234     a.foo();          // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
235   }
236   // If a path exist where we not reinitialize the variable we report a bug.
237   {
238     A a;
239     A b;
240     b = std::move(a); // expected-note {{Object 'a' is moved}}
241     if (i < 10) {     // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}}
242       a = A();
243     }
244     if (i > 5) { // expected-note {{Taking true branch}}
245       a.foo();   // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
246     }
247   }
248 }
249 
250 // Using decltype on an expression is not a use.
251 void decltypeIsNotUseTest() {
252   A a;
253   // A b(std::move(a));
254   decltype(a) other_a; // no-warning
255 }
256 
257 void loopTest() {
258   {
259     A a;
260     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
261       rightRefCall(std::move(a));        // no-warning
262     }
263   }
264   {
265     A a;
266     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
267       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
268 			//expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
269       rightRefCall(std::move(a)); // no-warning
270     }
271   }
272   {
273     A a;
274     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
275       leftRefCall(a);                    // no-warning
276     }
277   }
278   {
279     A a;
280     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
281       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
282 			//expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
283       leftRefCall(a);             // no-warning
284     }
285   }
286   {
287     A a;
288     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
289       constCopyOrMoveCall(a);            // no-warning
290     }
291   }
292   {
293     A a;
294     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
295       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
296 			//expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
297       constCopyOrMoveCall(a);     // no-warning
298     }
299   }
300   {
301     A a;
302     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
303       moveInsideFunctionCall(a);         // no-warning
304     }
305   }
306   {
307     A a;
308     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
309       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
310 			//expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
311       moveInsideFunctionCall(a);  // no-warning
312     }
313   }
314   {
315     A a;
316     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
317       copyOrMoveCall(a);                 // no-warning
318     }
319   }
320   {
321     A a;
322     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}}
323       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
324 			//expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
325       copyOrMoveCall(a);          // no-warning
326     }
327   }
328   {
329     A a;
330     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true.  Entering loop body}} expected-note {{Loop condition is true.  Entering loop body}}
331       constCopyOrMoveCall(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}}
332       // expected-note@-1 {{Object 'a' is moved}}
333     }
334   }
335 
336   // Don't warn if we return after the move.
337   {
338     A a;
339     for (int i = 0; i < 3; ++i) {
340       a.bar();
341       if (a.foo() > 0) {
342         A b;
343         b = std::move(a); // no-warning
344         return;
345       }
346     }
347   }
348 }
349 
350 //report a usage of a moved-from object only at the first use
351 void uniqueTest(bool cond) {
352   A a(42, 42.0);
353   A b;
354   b = std::move(a); // expected-note {{Object 'a' is moved}}
355 
356   if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}}
357     a.foo();  // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
358   }
359   if (cond) {
360     a.bar(); // no-warning
361   }
362 
363   a.bar(); // no-warning
364 }
365 
366 void uniqueTest2() {
367   A a;
368   A a1 = std::move(a); // expected-note {{Object 'a' is moved}}
369   a.foo();             // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
370 
371   A a2 = std::move(a); // no-warning
372   a.foo();             // no-warning
373 }
374 
375 // There are exceptions where we assume in general that the method works fine
376 //even on moved-from objects.
377 void moveSafeFunctionsTest() {
378   A a;
379   A b = std::move(a); // expected-note {{Object 'a' is moved}}
380   a.empty();          // no-warning
381   a.isEmpty();        // no-warning
382   (void)a;            // no-warning
383   (bool)a;            // expected-warning {{expression result unused}}
384   a.foo();            // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
385 }
386 
387 void moveStateResetFunctionsTest() {
388   {
389     A a;
390     A b = std::move(a);
391     a.reset(); // no-warning
392     a.foo();   // no-warning
393     // Test if resets the state of subregions as well.
394     a.b.foo(); // no-warning
395   }
396   {
397     A a;
398     A b = std::move(a);
399     a.destroy(); // no-warning
400     a.foo();     // no-warning
401   }
402   {
403     A a;
404     A b = std::move(a);
405     a.clear(); // no-warning
406     a.foo();   // no-warning
407     a.b.foo(); // no-warning
408   }
409   {
410     A a;
411     A b = std::move(a);
412     a.resize(0); // no-warning
413     a.foo();   // no-warning
414     a.b.foo(); // no-warning
415   }
416 }
417 
418 // Moves or uses that occur as part of template arguments.
419 template <int>
420 class ClassTemplate {
421 public:
422   void foo(A a);
423 };
424 
425 template <int>
426 void functionTemplate(A a);
427 
428 void templateArgIsNotUseTest() {
429   {
430     // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
431     // Google Test.
432     A a;
433     ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
434   }
435   {
436     A a;
437     functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
438   }
439 }
440 
441 // Moves of global variables are not reported.
442 A global_a;
443 void globalVariablesTest() {
444   std::move(global_a);
445   global_a.foo(); // no-warning
446 }
447 
448 // Moves of member variables.
449 class memberVariablesTest {
450   A a;
451   static A static_a;
452 
453   void f() {
454     A b;
455     b = std::move(a);
456     a.foo();
457 #ifdef AGGRESSIVE
458     // expected-note@-3{{Object 'a' is moved}}
459     // expected-warning@-3 {{Method called on moved-from object 'a'}}
460     // expected-note@-4{{Method called on moved-from object 'a'}}
461 #endif
462 
463     b = std::move(static_a);
464     static_a.foo();
465 #ifdef AGGRESSIVE
466     // expected-note@-3{{Object 'static_a' is moved}}
467     // expected-warning@-3{{Method called on moved-from object 'static_a'}}
468     // expected-note@-4{{Method called on moved-from object 'static_a'}}
469 #endif
470   }
471 };
472 
473 void PtrAndArrayTest() {
474   A *Ptr = new A(1, 1.5);
475   A Arr[10];
476   Arr[2] = std::move(*Ptr);
477   (*Ptr).foo();
478 #ifdef AGGRESSIVE
479   // expected-note@-3{{Object is moved}}
480   // expected-warning@-3{{Method called on moved-from object}}
481   // expected-note@-4{{Method called on moved-from object}}
482 #endif
483 
484   Ptr = &Arr[1];
485   Arr[3] = std::move(Arr[1]);
486   Ptr->foo();
487 #ifdef AGGRESSIVE
488   // expected-note@-3{{Object is moved}}
489   // expected-warning@-3{{Method called on moved-from object}}
490   // expected-note@-4{{Method called on moved-from object}}
491 #endif
492 
493   Arr[3] = std::move(Arr[2]);
494   Arr[2].foo();
495 #ifdef AGGRESSIVE
496   // expected-note@-3{{Object is moved}}
497   // expected-warning@-3{{Method called on moved-from object}}
498   // expected-note@-4{{Method called on moved-from object}}
499 #endif
500 
501   Arr[2] = std::move(Arr[3]); // reinitialization
502   Arr[2].foo();               // no-warning
503 }
504 
505 void exclusiveConditionsTest(bool cond) {
506   A a;
507   if (cond) {
508     A b;
509     b = std::move(a);
510   }
511   if (!cond) {
512     a.bar(); // no-warning
513   }
514 }
515 
516 void differentBranchesTest(int i) {
517   // Don't warn if the use is in a different branch from the move.
518   {
519     A a;
520     if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}}
521       A b;
522       b = std::move(a);
523     } else {
524       a.foo(); // no-warning
525     }
526   }
527   // Same thing, but with a ternary operator.
528   {
529     A a, b;
530     i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning  // expected-note {{'?' condition is true}}
531   }
532   // A variation on the theme above.
533   {
534     A a;
535 #ifdef DFS
536     a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}}
537 #else
538     a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is true}} expected-note {{'?' condition is true}}
539 #endif
540   }
541   // Same thing, but with a switch statement.
542   {
543     A a, b;
544     switch (i) { // expected-note {{Control jumps to 'case 1:'}}
545     case 1:
546       b = std::move(a); // no-warning
547       break;            // expected-note {{Execution jumps to the end of the function}}
548     case 2:
549       a.foo(); // no-warning
550       break;
551     }
552   }
553   // However, if there's a fallthrough, we do warn.
554   {
555     A a, b;
556     switch (i) { // expected-note {{Control jumps to 'case 1:'}}
557     case 1:
558       b = std::move(a); // expected-note {{Object 'a' is moved}}
559     case 2:
560       a.foo(); // expected-warning {{Method called on moved-from object}} expected-note {{Method called on moved-from object 'a'}}
561       break;
562     }
563   }
564 }
565 
566 void tempTest() {
567   A a = A::get();
568   A::get().foo(); // no-warning
569   for (int i = 0; i < bignum(); i++) {
570     A::get().foo(); // no-warning
571   }
572 }
573 
574 void interFunTest1(A &a) {
575   a.bar(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
576 }
577 
578 void interFunTest2() {
579   A a;
580   A b;
581   b = std::move(a); // expected-note {{Object 'a' is moved}}
582   interFunTest1(a); // expected-note {{Calling 'interFunTest1'}}
583 }
584 
585 void foobar(A a, int i);
586 void foobar(int i, A a);
587 
588 void paramEvaluateOrderTest() {
589   A a;
590   foobar(std::move(a), a.getI()); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
591   // expected-note@-1 {{Object 'a' is moved}}
592 
593   //FALSE NEGATIVE since parameters evaluate order is undefined
594   foobar(a.getI(), std::move(a)); //no-warning
595 }
596 
597 void not_known(A &a);
598 void not_known(A *a);
599 
600 void regionAndPointerEscapeTest() {
601   {
602     A a;
603     A b;
604     b = std::move(a);
605     not_known(a);
606     a.foo(); //no-warning
607   }
608   {
609     A a;
610     A b;
611     b = std::move(a);
612     not_known(&a);
613     a.foo(); // no-warning
614   }
615 }
616 
617 // A declaration statement containing multiple declarations sequences the
618 // initializer expressions.
619 void declarationSequenceTest() {
620   {
621     A a;
622     A a1 = a, a2 = std::move(a); // no-warning
623   }
624   {
625     A a;
626     A a1 = std::move(a), a2 = a; // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}}
627     // expected-note@-1 {{Object 'a' is moved}}
628   }
629 }
630 
631 // The logical operators && and || sequence their operands.
632 void logicalOperatorsSequenceTest() {
633   {
634     A a;
635     if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
636       // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
637 			//expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}}
638       A().bar();
639     }
640   }
641   // A variation: Negate the result of the && (which pushes the && further down
642   // into the AST).
643   {
644     A a;
645     if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
646       // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
647       // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}}
648       A().bar();
649     }
650   }
651   {
652     A a;
653     if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
654       // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}}
655       // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}}
656       // expected-note@-3 {{Taking false branch}}
657       A().bar();
658     }
659   }
660   {
661     A a;
662     if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}}
663 			//expected-note@-1 {{Left side of '||' is true}}
664 			//expected-note@-2 {{Taking true branch}}
665       A().bar();
666     }
667   }
668   {
669     A a;
670     if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
671       // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}}
672       A().bar();
673     }
674   }
675 }
676 
677 // A range-based for sequences the loop variable declaration before the body.
678 void forRangeSequencesTest() {
679   A v[2] = {A(), A()};
680   for (A &a : v) {
681     A b;
682     b = std::move(a); // no-warning
683   }
684 }
685 
686 // If a variable is declared in an if statement, the declaration of the variable
687 // (which is treated like a reinitialization by the check) is sequenced before
688 // the evaluation of the condition (which constitutes a use).
689 void ifStmtSequencesDeclAndConditionTest() {
690   for (int i = 0; i < 3; ++i) {
691     if (A a = A()) {
692       A b;
693       b = std::move(a); // no-warning
694     }
695   }
696 }
697 
698 struct C : public A {
699   [[clang::reinitializes]] void reinit();
700 };
701 
702 void subRegionMoveTest() {
703   {
704     A a;
705     B b = std::move(a.b);
706     a.b.foo();
707 #ifdef AGGRESSIVE
708     // expected-note@-3{{Object 'b' is moved}}
709     // expected-warning@-3{{Method called on moved-from object 'b'}}
710     // expected-note@-4 {{Method called on moved-from object 'b'}}
711 #endif
712   }
713   {
714     A a;
715     A a1 = std::move(a);
716     a.b.foo();
717 #ifdef AGGRESSIVE
718     // expected-note@-3{{Calling move constructor for 'A'}}
719     // expected-note@-4{{Returning from move constructor for 'A'}}
720     // expected-warning@-4{{Method called on moved-from object 'b'}}
721     // expected-note@-5{{Method called on moved-from object 'b'}}
722 #endif
723   }
724   // Don't report a misuse if any SuperRegion is already reported.
725   {
726     A a;
727     A a1 = std::move(a); // expected-note {{Object 'a' is moved}}
728     a.foo();             // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}}
729     a.b.foo();           // no-warning
730   }
731   {
732     C c;
733     C c1 = std::move(c); // expected-note {{Object 'c' is moved}}
734     c.foo();             // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}}
735     c.b.foo();           // no-warning
736   }
737 }
738 
739 void resetSuperClass() {
740   C c;
741   C c1 = std::move(c);
742   c.clear();
743   C c2 = c; // no-warning
744 }
745 
746 void resetSuperClass2() {
747   C c;
748   C c1 = std::move(c);
749   c.reinit();
750   C c2 = c; // no-warning
751 }
752 
753 void reportSuperClass() {
754   C c;
755   C c1 = std::move(c); // expected-note {{Object 'c' is moved}}
756   c.foo();             // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}}
757   C c2 = c;            // no-warning
758 }
759 
760 struct Empty {};
761 
762 Empty inlinedCall() {
763   // Used to warn because region 'e' failed to be cleaned up because no symbols
764   // have ever died during the analysis and the checkDeadSymbols callback
765   // was skipped entirely.
766   Empty e{};
767   return e; // no-warning
768 }
769 
770 void checkInlinedCallZombies() {
771   while (true)
772     inlinedCall();
773 }
774 
775 void checkLoopZombies() {
776   while (true) {
777     Empty e{};
778     Empty f = std::move(e); // no-warning
779   }
780 }
781 
782 struct MoveOnlyWithDestructor {
783   MoveOnlyWithDestructor();
784   ~MoveOnlyWithDestructor();
785   MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete;
786   MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m);
787 };
788 
789 MoveOnlyWithDestructor foo() {
790   MoveOnlyWithDestructor m;
791   return m;
792 }
793 
794 class HasSTLField {
795   std::vector<int> V;
796   void foo() {
797     // Warn even in non-aggressive mode when it comes to STL, because
798     // in STL the object is left in "valid but unspecified state" after move.
799     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}}
800     V.push_back(123); // expected-warning{{Method called on moved-from object 'V'}}
801                       // expected-note@-1{{Method called on moved-from object 'V'}}
802   }
803 };
804 
805 void localRValueMove(A &&a) {
806   A b = std::move(a); // expected-note{{Object 'a' is moved}}
807   a.foo(); // expected-warning{{Method called on moved-from object 'a'}}
808            // expected-note@-1{{Method called on moved-from object 'a'}}
809 }
810