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 #ifdef DFS 574 // peaceful-note@-2 {{Assuming the condition is false}} 575 // peaceful-note@-3 {{'?' condition is false}} 576 #else 577 // peaceful-note@-5 {{Assuming the condition is true}} 578 // peaceful-note@-6 {{'?' condition is true}} 579 #endif 580 } 581 // Same thing, but with a switch statement. 582 { 583 A a, b; 584 switch (i) { // peaceful-note {{Control jumps to 'case 1:'}} 585 case 1: 586 b = std::move(a); // no-warning 587 // FIXME: Execution doesn't jump to the end of the function yet. 588 break; // peaceful-note {{Execution jumps to the end of the function}} 589 case 2: 590 a.foo(); // no-warning 591 break; 592 } 593 } 594 // However, if there's a fallthrough, we do warn. 595 { 596 A a, b; 597 switch (i) { // peaceful-note {{Control jumps to 'case 1:'}} 598 case 1: 599 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 600 case 2: 601 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 602 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 603 break; 604 } 605 } 606 } 607 608 void tempTest() { 609 A a = A::get(); 610 A::get().foo(); // no-warning 611 for (int i = 0; i < bignum(); i++) { 612 A::get().foo(); // no-warning 613 } 614 } 615 616 void interFunTest1(A &a) { 617 a.bar(); // peaceful-warning {{Method called on moved-from object 'a'}} 618 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 619 } 620 621 void interFunTest2() { 622 A a; 623 A b; 624 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 625 interFunTest1(a); // peaceful-note {{Calling 'interFunTest1'}} 626 } 627 628 void foobar(A a, int i); 629 void foobar(int i, A a); 630 631 void paramEvaluateOrderTest() { 632 A a; 633 foobar(std::move(a), a.getI()); // peaceful-note {{Object 'a' is moved}} 634 // peaceful-warning@-1 {{Method called on moved-from object 'a'}} 635 // peaceful-note@-2 {{Method called on moved-from object 'a'}} 636 637 //FALSE NEGATIVE since parameters evaluate order is undefined 638 foobar(a.getI(), std::move(a)); //no-warning 639 } 640 641 void not_known_pass_by_ref(A &a); 642 void not_known_pass_by_const_ref(const A &a); 643 void not_known_pass_by_rvalue_ref(A &&a); 644 void not_known_pass_by_ptr(A *a); 645 void not_known_pass_by_const_ptr(const A *a); 646 647 void regionAndPointerEscapeTest() { 648 { 649 A a; 650 A b; 651 b = std::move(a); 652 not_known_pass_by_ref(a); 653 a.foo(); // no-warning 654 } 655 { 656 A a; 657 A b; 658 b = std::move(a); // peaceful-note{{Object 'a' is moved}} 659 not_known_pass_by_const_ref(a); 660 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 661 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 662 } 663 { 664 A a; 665 A b; 666 b = std::move(a); 667 not_known_pass_by_rvalue_ref(std::move(a)); 668 a.foo(); // no-warning 669 } 670 { 671 A a; 672 A b; 673 b = std::move(a); 674 not_known_pass_by_ptr(&a); 675 a.foo(); // no-warning 676 } 677 { 678 A a; 679 A b; 680 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 681 not_known_pass_by_const_ptr(&a); 682 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 683 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 684 } 685 } 686 687 // A declaration statement containing multiple declarations sequences the 688 // initializer expressions. 689 void declarationSequenceTest() { 690 { 691 A a; 692 A a1 = a, a2 = std::move(a); // no-warning 693 } 694 { 695 A a; 696 A a1 = std::move(a), a2 = a; // peaceful-note {{Object 'a' is moved}} 697 // peaceful-warning@-1 {{Moved-from object 'a' is copied}} 698 // peaceful-note@-2 {{Moved-from object 'a' is copied}} 699 } 700 } 701 702 // The logical operators && and || sequence their operands. 703 void logicalOperatorsSequenceTest() { 704 { 705 A a; 706 if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // peaceful-note {{Assuming the condition is false}} 707 // peaceful-note@-1 {{Left side of '&&' is false}} 708 // peaceful-note@-2 {{Taking false branch}} 709 // And the other report: 710 // peaceful-note@-4 {{Assuming the condition is false}} 711 // peaceful-note@-5 {{Left side of '&&' is false}} 712 // peaceful-note@-6 {{Taking false branch}} 713 A().bar(); 714 } 715 } 716 // A variation: Negate the result of the && (which pushes the && further down 717 // into the AST). 718 { 719 A a; 720 if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // peaceful-note {{Assuming the condition is false}} 721 // peaceful-note@-1 {{Left side of '&&' is false}} 722 // peaceful-note@-2 {{Taking true branch}} 723 // And the other report: 724 // peaceful-note@-4 {{Assuming the condition is false}} 725 // peaceful-note@-5 {{Left side of '&&' is false}} 726 // peaceful-note@-6 {{Taking true branch}} 727 A().bar(); 728 } 729 } 730 { 731 A a; 732 if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // peaceful-note {{Object 'a' is moved}} 733 // peaceful-note@-1 {{Assuming the condition is true}} 734 // peaceful-note@-2 {{Left side of '&&' is true}} 735 // peaceful-warning@-3 {{Method called on moved-from object 'a'}} 736 // peaceful-note@-4 {{Method called on moved-from object 'a'}} 737 // And the other report: 738 // peaceful-note@-6 {{Assuming the condition is false}} 739 // peaceful-note@-7 {{Left side of '&&' is false}} 740 // peaceful-note@-8 {{Taking false branch}} 741 A().bar(); 742 } 743 } 744 { 745 A a; 746 if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // peaceful-note {{Assuming the condition is true}} 747 // peaceful-note@-1 {{Left side of '||' is true}} 748 // peaceful-note@-2 {{Taking true branch}} 749 A().bar(); 750 } 751 } 752 { 753 A a; 754 if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // peaceful-note {{Object 'a' is moved}} 755 // peaceful-note@-1 {{Assuming the condition is false}} 756 // peaceful-note@-2 {{Left side of '||' is false}} 757 // peaceful-warning@-3 {{Method called on moved-from object 'a'}} 758 // peaceful-note@-4 {{Method called on moved-from object 'a'}} 759 A().bar(); 760 } 761 } 762 } 763 764 // A range-based for sequences the loop variable declaration before the body. 765 void forRangeSequencesTest() { 766 A v[2] = {A(), A()}; 767 for (A &a : v) { 768 A b; 769 b = std::move(a); // no-warning 770 } 771 } 772 773 // If a variable is declared in an if statement, the declaration of the variable 774 // (which is treated like a reinitialization by the check) is sequenced before 775 // the evaluation of the condition (which constitutes a use). 776 void ifStmtSequencesDeclAndConditionTest() { 777 for (int i = 0; i < 3; ++i) { 778 if (A a = A()) { 779 A b; 780 b = std::move(a); // no-warning 781 } 782 } 783 } 784 785 struct C : public A { 786 [[clang::reinitializes]] void reinit(); 787 }; 788 789 void subRegionMoveTest() { 790 { 791 A a; 792 B b = std::move(a.b); // aggressive-note {{Object 'b' is moved}} 793 a.b.foo(); // aggressive-warning {{Method called on moved-from object 'b'}} 794 // aggressive-note@-1 {{Method called on moved-from object 'b'}} 795 } 796 { 797 A a; 798 A a1 = std::move(a); // aggressive-note {{Calling move constructor for 'A'}} 799 // aggressive-note@-1 {{Returning from move constructor for 'A'}} 800 a.b.foo(); // aggressive-warning{{Method called on moved-from object 'b'}} 801 // aggressive-note@-1{{Method called on moved-from object 'b'}} 802 } 803 // Don't report a misuse if any SuperRegion is already reported. 804 { 805 A a; 806 A a1 = std::move(a); // peaceful-note {{Object 'a' is moved}} 807 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 808 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 809 a.b.foo(); // no-warning 810 } 811 { 812 C c; 813 C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}} 814 c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}} 815 // peaceful-note@-1 {{Method called on moved-from object 'c'}} 816 c.b.foo(); // no-warning 817 } 818 } 819 820 void resetSuperClass() { 821 C c; 822 C c1 = std::move(c); 823 c.clear(); 824 C c2 = c; // no-warning 825 } 826 827 void resetSuperClass2() { 828 C c; 829 C c1 = std::move(c); 830 c.reinit(); 831 C c2 = c; // no-warning 832 } 833 834 void reportSuperClass() { 835 C c; 836 C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}} 837 c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}} 838 // peaceful-note@-1 {{Method called on moved-from object 'c'}} 839 C c2 = c; // no-warning 840 } 841 842 struct Empty {}; 843 844 Empty inlinedCall() { 845 // Used to warn because region 'e' failed to be cleaned up because no symbols 846 // have ever died during the analysis and the checkDeadSymbols callback 847 // was skipped entirely. 848 Empty e{}; 849 return e; // no-warning 850 } 851 852 void checkInlinedCallZombies() { 853 while (true) 854 inlinedCall(); 855 } 856 857 void checkLoopZombies() { 858 while (true) { 859 Empty e{}; 860 Empty f = std::move(e); // no-warning 861 } 862 } 863 864 void checkMoreLoopZombies1(bool flag) { 865 while (flag) { 866 Empty e{}; 867 if (true) 868 e; // expected-warning {{expression result unused}} 869 Empty f = std::move(e); // no-warning 870 } 871 } 872 873 bool coin(); 874 875 void checkMoreLoopZombies2(bool flag) { 876 while (flag) { 877 Empty e{}; 878 while (coin()) 879 e; // expected-warning {{expression result unused}} 880 Empty f = std::move(e); // no-warning 881 } 882 } 883 884 void checkMoreLoopZombies3(bool flag) { 885 while (flag) { 886 Empty e{}; 887 do 888 e; // expected-warning {{expression result unused}} 889 while (coin()); 890 Empty f = std::move(e); // no-warning 891 } 892 } 893 894 void checkMoreLoopZombies4(bool flag) { 895 while (flag) { 896 Empty e{}; 897 for (; coin();) 898 e; // expected-warning {{expression result unused}} 899 Empty f = std::move(e); // no-warning 900 } 901 } 902 903 struct MoveOnlyWithDestructor { 904 MoveOnlyWithDestructor(); 905 ~MoveOnlyWithDestructor(); 906 MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete; 907 MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m); 908 }; 909 910 MoveOnlyWithDestructor foo() { 911 MoveOnlyWithDestructor m; 912 return m; 913 } 914 915 class HasSTLField { 916 std::vector<int> V; 917 void testVector() { 918 // Warn even in non-aggressive mode when it comes to STL, because 919 // in STL the object is left in "valid but unspecified state" after move. 920 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}} 921 V.push_back(123); // expected-warning {{Method called on moved-from object 'V'}} 922 // expected-note@-1 {{Method called on moved-from object 'V'}} 923 } 924 925 std::unique_ptr<int> P; 926 void testUniquePtr() { 927 // unique_ptr remains in a well-defined state after move. 928 std::unique_ptr<int> Q = std::move(P); // aggressive-note {{Object 'P' is moved}} 929 // non-aggressive-note@-1 {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}} 930 P.get(); // aggressive-warning{{Method called on moved-from object 'P'}} 931 // aggressive-note@-1{{Method called on moved-from object 'P'}} 932 933 // Because that well-defined state is null, dereference is still UB. 934 // Note that in aggressive mode we already warned about 'P', 935 // so no extra warning is generated. 936 *P += 1; // non-aggressive-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 937 // non-aggressive-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 938 939 // The program should have crashed by now. 940 clang_analyzer_warnIfReached(); // no-warning 941 } 942 }; 943 944 void localRValueMove(A &&a) { 945 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 946 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 947 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 948 } 949 950 void localUniquePtr(std::unique_ptr<int> P) { 951 // Even though unique_ptr is safe to use after move, 952 // reusing a local variable this way usually indicates a bug. 953 std::unique_ptr<int> Q = std::move(P); // peaceful-note {{Object 'P' is moved}} 954 P.get(); // peaceful-warning {{Method called on moved-from object 'P'}} 955 // peaceful-note@-1 {{Method called on moved-from object 'P'}} 956 } 957 958 void localUniquePtrWithArrow(std::unique_ptr<A> P) { 959 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}} 960 P->foo(); // expected-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 961 // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 962 } 963 964 void getAfterMove(std::unique_ptr<A> P) { 965 std::unique_ptr<A> Q = std::move(P); // peaceful-note {{Object 'P' is moved}} 966 967 // TODO: Explain why (bool)P is false. 968 if (P) // peaceful-note{{Taking false branch}} 969 clang_analyzer_warnIfReached(); // no-warning 970 971 A *a = P.get(); // peaceful-warning {{Method called on moved-from object 'P'}} 972 // peaceful-note@-1 {{Method called on moved-from object 'P'}} 973 974 // TODO: Warn on a null dereference here. 975 a->foo(); 976 } 977 978 struct OtherMoveSafeClasses { 979 std::packaged_task<int(void)> Task; 980 981 void test() { 982 // Test the suppression caused by use-after-move semantics of 983 // std::package_task being different from other standard classes. 984 // Only warn in aggressive mode. Don't say that the object 985 // is left in unspecified state after move. 986 std::packaged_task<int(void)> Task2 = std::move(Task); 987 // aggressive-note@-1 {{Object 'Task' is moved}} 988 std::packaged_task<int(void)> Task3 = std::move(Task); 989 // aggressive-warning@-1{{Moved-from object 'Task' is moved}} 990 // aggressive-note@-2 {{Moved-from object 'Task' is moved}} 991 } 992 }; 993