Clang Project

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