1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %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: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ 5 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 6 // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1 7 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ 8 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 9 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 10 // RUN: -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE 11 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.Move -verify %s\ 12 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 13 // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ 14 // RUN: -analyzer-config alpha.cplusplus.Move:Aggressive=true -DAGGRESSIVE 15 16 namespace std { 17 18 typedef __typeof(sizeof(int)) size_t; 19 20 template <typename> 21 struct remove_reference; 22 23 template <typename _Tp> 24 struct remove_reference { typedef _Tp type; }; 25 26 template <typename _Tp> 27 struct remove_reference<_Tp &> { typedef _Tp type; }; 28 29 template <typename _Tp> 30 struct remove_reference<_Tp &&> { typedef _Tp type; }; 31 32 template <typename _Tp> 33 typename remove_reference<_Tp>::type &&move(_Tp &&__t) { 34 return static_cast<typename remove_reference<_Tp>::type &&>(__t); 35 } 36 37 template <typename _Tp> 38 _Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept { 39 return static_cast<_Tp &&>(__t); 40 } 41 42 template <class T> 43 void swap(T &a, T &b) { 44 T c(std::move(a)); 45 a = std::move(b); 46 b = std::move(c); 47 } 48 49 template <typename T> 50 class vector { 51 public: 52 vector(); 53 void push_back(const T &t); 54 }; 55 56 } // namespace std 57 58 class B { 59 public: 60 B() = default; 61 B(const B &) = default; 62 B(B &&) = default; 63 B& operator=(const B &q) = default; 64 void operator=(B &&b) { 65 return; 66 } 67 void foo() { return; } 68 }; 69 70 class A { 71 int i; 72 double d; 73 74 public: 75 B b; 76 A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {} 77 void moveconstruct(A &&other) { 78 std::swap(b, other.b); 79 std::swap(d, other.d); 80 std::swap(i, other.i); 81 return; 82 } 83 static A get() { 84 A v(12, 13); 85 return v; 86 } 87 A(A *a) { 88 moveconstruct(std::move(*a)); 89 } 90 A(const A &other) : i(other.i), d(other.d), b(other.b) {} 91 A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { 92 #ifdef AGGRESSIVE 93 // expected-note@-2{{Object 'b' is moved}} 94 #endif 95 } 96 A(A &&other, char *k) { 97 moveconstruct(std::move(other)); 98 } 99 void operator=(const A &other) { 100 i = other.i; 101 d = other.d; 102 b = other.b; 103 return; 104 } 105 void operator=(A &&other) { 106 moveconstruct(std::move(other)); 107 return; 108 } 109 int getI() { return i; } 110 int foo() const; 111 void bar() const; 112 void reset(); 113 void destroy(); 114 void clear(); 115 void resize(std::size_t); 116 bool empty() const; 117 bool isEmpty() const; 118 operator bool() const; 119 }; 120 121 int bignum(); 122 123 void moveInsideFunctionCall(A a) { 124 A b = std::move(a); 125 } 126 void leftRefCall(A &a) { 127 a.foo(); 128 } 129 void rightRefCall(A &&a) { 130 a.foo(); 131 } 132 void constCopyOrMoveCall(const A a) { 133 a.foo(); 134 } 135 136 void copyOrMoveCall(A a) { 137 a.foo(); 138 } 139 140 void simpleMoveCtorTest() { 141 { 142 A a; 143 A b = std::move(a); // expected-note {{Object 'a' is moved}} 144 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 145 } 146 { 147 A a; 148 A b = std::move(a); // expected-note {{Object 'a' is moved}} 149 b = a; // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} 150 } 151 { 152 A a; 153 A b = std::move(a); // expected-note {{Object 'a' is moved}} 154 b = std::move(a); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} 155 } 156 } 157 158 void simpleMoveAssignementTest() { 159 { 160 A a; 161 A b; 162 b = std::move(a); // expected-note {{Object 'a' is moved}} 163 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 164 } 165 { 166 A a; 167 A b; 168 b = std::move(a); // expected-note {{Object 'a' is moved}} 169 A c(a); // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} 170 } 171 { 172 A a; 173 A b; 174 b = std::move(a); // expected-note {{Object 'a' is moved}} 175 A c(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} 176 } 177 } 178 179 void moveInInitListTest() { 180 struct S { 181 A a; 182 }; 183 A a; 184 S s{std::move(a)}; // expected-note {{Object 'a' is moved}} 185 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 186 } 187 188 // Don't report a bug if the variable was assigned to in the meantime. 189 void reinitializationTest(int i) { 190 { 191 A a; 192 A b; 193 b = std::move(a); 194 a = A(); 195 a.foo(); 196 } 197 { 198 A a; 199 if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}} 200 // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}} 201 A b; 202 b = std::move(a); 203 a = A(); 204 } 205 if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}} 206 //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}} 207 a.foo(); // no-warning 208 } 209 } 210 { 211 A a; 212 if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} 213 std::move(a); 214 } 215 if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}} 216 a = A(); 217 a.foo(); 218 } 219 } 220 // The built-in assignment operator should also be recognized as a 221 // reinitialization. (std::move() may be called on built-in types in template 222 // code.) 223 { 224 int a1 = 1, a2 = 2; 225 std::swap(a1, a2); 226 } 227 // A std::move() after the assignment makes the variable invalid again. 228 { 229 A a; 230 A b; 231 b = std::move(a); 232 a = A(); 233 b = std::move(a); // expected-note {{Object 'a' is moved}} 234 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 235 } 236 // If a path exist where we not reinitialize the variable we report a bug. 237 { 238 A a; 239 A b; 240 b = std::move(a); // expected-note {{Object 'a' is moved}} 241 if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}} 242 a = A(); 243 } 244 if (i > 5) { // expected-note {{Taking true branch}} 245 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 246 } 247 } 248 } 249 250 // Using decltype on an expression is not a use. 251 void decltypeIsNotUseTest() { 252 A a; 253 // A b(std::move(a)); 254 decltype(a) other_a; // no-warning 255 } 256 257 void loopTest() { 258 { 259 A a; 260 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} 261 rightRefCall(std::move(a)); // no-warning 262 } 263 } 264 { 265 A a; 266 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} 267 //expected-note@-1 {{Loop condition is true. Entering loop body}} 268 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 269 rightRefCall(std::move(a)); // no-warning 270 } 271 } 272 { 273 A a; 274 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} 275 leftRefCall(a); // no-warning 276 } 277 } 278 { 279 A a; 280 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} 281 //expected-note@-1 {{Loop condition is true. Entering loop body}} 282 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 283 leftRefCall(a); // no-warning 284 } 285 } 286 { 287 A a; 288 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} 289 constCopyOrMoveCall(a); // no-warning 290 } 291 } 292 { 293 A a; 294 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} 295 //expected-note@-1 {{Loop condition is true. Entering loop body}} 296 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 297 constCopyOrMoveCall(a); // no-warning 298 } 299 } 300 { 301 A a; 302 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} 303 moveInsideFunctionCall(a); // no-warning 304 } 305 } 306 { 307 A a; 308 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}} 309 //expected-note@-1 {{Loop condition is true. Entering loop body}} 310 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 311 moveInsideFunctionCall(a); // no-warning 312 } 313 } 314 { 315 A a; 316 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}} 317 copyOrMoveCall(a); // no-warning 318 } 319 } 320 { 321 A a; 322 for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}} 323 //expected-note@-1 {{Loop condition is true. Entering loop body}} 324 //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 325 copyOrMoveCall(a); // no-warning 326 } 327 } 328 { 329 A a; 330 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}} 331 constCopyOrMoveCall(std::move(a)); // expected-warning {{Moved-from object 'a' is moved}} expected-note {{Moved-from object 'a' is moved}} 332 // expected-note@-1 {{Object 'a' is moved}} 333 } 334 } 335 336 // Don't warn if we return after the move. 337 { 338 A a; 339 for (int i = 0; i < 3; ++i) { 340 a.bar(); 341 if (a.foo() > 0) { 342 A b; 343 b = std::move(a); // no-warning 344 return; 345 } 346 } 347 } 348 } 349 350 //report a usage of a moved-from object only at the first use 351 void uniqueTest(bool cond) { 352 A a(42, 42.0); 353 A b; 354 b = std::move(a); // expected-note {{Object 'a' is moved}} 355 356 if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}} 357 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 358 } 359 if (cond) { 360 a.bar(); // no-warning 361 } 362 363 a.bar(); // no-warning 364 } 365 366 void uniqueTest2() { 367 A a; 368 A a1 = std::move(a); // expected-note {{Object 'a' is moved}} 369 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 370 371 A a2 = std::move(a); // no-warning 372 a.foo(); // no-warning 373 } 374 375 // There are exceptions where we assume in general that the method works fine 376 //even on moved-from objects. 377 void moveSafeFunctionsTest() { 378 A a; 379 A b = std::move(a); // expected-note {{Object 'a' is moved}} 380 a.empty(); // no-warning 381 a.isEmpty(); // no-warning 382 (void)a; // no-warning 383 (bool)a; // expected-warning {{expression result unused}} 384 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 385 } 386 387 void moveStateResetFunctionsTest() { 388 { 389 A a; 390 A b = std::move(a); 391 a.reset(); // no-warning 392 a.foo(); // no-warning 393 // Test if resets the state of subregions as well. 394 a.b.foo(); // no-warning 395 } 396 { 397 A a; 398 A b = std::move(a); 399 a.destroy(); // no-warning 400 a.foo(); // no-warning 401 } 402 { 403 A a; 404 A b = std::move(a); 405 a.clear(); // no-warning 406 a.foo(); // no-warning 407 a.b.foo(); // no-warning 408 } 409 { 410 A a; 411 A b = std::move(a); 412 a.resize(0); // no-warning 413 a.foo(); // no-warning 414 a.b.foo(); // no-warning 415 } 416 } 417 418 // Moves or uses that occur as part of template arguments. 419 template <int> 420 class ClassTemplate { 421 public: 422 void foo(A a); 423 }; 424 425 template <int> 426 void functionTemplate(A a); 427 428 void templateArgIsNotUseTest() { 429 { 430 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in 431 // Google Test. 432 A a; 433 ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning 434 } 435 { 436 A a; 437 functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning 438 } 439 } 440 441 // Moves of global variables are not reported. 442 A global_a; 443 void globalVariablesTest() { 444 std::move(global_a); 445 global_a.foo(); // no-warning 446 } 447 448 // Moves of member variables. 449 class memberVariablesTest { 450 A a; 451 static A static_a; 452 453 void f() { 454 A b; 455 b = std::move(a); 456 a.foo(); 457 #ifdef AGGRESSIVE 458 // expected-note@-3{{Object 'a' is moved}} 459 // expected-warning@-3 {{Method called on moved-from object 'a'}} 460 // expected-note@-4{{Method called on moved-from object 'a'}} 461 #endif 462 463 b = std::move(static_a); 464 static_a.foo(); 465 #ifdef AGGRESSIVE 466 // expected-note@-3{{Object 'static_a' is moved}} 467 // expected-warning@-3{{Method called on moved-from object 'static_a'}} 468 // expected-note@-4{{Method called on moved-from object 'static_a'}} 469 #endif 470 } 471 }; 472 473 void PtrAndArrayTest() { 474 A *Ptr = new A(1, 1.5); 475 A Arr[10]; 476 Arr[2] = std::move(*Ptr); 477 (*Ptr).foo(); 478 #ifdef AGGRESSIVE 479 // expected-note@-3{{Object is moved}} 480 // expected-warning@-3{{Method called on moved-from object}} 481 // expected-note@-4{{Method called on moved-from object}} 482 #endif 483 484 Ptr = &Arr[1]; 485 Arr[3] = std::move(Arr[1]); 486 Ptr->foo(); 487 #ifdef AGGRESSIVE 488 // expected-note@-3{{Object is moved}} 489 // expected-warning@-3{{Method called on moved-from object}} 490 // expected-note@-4{{Method called on moved-from object}} 491 #endif 492 493 Arr[3] = std::move(Arr[2]); 494 Arr[2].foo(); 495 #ifdef AGGRESSIVE 496 // expected-note@-3{{Object is moved}} 497 // expected-warning@-3{{Method called on moved-from object}} 498 // expected-note@-4{{Method called on moved-from object}} 499 #endif 500 501 Arr[2] = std::move(Arr[3]); // reinitialization 502 Arr[2].foo(); // no-warning 503 } 504 505 void exclusiveConditionsTest(bool cond) { 506 A a; 507 if (cond) { 508 A b; 509 b = std::move(a); 510 } 511 if (!cond) { 512 a.bar(); // no-warning 513 } 514 } 515 516 void differentBranchesTest(int i) { 517 // Don't warn if the use is in a different branch from the move. 518 { 519 A a; 520 if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}} 521 A b; 522 b = std::move(a); 523 } else { 524 a.foo(); // no-warning 525 } 526 } 527 // Same thing, but with a ternary operator. 528 { 529 A a, b; 530 i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}} 531 } 532 // A variation on the theme above. 533 { 534 A a; 535 #ifdef DFS 536 a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}} 537 #else 538 a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is true}} expected-note {{'?' condition is true}} 539 #endif 540 } 541 // Same thing, but with a switch statement. 542 { 543 A a, b; 544 switch (i) { // expected-note {{Control jumps to 'case 1:'}} 545 case 1: 546 b = std::move(a); // no-warning 547 break; // expected-note {{Execution jumps to the end of the function}} 548 case 2: 549 a.foo(); // no-warning 550 break; 551 } 552 } 553 // However, if there's a fallthrough, we do warn. 554 { 555 A a, b; 556 switch (i) { // expected-note {{Control jumps to 'case 1:'}} 557 case 1: 558 b = std::move(a); // expected-note {{Object 'a' is moved}} 559 case 2: 560 a.foo(); // expected-warning {{Method called on moved-from object}} expected-note {{Method called on moved-from object 'a'}} 561 break; 562 } 563 } 564 } 565 566 void tempTest() { 567 A a = A::get(); 568 A::get().foo(); // no-warning 569 for (int i = 0; i < bignum(); i++) { 570 A::get().foo(); // no-warning 571 } 572 } 573 574 void interFunTest1(A &a) { 575 a.bar(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 576 } 577 578 void interFunTest2() { 579 A a; 580 A b; 581 b = std::move(a); // expected-note {{Object 'a' is moved}} 582 interFunTest1(a); // expected-note {{Calling 'interFunTest1'}} 583 } 584 585 void foobar(A a, int i); 586 void foobar(int i, A a); 587 588 void paramEvaluateOrderTest() { 589 A a; 590 foobar(std::move(a), a.getI()); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 591 // expected-note@-1 {{Object 'a' is moved}} 592 593 //FALSE NEGATIVE since parameters evaluate order is undefined 594 foobar(a.getI(), std::move(a)); //no-warning 595 } 596 597 void not_known(A &a); 598 void not_known(A *a); 599 600 void regionAndPointerEscapeTest() { 601 { 602 A a; 603 A b; 604 b = std::move(a); 605 not_known(a); 606 a.foo(); //no-warning 607 } 608 { 609 A a; 610 A b; 611 b = std::move(a); 612 not_known(&a); 613 a.foo(); // no-warning 614 } 615 } 616 617 // A declaration statement containing multiple declarations sequences the 618 // initializer expressions. 619 void declarationSequenceTest() { 620 { 621 A a; 622 A a1 = a, a2 = std::move(a); // no-warning 623 } 624 { 625 A a; 626 A a1 = std::move(a), a2 = a; // expected-warning {{Moved-from object 'a' is copied}} expected-note {{Moved-from object 'a' is copied}} 627 // expected-note@-1 {{Object 'a' is moved}} 628 } 629 } 630 631 // The logical operators && and || sequence their operands. 632 void logicalOperatorsSequenceTest() { 633 { 634 A a; 635 if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} 636 // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} 637 //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}} 638 A().bar(); 639 } 640 } 641 // A variation: Negate the result of the && (which pushes the && further down 642 // into the AST). 643 { 644 A a; 645 if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}} 646 // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}} 647 // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}} 648 A().bar(); 649 } 650 } 651 { 652 A a; 653 if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 654 // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}} 655 // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}} 656 // expected-note@-3 {{Taking false branch}} 657 A().bar(); 658 } 659 } 660 { 661 A a; 662 if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}} 663 //expected-note@-1 {{Left side of '||' is true}} 664 //expected-note@-2 {{Taking true branch}} 665 A().bar(); 666 } 667 } 668 { 669 A a; 670 if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 671 // expected-note@-1 {{Object 'a' is moved}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}} 672 A().bar(); 673 } 674 } 675 } 676 677 // A range-based for sequences the loop variable declaration before the body. 678 void forRangeSequencesTest() { 679 A v[2] = {A(), A()}; 680 for (A &a : v) { 681 A b; 682 b = std::move(a); // no-warning 683 } 684 } 685 686 // If a variable is declared in an if statement, the declaration of the variable 687 // (which is treated like a reinitialization by the check) is sequenced before 688 // the evaluation of the condition (which constitutes a use). 689 void ifStmtSequencesDeclAndConditionTest() { 690 for (int i = 0; i < 3; ++i) { 691 if (A a = A()) { 692 A b; 693 b = std::move(a); // no-warning 694 } 695 } 696 } 697 698 struct C : public A { 699 [[clang::reinitializes]] void reinit(); 700 }; 701 702 void subRegionMoveTest() { 703 { 704 A a; 705 B b = std::move(a.b); 706 a.b.foo(); 707 #ifdef AGGRESSIVE 708 // expected-note@-3{{Object 'b' is moved}} 709 // expected-warning@-3{{Method called on moved-from object 'b'}} 710 // expected-note@-4 {{Method called on moved-from object 'b'}} 711 #endif 712 } 713 { 714 A a; 715 A a1 = std::move(a); 716 a.b.foo(); 717 #ifdef AGGRESSIVE 718 // expected-note@-3{{Calling move constructor for 'A'}} 719 // expected-note@-4{{Returning from move constructor for 'A'}} 720 // expected-warning@-4{{Method called on moved-from object 'b'}} 721 // expected-note@-5{{Method called on moved-from object 'b'}} 722 #endif 723 } 724 // Don't report a misuse if any SuperRegion is already reported. 725 { 726 A a; 727 A a1 = std::move(a); // expected-note {{Object 'a' is moved}} 728 a.foo(); // expected-warning {{Method called on moved-from object 'a'}} expected-note {{Method called on moved-from object 'a'}} 729 a.b.foo(); // no-warning 730 } 731 { 732 C c; 733 C c1 = std::move(c); // expected-note {{Object 'c' is moved}} 734 c.foo(); // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}} 735 c.b.foo(); // no-warning 736 } 737 } 738 739 void resetSuperClass() { 740 C c; 741 C c1 = std::move(c); 742 c.clear(); 743 C c2 = c; // no-warning 744 } 745 746 void resetSuperClass2() { 747 C c; 748 C c1 = std::move(c); 749 c.reinit(); 750 C c2 = c; // no-warning 751 } 752 753 void reportSuperClass() { 754 C c; 755 C c1 = std::move(c); // expected-note {{Object 'c' is moved}} 756 c.foo(); // expected-warning {{Method called on moved-from object 'c'}} expected-note {{Method called on moved-from object 'c'}} 757 C c2 = c; // no-warning 758 } 759 760 struct Empty {}; 761 762 Empty inlinedCall() { 763 // Used to warn because region 'e' failed to be cleaned up because no symbols 764 // have ever died during the analysis and the checkDeadSymbols callback 765 // was skipped entirely. 766 Empty e{}; 767 return e; // no-warning 768 } 769 770 void checkInlinedCallZombies() { 771 while (true) 772 inlinedCall(); 773 } 774 775 void checkLoopZombies() { 776 while (true) { 777 Empty e{}; 778 Empty f = std::move(e); // no-warning 779 } 780 } 781 782 struct MoveOnlyWithDestructor { 783 MoveOnlyWithDestructor(); 784 ~MoveOnlyWithDestructor(); 785 MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete; 786 MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m); 787 }; 788 789 MoveOnlyWithDestructor foo() { 790 MoveOnlyWithDestructor m; 791 return m; 792 } 793 794 class HasSTLField { 795 std::vector<int> V; 796 void foo() { 797 // Warn even in non-aggressive mode when it comes to STL, because 798 // in STL the object is left in "valid but unspecified state" after move. 799 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}} 800 V.push_back(123); // expected-warning{{Method called on moved-from object 'V'}} 801 // expected-note@-1{{Method called on moved-from object 'V'}} 802 } 803 }; 804 805 void localRValueMove(A &&a) { 806 A b = std::move(a); // expected-note{{Object 'a' is moved}} 807 a.foo(); // expected-warning{{Method called on moved-from object 'a'}} 808 // expected-note@-1{{Method called on moved-from object 'a'}} 809 } 810