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