1 // RUN: %clang_analyze_cc1 -analyzer-checker=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: -analyzer-checker debug.ExprInspection 5 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 6 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 7 // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ 8 // RUN: -analyzer-checker debug.ExprInspection 9 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 10 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 11 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 12 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly -DPEACEFUL\ 13 // RUN: -analyzer-checker debug.ExprInspection 14 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 15 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 16 // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ 17 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly -DPEACEFUL\ 18 // RUN: -analyzer-checker debug.ExprInspection 19 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 20 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 21 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 22 // RUN: -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE\ 23 // RUN: -analyzer-checker debug.ExprInspection 24 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 25 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 26 // RUN: -analyzer-config exploration_strategy=dfs -DDFS=1\ 27 // RUN: -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE\ 28 // RUN: -analyzer-checker debug.ExprInspection 29 30 #include "Inputs/system-header-simulator-cxx.h" 31 32 void clang_analyzer_warnIfReached(); 33 34 class B { 35 public: 36 B() = default; 37 B(const B &) = default; 38 B(B &&) = default; 39 B& operator=(const B &q) = default; 40 void operator=(B &&b) { 41 return; 42 } 43 void foo() { return; } 44 }; 45 46 class A { 47 int i; 48 double d; 49 50 public: 51 B b; 52 A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {} 53 void moveconstruct(A &&other) { 54 std::swap(b, other.b); 55 std::swap(d, other.d); 56 std::swap(i, other.i); 57 return; 58 } 59 static A get() { 60 A v(12, 13); 61 return v; 62 } 63 A(A *a) { 64 moveconstruct(std::move(*a)); 65 } 66 A(const A &other) : i(other.i), d(other.d), b(other.b) {} 67 A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { 68 #ifdef AGGRESSIVE 69 // expected-note@-2{{Object 'b' is moved}} 70 #endif 71 } 72 A(A &&other, char *k) { 73 moveconstruct(std::move(other)); 74 } 75 void operator=(const A &other) { 76 i = other.i; 77 d = other.d; 78 b = other.b; 79 return; 80 } 81 void operator=(A &&other) { 82 moveconstruct(std::move(other)); 83 return; 84 } 85 int getI() { return i; } 86 int foo() const; 87 void bar() const; 88 void reset(); 89 void destroy(); 90 void clear(); 91 void resize(std::size_t); 92 bool empty() const; 93 bool isEmpty() const; 94 operator bool() const; 95 96 void testUpdateField() { 97 A a; 98 A b = std::move(a); 99 a.i = 1; 100 a.foo(); // no-warning 101 } 102 void testUpdateFieldDouble() { 103 A a; 104 A b = std::move(a); 105 a.d = 1.0; 106 a.foo(); // no-warning 107 } 108 }; 109 110 int bignum(); 111 112 void moveInsideFunctionCall(A a) { 113 A b = std::move(a); 114 } 115 void leftRefCall(A &a) { 116 a.foo(); 117 } 118 void rightRefCall(A &&a) { 119 a.foo(); 120 } 121 void constCopyOrMoveCall(const A a) { 122 a.foo(); 123 } 124 125 void copyOrMoveCall(A a) { 126 a.foo(); 127 } 128 129 void simpleMoveCtorTest() { 130 { 131 A a; 132 A b = std::move(a); 133 a.foo(); 134 #ifndef PEACEFUL 135 // expected-note@-3 {{Object 'a' is moved}} 136 // expected-warning@-3 {{Method called on moved-from object 'a'}} 137 // expected-note@-4 {{Method called on moved-from object 'a'}} 138 #endif 139 } 140 { 141 A a; 142 A b = std::move(a); 143 b = a; 144 #ifndef PEACEFUL 145 // expected-note@-3 {{Object 'a' is moved}} 146 // expected-warning@-3 {{Moved-from object 'a' is copied}} 147 // expected-note@-4 {{Moved-from object 'a' is copied}} 148 #endif 149 } 150 { 151 A a; 152 A b = std::move(a); 153 b = std::move(a); 154 #ifndef PEACEFUL 155 // expected-note@-3 {{Object 'a' is moved}} 156 // expected-warning@-3 {{Moved-from object 'a' is moved}} 157 // expected-note@-4 {{Moved-from object 'a' is moved}} 158 #endif 159 } 160 } 161 162 void simpleMoveAssignementTest() { 163 { 164 A a; 165 A b; 166 b = std::move(a); 167 a.foo(); 168 #ifndef PEACEFUL 169 // expected-note@-3 {{Object 'a' is moved}} 170 // expected-warning@-3 {{Method called on moved-from object 'a'}} 171 // expected-note@-4 {{Method called on moved-from object 'a'}} 172 #endif 173 } 174 { 175 A a; 176 A b; 177 b = std::move(a); 178 A c(a); 179 #ifndef PEACEFUL 180 // expected-note@-3 {{Object 'a' is moved}} 181 // expected-warning@-3 {{Moved-from object 'a' is copied}} 182 // expected-note@-4 {{Moved-from object 'a' is copied}} 183 #endif 184 } 185 { 186 A a; 187 A b; 188 b = std::move(a); 189 A c(std::move(a)); 190 #ifndef PEACEFUL 191 // expected-note@-3 {{Object 'a' is moved}} 192 // expected-warning@-3 {{Moved-from object 'a' is moved}} 193 // expected-note@-4 {{Moved-from object 'a' is moved}} 194 #endif 195 } 196 } 197 198 void moveInInitListTest() { 199 struct S { 200 A a; 201 }; 202 A a; 203 S s{std::move(a)}; 204 a.foo(); 205 #ifndef PEACEFUL 206 // expected-note@-3 {{Object 'a' is moved}} 207 // expected-warning@-3 {{Method called on moved-from object 'a'}} 208 // expected-note@-4 {{Method called on moved-from object 'a'}} 209 #endif 210 } 211 212 // Don't report a bug if the variable was assigned to in the meantime. 213 void reinitializationTest(int i) { 214 { 215 A a; 216 A b; 217 b = std::move(a); 218 a = A(); 219 a.foo(); 220 } 221 { 222 A a; 223 if (i == 1) { 224 #ifndef PEACEFUL 225 // expected-note@-2 {{Assuming 'i' is not equal to 1}} 226 // expected-note@-3 {{Taking false branch}} 227 // And the other report: 228 // expected-note@-5 {{Assuming 'i' is not equal to 1}} 229 // expected-note@-6 {{Taking false branch}} 230 #endif 231 A b; 232 b = std::move(a); 233 a = A(); 234 } 235 if (i == 2) { 236 #ifndef PEACEFUL 237 // expected-note@-2 {{Assuming 'i' is not equal to 2}} 238 // expected-note@-3 {{Taking false branch}} 239 // And the other report: 240 // expected-note@-5 {{Assuming 'i' is not equal to 2}} 241 // expected-note@-6 {{Taking false branch}} 242 #endif 243 a.foo(); // no-warning 244 } 245 } 246 { 247 A a; 248 if (i == 1) { 249 #ifndef PEACEFUL 250 // expected-note@-2 {{Taking false branch}} 251 // expected-note@-3 {{Taking false branch}} 252 #endif 253 std::move(a); 254 } 255 if (i == 2) { 256 #ifndef PEACEFUL 257 // expected-note@-2 {{Taking false branch}} 258 // expected-note@-3 {{Taking false branch}} 259 #endif 260 a = A(); 261 a.foo(); 262 } 263 } 264 // The built-in assignment operator should also be recognized as a 265 // reinitialization. (std::move() may be called on built-in types in template 266 // code.) 267 { 268 int a1 = 1, a2 = 2; 269 std::swap(a1, a2); 270 } 271 // A std::move() after the assignment makes the variable invalid again. 272 { 273 A a; 274 A b; 275 b = std::move(a); 276 a = A(); 277 b = std::move(a); 278 a.foo(); 279 #ifndef PEACEFUL 280 // expected-note@-3 {{Object 'a' is moved}} 281 // expected-warning@-3 {{Method called on moved-from object 'a'}} 282 // expected-note@-4 {{Method called on moved-from object 'a'}} 283 #endif 284 } 285 // If a path exist where we not reinitialize the variable we report a bug. 286 { 287 A a; 288 A b; 289 b = std::move(a); 290 #ifndef PEACEFUL 291 // expected-note@-2 {{Object 'a' is moved}} 292 #endif 293 if (i < 10) { 294 #ifndef PEACEFUL 295 // expected-note@-2 {{Assuming 'i' is >= 10}} 296 // expected-note@-3 {{Taking false branch}} 297 #endif 298 a = A(); 299 } 300 if (i > 5) { 301 a.foo(); 302 #ifndef PEACEFUL 303 // expected-note@-3 {{Taking true branch}} 304 // expected-warning@-3 {{Method called on moved-from object 'a'}} 305 // expected-note@-4 {{Method called on moved-from object 'a'}} 306 #endif 307 } 308 } 309 } 310 311 // Using decltype on an expression is not a use. 312 void decltypeIsNotUseTest() { 313 A a; 314 // A b(std::move(a)); 315 decltype(a) other_a; // no-warning 316 } 317 318 void loopTest() { 319 { 320 A a; 321 for (int i = 0; i < bignum(); i++) { 322 #ifndef PEACEFUL 323 // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 324 #endif 325 rightRefCall(std::move(a)); // no-warning 326 } 327 } 328 { 329 A a; 330 for (int i = 0; i < 2; i++) { 331 #ifndef PEACEFUL 332 // expected-note@-2 {{Loop condition is true. Entering loop body}} 333 // expected-note@-3 {{Loop condition is true. Entering loop body}} 334 // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} 335 #endif 336 rightRefCall(std::move(a)); // no-warning 337 } 338 } 339 { 340 A a; 341 for (int i = 0; i < bignum(); i++) { 342 #ifndef PEACEFUL 343 // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 344 #endif 345 leftRefCall(a); // no-warning 346 } 347 } 348 { 349 A a; 350 for (int i = 0; i < 2; i++) { 351 #ifndef PEACEFUL 352 // expected-note@-2 {{Loop condition is true. Entering loop body}} 353 // expected-note@-3 {{Loop condition is true. Entering loop body}} 354 // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} 355 #endif 356 leftRefCall(a); // no-warning 357 } 358 } 359 { 360 A a; 361 for (int i = 0; i < bignum(); i++) { 362 #ifndef PEACEFUL 363 // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 364 #endif 365 constCopyOrMoveCall(a); // no-warning 366 } 367 } 368 { 369 A a; 370 for (int i = 0; i < 2; i++) { 371 #ifndef PEACEFUL 372 // expected-note@-2 {{Loop condition is true. Entering loop body}} 373 // expected-note@-3 {{Loop condition is true. Entering loop body}} 374 // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} 375 #endif 376 constCopyOrMoveCall(a); // no-warning 377 } 378 } 379 { 380 A a; 381 for (int i = 0; i < bignum(); i++) { 382 #ifndef PEACEFUL 383 // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 384 #endif 385 moveInsideFunctionCall(a); // no-warning 386 } 387 } 388 { 389 A a; 390 for (int i = 0; i < 2; i++) { 391 #ifndef PEACEFUL 392 // expected-note@-2 {{Loop condition is true. Entering loop body}} 393 // expected-note@-3 {{Loop condition is true. Entering loop body}} 394 // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} 395 #endif 396 moveInsideFunctionCall(a); // no-warning 397 } 398 } 399 { 400 A a; 401 for (int i = 0; i < bignum(); i++) { 402 #ifndef PEACEFUL 403 // expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 404 #endif 405 copyOrMoveCall(a); // no-warning 406 } 407 } 408 { 409 A a; 410 for (int i = 0; i < 2; i++) { 411 #ifndef PEACEFUL 412 // expected-note@-2 {{Loop condition is true. Entering loop body}} 413 // expected-note@-3 {{Loop condition is true. Entering loop body}} 414 // expected-note@-4 {{Loop condition is false. Execution jumps to the end of the function}} 415 #endif 416 copyOrMoveCall(a); // no-warning 417 } 418 } 419 { 420 A a; 421 for (int i = 0; i < bignum(); i++) { 422 #ifndef PEACEFUL 423 // expected-note@-2 {{Loop condition is true. Entering loop body}} 424 // expected-note@-3 {{Loop condition is true. Entering loop body}} 425 #endif 426 constCopyOrMoveCall(std::move(a)); 427 #ifndef PEACEFUL 428 // expected-note@-2 {{Object 'a' is moved}} 429 // expected-warning@-3 {{Moved-from object 'a' is moved}} 430 // expected-note@-4 {{Moved-from object 'a' is moved}} 431 #endif 432 } 433 } 434 435 // Don't warn if we return after the move. 436 { 437 A a; 438 for (int i = 0; i < 3; ++i) { 439 a.bar(); 440 if (a.foo() > 0) { 441 A b; 442 b = std::move(a); // no-warning 443 return; 444 } 445 } 446 } 447 } 448 449 // Report a usage of a moved-from object only at the first use. 450 void uniqueTest(bool cond) { 451 A a(42, 42.0); 452 A b; 453 b = std::move(a); 454 455 if (cond) { 456 a.foo(); 457 #ifndef PEACEFUL 458 // expected-note@-5 {{Object 'a' is moved}} 459 // expected-note@-4 {{Assuming 'cond' is not equal to 0}} 460 // expected-note@-5 {{Taking true branch}} 461 // expected-warning@-5 {{Method called on moved-from object 'a'}} 462 // expected-note@-6 {{Method called on moved-from object 'a'}} 463 #endif 464 } 465 if (cond) { 466 a.bar(); // no-warning 467 } 468 469 a.bar(); // no-warning 470 } 471 472 void uniqueTest2() { 473 A a; 474 A a1 = std::move(a); 475 a.foo(); 476 #ifndef PEACEFUL 477 // expected-note@-3 {{Object 'a' is moved}} 478 // expected-warning@-3 {{Method called on moved-from object 'a'}} 479 // expected-note@-4 {{Method called on moved-from object 'a'}} 480 #endif 481 482 A a2 = std::move(a); // no-warning 483 a.foo(); // no-warning 484 } 485 486 // There are exceptions where we assume in general that the method works fine 487 //even on moved-from objects. 488 void moveSafeFunctionsTest() { 489 A a; 490 A b = std::move(a); 491 #ifndef PEACEFUL 492 // expected-note@-2 {{Object 'a' is moved}} 493 #endif 494 a.empty(); // no-warning 495 a.isEmpty(); // no-warning 496 (void)a; // no-warning 497 (bool)a; // expected-warning {{expression result unused}} 498 a.foo(); 499 #ifndef PEACEFUL 500 // expected-warning@-2 {{Method called on moved-from object 'a'}} 501 // expected-note@-3 {{Method called on moved-from object 'a'}} 502 #endif 503 } 504 505 void moveStateResetFunctionsTest() { 506 { 507 A a; 508 A b = std::move(a); 509 a.reset(); // no-warning 510 a.foo(); // no-warning 511 // Test if resets the state of subregions as well. 512 a.b.foo(); // no-warning 513 } 514 { 515 A a; 516 A b = std::move(a); 517 a.destroy(); // no-warning 518 a.foo(); // no-warning 519 } 520 { 521 A a; 522 A b = std::move(a); 523 a.clear(); // no-warning 524 a.foo(); // no-warning 525 a.b.foo(); // no-warning 526 } 527 { 528 A a; 529 A b = std::move(a); 530 a.resize(0); // no-warning 531 a.foo(); // no-warning 532 a.b.foo(); // no-warning 533 } 534 } 535 536 // Moves or uses that occur as part of template arguments. 537 template <int> 538 class ClassTemplate { 539 public: 540 void foo(A a); 541 }; 542 543 template <int> 544 void functionTemplate(A a); 545 546 void templateArgIsNotUseTest() { 547 { 548 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in 549 // Google Test. 550 A a; 551 ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning 552 } 553 { 554 A a; 555 functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning 556 } 557 } 558 559 // Moves of global variables are not reported. 560 A global_a; 561 void globalVariablesTest() { 562 std::move(global_a); 563 global_a.foo(); // no-warning 564 } 565 566 // Moves of member variables. 567 class memberVariablesTest { 568 A a; 569 static A static_a; 570 571 void f() { 572 A b; 573 b = std::move(a); 574 a.foo(); 575 #ifdef AGGRESSIVE 576 // expected-note@-3{{Object 'a' is moved}} 577 // expected-warning@-3 {{Method called on moved-from object 'a'}} 578 // expected-note@-4{{Method called on moved-from object 'a'}} 579 #endif 580 581 b = std::move(static_a); 582 static_a.foo(); 583 #ifdef AGGRESSIVE 584 // expected-note@-3{{Object 'static_a' is moved}} 585 // expected-warning@-3{{Method called on moved-from object 'static_a'}} 586 // expected-note@-4{{Method called on moved-from object 'static_a'}} 587 #endif 588 } 589 }; 590 591 void PtrAndArrayTest() { 592 A *Ptr = new A(1, 1.5); 593 A Arr[10]; 594 Arr[2] = std::move(*Ptr); 595 (*Ptr).foo(); 596 #ifdef AGGRESSIVE 597 // expected-note@-3{{Object is moved}} 598 // expected-warning@-3{{Method called on moved-from object}} 599 // expected-note@-4{{Method called on moved-from object}} 600 #endif 601 602 Ptr = &Arr[1]; 603 Arr[3] = std::move(Arr[1]); 604 Ptr->foo(); 605 #ifdef AGGRESSIVE 606 // expected-note@-3{{Object is moved}} 607 // expected-warning@-3{{Method called on moved-from object}} 608 // expected-note@-4{{Method called on moved-from object}} 609 #endif 610 611 Arr[3] = std::move(Arr[2]); 612 Arr[2].foo(); 613 #ifdef AGGRESSIVE 614 // expected-note@-3{{Object is moved}} 615 // expected-warning@-3{{Method called on moved-from object}} 616 // expected-note@-4{{Method called on moved-from object}} 617 #endif 618 619 Arr[2] = std::move(Arr[3]); // reinitialization 620 Arr[2].foo(); // no-warning 621 } 622 623 void exclusiveConditionsTest(bool cond) { 624 A a; 625 if (cond) { 626 A b; 627 b = std::move(a); 628 } 629 if (!cond) { 630 a.bar(); // no-warning 631 } 632 } 633 634 void differentBranchesTest(int i) { 635 // Don't warn if the use is in a different branch from the move. 636 { 637 A a; 638 if (i > 0) { 639 #ifndef PEACEFUL 640 // expected-note@-2 {{Assuming 'i' is > 0}} 641 // expected-note@-3 {{Taking true branch}} 642 #endif 643 A b; 644 b = std::move(a); 645 } else { 646 a.foo(); // no-warning 647 } 648 } 649 // Same thing, but with a ternary operator. 650 { 651 A a, b; 652 i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning 653 #ifndef PEACEFUL 654 // expected-note@-2 {{'?' condition is true}} 655 #endif 656 } 657 // A variation on the theme above. 658 { 659 A a; 660 a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); 661 #ifdef DFS 662 #ifndef PEACEFUL 663 // expected-note@-3 {{Assuming the condition is false}} 664 // expected-note@-4 {{'?' condition is false}} 665 #endif 666 #else 667 #ifndef PEACEFUL 668 // expected-note@-8 {{Assuming the condition is true}} 669 // expected-note@-9 {{'?' condition is true}} 670 #endif 671 #endif 672 } 673 // Same thing, but with a switch statement. 674 { 675 A a, b; 676 switch (i) { 677 #ifndef PEACEFUL 678 // expected-note@-2 {{Control jumps to 'case 1:'}} 679 #endif 680 case 1: 681 b = std::move(a); // no-warning 682 break; 683 #ifndef PEACEFUL 684 // expected-note@-2 {{Execution jumps to the end of the function}} 685 #endif 686 case 2: 687 a.foo(); // no-warning 688 break; 689 } 690 } 691 // However, if there's a fallthrough, we do warn. 692 { 693 A a, b; 694 switch (i) { 695 #ifndef PEACEFUL 696 // expected-note@-2 {{Control jumps to 'case 1:'}} 697 #endif 698 case 1: 699 b = std::move(a); 700 #ifndef PEACEFUL 701 // expected-note@-2 {{Object 'a' is moved}} 702 #endif 703 case 2: 704 a.foo(); 705 #ifndef PEACEFUL 706 // expected-warning@-2 {{Method called on moved-from object}} 707 // expected-note@-3 {{Method called on moved-from object 'a'}} 708 #endif 709 break; 710 } 711 } 712 } 713 714 void tempTest() { 715 A a = A::get(); 716 A::get().foo(); // no-warning 717 for (int i = 0; i < bignum(); i++) { 718 A::get().foo(); // no-warning 719 } 720 } 721 722 void interFunTest1(A &a) { 723 a.bar(); 724 #ifndef PEACEFUL 725 // expected-warning@-2 {{Method called on moved-from object 'a'}} 726 // expected-note@-3 {{Method called on moved-from object 'a'}} 727 #endif 728 } 729 730 void interFunTest2() { 731 A a; 732 A b; 733 b = std::move(a); 734 interFunTest1(a); 735 #ifndef PEACEFUL 736 // expected-note@-3 {{Object 'a' is moved}} 737 // expected-note@-3 {{Calling 'interFunTest1'}} 738 #endif 739 } 740 741 void foobar(A a, int i); 742 void foobar(int i, A a); 743 744 void paramEvaluateOrderTest() { 745 A a; 746 foobar(std::move(a), a.getI()); 747 #ifndef PEACEFUL 748 // expected-note@-2 {{Object 'a' is moved}} 749 // expected-warning@-3 {{Method called on moved-from object 'a'}} 750 // expected-note@-4 {{Method called on moved-from object 'a'}} 751 #endif 752 753 //FALSE NEGATIVE since parameters evaluate order is undefined 754 foobar(a.getI(), std::move(a)); //no-warning 755 } 756 757 void not_known_pass_by_ref(A &a); 758 void not_known_pass_by_const_ref(const A &a); 759 void not_known_pass_by_rvalue_ref(A &&a); 760 void not_known_pass_by_ptr(A *a); 761 void not_known_pass_by_const_ptr(const A *a); 762 763 void regionAndPointerEscapeTest() { 764 { 765 A a; 766 A b; 767 b = std::move(a); 768 not_known_pass_by_ref(a); 769 a.foo(); // no-warning 770 } 771 { 772 A a; 773 A b; 774 b = std::move(a); 775 not_known_pass_by_const_ref(a); 776 a.foo(); 777 #ifndef PEACEFUL 778 // expected-note@-4{{Object 'a' is moved}} 779 // expected-warning@-3{{Method called on moved-from object 'a'}} 780 // expected-note@-4 {{Method called on moved-from object 'a'}} 781 #endif 782 } 783 { 784 A a; 785 A b; 786 b = std::move(a); 787 not_known_pass_by_rvalue_ref(std::move(a)); 788 a.foo(); // no-warning 789 } 790 { 791 A a; 792 A b; 793 b = std::move(a); 794 not_known_pass_by_ptr(&a); 795 a.foo(); // no-warning 796 } 797 { 798 A a; 799 A b; 800 b = std::move(a); 801 not_known_pass_by_const_ptr(&a); 802 a.foo(); 803 #ifndef PEACEFUL 804 // expected-note@-4{{Object 'a' is moved}} 805 // expected-warning@-3{{Method called on moved-from object 'a'}} 806 // expected-note@-4 {{Method called on moved-from object 'a'}} 807 #endif 808 } 809 } 810 811 // A declaration statement containing multiple declarations sequences the 812 // initializer expressions. 813 void declarationSequenceTest() { 814 { 815 A a; 816 A a1 = a, a2 = std::move(a); // no-warning 817 } 818 { 819 A a; 820 A a1 = std::move(a), a2 = a; 821 #ifndef PEACEFUL 822 // expected-note@-2 {{Object 'a' is moved}} 823 // expected-warning@-3 {{Moved-from object 'a' is copied}} 824 // expected-note@-4 {{Moved-from object 'a' is copied}} 825 #endif 826 } 827 } 828 829 // The logical operators && and || sequence their operands. 830 void logicalOperatorsSequenceTest() { 831 { 832 A a; 833 if (a.foo() > 0 && A(std::move(a)).foo() > 0) { 834 #ifndef PEACEFUL 835 // expected-note@-2 {{Assuming the condition is false}} 836 // expected-note@-3 {{Left side of '&&' is false}} 837 // expected-note@-4 {{Taking false branch}} 838 // And the other report: 839 // expected-note@-6 {{Assuming the condition is false}} 840 // expected-note@-7 {{Left side of '&&' is false}} 841 // expected-note@-8 {{Taking false branch}} 842 A().bar(); 843 #endif 844 } 845 } 846 // A variation: Negate the result of the && (which pushes the && further down 847 // into the AST). 848 { 849 A a; 850 if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { 851 #ifndef PEACEFUL 852 // expected-note@-2 {{Assuming the condition is false}} 853 // expected-note@-3 {{Left side of '&&' is false}} 854 // expected-note@-4 {{Taking true branch}} 855 // And the other report: 856 // expected-note@-6 {{Assuming the condition is false}} 857 // expected-note@-7 {{Left side of '&&' is false}} 858 // expected-note@-8 {{Taking true branch}} 859 #endif 860 A().bar(); 861 } 862 } 863 { 864 A a; 865 if (A(std::move(a)).foo() > 0 && a.foo() > 0) { 866 #ifndef PEACEFUL 867 // expected-note@-2 {{Object 'a' is moved}} 868 // expected-note@-3 {{Assuming the condition is true}} 869 // expected-note@-4 {{Left side of '&&' is true}} 870 // expected-warning@-5 {{Method called on moved-from object 'a'}} 871 // expected-note@-6 {{Method called on moved-from object 'a'}} 872 // And the other report: 873 // expected-note@-8 {{Assuming the condition is false}} 874 // expected-note@-9 {{Left side of '&&' is false}} 875 // expected-note@-10{{Taking false branch}} 876 #endif 877 A().bar(); 878 } 879 } 880 { 881 A a; 882 if (a.foo() > 0 || A(std::move(a)).foo() > 0) { 883 #ifndef PEACEFUL 884 // expected-note@-2 {{Assuming the condition is true}} 885 // expected-note@-3 {{Left side of '||' is true}} 886 // expected-note@-4 {{Taking true branch}} 887 #endif 888 A().bar(); 889 } 890 } 891 { 892 A a; 893 if (A(std::move(a)).foo() > 0 || a.foo() > 0) { 894 #ifndef PEACEFUL 895 // expected-note@-2 {{Object 'a' is moved}} 896 // expected-note@-3 {{Assuming the condition is false}} 897 // expected-note@-4 {{Left side of '||' is false}} 898 // expected-warning@-5 {{Method called on moved-from object 'a'}} 899 // expected-note@-6 {{Method called on moved-from object 'a'}} 900 #endif 901 A().bar(); 902 } 903 } 904 } 905 906 // A range-based for sequences the loop variable declaration before the body. 907 void forRangeSequencesTest() { 908 A v[2] = {A(), A()}; 909 for (A &a : v) { 910 A b; 911 b = std::move(a); // no-warning 912 } 913 } 914 915 // If a variable is declared in an if statement, the declaration of the variable 916 // (which is treated like a reinitialization by the check) is sequenced before 917 // the evaluation of the condition (which constitutes a use). 918 void ifStmtSequencesDeclAndConditionTest() { 919 for (int i = 0; i < 3; ++i) { 920 if (A a = A()) { 921 A b; 922 b = std::move(a); // no-warning 923 } 924 } 925 } 926 927 struct C : public A { 928 [[clang::reinitializes]] void reinit(); 929 }; 930 931 void subRegionMoveTest() { 932 { 933 A a; 934 B b = std::move(a.b); 935 a.b.foo(); 936 #ifdef AGGRESSIVE 937 // expected-note@-3{{Object 'b' is moved}} 938 // expected-warning@-3{{Method called on moved-from object 'b'}} 939 // expected-note@-4 {{Method called on moved-from object 'b'}} 940 #endif 941 } 942 { 943 A a; 944 A a1 = std::move(a); 945 a.b.foo(); 946 #ifdef AGGRESSIVE 947 // expected-note@-3{{Calling move constructor for 'A'}} 948 // expected-note@-4{{Returning from move constructor for 'A'}} 949 // expected-warning@-4{{Method called on moved-from object 'b'}} 950 // expected-note@-5{{Method called on moved-from object 'b'}} 951 #endif 952 } 953 // Don't report a misuse if any SuperRegion is already reported. 954 { 955 A a; 956 A a1 = std::move(a); 957 a.foo(); 958 #ifndef PEACEFUL 959 // expected-note@-3 {{Object 'a' is moved}} 960 // expected-warning@-3 {{Method called on moved-from object 'a'}} 961 // expected-note@-4 {{Method called on moved-from object 'a'}} 962 #endif 963 a.b.foo(); // no-warning 964 } 965 { 966 C c; 967 C c1 = std::move(c); 968 c.foo(); 969 #ifndef PEACEFUL 970 // expected-note@-3 {{Object 'c' is moved}} 971 // expected-warning@-3 {{Method called on moved-from object 'c'}} 972 // expected-note@-4 {{Method called on moved-from object 'c'}} 973 #endif 974 c.b.foo(); // no-warning 975 } 976 } 977 978 void resetSuperClass() { 979 C c; 980 C c1 = std::move(c); 981 c.clear(); 982 C c2 = c; // no-warning 983 } 984 985 void resetSuperClass2() { 986 C c; 987 C c1 = std::move(c); 988 c.reinit(); 989 C c2 = c; // no-warning 990 } 991 992 void reportSuperClass() { 993 C c; 994 C c1 = std::move(c); 995 c.foo(); 996 #ifndef PEACEFUL 997 // expected-note@-3 {{Object 'c' is moved}} 998 // expected-warning@-3 {{Method called on moved-from object 'c'}} 999 // expected-note@-4 {{Method called on moved-from object 'c'}} 1000 #endif 1001 C c2 = c; // no-warning 1002 } 1003 1004 struct Empty {}; 1005 1006 Empty inlinedCall() { 1007 // Used to warn because region 'e' failed to be cleaned up because no symbols 1008 // have ever died during the analysis and the checkDeadSymbols callback 1009 // was skipped entirely. 1010 Empty e{}; 1011 return e; // no-warning 1012 } 1013 1014 void checkInlinedCallZombies() { 1015 while (true) 1016 inlinedCall(); 1017 } 1018 1019 void checkLoopZombies() { 1020 while (true) { 1021 Empty e{}; 1022 Empty f = std::move(e); // no-warning 1023 } 1024 } 1025 1026 void checkMoreLoopZombies1(bool flag) { 1027 while (flag) { 1028 Empty e{}; 1029 if (true) 1030 e; // expected-warning {{expression result unused}} 1031 Empty f = std::move(e); // no-warning 1032 } 1033 } 1034 1035 bool coin(); 1036 1037 void checkMoreLoopZombies2(bool flag) { 1038 while (flag) { 1039 Empty e{}; 1040 while (coin()) 1041 e; // expected-warning {{expression result unused}} 1042 Empty f = std::move(e); // no-warning 1043 } 1044 } 1045 1046 void checkMoreLoopZombies3(bool flag) { 1047 while (flag) { 1048 Empty e{}; 1049 do 1050 e; // expected-warning {{expression result unused}} 1051 while (coin()); 1052 Empty f = std::move(e); // no-warning 1053 } 1054 } 1055 1056 void checkMoreLoopZombies4(bool flag) { 1057 while (flag) { 1058 Empty e{}; 1059 for (; coin();) 1060 e; // expected-warning {{expression result unused}} 1061 Empty f = std::move(e); // no-warning 1062 } 1063 } 1064 1065 struct MoveOnlyWithDestructor { 1066 MoveOnlyWithDestructor(); 1067 ~MoveOnlyWithDestructor(); 1068 MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete; 1069 MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m); 1070 }; 1071 1072 MoveOnlyWithDestructor foo() { 1073 MoveOnlyWithDestructor m; 1074 return m; 1075 } 1076 1077 class HasSTLField { 1078 std::vector<int> V; 1079 void testVector() { 1080 // Warn even in non-aggressive mode when it comes to STL, because 1081 // in STL the object is left in "valid but unspecified state" after move. 1082 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}} 1083 V.push_back(123); // expected-warning{{Method called on moved-from object 'V'}} 1084 // expected-note@-1{{Method called on moved-from object 'V'}} 1085 } 1086 1087 std::unique_ptr<int> P; 1088 void testUniquePtr() { 1089 // unique_ptr remains in a well-defined state after move. 1090 std::unique_ptr<int> Q = std::move(P); 1091 P.get(); 1092 #ifdef AGGRESSIVE 1093 // expected-warning@-2{{Method called on moved-from object 'P'}} 1094 // expected-note@-4{{Object 'P' is moved}} 1095 // expected-note@-4{{Method called on moved-from object 'P'}} 1096 #endif 1097 1098 // Because that well-defined state is null, dereference is still UB. 1099 // Note that in aggressive mode we already warned about 'P', 1100 // so no extra warning is generated. 1101 *P += 1; 1102 #ifndef AGGRESSIVE 1103 // expected-warning@-2{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 1104 // expected-note@-14{{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}} 1105 // expected-note@-4{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 1106 #endif 1107 1108 // The program should have crashed by now. 1109 clang_analyzer_warnIfReached(); // no-warning 1110 } 1111 }; 1112 1113 void localRValueMove(A &&a) { 1114 A b = std::move(a); 1115 a.foo(); 1116 #ifndef PEACEFUL 1117 // expected-note@-3 {{Object 'a' is moved}} 1118 // expected-warning@-3 {{Method called on moved-from object 'a'}} 1119 // expected-note@-4 {{Method called on moved-from object 'a'}} 1120 #endif 1121 } 1122 1123 void localUniquePtr(std::unique_ptr<int> P) { 1124 // Even though unique_ptr is safe to use after move, 1125 // reusing a local variable this way usually indicates a bug. 1126 std::unique_ptr<int> Q = std::move(P); 1127 P.get(); 1128 #ifndef PEACEFUL 1129 // expected-note@-3 {{Object 'P' is moved}} 1130 // expected-warning@-3 {{Method called on moved-from object 'P'}} 1131 // expected-note@-4 {{Method called on moved-from object 'P'}} 1132 #endif 1133 } 1134 1135 void localUniquePtrWithArrow(std::unique_ptr<A> P) { 1136 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}} 1137 P->foo(); // expected-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 1138 // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 1139 } 1140