1 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
2 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
3 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
4 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
5 // RUN: -verify=expected,peaceful,non-aggressive
6 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
7 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
8 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\
9 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
10 // RUN: -verify=expected,peaceful,non-aggressive
11 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
12 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
13 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
14 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
15 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
16 // RUN: -verify=expected,non-aggressive
17 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
18 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
19 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\
20 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
21 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
22 // RUN: -verify=expected,non-aggressive
23 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
24 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
25 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\
26 // RUN: -analyzer-config cplusplus.Move:WarnOn=All\
27 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
28 // RUN: -verify=expected,peaceful,aggressive
29 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
30 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
31 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\
32 // RUN: -analyzer-config cplusplus.Move:WarnOn=All\
33 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
34 // RUN: -verify=expected,peaceful,aggressive
36 // RUN: not %clang_analyze_cc1 -verify %s \
37 // RUN: -analyzer-checker=core \
38 // RUN: -analyzer-checker=cplusplus.Move \
39 // RUN: -analyzer-config cplusplus.Move:WarnOn="a bunch of things" \
40 // RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-MOVE-INVALID-VALUE
42 // CHECK-MOVE-INVALID-VALUE: (frontend): invalid input for checker option
43 // CHECK-MOVE-INVALID-VALUE-SAME: 'cplusplus.Move:WarnOn', that expects either
44 // CHECK-MOVE-INVALID-VALUE-SAME: "KnownsOnly", "KnownsAndLocals" or "All"
45 // CHECK-MOVE-INVALID-VALUE-SAME: string value
47 // Tests checker-messages printing.
48 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
49 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
50 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\
51 // RUN: -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
52 // RUN: -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
53 // RUN: -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
55 #include "Inputs/system-header-simulator-cxx.h"
57 void clang_analyzer_warnIfReached();
58 void clang_analyzer_printState();
63 B(const B
&) = default;
65 B
& operator=(const B
&q
) = default;
66 void operator=(B
&&b
) {
69 void foo() { return; }
78 A(int ii
= 42, double dd
= 1.0) : d(dd
), i(ii
), b(B()) {}
79 void moveconstruct(A
&&other
) {
80 std::swap(b
, other
.b
);
81 std::swap(d
, other
.d
);
82 std::swap(i
, other
.i
);
90 moveconstruct(std::move(*a
));
92 A(const A
&other
) : i(other
.i
), d(other
.d
), b(other
.b
) {}
93 A(A
&&other
) : i(other
.i
), d(other
.d
), b(std::move(other
.b
)) { // aggressive-note{{Object 'b' is moved}}
95 A(A
&&other
, char *k
) {
96 moveconstruct(std::move(other
));
98 void operator=(const A
&other
) {
104 void operator=(A
&&other
) {
105 moveconstruct(std::move(other
));
108 int getI() { return i
; }
114 void resize(std::size_t);
115 void assign(const A
&);
117 bool isEmpty() const;
118 operator bool() const;
120 void testUpdateField() {
124 a
.foo(); // no-warning
126 void testUpdateFieldDouble() {
130 a
.foo(); // no-warning
136 void moveInsideFunctionCall(A a
) {
139 void leftRefCall(A
&a
) {
142 void rightRefCall(A
&&a
) {
145 void constCopyOrMoveCall(const A a
) {
149 void copyOrMoveCall(A a
) {
153 void simpleMoveCtorTest() {
156 A b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
158 #ifdef AGGRESSIVE_DFS
159 clang_analyzer_printState();
161 // CHECK: "checker_messages": [
162 // CHECK-NEXT: { "checker": "cplusplus.Move", "messages": [
163 // CHECK-NEXT: "Moved-from objects :",
164 // CHECK: "a: moved",
170 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
171 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
175 A b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
176 b
= a
; // peaceful-warning {{Moved-from object 'a' is copied}}
177 // peaceful-note@-1 {{Moved-from object 'a' is copied}}
181 A b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
182 b
= std::move(a
); // peaceful-warning {{Moved-from object 'a' is moved}}
183 // peaceful-note@-1 {{Moved-from object 'a' is moved}}
187 void simpleMoveAssignementTest() {
191 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
192 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
193 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
198 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
199 A
c(a
); // peaceful-warning {{Moved-from object 'a' is copied}}
200 // peaceful-note@-1 {{Moved-from object 'a' is copied}}
205 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
206 A
c(std::move(a
)); // peaceful-warning {{Moved-from object 'a' is moved}}
207 // peaceful-note@-1 {{Moved-from object 'a' is moved}}
211 void moveInInitListTest() {
216 S s
{std::move(a
)}; // peaceful-note {{Object 'a' is moved}}
217 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
218 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
221 // Don't report a bug if the variable was assigned to in the meantime.
222 void reinitializationTest(int i
) {
232 if (i
== 1) { // peaceful-note 2 {{Assuming 'i' is not equal to 1}}
233 // peaceful-note@-1 2 {{Taking false branch}}
238 if (i
== 2) { // peaceful-note 2 {{Assuming 'i' is not equal to 2}}
239 // peaceful-note@-1 2 {{Taking false branch}}
240 a
.foo(); // no-warning
245 if (i
== 1) { // peaceful-note 2 {{'i' is not equal to 1}}
246 // peaceful-note@-1 2 {{Taking false branch}}
249 if (i
== 2) { // peaceful-note 2 {{'i' is not equal to 2}}
250 // peaceful-note@-1 2 {{Taking false branch}}
255 // The built-in assignment operator should also be recognized as a
256 // reinitialization. (std::move() may be called on built-in types in template
262 // A std::move() after the assignment makes the variable invalid again.
268 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
269 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
270 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
272 // If a path exist where we not reinitialize the variable we report a bug.
276 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
277 if (i
< 10) { // peaceful-note {{Assuming 'i' is >= 10}}
278 // peaceful-note@-1 {{Taking false branch}}
281 if (i
> 5) { // peaceful-note {{'i' is > 5}}
282 // peaceful-note@-1 {{Taking true branch}}
283 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
284 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
289 // Using decltype on an expression is not a use.
290 void decltypeIsNotUseTest() {
292 // A b(std::move(a));
293 decltype(a
) other_a
; // no-warning
299 // FIXME: Execution doesn't jump to the end of the function yet.
300 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
301 rightRefCall(std::move(a
)); // no-warning
306 for (int i
= 0; i
< 2; i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
307 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
308 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
309 rightRefCall(std::move(a
)); // no-warning
314 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
315 leftRefCall(a
); // no-warning
320 for (int i
= 0; i
< 2; i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
321 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
322 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
323 leftRefCall(a
); // no-warning
328 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
329 constCopyOrMoveCall(a
); // no-warning
334 for (int i
= 0; i
< 2; i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
335 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
336 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
337 constCopyOrMoveCall(a
); // no-warning
342 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
343 moveInsideFunctionCall(a
); // no-warning
348 for (int i
= 0; i
< 2; i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
349 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
350 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
351 moveInsideFunctionCall(a
); // no-warning
356 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}}
357 copyOrMoveCall(a
); // no-warning
362 for (int i
= 0; i
< 2; i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
363 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
364 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
365 copyOrMoveCall(a
); // no-warning
370 for (int i
= 0; i
< bignum(); i
++) { // peaceful-note {{Loop condition is true. Entering loop body}}
371 // peaceful-note@-1 {{Loop condition is true. Entering loop body}}
372 constCopyOrMoveCall(std::move(a
)); // peaceful-note {{Object 'a' is moved}}
373 // peaceful-warning@-1 {{Moved-from object 'a' is moved}}
374 // peaceful-note@-2 {{Moved-from object 'a' is moved}}
378 // Don't warn if we return after the move.
381 for (int i
= 0; i
< 3; ++i
) {
385 b
= std::move(a
); // no-warning
392 // Report a usage of a moved-from object only at the first use.
393 void uniqueTest(bool cond
) {
396 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
398 if (cond
) { // peaceful-note {{Assuming 'cond' is true}}
399 // peaceful-note@-1 {{Taking true branch}}
400 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
401 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
404 a
.bar(); // no-warning
407 a
.bar(); // no-warning
412 A a1
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
413 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
414 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
416 A a2
= std::move(a
); // no-warning
417 a
.foo(); // no-warning
420 // There are exceptions where we assume in general that the method works fine
421 //even on moved-from objects.
422 void moveSafeFunctionsTest() {
424 A b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
425 a
.empty(); // no-warning
426 a
.isEmpty(); // no-warning
427 (void)a
; // no-warning
428 (bool)a
; // expected-warning {{expression result unused}}
429 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
430 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
433 void moveStateResetFunctionsTest() {
437 a
.reset(); // no-warning
438 a
.foo(); // no-warning
439 // Test if resets the state of subregions as well.
440 a
.b
.foo(); // no-warning
445 a
.destroy(); // no-warning
446 a
.foo(); // no-warning
451 a
.clear(); // no-warning
452 a
.foo(); // no-warning
453 a
.b
.foo(); // no-warning
458 a
.resize(0); // no-warning
459 a
.foo(); // no-warning
460 a
.b
.foo(); // no-warning
465 a
.assign(A()); // no-warning
466 a
.foo(); // no-warning
467 a
.b
.foo(); // no-warning
471 // Moves or uses that occur as part of template arguments.
473 class ClassTemplate
{
479 void functionTemplate(A a
);
481 void templateArgIsNotUseTest() {
483 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
486 ClassTemplate
<sizeof(A(std::move(a
)))>().foo(std::move(a
)); // no-warning
490 functionTemplate
<sizeof(A(std::move(a
)))>(std::move(a
)); // no-warning
494 // Moves of global variables are not reported.
496 void globalVariablesTest() {
497 (void)std::move(global_a
);
498 global_a
.foo(); // no-warning
501 // Moves of member variables.
502 class memberVariablesTest
{
508 b
= std::move(a
); // aggressive-note {{Object 'a' is moved}}
510 a
.foo(); // aggressive-warning {{Method called on moved-from object 'a'}}
511 // aggressive-note@-1 {{Method called on moved-from object 'a'}}
513 b
= std::move(static_a
); // aggressive-note {{Object 'static_a' is moved}}
514 static_a
.foo(); // aggressive-warning {{Method called on moved-from object 'static_a'}}
515 // aggressive-note@-1 {{Method called on moved-from object 'static_a'}}
519 void PtrAndArrayTest() {
520 A
*Ptr
= new A(1, 1.5);
522 Arr
[2] = std::move(*Ptr
); // aggressive-note{{Object is moved}}
523 (*Ptr
).foo(); // aggressive-warning{{Method called on moved-from object}}
524 // aggressive-note@-1{{Method called on moved-from object}}
527 Arr
[3] = std::move(Arr
[1]); // aggressive-note {{Object is moved}}
528 Ptr
->foo(); // aggressive-warning {{Method called on moved-from object}}
529 // aggressive-note@-1 {{Method called on moved-from object}}
531 Arr
[3] = std::move(Arr
[2]); // aggressive-note{{Object is moved}}
532 Arr
[2].foo(); // aggressive-warning{{Method called on moved-from object}}
533 // aggressive-note@-1{{Method called on moved-from object}}
535 Arr
[2] = std::move(Arr
[3]); // reinitialization
536 Arr
[2].foo(); // no-warning
539 void exclusiveConditionsTest(bool cond
) {
546 a
.bar(); // no-warning
550 void differentBranchesTest(int i
) {
551 // Don't warn if the use is in a different branch from the move.
554 if (i
> 0) { // peaceful-note {{Assuming 'i' is > 0}}
555 // peaceful-note@-1 {{Taking true branch}}
559 a
.foo(); // no-warning
562 // Same thing, but with a ternary operator.
565 i
> 0 ? (void)(b
= std::move(a
)) : a
.bar(); // no-warning
566 // peaceful-note@-1 {{'i' is > 0}}
567 // peaceful-note@-2 {{'?' condition is true}}
569 // A variation on the theme above.
572 a
.foo() > 0 ? a
.foo() : A(std::move(a
)).foo();
574 // peaceful-note@-2 {{Assuming the condition is false}}
575 // peaceful-note@-3 {{'?' condition is false}}
577 // peaceful-note@-5 {{Assuming the condition is true}}
578 // peaceful-note@-6 {{'?' condition is true}}
581 // Same thing, but with a switch statement.
584 switch (i
) { // peaceful-note {{Control jumps to 'case 1:'}}
586 b
= std::move(a
); // no-warning
587 // FIXME: Execution doesn't jump to the end of the function yet.
588 break; // peaceful-note {{Execution jumps to the end of the function}}
590 a
.foo(); // no-warning
594 // However, if there's a fallthrough, we do warn.
597 switch (i
) { // peaceful-note {{Control jumps to 'case 1:'}}
599 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
601 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
602 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
610 A::get().foo(); // no-warning
611 for (int i
= 0; i
< bignum(); i
++) {
612 A::get().foo(); // no-warning
616 void lifeTimeExtendTest() {
618 A b
= std::move(a
); // peaceful-note {{Object is moved}}
620 a
.foo(); // peaceful-warning {{Method called on moved-from object}}
621 // peaceful-note@-1 {{Method called on moved-from object}}
624 void interFunTest1(A
&a
) {
625 a
.bar(); // peaceful-warning {{Method called on moved-from object 'a'}}
626 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
629 void interFunTest2() {
632 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
633 interFunTest1(a
); // peaceful-note {{Calling 'interFunTest1'}}
636 void foobar(A a
, int i
);
637 void foobar(int i
, A a
);
639 void paramEvaluateOrderTest() {
641 foobar(std::move(a
), a
.getI()); // peaceful-note {{Object 'a' is moved}}
642 // peaceful-warning@-1 {{Method called on moved-from object 'a'}}
643 // peaceful-note@-2 {{Method called on moved-from object 'a'}}
645 //FALSE NEGATIVE since parameters evaluate order is undefined
646 foobar(a
.getI(), std::move(a
)); //no-warning
649 void not_known_pass_by_ref(A
&a
);
650 void not_known_pass_by_const_ref(const A
&a
);
651 void not_known_pass_by_rvalue_ref(A
&&a
);
652 void not_known_pass_by_ptr(A
*a
);
653 void not_known_pass_by_const_ptr(const A
*a
);
655 void regionAndPointerEscapeTest() {
660 not_known_pass_by_ref(a
);
661 a
.foo(); // no-warning
666 b
= std::move(a
); // peaceful-note{{Object 'a' is moved}}
667 not_known_pass_by_const_ref(a
);
668 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
669 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
675 not_known_pass_by_rvalue_ref(std::move(a
));
676 a
.foo(); // no-warning
682 not_known_pass_by_ptr(&a
);
683 a
.foo(); // no-warning
688 b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
689 not_known_pass_by_const_ptr(&a
);
690 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
691 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
695 // A declaration statement containing multiple declarations sequences the
696 // initializer expressions.
697 void declarationSequenceTest() {
700 A a1
= a
, a2
= std::move(a
); // no-warning
704 A a1
= std::move(a
), a2
= a
; // peaceful-note {{Object 'a' is moved}}
705 // peaceful-warning@-1 {{Moved-from object 'a' is copied}}
706 // peaceful-note@-2 {{Moved-from object 'a' is copied}}
710 // The logical operators && and || sequence their operands.
711 void logicalOperatorsSequenceTest() {
714 if (a
.foo() > 0 && A(std::move(a
)).foo() > 0) { // peaceful-note {{Assuming the condition is false}}
715 // peaceful-note@-1 {{Left side of '&&' is false}}
716 // peaceful-note@-2 {{Taking false branch}}
717 // And the other report:
718 // peaceful-note@-4 {{Assuming the condition is false}}
719 // peaceful-note@-5 {{Left side of '&&' is false}}
720 // peaceful-note@-6 {{Taking false branch}}
724 // A variation: Negate the result of the && (which pushes the && further down
728 if (!(a
.foo() > 0 && A(std::move(a
)).foo() > 0)) { // peaceful-note {{Assuming the condition is false}}
729 // peaceful-note@-1 {{Left side of '&&' is false}}
730 // peaceful-note@-2 {{Taking true branch}}
731 // And the other report:
732 // peaceful-note@-4 {{Assuming the condition is false}}
733 // peaceful-note@-5 {{Left side of '&&' is false}}
734 // peaceful-note@-6 {{Taking true branch}}
740 if (A(std::move(a
)).foo() > 0 && a
.foo() > 0) { // peaceful-note {{Object 'a' is moved}}
741 // peaceful-note@-1 {{Assuming the condition is true}}
742 // peaceful-note@-2 {{Left side of '&&' is true}}
743 // peaceful-warning@-3 {{Method called on moved-from object 'a'}}
744 // peaceful-note@-4 {{Method called on moved-from object 'a'}}
745 // And the other report:
746 // peaceful-note@-6 {{Assuming the condition is false}}
747 // peaceful-note@-7 {{Left side of '&&' is false}}
748 // peaceful-note@-8 {{Taking false branch}}
754 if (a
.foo() > 0 || A(std::move(a
)).foo() > 0) { // peaceful-note {{Assuming the condition is true}}
755 // peaceful-note@-1 {{Left side of '||' is true}}
756 // peaceful-note@-2 {{Taking true branch}}
762 if (A(std::move(a
)).foo() > 0 || a
.foo() > 0) { // peaceful-note {{Object 'a' is moved}}
763 // peaceful-note@-1 {{Assuming the condition is false}}
764 // peaceful-note@-2 {{Left side of '||' is false}}
765 // peaceful-warning@-3 {{Method called on moved-from object 'a'}}
766 // peaceful-note@-4 {{Method called on moved-from object 'a'}}
772 // A range-based for sequences the loop variable declaration before the body.
773 void forRangeSequencesTest() {
777 b
= std::move(a
); // no-warning
781 // If a variable is declared in an if statement, the declaration of the variable
782 // (which is treated like a reinitialization by the check) is sequenced before
783 // the evaluation of the condition (which constitutes a use).
784 void ifStmtSequencesDeclAndConditionTest() {
785 for (int i
= 0; i
< 3; ++i
) {
788 b
= std::move(a
); // no-warning
793 struct C
: public A
{
794 [[clang::reinitializes
]] void reinit();
797 void subRegionMoveTest() {
800 B b
= std::move(a
.b
); // aggressive-note {{Object 'b' is moved}}
801 a
.b
.foo(); // aggressive-warning {{Method called on moved-from object 'b'}}
802 // aggressive-note@-1 {{Method called on moved-from object 'b'}}
806 A a1
= std::move(a
); // aggressive-note {{Calling move constructor for 'A'}}
807 // aggressive-note@-1 {{Returning from move constructor for 'A'}}
808 a
.b
.foo(); // aggressive-warning{{Method called on moved-from object 'b'}}
809 // aggressive-note@-1{{Method called on moved-from object 'b'}}
811 // Don't report a misuse if any SuperRegion is already reported.
814 A a1
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
815 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
816 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
817 a
.b
.foo(); // no-warning
821 C c1
= std::move(c
); // peaceful-note {{Object 'c' is moved}}
822 c
.foo(); // peaceful-warning {{Method called on moved-from object 'c'}}
823 // peaceful-note@-1 {{Method called on moved-from object 'c'}}
824 c
.b
.foo(); // no-warning
828 void resetSuperClass() {
832 C c2
= c
; // no-warning
835 void resetSuperClass2() {
839 C c2
= c
; // no-warning
842 void reportSuperClass() {
844 C c1
= std::move(c
); // peaceful-note {{Object 'c' is moved}}
845 c
.foo(); // peaceful-warning {{Method called on moved-from object 'c'}}
846 // peaceful-note@-1 {{Method called on moved-from object 'c'}}
847 C c2
= c
; // no-warning
852 Empty
inlinedCall() {
853 // Used to warn because region 'e' failed to be cleaned up because no symbols
854 // have ever died during the analysis and the checkDeadSymbols callback
855 // was skipped entirely.
857 return e
; // no-warning
860 void checkInlinedCallZombies() {
865 void checkLoopZombies() {
868 Empty f
= std::move(e
); // no-warning
872 void checkMoreLoopZombies1(bool flag
) {
876 e
; // expected-warning {{expression result unused}}
877 Empty f
= std::move(e
); // no-warning
883 void checkMoreLoopZombies2(bool flag
) {
887 e
; // expected-warning {{expression result unused}}
888 Empty f
= std::move(e
); // no-warning
892 void checkMoreLoopZombies3(bool flag
) {
896 e
; // expected-warning {{expression result unused}}
898 Empty f
= std::move(e
); // no-warning
902 void checkMoreLoopZombies4(bool flag
) {
906 e
; // expected-warning {{expression result unused}}
907 Empty f
= std::move(e
); // no-warning
911 void checkExplicitDestructorCalls() {
912 // The below code segments invoke the destructor twice (explicit and
913 // implicit). While this is not a desired code behavior, it is
914 // not the use-after-move checker's responsibility to issue such a warning.
918 b
->~B(); // no-warning
923 new (&a
) B(reinterpret_cast<B
&&>(b
));
924 (&b
)->~B(); // no-warning
929 b
.~B(); // no-warning
933 struct MoveOnlyWithDestructor
{
934 MoveOnlyWithDestructor();
935 ~MoveOnlyWithDestructor();
936 MoveOnlyWithDestructor(const MoveOnlyWithDestructor
&m
) = delete;
937 MoveOnlyWithDestructor(MoveOnlyWithDestructor
&&m
);
940 MoveOnlyWithDestructor
foo() {
941 MoveOnlyWithDestructor m
;
948 // Warn even in non-aggressive mode when it comes to STL, because
949 // in STL the object is left in "valid but unspecified state" after move.
950 std::vector
<int> W
= std::move(V
); // expected-note {{Object 'V' of type 'std::vector' is left in a valid but unspecified state after move}}
951 V
.push_back(123); // expected-warning {{Method called on moved-from object 'V'}}
952 // expected-note@-1 {{Method called on moved-from object 'V'}}
955 std::unique_ptr
<int> P
;
956 void testUniquePtr() {
957 // unique_ptr remains in a well-defined state after move.
958 std::unique_ptr
<int> Q
= std::move(P
); // aggressive-note {{Object 'P' is moved}}
959 // non-aggressive-note@-1 {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
960 P
.get(); // aggressive-warning{{Method called on moved-from object 'P'}}
961 // aggressive-note@-1{{Method called on moved-from object 'P'}}
963 // Because that well-defined state is null, dereference is still UB.
964 // Note that in aggressive mode we already warned about 'P',
965 // so no extra warning is generated.
966 *P
+= 1; // non-aggressive-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
967 // non-aggressive-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
969 // The program should have crashed by now.
970 clang_analyzer_warnIfReached(); // no-warning
974 void localRValueMove(A
&&a
) {
975 A b
= std::move(a
); // peaceful-note {{Object 'a' is moved}}
976 a
.foo(); // peaceful-warning {{Method called on moved-from object 'a'}}
977 // peaceful-note@-1 {{Method called on moved-from object 'a'}}
980 void localUniquePtr(std::unique_ptr
<int> P
) {
981 // Even though unique_ptr is safe to use after move,
982 // reusing a local variable this way usually indicates a bug.
983 std::unique_ptr
<int> Q
= std::move(P
); // peaceful-note {{Object 'P' is moved}}
984 P
.get(); // peaceful-warning {{Method called on moved-from object 'P'}}
985 // peaceful-note@-1 {{Method called on moved-from object 'P'}}
988 void localUniquePtrWithArrow(std::unique_ptr
<A
> P
) {
989 std::unique_ptr
<A
> Q
= std::move(P
); // expected-note{{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
990 P
->foo(); // expected-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
991 // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
994 void getAfterMove(std::unique_ptr
<A
> P
) {
995 std::unique_ptr
<A
> Q
= std::move(P
); // peaceful-note {{Object 'P' is moved}}
997 // TODO: Explain why (bool)P is false.
998 if (P
) // peaceful-note{{Taking false branch}}
999 clang_analyzer_warnIfReached(); // no-warning
1001 A
*a
= P
.get(); // peaceful-warning {{Method called on moved-from object 'P'}}
1002 // peaceful-note@-1 {{Method called on moved-from object 'P'}}
1004 // TODO: Warn on a null dereference here.
1008 struct OtherMoveSafeClasses
{
1009 std::packaged_task
<int(void)> Task
;
1012 // Test the suppression caused by use-after-move semantics of
1013 // std::package_task being different from other standard classes.
1014 // Only warn in aggressive mode. Don't say that the object
1015 // is left in unspecified state after move.
1016 std::packaged_task
<int(void)> Task2
= std::move(Task
);
1017 // aggressive-note@-1 {{Object 'Task' is moved}}
1018 std::packaged_task
<int(void)> Task3
= std::move(Task
);
1019 // aggressive-warning@-1{{Moved-from object 'Task' is moved}}
1020 // aggressive-note@-2 {{Moved-from object 'Task' is moved}}