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