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