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