1 // RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 -fno-delayed-template-parsing
2
3 typedef decltype(nullptr) nullptr_t;
4
5 namespace std {
6 typedef unsigned size_t;
7
8 template <typename T>
9 struct unique_ptr {
10 unique_ptr();
11 T *get() const;
12 explicit operator bool() const;
13 void reset(T *ptr);
14 T &operator*() const;
15 T *operator->() const;
16 T& operator[](size_t i) const;
17 };
18
19 template <typename T>
20 struct shared_ptr {
21 shared_ptr();
22 T *get() const;
23 explicit operator bool() const;
24 void reset(T *ptr);
25 T &operator*() const;
26 T *operator->() const;
27 };
28
29 template <typename T>
30 struct weak_ptr {
31 weak_ptr();
32 bool expired() const;
33 };
34
35 #define DECLARE_STANDARD_CONTAINER(name) \
36 template <typename T> \
37 struct name { \
38 name(); \
39 void clear(); \
40 bool empty(); \
41 }
42
43 #define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
44 template <typename T> \
45 struct name { \
46 name(); \
47 void clear(); \
48 bool empty(); \
49 void assign(size_t, const T &); \
50 }
51
52 DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
53 DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
54 DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
55 DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
56 DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
57 DECLARE_STANDARD_CONTAINER(set);
58 DECLARE_STANDARD_CONTAINER(map);
59 DECLARE_STANDARD_CONTAINER(multiset);
60 DECLARE_STANDARD_CONTAINER(multimap);
61 DECLARE_STANDARD_CONTAINER(unordered_set);
62 DECLARE_STANDARD_CONTAINER(unordered_map);
63 DECLARE_STANDARD_CONTAINER(unordered_multiset);
64 DECLARE_STANDARD_CONTAINER(unordered_multimap);
65
66 typedef basic_string<char> string;
67
68 template <typename>
69 struct remove_reference;
70
71 template <typename _Tp>
72 struct remove_reference {
73 typedef _Tp type;
74 };
75
76 template <typename _Tp>
77 struct remove_reference<_Tp &> {
78 typedef _Tp type;
79 };
80
81 template <typename _Tp>
82 struct remove_reference<_Tp &&> {
83 typedef _Tp type;
84 };
85
86 template <typename _Tp>
move(_Tp && __t)87 constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
88 return static_cast<typename remove_reference<_Tp>::type &&>(__t);
89 }
90
91 } // namespace std
92
93 class A {
94 public:
95 A();
96 A(const A &);
97 A(A &&);
98
99 A &operator=(const A &);
100 A &operator=(A &&);
101
102 void foo() const;
103 int getInt() const;
104
105 operator bool() const;
106
107 int i;
108 };
109
110 template <class T>
111 class AnnotatedContainer {
112 public:
113 AnnotatedContainer();
114
115 void foo() const;
116 [[clang::reinitializes]] void clear();
117 };
118
119 ////////////////////////////////////////////////////////////////////////////////
120 // General tests.
121
122 // Simple case.
simple()123 void simple() {
124 A a;
125 a.foo();
126 A other_a = std::move(a);
127 a.foo();
128 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
129 // CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
130 }
131
132 // A warning should only be emitted for one use-after-move.
onlyFlagOneUseAfterMove()133 void onlyFlagOneUseAfterMove() {
134 A a;
135 a.foo();
136 A other_a = std::move(a);
137 a.foo();
138 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
139 // CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
140 a.foo();
141 }
142
moveAfterMove()143 void moveAfterMove() {
144 // Move-after-move also counts as a use.
145 {
146 A a;
147 std::move(a);
148 std::move(a);
149 // CHECK-NOTES: [[@LINE-1]]:15: warning: 'a' used after it was moved
150 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
151 }
152 // This is also true if the move itself turns into the use on the second loop
153 // iteration.
154 {
155 A a;
156 for (int i = 0; i < 10; ++i) {
157 std::move(a);
158 // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
159 // CHECK-NOTES: [[@LINE-2]]:7: note: move occurred here
160 // CHECK-NOTES: [[@LINE-3]]:17: note: the use happens in a later loop
161 }
162 }
163 }
164
165 // Checks also works on function parameters that have a use-after move.
parameters(A a)166 void parameters(A a) {
167 std::move(a);
168 a.foo();
169 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
170 // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
171 }
172
standardSmartPtr()173 void standardSmartPtr() {
174 // std::unique_ptr<>, std::shared_ptr<> and std::weak_ptr<> are guaranteed to
175 // be null after a std::move. So the check only flags accesses that would
176 // dereference the pointer.
177 {
178 std::unique_ptr<A> ptr;
179 std::move(ptr);
180 ptr.get();
181 static_cast<bool>(ptr);
182 *ptr;
183 // CHECK-NOTES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
184 // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
185 }
186 {
187 std::unique_ptr<A> ptr;
188 std::move(ptr);
189 ptr->foo();
190 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
191 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
192 }
193 {
194 std::unique_ptr<A> ptr;
195 std::move(ptr);
196 ptr[0];
197 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
198 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
199 }
200 {
201 std::shared_ptr<A> ptr;
202 std::move(ptr);
203 ptr.get();
204 static_cast<bool>(ptr);
205 *ptr;
206 // CHECK-NOTES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
207 // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
208 }
209 {
210 std::shared_ptr<A> ptr;
211 std::move(ptr);
212 ptr->foo();
213 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
214 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
215 }
216 {
217 // std::weak_ptr<> cannot be dereferenced directly, so we only check that
218 // member functions may be called on it after a move.
219 std::weak_ptr<A> ptr;
220 std::move(ptr);
221 ptr.expired();
222 }
223 // Make sure we recognize std::unique_ptr<> or std::shared_ptr<> if they're
224 // wrapped in a typedef.
225 {
226 typedef std::unique_ptr<A> PtrToA;
227 PtrToA ptr;
228 std::move(ptr);
229 ptr.get();
230 }
231 {
232 typedef std::shared_ptr<A> PtrToA;
233 PtrToA ptr;
234 std::move(ptr);
235 ptr.get();
236 }
237 // And we don't get confused if the template argument is a little more
238 // involved.
239 {
240 struct B {
241 typedef A AnotherNameForA;
242 };
243 std::unique_ptr<B::AnotherNameForA> ptr;
244 std::move(ptr);
245 ptr.get();
246 }
247 // Make sure we treat references to smart pointers correctly.
248 {
249 std::unique_ptr<A> ptr;
250 std::unique_ptr<A>& ref_to_ptr = ptr;
251 std::move(ref_to_ptr);
252 ref_to_ptr.get();
253 }
254 {
255 std::unique_ptr<A> ptr;
256 std::unique_ptr<A>&& rvalue_ref_to_ptr = std::move(ptr);
257 std::move(rvalue_ref_to_ptr);
258 rvalue_ref_to_ptr.get();
259 }
260 // We don't give any special treatment to types that are called "unique_ptr"
261 // or "shared_ptr" but are not in the "::std" namespace.
262 {
263 struct unique_ptr {
264 void get();
265 } ptr;
266 std::move(ptr);
267 ptr.get();
268 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
269 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
270 }
271 }
272
273 // The check also works in member functions.
274 class Container {
useAfterMoveInMemberFunction()275 void useAfterMoveInMemberFunction() {
276 A a;
277 std::move(a);
278 a.foo();
279 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
280 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
281 }
282 };
283
284 // We see the std::move() if it's inside a declaration.
moveInDeclaration()285 void moveInDeclaration() {
286 A a;
287 A another_a(std::move(a));
288 a.foo();
289 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
290 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
291 }
292
293 // We see the std::move if it's inside an initializer list. Initializer lists
294 // are a special case because they cause ASTContext::getParents() to return
295 // multiple parents for certain nodes in their subtree. This is because
296 // RecursiveASTVisitor visits both the syntactic and semantic forms of
297 // InitListExpr, and the parent-child relationships are different between the
298 // two forms.
moveInInitList()299 void moveInInitList() {
300 struct S {
301 A a;
302 };
303 A a;
304 S s{std::move(a)};
305 a.foo();
306 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
307 // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
308 }
309
lambdas()310 void lambdas() {
311 // Use-after-moves inside a lambda should be detected.
312 {
313 A a;
314 auto lambda = [a] {
315 std::move(a);
316 a.foo();
317 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
318 // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
319 };
320 }
321 // This is just as true if the variable was declared inside the lambda.
322 {
323 auto lambda = [] {
324 A a;
325 std::move(a);
326 a.foo();
327 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
328 // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
329 };
330 }
331 // But don't warn if the move happened inside the lambda but the use happened
332 // outside -- because
333 // - the 'a' inside the lambda is a copy, and
334 // - we don't know when the lambda will get called anyway
335 {
336 A a;
337 auto lambda = [a] {
338 std::move(a);
339 };
340 a.foo();
341 }
342 // Warn if the use consists of a capture that happens after a move.
343 {
344 A a;
345 std::move(a);
346 auto lambda = [a]() { a.foo(); };
347 // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
348 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
349 }
350 // ...even if the capture was implicit.
351 {
352 A a;
353 std::move(a);
354 auto lambda = [=]() { a.foo(); };
355 // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
356 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
357 }
358 // Same tests but for capture by reference.
359 {
360 A a;
361 std::move(a);
362 auto lambda = [&a]() { a.foo(); };
363 // CHECK-NOTES: [[@LINE-1]]:21: warning: 'a' used after it was moved
364 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
365 }
366 {
367 A a;
368 std::move(a);
369 auto lambda = [&]() { a.foo(); };
370 // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
371 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
372 }
373 // But don't warn if the move happened after the capture.
374 {
375 A a;
376 auto lambda = [a]() { a.foo(); };
377 std::move(a);
378 }
379 // ...and again, same thing with an implicit move.
380 {
381 A a;
382 auto lambda = [=]() { a.foo(); };
383 std::move(a);
384 }
385 // Same tests but for capture by reference.
386 {
387 A a;
388 auto lambda = [&a]() { a.foo(); };
389 std::move(a);
390 }
391 {
392 A a;
393 auto lambda = [&]() { a.foo(); };
394 std::move(a);
395 }
396 }
397
398 // Use-after-moves are detected in uninstantiated templates if the moved type
399 // is not a dependent type.
400 template <class T>
movedTypeIsNotDependentType()401 void movedTypeIsNotDependentType() {
402 T t;
403 A a;
404 std::move(a);
405 a.foo();
406 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
407 // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
408 }
409
410 // And if the moved type is a dependent type, the use-after-move is detected if
411 // the template is instantiated.
412 template <class T>
movedTypeIsDependentType()413 void movedTypeIsDependentType() {
414 T t;
415 std::move(t);
416 t.foo();
417 // CHECK-NOTES: [[@LINE-1]]:3: warning: 't' used after it was moved
418 // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
419 }
420 template void movedTypeIsDependentType<A>();
421
422 // We handle the case correctly where the move consists of an implicit call
423 // to a conversion operator.
implicitConversionOperator()424 void implicitConversionOperator() {
425 struct Convertible {
426 operator A() && { return A(); }
427 };
428 void takeA(A a);
429
430 Convertible convertible;
431 takeA(std::move(convertible));
432 convertible;
433 // CHECK-NOTES: [[@LINE-1]]:3: warning: 'convertible' used after it was moved
434 // CHECK-NOTES: [[@LINE-3]]:9: note: move occurred here
435 }
436
437 // Using decltype on an expression is not a use.
decltypeIsNotUse()438 void decltypeIsNotUse() {
439 A a;
440 std::move(a);
441 decltype(a) other_a;
442 }
443
444 // Ignore moves or uses that occur as part of template arguments.
445 template <int>
446 class ClassTemplate {
447 public:
448 void foo(A a);
449 };
450 template <int>
451 void functionTemplate(A a);
templateArgIsNotUse()452 void templateArgIsNotUse() {
453 {
454 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
455 // Google Test.
456 A a;
457 ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a));
458 }
459 {
460 A a;
461 functionTemplate<sizeof(A(std::move(a)))>(std::move(a));
462 }
463 }
464
465 // Ignore moves of global variables.
466 A global_a;
ignoreGlobalVariables()467 void ignoreGlobalVariables() {
468 std::move(global_a);
469 global_a.foo();
470 }
471
472 // Ignore moves of member variables.
473 class IgnoreMemberVariables {
474 A a;
475 static A static_a;
476
f()477 void f() {
478 std::move(a);
479 a.foo();
480
481 std::move(static_a);
482 static_a.foo();
483 }
484 };
485
486 ////////////////////////////////////////////////////////////////////////////////
487 // Tests involving control flow.
488
useAndMoveInLoop()489 void useAndMoveInLoop() {
490 // Warn about use-after-moves if they happen in a later loop iteration than
491 // the std::move().
492 {
493 A a;
494 for (int i = 0; i < 10; ++i) {
495 a.foo();
496 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
497 // CHECK-NOTES: [[@LINE+2]]:7: note: move occurred here
498 // CHECK-NOTES: [[@LINE-3]]:7: note: the use happens in a later loop
499 std::move(a);
500 }
501 }
502 // However, this case shouldn't be flagged -- the scope of the declaration of
503 // 'a' is important.
504 {
505 for (int i = 0; i < 10; ++i) {
506 A a;
507 a.foo();
508 std::move(a);
509 }
510 }
511 // Same as above, except that we have an unrelated variable being declared in
512 // the same declaration as 'a'. This case is interesting because it tests that
513 // the synthetic DeclStmts generated by the CFG are sequenced correctly
514 // relative to the other statements.
515 {
516 for (int i = 0; i < 10; ++i) {
517 A a, other;
518 a.foo();
519 std::move(a);
520 }
521 }
522 // Don't warn if we return after the move.
523 {
524 A a;
525 for (int i = 0; i < 10; ++i) {
526 a.foo();
527 if (a.getInt() > 0) {
528 std::move(a);
529 return;
530 }
531 }
532 }
533 }
534
differentBranches(int i)535 void differentBranches(int i) {
536 // Don't warn if the use is in a different branch from the move.
537 {
538 A a;
539 if (i > 0) {
540 std::move(a);
541 } else {
542 a.foo();
543 }
544 }
545 // Same thing, but with a ternary operator.
546 {
547 A a;
548 i > 0 ? (void)std::move(a) : a.foo();
549 }
550 // A variation on the theme above.
551 {
552 A a;
553 a.getInt() > 0 ? a.getInt() : A(std::move(a)).getInt();
554 }
555 // Same thing, but with a switch statement.
556 {
557 A a;
558 switch (i) {
559 case 1:
560 std::move(a);
561 break;
562 case 2:
563 a.foo();
564 break;
565 }
566 }
567 // However, if there's a fallthrough, we do warn.
568 {
569 A a;
570 switch (i) {
571 case 1:
572 std::move(a);
573 case 2:
574 a.foo();
575 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
576 // CHECK-NOTES: [[@LINE-4]]:7: note: move occurred here
577 break;
578 }
579 }
580 }
581
582 // False positive: A use-after-move is flagged even though the "if (b)" and
583 // "if (!b)" are mutually exclusive.
mutuallyExclusiveBranchesFalsePositive(bool b)584 void mutuallyExclusiveBranchesFalsePositive(bool b) {
585 A a;
586 if (b) {
587 std::move(a);
588 }
589 if (!b) {
590 a.foo();
591 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
592 // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
593 }
594 }
595
596 // Destructors marked [[noreturn]] are handled correctly in the control flow
597 // analysis. (These are used in some styles of assertion macros.)
598 class FailureLogger {
599 public:
600 FailureLogger();
601 [[noreturn]] ~FailureLogger();
602 void log(const char *);
603 };
604 #define ASSERT(x) \
605 while (x) \
606 FailureLogger().log(#x)
607 bool operationOnA(A);
noreturnDestructor()608 void noreturnDestructor() {
609 A a;
610 // The while loop in the ASSERT() would ordinarily have the potential to cause
611 // a use-after-move because the second iteration of the loop would be using a
612 // variable that had been moved from in the first iteration. Check that the
613 // CFG knows that the second iteration of the loop is never reached because
614 // the FailureLogger destructor is marked [[noreturn]].
615 ASSERT(operationOnA(std::move(a)));
616 }
617 #undef ASSERT
618
619 ////////////////////////////////////////////////////////////////////////////////
620 // Tests for reinitializations
621
622 template <class T>
swap(T & a,T & b)623 void swap(T &a, T &b) {
624 T tmp = std::move(a);
625 a = std::move(b);
626 b = std::move(tmp);
627 }
assignments(int i)628 void assignments(int i) {
629 // Don't report a use-after-move if the variable was assigned to in the
630 // meantime.
631 {
632 A a;
633 std::move(a);
634 a = A();
635 a.foo();
636 }
637 // The assignment should also be recognized if move, assignment and use don't
638 // all happen in the same block (but the assignment is still guaranteed to
639 // prevent a use-after-move).
640 {
641 A a;
642 if (i == 1) {
643 std::move(a);
644 a = A();
645 }
646 if (i == 2) {
647 a.foo();
648 }
649 }
650 {
651 A a;
652 if (i == 1) {
653 std::move(a);
654 }
655 if (i == 2) {
656 a = A();
657 a.foo();
658 }
659 }
660 // The built-in assignment operator should also be recognized as a
661 // reinitialization. (std::move() may be called on built-in types in template
662 // code.)
663 {
664 int a1 = 1, a2 = 2;
665 swap(a1, a2);
666 }
667 // A std::move() after the assignment makes the variable invalid again.
668 {
669 A a;
670 std::move(a);
671 a = A();
672 std::move(a);
673 a.foo();
674 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
675 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
676 }
677 // Report a use-after-move if we can't be sure that the variable was assigned
678 // to.
679 {
680 A a;
681 std::move(a);
682 if (i < 10) {
683 a = A();
684 }
685 if (i > 5) {
686 a.foo();
687 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
688 // CHECK-NOTES: [[@LINE-7]]:5: note: move occurred here
689 }
690 }
691 }
692
693 // Passing the object to a function through a non-const pointer or reference
694 // counts as a re-initialization.
695 void passByNonConstPointer(A *);
696 void passByNonConstReference(A &);
passByNonConstPointerIsReinit()697 void passByNonConstPointerIsReinit() {
698 {
699 A a;
700 std::move(a);
701 passByNonConstPointer(&a);
702 a.foo();
703 }
704 {
705 A a;
706 std::move(a);
707 passByNonConstReference(a);
708 a.foo();
709 }
710 }
711
712 // Passing the object through a const pointer or reference counts as a use --
713 // since the called function cannot reinitialize the object.
714 void passByConstPointer(const A *);
715 void passByConstReference(const A &);
passByConstPointerIsUse()716 void passByConstPointerIsUse() {
717 {
718 // Declaring 'a' as const so that no ImplicitCastExpr is inserted into the
719 // AST -- we wouldn't want the check to rely solely on that to detect a
720 // const pointer argument.
721 const A a;
722 std::move(a);
723 passByConstPointer(&a);
724 // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
725 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
726 }
727 const A a;
728 std::move(a);
729 passByConstReference(a);
730 // CHECK-NOTES: [[@LINE-1]]:24: warning: 'a' used after it was moved
731 // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
732 }
733
734 // Clearing a standard container using clear() is treated as a
735 // re-initialization.
standardContainerClearIsReinit()736 void standardContainerClearIsReinit() {
737 {
738 std::string container;
739 std::move(container);
740 container.clear();
741 container.empty();
742 }
743 {
744 std::vector<int> container;
745 std::move(container);
746 container.clear();
747 container.empty();
748
749 auto container2 = container;
750 std::move(container2);
751 container2.clear();
752 container2.empty();
753 }
754 {
755 std::deque<int> container;
756 std::move(container);
757 container.clear();
758 container.empty();
759 }
760 {
761 std::forward_list<int> container;
762 std::move(container);
763 container.clear();
764 container.empty();
765 }
766 {
767 std::list<int> container;
768 std::move(container);
769 container.clear();
770 container.empty();
771 }
772 {
773 std::set<int> container;
774 std::move(container);
775 container.clear();
776 container.empty();
777 }
778 {
779 std::map<int> container;
780 std::move(container);
781 container.clear();
782 container.empty();
783 }
784 {
785 std::multiset<int> container;
786 std::move(container);
787 container.clear();
788 container.empty();
789 }
790 {
791 std::multimap<int> container;
792 std::move(container);
793 container.clear();
794 container.empty();
795 }
796 {
797 std::unordered_set<int> container;
798 std::move(container);
799 container.clear();
800 container.empty();
801 }
802 {
803 std::unordered_map<int> container;
804 std::move(container);
805 container.clear();
806 container.empty();
807 }
808 {
809 std::unordered_multiset<int> container;
810 std::move(container);
811 container.clear();
812 container.empty();
813 }
814 {
815 std::unordered_multimap<int> container;
816 std::move(container);
817 container.clear();
818 container.empty();
819 }
820 // This should also work for typedefs of standard containers.
821 {
822 typedef std::vector<int> IntVector;
823 IntVector container;
824 std::move(container);
825 container.clear();
826 container.empty();
827 }
828 // But it shouldn't work for non-standard containers.
829 {
830 // This might be called "vector", but it's not in namespace "std".
831 struct vector {
832 void clear() {}
833 } container;
834 std::move(container);
835 container.clear();
836 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container' used after it was
837 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
838 }
839 // An intervening clear() on a different container does not reinitialize.
840 {
841 std::vector<int> container1, container2;
842 std::move(container1);
843 container2.clear();
844 container1.empty();
845 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container1' used after it was
846 // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
847 }
848 }
849
850 // Clearing a standard container using assign() is treated as a
851 // re-initialization.
standardContainerAssignIsReinit()852 void standardContainerAssignIsReinit() {
853 {
854 std::string container;
855 std::move(container);
856 container.assign(0, ' ');
857 container.empty();
858 }
859 {
860 std::vector<int> container;
861 std::move(container);
862 container.assign(0, 0);
863 container.empty();
864 }
865 {
866 std::deque<int> container;
867 std::move(container);
868 container.assign(0, 0);
869 container.empty();
870 }
871 {
872 std::forward_list<int> container;
873 std::move(container);
874 container.assign(0, 0);
875 container.empty();
876 }
877 {
878 std::list<int> container;
879 std::move(container);
880 container.clear();
881 container.empty();
882 }
883 // But it doesn't work for non-standard containers.
884 {
885 // This might be called "vector", but it's not in namespace "std".
886 struct vector {
887 void assign(std::size_t, int) {}
888 } container;
889 std::move(container);
890 container.assign(0, 0);
891 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container' used after it was
892 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
893 }
894 // An intervening assign() on a different container does not reinitialize.
895 {
896 std::vector<int> container1, container2;
897 std::move(container1);
898 container2.assign(0, 0);
899 container1.empty();
900 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container1' used after it was
901 // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
902 }
903 }
904
905 // Resetting the standard smart pointer types using reset() is treated as a
906 // re-initialization. (We don't test std::weak_ptr<> because it can't be
907 // dereferenced directly.)
standardSmartPointerResetIsReinit()908 void standardSmartPointerResetIsReinit() {
909 {
910 std::unique_ptr<A> ptr;
911 std::move(ptr);
912 ptr.reset(new A);
913 *ptr;
914 }
915 {
916 std::shared_ptr<A> ptr;
917 std::move(ptr);
918 ptr.reset(new A);
919 *ptr;
920 }
921 }
922
reinitAnnotation()923 void reinitAnnotation() {
924 {
925 AnnotatedContainer<int> obj;
926 std::move(obj);
927 obj.foo();
928 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'obj' used after it was
929 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
930 }
931 {
932 AnnotatedContainer<int> obj;
933 std::move(obj);
934 obj.clear();
935 obj.foo();
936 }
937 {
938 // Calling clear() on a different object to the one that was moved is not
939 // considered a reinitialization.
940 AnnotatedContainer<int> obj1, obj2;
941 std::move(obj1);
942 obj2.clear();
943 obj1.foo();
944 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'obj1' used after it was
945 // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
946 }
947 }
948
949 ////////////////////////////////////////////////////////////////////////////////
950 // Tests related to order of evaluation within expressions
951
952 // Relative sequencing of move and use.
953 void passByRvalueReference(int i, A &&a);
954 void passByValue(int i, A a);
955 void passByValue(A a, int i);
956 A g(A, A &&);
957 int intFromA(A &&);
958 int intFromInt(int);
sequencingOfMoveAndUse()959 void sequencingOfMoveAndUse() {
960 // This case is fine because the move only happens inside
961 // passByRvalueReference(). At this point, a.getInt() is guaranteed to have
962 // been evaluated.
963 {
964 A a;
965 passByRvalueReference(a.getInt(), std::move(a));
966 }
967 // However, if we pass by value, the move happens when the move constructor is
968 // called to create a temporary, and this happens before the call to
969 // passByValue(). Because the order in which arguments are evaluated isn't
970 // defined, the move may happen before the call to a.getInt().
971 //
972 // Check that we warn about a potential use-after move for both orderings of
973 // a.getInt() and std::move(a), independent of the order in which the
974 // arguments happen to get evaluated by the compiler.
975 {
976 A a;
977 passByValue(a.getInt(), std::move(a));
978 // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
979 // CHECK-NOTES: [[@LINE-2]]:29: note: move occurred here
980 // CHECK-NOTES: [[@LINE-3]]:17: note: the use and move are unsequenced
981 }
982 {
983 A a;
984 passByValue(std::move(a), a.getInt());
985 // CHECK-NOTES: [[@LINE-1]]:31: warning: 'a' used after it was moved
986 // CHECK-NOTES: [[@LINE-2]]:17: note: move occurred here
987 // CHECK-NOTES: [[@LINE-3]]:31: note: the use and move are unsequenced
988 }
989 // An even more convoluted example.
990 {
991 A a;
992 g(g(a, std::move(a)), g(a, std::move(a)));
993 // CHECK-NOTES: [[@LINE-1]]:9: warning: 'a' used after it was moved
994 // CHECK-NOTES: [[@LINE-2]]:27: note: move occurred here
995 // CHECK-NOTES: [[@LINE-3]]:9: note: the use and move are unsequenced
996 // CHECK-NOTES: [[@LINE-4]]:29: warning: 'a' used after it was moved
997 // CHECK-NOTES: [[@LINE-5]]:7: note: move occurred here
998 // CHECK-NOTES: [[@LINE-6]]:29: note: the use and move are unsequenced
999 }
1000 // This case is fine because the actual move only happens inside the call to
1001 // operator=(). a.getInt(), by necessity, is evaluated before that call.
1002 {
1003 A a;
1004 A vec[1];
1005 vec[a.getInt()] = std::move(a);
1006 }
1007 // However, in the following case, the move happens before the assignment, and
1008 // so the order of evaluation is not guaranteed.
1009 {
1010 A a;
1011 int v[3];
1012 v[a.getInt()] = intFromA(std::move(a));
1013 // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
1014 // CHECK-NOTES: [[@LINE-2]]:21: note: move occurred here
1015 // CHECK-NOTES: [[@LINE-3]]:7: note: the use and move are unsequenced
1016 }
1017 {
1018 A a;
1019 int v[3];
1020 v[intFromA(std::move(a))] = intFromInt(a.i);
1021 // CHECK-NOTES: [[@LINE-1]]:44: warning: 'a' used after it was moved
1022 // CHECK-NOTES: [[@LINE-2]]:7: note: move occurred here
1023 // CHECK-NOTES: [[@LINE-3]]:44: note: the use and move are unsequenced
1024 }
1025 }
1026
1027 // Relative sequencing of move and reinitialization. If the two are unsequenced,
1028 // we conservatively assume that the move happens after the reinitialization,
1029 // i.e. the that object does not get reinitialized after the move.
1030 A MutateA(A a);
1031 void passByValue(A a1, A a2);
sequencingOfMoveAndReinit()1032 void sequencingOfMoveAndReinit() {
1033 // Move and reinitialization as function arguments (which are indeterminately
1034 // sequenced). Again, check that we warn for both orderings.
1035 {
1036 A a;
1037 passByValue(std::move(a), (a = A()));
1038 a.foo();
1039 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
1040 // CHECK-NOTES: [[@LINE-3]]:17: note: move occurred here
1041 }
1042 {
1043 A a;
1044 passByValue((a = A()), std::move(a));
1045 a.foo();
1046 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
1047 // CHECK-NOTES: [[@LINE-3]]:28: note: move occurred here
1048 }
1049 // Common usage pattern: Move the object to a function that mutates it in some
1050 // way, then reassign the result to the object. This pattern is fine.
1051 {
1052 A a;
1053 a = MutateA(std::move(a));
1054 a.foo();
1055 }
1056 }
1057
1058 // Relative sequencing of reinitialization and use. If the two are unsequenced,
1059 // we conservatively assume that the reinitialization happens after the use,
1060 // i.e. that the object is not reinitialized at the point in time when it is
1061 // used.
sequencingOfReinitAndUse()1062 void sequencingOfReinitAndUse() {
1063 // Reinitialization and use in function arguments. Again, check both possible
1064 // orderings.
1065 {
1066 A a;
1067 std::move(a);
1068 passByValue(a.getInt(), (a = A()));
1069 // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
1070 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
1071 }
1072 {
1073 A a;
1074 std::move(a);
1075 passByValue((a = A()), a.getInt());
1076 // CHECK-NOTES: [[@LINE-1]]:28: warning: 'a' used after it was moved
1077 // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
1078 }
1079 }
1080
1081 // The comma operator sequences its operands.
commaOperatorSequences()1082 void commaOperatorSequences() {
1083 {
1084 A a;
1085 A(std::move(a))
1086 , (a = A());
1087 a.foo();
1088 }
1089 {
1090 A a;
1091 (a = A()), A(std::move(a));
1092 a.foo();
1093 // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
1094 // CHECK-NOTES: [[@LINE-3]]:16: note: move occurred here
1095 }
1096 }
1097
1098 // An initializer list sequences its initialization clauses.
initializerListSequences()1099 void initializerListSequences() {
1100 {
1101 struct S1 {
1102 int i;
1103 A a;
1104 };
1105 A a;
1106 S1 s1{a.getInt(), std::move(a)};
1107 }
1108 {
1109 struct S2 {
1110 A a;
1111 int i;
1112 };
1113 A a;
1114 S2 s2{std::move(a), a.getInt()};
1115 // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
1116 // CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here
1117 }
1118 }
1119
1120 // A declaration statement containing multiple declarations sequences the
1121 // initializer expressions.
declarationSequences()1122 void declarationSequences() {
1123 {
1124 A a;
1125 A a1 = a, a2 = std::move(a);
1126 }
1127 {
1128 A a;
1129 A a1 = std::move(a), a2 = a;
1130 // CHECK-NOTES: [[@LINE-1]]:31: warning: 'a' used after it was moved
1131 // CHECK-NOTES: [[@LINE-2]]:12: note: move occurred here
1132 }
1133 }
1134
1135 // The logical operators && and || sequence their operands.
logicalOperatorsSequence()1136 void logicalOperatorsSequence() {
1137 {
1138 A a;
1139 if (a.getInt() > 0 && A(std::move(a)).getInt() > 0) {
1140 A().foo();
1141 }
1142 }
1143 // A variation: Negate the result of the && (which pushes the && further down
1144 // into the AST).
1145 {
1146 A a;
1147 if (!(a.getInt() > 0 && A(std::move(a)).getInt() > 0)) {
1148 A().foo();
1149 }
1150 }
1151 {
1152 A a;
1153 if (A(std::move(a)).getInt() > 0 && a.getInt() > 0) {
1154 // CHECK-NOTES: [[@LINE-1]]:41: warning: 'a' used after it was moved
1155 // CHECK-NOTES: [[@LINE-2]]:9: note: move occurred here
1156 A().foo();
1157 }
1158 }
1159 {
1160 A a;
1161 if (a.getInt() > 0 || A(std::move(a)).getInt() > 0) {
1162 A().foo();
1163 }
1164 }
1165 {
1166 A a;
1167 if (A(std::move(a)).getInt() > 0 || a.getInt() > 0) {
1168 // CHECK-NOTES: [[@LINE-1]]:41: warning: 'a' used after it was moved
1169 // CHECK-NOTES: [[@LINE-2]]:9: note: move occurred here
1170 A().foo();
1171 }
1172 }
1173 }
1174
1175 // A range-based for sequences the loop variable declaration before the body.
forRangeSequences()1176 void forRangeSequences() {
1177 A v[2] = {A(), A()};
1178 for (A &a : v) {
1179 std::move(a);
1180 }
1181 }
1182
1183 // If a variable is declared in an if, while or switch statement, the init
1184 // statement (for if and switch) is sequenced before the variable declaration,
1185 // which in turn is sequenced before the evaluation of the condition. We place
1186 // all tests inside a for loop to ensure that the checker understands the
1187 // sequencing. If it didn't, then the loop would trigger the "moved twice"
1188 // logic.
ifWhileAndSwitchSequenceInitDeclAndCondition()1189 void ifWhileAndSwitchSequenceInitDeclAndCondition() {
1190 for (int i = 0; i < 10; ++i) {
1191 A a1;
1192 if (A a2 = std::move(a1)) {
1193 std::move(a2);
1194 }
1195 }
1196 for (int i = 0; i < 10; ++i) {
1197 A a1;
1198 if (A a2 = std::move(a1); a2) {
1199 std::move(a2);
1200 }
1201 }
1202 for (int i = 0; i < 10; ++i) {
1203 A a1;
1204 if (A a2 = std::move(a1); A a3 = std::move(a2)) {
1205 std::move(a3);
1206 }
1207 }
1208 for (int i = 0; i < 10; ++i) {
1209 // init followed by condition with move, but without variable declaration.
1210 if (A a1; A(std::move(a1)).getInt() > 0) {}
1211 }
1212 for (int i = 0; i < 10; ++i) {
1213 if (A a1; A(std::move(a1)).getInt() > a1.getInt()) {}
1214 // CHECK-NOTES: [[@LINE-1]]:43: warning: 'a1' used after it was moved
1215 // CHECK-NOTES: [[@LINE-2]]:15: note: move occurred here
1216 // CHECK-NOTES: [[@LINE-3]]:43: note: the use and move are unsequenced
1217 }
1218 for (int i = 0; i < 10; ++i) {
1219 A a1;
1220 if (A a2 = std::move(a1); A(a1) > 0) {}
1221 // CHECK-NOTES: [[@LINE-1]]:33: warning: 'a1' used after it was moved
1222 // CHECK-NOTES: [[@LINE-2]]:16: note: move occurred here
1223 }
1224 while (A a = A()) {
1225 std::move(a);
1226 }
1227 for (int i = 0; i < 10; ++i) {
1228 A a1;
1229 switch (A a2 = std::move(a1); a2) {
1230 case true:
1231 std::move(a2);
1232 }
1233 }
1234 for (int i = 0; i < 10; ++i) {
1235 A a1;
1236 switch (A a2 = a1; A a3 = std::move(a2)) {
1237 case true:
1238 std::move(a3);
1239 }
1240 }
1241 }
1242
1243 // Some statements in templates (e.g. null, break and continue statements) may
1244 // be shared between the uninstantiated and instantiated versions of the
1245 // template and therefore have multiple parents. Make sure the sequencing code
1246 // handles this correctly.
nullStatementSequencesInTemplate()1247 template <class> void nullStatementSequencesInTemplate() {
1248 int c = 0;
1249 (void)c;
1250 ;
1251 std::move(c);
1252 }
1253 template void nullStatementSequencesInTemplate<int>();
1254
1255 namespace PR33020 {
1256 class D {
1257 ~D();
1258 };
1259 struct A {
1260 D d;
1261 };
1262 class B {
1263 A a;
1264 };
1265 template <typename T>
1266 class C : T, B {
m_fn1()1267 void m_fn1() {
1268 int a;
1269 std::move(a);
1270 C c;
1271 }
1272 };
1273 } // namespace PR33020
1274
1275 namespace UnevalContext {
1276 struct Foo {};
noExcept()1277 void noExcept() {
1278 Foo Bar;
1279 (void) noexcept(Foo{std::move(Bar)});
1280 Foo Other{std::move(Bar)};
1281 }
sizeOf()1282 void sizeOf() {
1283 Foo Bar;
1284 (void)sizeof(Foo{std::move(Bar)});
1285 Foo Other{std::move(Bar)};
1286 }
alignOf()1287 void alignOf() {
1288 Foo Bar;
1289 #pragma clang diagnostic push
1290 #pragma clang diagnostic ignored "-Wgnu-alignof-expression"
1291 (void)alignof(Foo{std::move(Bar)});
1292 #pragma clang diagnostic pop
1293 Foo Other{std::move(Bar)};
1294 }
typeId()1295 void typeId() {
1296 Foo Bar;
1297 // error: you need to include <typeinfo> before using the 'typeid' operator
1298 // (void) typeid(Foo{std::move(Bar)}).name();
1299 Foo Other{std::move(Bar)};
1300 }
1301 } // namespace UnevalContext
1302