1 // RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
6 struct remove_reference;
8 template <typename _Tp>
9 struct remove_reference { typedef _Tp type; };
11 template <typename _Tp>
12 struct remove_reference<_Tp &> { typedef _Tp type; };
14 template <typename _Tp>
15 struct remove_reference<_Tp &&> { typedef _Tp type; };
17 template <typename _Tp>
18 typename remove_reference<_Tp>::type &&move(_Tp &&__t) {
19 return static_cast<typename remove_reference<_Tp>::type &&>(__t);
22 template <typename _Tp>
23 _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
24 return static_cast<_Tp &&>(__t);
28 void swap(T &a, T &b) {
39 B(const B &) = default;
41 void operator=(B &&b) {
44 void foo() { return; }
53 A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
54 void moveconstruct(A &&other) {
55 std::swap(b, other.b);
56 std::swap(d, other.d);
57 std::swap(i, other.i);
65 moveconstruct(std::move(*a));
67 A(const A &other) : i(other.i), d(other.d), b(other.b) {}
68 A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // expected-note {{'b' became 'moved-from' here}}
70 A(A &&other, char *k) {
71 moveconstruct(std::move(other));
73 void operator=(A &&other) {
74 moveconstruct(std::move(other));
77 int getI() { return i; }
85 operator bool() const;
90 void moveInsideFunctionCall(A a) {
93 void leftRefCall(A &a) {
96 void rightRefCall(A &&a) {
99 void constCopyOrMoveCall(const A a) {
103 void copyOrMoveCall(A a) {
107 void simpleMoveCtorTest() {
110 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
111 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
114 void simpleMoveAssignementTest() {
117 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
118 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
121 void moveInInitListTest() {
126 S s{std::move(a)}; // expected-note {{'a' became 'moved-from' here}}
127 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
130 // Don't report a bug if the variable was assigned to in the meantime.
131 void reinitializationTest(int i) {
141 if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}}
142 // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}}
147 if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}}
148 //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}}
149 a.foo(); // no-warning
154 if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
157 if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
162 // The built-in assignment operator should also be recognized as a
163 // reinitialization. (std::move() may be called on built-in types in template
169 // A std::move() after the assignment makes the variable invalid again.
175 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
176 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
178 // If a path exist where we not reinitialize the variable we report a bug.
182 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
183 if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}}
186 if (i > 5) { // expected-note {{Taking true branch}}
187 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
192 // Using decltype on an expression is not a use.
193 void decltypeIsNotUseTest() {
195 // A b(std::move(a));
196 decltype(a) other_a; // no-warning
202 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
203 rightRefCall(std::move(a)); // no-warning
208 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
209 //expected-note@-1 {{Loop condition is true. Entering loop body}}
210 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
211 rightRefCall(std::move(a)); // no-warning
216 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
217 leftRefCall(a); // no-warning
222 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
223 //expected-note@-1 {{Loop condition is true. Entering loop body}}
224 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
225 leftRefCall(a); // no-warning
230 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
231 constCopyOrMoveCall(a); // no-warning
236 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
237 //expected-note@-1 {{Loop condition is true. Entering loop body}}
238 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
239 constCopyOrMoveCall(a); // no-warning
244 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
245 moveInsideFunctionCall(a); // no-warning
250 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
251 //expected-note@-1 {{Loop condition is true. Entering loop body}}
252 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
253 moveInsideFunctionCall(a); // no-warning
258 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
259 copyOrMoveCall(a); // no-warning
264 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}}
265 //expected-note@-1 {{Loop condition is true. Entering loop body}}
266 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
267 copyOrMoveCall(a); // no-warning
272 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true. Entering loop body}} expected-note {{Loop condition is true. Entering loop body}}
273 constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
274 // expected-note@-1 {{'a' became 'moved-from' here}}
278 // Don't warn if we return after the move.
281 for (int i = 0; i < 3; ++i) {
285 b = std::move(a); // no-warning
292 //report a usage of a moved-from object only at the first use
293 void uniqueTest(bool cond) {
296 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
298 if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}}
299 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
302 a.bar(); // no-warning
305 a.bar(); // no-warning
310 A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
311 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
313 A a2 = std::move(a); // no-warning
314 a.foo(); // no-warning
317 // There are exceptions where we assume in general that the method works fine
318 //even on moved-from objects.
319 void moveSafeFunctionsTest() {
321 A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
322 a.empty(); // no-warning
323 a.isEmpty(); // no-warning
324 (void)a; // no-warning
325 (bool)a; // expected-warning {{expression result unused}}
326 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
329 void moveStateResetFunctionsTest() {
333 a.reset(); // no-warning
334 a.foo(); // no-warning
339 a.destroy(); // no-warning
340 a.foo(); // no-warning
345 a.clear(); // no-warning
346 a.foo(); // no-warning
350 // Moves or uses that occur as part of template arguments.
352 class ClassTemplate {
358 void functionTemplate(A a);
360 void templateArgIsNotUseTest() {
362 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
365 ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
369 functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
373 // Moves of global variables are not reported.
375 void globalVariablesTest() {
377 global_a.foo(); // no-warning
380 // Moves of member variables.
381 class memberVariablesTest {
387 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
388 a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
390 b = std::move(static_a); // expected-note {{'static_a' became 'moved-from' here}}
391 static_a.foo(); // expected-warning {{Method call on a 'moved-from' object 'static_a'}} expected-note {{Method call on a 'moved-from' object 'static_a'}}
395 void PtrAndArrayTest() {
396 A *Ptr = new A(1, 1.5);
398 Arr[2] = std::move(*Ptr); // expected-note {{Became 'moved-from' here}}
399 (*Ptr).foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
402 Arr[3] = std::move(Arr[1]); // expected-note {{Became 'moved-from' here}}
403 Ptr->foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
405 Arr[3] = std::move(Arr[2]); // expected-note {{Became 'moved-from' here}}
406 Arr[2].foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
408 Arr[2] = std::move(Arr[3]); // reinitialization
409 Arr[2].foo(); // no-warning
412 void exclusiveConditionsTest(bool cond) {
419 a.bar(); // no-warning
423 void differentBranchesTest(int i) {
424 // Don't warn if the use is in a different branch from the move.
427 if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}}
431 a.foo(); // no-warning
434 // Same thing, but with a ternary operator.
437 i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}}
439 // A variation on the theme above.
442 a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}}
444 // Same thing, but with a switch statement.
447 switch (i) { // expected-note {{Control jumps to 'case 1:' at line 448}}
449 b = std::move(a); // no-warning
450 break; // expected-note {{Execution jumps to the end of the function}}
452 a.foo(); // no-warning
456 // However, if there's a fallthrough, we do warn.
459 switch (i) { // expected-note {{Control jumps to 'case 1:' at line 460}}
461 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
463 a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
471 A::get().foo(); // no-warning
472 for (int i = 0; i < bignum(); i++) {
473 A::get().foo(); // no-warning
477 void interFunTest1(A &a) {
478 a.bar(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
481 void interFunTest2() {
484 b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
485 interFunTest1(a); // expected-note {{Calling 'interFunTest1'}}
488 void foobar(A a, int i);
489 void foobar(int i, A a);
491 void paramEvaluateOrderTest() {
493 foobar(std::move(a), a.getI()); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
494 // expected-note@-1 {{'a' became 'moved-from' here}}
496 //FALSE NEGATIVE since parameters evaluate order is undefined
497 foobar(a.getI(), std::move(a)); //no-warning
500 void not_known(A &a);
501 void not_known(A *a);
503 void regionAndPointerEscapeTest() {
509 a.foo(); //no-warning
516 a.foo(); // no-warning
520 // A declaration statement containing multiple declarations sequences the
521 // initializer expressions.
522 void declarationSequenceTest() {
525 A a1 = a, a2 = std::move(a); // no-warning
529 A a1 = std::move(a), a2 = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
530 // expected-note@-1 {{'a' became 'moved-from' here}}
534 // The logical operators && and || sequence their operands.
535 void logicalOperatorsSequenceTest() {
538 if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
539 // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
540 //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}}
544 // A variation: Negate the result of the && (which pushes the && further down
548 if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
549 // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
550 // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}}
556 if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
557 // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}}
558 // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}}
559 // expected-note@-3 {{Taking false branch}}
565 if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}}
566 //expected-note@-1 {{Left side of '||' is true}}
567 //expected-note@-2 {{Taking true branch}}
573 if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
574 // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}}
580 // A range-based for sequences the loop variable declaration before the body.
581 void forRangeSequencesTest() {
585 b = std::move(a); // no-warning
589 // If a variable is declared in an if statement, the declaration of the variable
590 // (which is treated like a reinitialization by the check) is sequenced before
591 // the evaluation of the condition (which constitutes a use).
592 void ifStmtSequencesDeclAndConditionTest() {
593 for (int i = 0; i < 3; ++i) {
596 b = std::move(a); // no-warning
601 void subRegionMoveTest() {
604 B b = std::move(a.b); // expected-note {{'b' became 'moved-from' here}}
605 a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
609 A a1 = std::move(a); // expected-note {{Calling move constructor for 'A'}} expected-note {{Returning from move constructor for 'A'}}
610 a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
612 // Don't report a misuse if any SuperRegion is already reported.
615 A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
616 a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
617 a.b.foo(); // no-warning