]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/Analysis/MisusedMovedObject.cpp
Vendor import of clang trunk r300422:
[FreeBSD/FreeBSD.git] / test / Analysis / MisusedMovedObject.cpp
1 // RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
2
3 namespace std {
4
5 template <typename>
6 struct remove_reference;
7
8 template <typename _Tp>
9 struct remove_reference { typedef _Tp type; };
10
11 template <typename _Tp>
12 struct remove_reference<_Tp &> { typedef _Tp type; };
13
14 template <typename _Tp>
15 struct remove_reference<_Tp &&> { typedef _Tp type; };
16
17 template <typename _Tp>
18 typename remove_reference<_Tp>::type &&move(_Tp &&__t) {
19   return static_cast<typename remove_reference<_Tp>::type &&>(__t);
20 }
21
22 template <typename _Tp>
23 _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
24   return static_cast<_Tp &&>(__t);
25 }
26
27 template <class T>
28 void swap(T &a, T &b) {
29   T c(std::move(a));
30   a = std::move(b);
31   b = std::move(c);
32 }
33
34 } // namespace std
35
36 class B {
37 public:
38   B() = default;
39   B(const B &) = default;
40   B(B &&) = default;
41   void operator=(B &&b) {
42     return;
43   }
44   void foo() { return; }
45 };
46
47 class A {
48   int i;
49   double d;
50
51 public:
52   B b;
53   A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
54   void moveconstruct(A &&other) {
55     std::swap(b, other.b);
56     std::swap(d, other.d);
57     std::swap(i, other.i);
58     return;
59   }
60   static A get() {
61     A v(12, 13);
62     return v;
63   }
64   A(A *a) {
65     moveconstruct(std::move(*a));
66   }
67   A(const A &other) : i(other.i), d(other.d), b(other.b) {}
68   A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // expected-note {{'b' became 'moved-from' here}}
69   }
70   A(A &&other, char *k) {
71     moveconstruct(std::move(other));
72   }
73   void operator=(A &&other) {
74     moveconstruct(std::move(other));
75     return;
76   }
77   int getI() { return i; }
78   int foo() const;
79   void bar() const;
80   void reset();
81   void destroy();
82   void clear();
83   bool empty() const;
84   bool isEmpty() const;
85   operator bool() const;
86 };
87
88 int bignum();
89
90 void moveInsideFunctionCall(A a) {
91   A b = std::move(a);
92 }
93 void leftRefCall(A &a) {
94   a.foo();
95 }
96 void rightRefCall(A &&a) {
97   a.foo();
98 }
99 void constCopyOrMoveCall(const A a) {
100   a.foo();
101 }
102
103 void copyOrMoveCall(A a) {
104   a.foo();
105 }
106
107 void simpleMoveCtorTest() {
108   A a;
109   A b;
110   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
111   a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
112 }
113
114 void simpleMoveAssignementTest() {
115   A a;
116   A b;
117   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
118   a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
119 }
120
121 void moveInInitListTest() {
122   struct S {
123     A a;
124   };
125   A a;
126   S s{std::move(a)}; // expected-note {{'a' became 'moved-from' here}}
127   a.foo();           // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
128 }
129
130 // Don't report a bug if the variable was assigned to in the meantime.
131 void reinitializationTest(int i) {
132   {
133     A a;
134     A b;
135     b = std::move(a);
136     a = A();
137     a.foo();
138   }
139   {
140     A a;
141     if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}}
142       // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}}
143       A b;
144       b = std::move(a);
145       a = A();
146     }
147     if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}}
148       //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}}
149       a.foo();    // no-warning
150     }
151   }
152   {
153     A a;
154     if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
155       std::move(a);
156     }
157     if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
158       a = A();
159       a.foo();
160     }
161   }
162   // The built-in assignment operator should also be recognized as a
163   // reinitialization. (std::move() may be called on built-in types in template
164   // code.)
165   {
166     int a1 = 1, a2 = 2;
167     std::swap(a1, a2);
168   }
169   // A std::move() after the assignment makes the variable invalid again.
170   {
171     A a;
172     A b;
173     b = std::move(a);
174     a = A();
175     b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
176     a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
177   }
178   // If a path exist where we not reinitialize the variable we report a bug.
179   {
180     A a;
181     A b;
182     b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
183     if (i < 10) {     // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}}
184       a = A();
185     }
186     if (i > 5) { // expected-note {{Taking true branch}}
187       a.foo();   // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
188     }
189   }
190 }
191
192 // Using decltype on an expression is not a use.
193 void decltypeIsNotUseTest() {
194   A a;
195   // A b(std::move(a));
196   decltype(a) other_a; // no-warning
197 }
198
199 void loopTest() {
200   {
201     A a;
202     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
203       rightRefCall(std::move(a));        // no-warning
204     }
205   }
206   {
207     A a;
208     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
209       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
210                         //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
211       rightRefCall(std::move(a)); // no-warning
212     }
213   }
214   {
215     A a;
216     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
217       leftRefCall(a);                    // no-warning
218     }
219   }
220   {
221     A a;
222     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}} 
223       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
224                         //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
225       leftRefCall(a);             // no-warning
226     }
227   }
228   {
229     A a;
230     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
231       constCopyOrMoveCall(a);            // no-warning
232     }
233   }
234   {
235     A a;
236     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}} 
237       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
238                         //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
239       constCopyOrMoveCall(a);     // no-warning
240     }
241   }
242   {
243     A a;
244     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
245       moveInsideFunctionCall(a);         // no-warning
246     }
247   }
248   {
249     A a;
250     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.  Entering loop body}}
251       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
252                         //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
253       moveInsideFunctionCall(a);  // no-warning
254     }
255   }
256   {
257     A a;
258     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
259       copyOrMoveCall(a);                 // no-warning
260     }
261   }
262   {
263     A a;
264     for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}}
265       //expected-note@-1 {{Loop condition is true.  Entering loop body}}
266                         //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
267       copyOrMoveCall(a);          // no-warning
268     }
269   }
270   {
271     A a;
272     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}}
273       constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
274       // expected-note@-1 {{'a' became 'moved-from' here}}
275     }
276   }
277
278   // Don't warn if we return after the move.
279   {
280     A a;
281     for (int i = 0; i < 3; ++i) {
282       a.bar();
283       if (a.foo() > 0) {
284         A b;
285         b = std::move(a); // no-warning
286         return;
287       }
288     }
289   }
290 }
291
292 //report a usage of a moved-from object only at the first use
293 void uniqueTest(bool cond) {
294   A a(42, 42.0);
295   A b;
296   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
297
298   if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}}
299     a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
300   }
301   if (cond) {
302     a.bar(); // no-warning
303   }
304
305   a.bar(); // no-warning
306 }
307
308 void uniqueTest2() {
309   A a;
310   A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
311   a.foo();             // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
312
313   A a2 = std::move(a); // no-warning
314   a.foo();             // no-warning
315 }
316
317 // There are exceptions where we assume in general that the method works fine
318 //even on moved-from objects.
319 void moveSafeFunctionsTest() {
320   A a;
321   A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
322   a.empty();          // no-warning
323   a.isEmpty();        // no-warning
324   (void)a;            // no-warning
325   (bool)a;            // expected-warning {{expression result unused}}
326   a.foo();            // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
327 }
328
329 void moveStateResetFunctionsTest() {
330   {
331     A a;
332     A b = std::move(a);
333     a.reset(); // no-warning
334     a.foo();   // no-warning
335   }
336   {
337     A a;
338     A b = std::move(a);
339     a.destroy(); // no-warning
340     a.foo();     // no-warning
341   }
342   {
343     A a;
344     A b = std::move(a);
345     a.clear(); // no-warning
346     a.foo();   // no-warning
347   }
348 }
349
350 // Moves or uses that occur as part of template arguments.
351 template <int>
352 class ClassTemplate {
353 public:
354   void foo(A a);
355 };
356
357 template <int>
358 void functionTemplate(A a);
359
360 void templateArgIsNotUseTest() {
361   {
362     // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
363     // Google Test.
364     A a;
365     ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
366   }
367   {
368     A a;
369     functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
370   }
371 }
372
373 // Moves of global variables are not reported.
374 A global_a;
375 void globalVariablesTest() {
376   std::move(global_a);
377   global_a.foo(); // no-warning
378 }
379
380 // Moves of member variables.
381 class memberVariablesTest {
382   A a;
383   static A static_a;
384
385   void f() {
386     A b;
387     b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
388     a.foo();          // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
389
390     b = std::move(static_a); // expected-note {{'static_a' became 'moved-from' here}}
391     static_a.foo();          // expected-warning {{Method call on a 'moved-from' object 'static_a'}} expected-note {{Method call on a 'moved-from' object 'static_a'}}
392   }
393 };
394
395 void PtrAndArrayTest() {
396   A *Ptr = new A(1, 1.5);
397   A Arr[10];
398   Arr[2] = std::move(*Ptr); // expected-note {{Became 'moved-from' here}}
399   (*Ptr).foo();             // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
400
401   Ptr = &Arr[1];
402   Arr[3] = std::move(Arr[1]); // expected-note {{Became 'moved-from' here}}
403   Ptr->foo();                 // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
404
405   Arr[3] = std::move(Arr[2]); // expected-note {{Became 'moved-from' here}}
406   Arr[2].foo();               // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
407
408   Arr[2] = std::move(Arr[3]); // reinitialization
409   Arr[2].foo();               // no-warning
410 }
411
412 void exclusiveConditionsTest(bool cond) {
413   A a;
414   if (cond) {
415     A b;
416     b = std::move(a);
417   }
418   if (!cond) {
419     a.bar(); // no-warning
420   }
421 }
422
423 void differentBranchesTest(int i) {
424   // Don't warn if the use is in a different branch from the move.
425   {
426     A a;
427     if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}}
428       A b;
429       b = std::move(a);
430     } else {
431       a.foo(); // no-warning
432     }
433   }
434   // Same thing, but with a ternary operator.
435   {
436     A a, b;
437     i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning  // expected-note {{'?' condition is true}}
438   }
439   // A variation on the theme above.
440   {
441     A a;
442     a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}}
443   }
444   // Same thing, but with a switch statement.
445   {
446     A a, b;
447     switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 448}}
448     case 1:
449       b = std::move(a); // no-warning
450       break;            // expected-note {{Execution jumps to the end of the function}}
451     case 2:
452       a.foo(); // no-warning
453       break;
454     }
455   }
456   // However, if there's a fallthrough, we do warn.
457   {
458     A a, b;
459     switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 460}}
460     case 1:
461       b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
462     case 2:
463       a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
464       break;
465     }
466   }
467 }
468
469 void tempTest() {
470   A a = A::get();
471   A::get().foo(); // no-warning
472   for (int i = 0; i < bignum(); i++) {
473     A::get().foo(); // no-warning
474   }
475 }
476
477 void interFunTest1(A &a) {
478   a.bar(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
479 }
480
481 void interFunTest2() {
482   A a;
483   A b;
484   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
485   interFunTest1(a); // expected-note {{Calling 'interFunTest1'}}
486 }
487
488 void foobar(A a, int i);
489 void foobar(int i, A a);
490
491 void paramEvaluateOrderTest() {
492   A a;
493   foobar(std::move(a), a.getI()); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
494   // expected-note@-1 {{'a' became 'moved-from' here}}
495
496   //FALSE NEGATIVE since parameters evaluate order is undefined
497   foobar(a.getI(), std::move(a)); //no-warning
498 }
499
500 void not_known(A &a);
501 void not_known(A *a);
502
503 void regionAndPointerEscapeTest() {
504   {
505     A a;
506     A b;
507     b = std::move(a);
508     not_known(a);
509     a.foo(); //no-warning
510   }
511   {
512     A a;
513     A b;
514     b = std::move(a);
515     not_known(&a);
516     a.foo(); // no-warning
517   }
518 }
519
520 // A declaration statement containing multiple declarations sequences the
521 // initializer expressions.
522 void declarationSequenceTest() {
523   {
524     A a;
525     A a1 = a, a2 = std::move(a); // no-warning
526   }
527   {
528     A a;
529     A a1 = std::move(a), a2 = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
530     // expected-note@-1 {{'a' became 'moved-from' here}}
531   }
532 }
533
534 // The logical operators && and || sequence their operands.
535 void logicalOperatorsSequenceTest() {
536   {
537     A a;
538     if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} 
539       // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
540                         //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}}
541       A().bar();
542     }
543   }
544   // A variation: Negate the result of the && (which pushes the && further down
545   // into the AST).
546   {
547     A a;
548     if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
549       // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
550       // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}}
551       A().bar();
552     }
553   }
554   {
555     A a;
556     if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
557       // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}}
558       // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}}
559       // expected-note@-3 {{Taking false branch}}
560       A().bar();
561     }
562   }
563   {
564     A a;
565     if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}} 
566                         //expected-note@-1 {{Left side of '||' is true}}
567                         //expected-note@-2 {{Taking true branch}}
568       A().bar();
569     }
570   }
571   {
572     A a;
573     if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
574       // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}}
575       A().bar();
576     }
577   }
578 }
579
580 // A range-based for sequences the loop variable declaration before the body.
581 void forRangeSequencesTest() {
582   A v[2] = {A(), A()};
583   for (A &a : v) {
584     A b;
585     b = std::move(a); // no-warning
586   }
587 }
588
589 // If a variable is declared in an if statement, the declaration of the variable
590 // (which is treated like a reinitialization by the check) is sequenced before
591 // the evaluation of the condition (which constitutes a use).
592 void ifStmtSequencesDeclAndConditionTest() {
593   for (int i = 0; i < 3; ++i) {
594     if (A a = A()) {
595       A b;
596       b = std::move(a); // no-warning
597     }
598   }
599 }
600
601 void subRegionMoveTest() {
602   {
603     A a;
604     B b = std::move(a.b); // expected-note {{'b' became 'moved-from' here}}
605     a.b.foo();            // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
606   }
607   {
608     A a;
609     A a1 = std::move(a); // expected-note {{Calling move constructor for 'A'}} expected-note {{Returning from move constructor for 'A'}}
610     a.b.foo();           // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
611   }
612   // Don't report a misuse if any SuperRegion is already reported.
613   {
614     A a;
615     A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
616     a.foo();             // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
617     a.b.foo();           // no-warning
618   }
619 }