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