1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++03 %s 2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++11 %s 3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11 4 5 extern bool clang_analyzer_eval(bool); 6 extern bool clang_analyzer_warnIfReached(); 7 void clang_analyzer_checkInlined(bool); 8 9 #include "Inputs/system-header-simulator-cxx.h"; 10 11 struct Trivial { 12 Trivial(int x) : value(x) {} 13 int value; 14 }; 15 16 struct NonTrivial : public Trivial { 17 NonTrivial(int x) : Trivial(x) {} 18 ~NonTrivial(); 19 }; 20 21 22 Trivial getTrivial() { 23 return Trivial(42); // no-warning 24 } 25 26 const Trivial &getTrivialRef() { 27 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} 28 } 29 30 31 NonTrivial getNonTrivial() { 32 return NonTrivial(42); // no-warning 33 } 34 35 const NonTrivial &getNonTrivialRef() { 36 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} 37 } 38 39 namespace rdar13265460 { 40 struct TrivialSubclass : public Trivial { 41 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} 42 int anotherValue; 43 }; 44 45 TrivialSubclass getTrivialSub() { 46 TrivialSubclass obj(1); 47 obj.value = 42; 48 obj.anotherValue = -42; 49 return obj; 50 } 51 52 void testImmediate() { 53 TrivialSubclass obj = getTrivialSub(); 54 55 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} 56 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} 57 58 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} 59 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} 60 } 61 62 void testMaterializeTemporaryExpr() { 63 const TrivialSubclass &ref = getTrivialSub(); 64 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 65 66 const Trivial &baseRef = getTrivialSub(); 67 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} 68 } 69 } 70 71 namespace rdar13281951 { 72 struct Derived : public Trivial { 73 Derived(int value) : Trivial(value), value2(-value) {} 74 int value2; 75 }; 76 77 void test() { 78 Derived obj(1); 79 obj.value = 42; 80 const Trivial * const &pointerRef = &obj; 81 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} 82 } 83 } 84 85 namespace compound_literals { 86 struct POD { 87 int x, y; 88 }; 89 struct HasCtor { 90 HasCtor(int x, int y) : x(x), y(y) {} 91 int x, y; 92 }; 93 struct HasDtor { 94 int x, y; 95 ~HasDtor(); 96 }; 97 struct HasCtorDtor { 98 HasCtorDtor(int x, int y) : x(x), y(y) {} 99 ~HasCtorDtor(); 100 int x, y; 101 }; 102 103 void test() { 104 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} 105 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} 106 107 #if __cplusplus >= 201103L 108 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} 109 110 // FIXME: should be TRUE, but we don't inline the constructors of 111 // temporaries because we can't model their destructors yet. 112 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} 113 #endif 114 } 115 } 116 117 namespace destructors { 118 struct Dtor { 119 ~Dtor(); 120 }; 121 extern bool coin(); 122 extern bool check(const Dtor &); 123 124 void testPR16664andPR18159Crash() { 125 // Regression test: we used to assert here when tmp dtors are enabled. 126 // PR16664 and PR18159 127 if (coin() && (coin() || coin() || check(Dtor()))) { 128 Dtor(); 129 } 130 } 131 132 #ifdef TEMPORARY_DTORS 133 struct NoReturnDtor { 134 ~NoReturnDtor() __attribute__((noreturn)); 135 }; 136 137 void noReturnTemp(int *x) { 138 if (! x) NoReturnDtor(); 139 *x = 47; // no warning 140 } 141 142 void noReturnInline(int **x) { 143 NoReturnDtor(); 144 } 145 146 void callNoReturn() { 147 int *x; 148 noReturnInline(&x); 149 *x = 47; // no warning 150 } 151 152 extern bool check(const NoReturnDtor &); 153 154 void testConsistencyIf(int i) { 155 if (i != 5) 156 return; 157 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { 158 clang_analyzer_eval(true); // no warning, unreachable code 159 } 160 } 161 162 void testConsistencyTernary(int i) { 163 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 164 165 clang_analyzer_eval(true); // expected-warning{{TRUE}} 166 167 if (i != 5) 168 return; 169 170 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 171 172 clang_analyzer_eval(true); // no warning, unreachable code 173 } 174 175 // Regression test: we used to assert here. 176 // PR16664 and PR18159 177 void testConsistencyNested(int i) { 178 extern bool compute(bool); 179 180 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 181 clang_analyzer_eval(true); // expected-warning{{TRUE}} 182 183 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 184 clang_analyzer_eval(true); // expected-warning{{TRUE}} 185 186 if (i != 5) 187 return; 188 189 if (compute(i == 5 && 190 (i == 4 || compute(true) || 191 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 192 i != 4) { 193 clang_analyzer_eval(true); // expected-warning{{TRUE}} 194 } 195 196 if (compute(i == 5 && 197 (i == 4 || i == 4 || 198 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 199 i != 4) { 200 clang_analyzer_eval(true); // no warning, unreachable code 201 } 202 } 203 204 // PR16664 and PR18159 205 void testConsistencyNestedSimple(bool value) { 206 if (value) { 207 if (!value || check(NoReturnDtor())) { 208 clang_analyzer_eval(true); // no warning, unreachable code 209 } 210 } 211 } 212 213 // PR16664 and PR18159 214 void testConsistencyNestedComplex(bool value) { 215 if (value) { 216 if (!value || !value || check(NoReturnDtor())) { 217 clang_analyzer_eval(true); // no warning, unreachable code 218 } 219 } 220 } 221 222 // PR16664 and PR18159 223 void testConsistencyNestedWarning(bool value) { 224 if (value) { 225 if (!value || value || check(NoReturnDtor())) { 226 clang_analyzer_eval(true); // expected-warning{{TRUE}} 227 } 228 } 229 } 230 // PR16664 and PR18159 231 void testConsistencyNestedComplexMidBranch(bool value) { 232 if (value) { 233 if (!value || !value || check(NoReturnDtor()) || value) { 234 clang_analyzer_eval(true); // no warning, unreachable code 235 } 236 } 237 } 238 239 // PR16664 and PR18159 240 void testConsistencyNestedComplexNestedBranch(bool value) { 241 if (value) { 242 if (!value || (!value || check(NoReturnDtor()) || value)) { 243 clang_analyzer_eval(true); // no warning, unreachable code 244 } 245 } 246 } 247 248 // PR16664 and PR18159 249 void testConsistencyNestedVariableModification(bool value) { 250 bool other = true; 251 if (value) { 252 if (!other || !value || (other = false) || check(NoReturnDtor()) || 253 !other) { 254 clang_analyzer_eval(true); // no warning, unreachable code 255 } 256 } 257 } 258 259 void testTernaryNoReturnTrueBranch(bool value) { 260 if (value) { 261 bool b = value && (value ? check(NoReturnDtor()) : true); 262 clang_analyzer_eval(true); // no warning, unreachable code 263 } 264 } 265 void testTernaryNoReturnFalseBranch(bool value) { 266 if (value) { 267 bool b = !value && !value ? true : check(NoReturnDtor()); 268 clang_analyzer_eval(true); // no warning, unreachable code 269 } 270 } 271 void testTernaryIgnoreNoreturnBranch(bool value) { 272 if (value) { 273 bool b = !value && !value ? check(NoReturnDtor()) : true; 274 clang_analyzer_eval(true); // expected-warning{{TRUE}} 275 } 276 } 277 void testTernaryTrueBranchReached(bool value) { 278 value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}} 279 check(NoReturnDtor()); 280 } 281 void testTernaryFalseBranchReached(bool value) { 282 value ? check(NoReturnDtor()) : 283 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 284 } 285 286 void testLoop() { 287 for (int i = 0; i < 10; ++i) { 288 if (i < 3 && (i >= 2 || check(NoReturnDtor()))) { 289 clang_analyzer_eval(true); // no warning, unreachable code 290 } 291 } 292 } 293 294 bool testRecursiveFrames(bool isInner) { 295 if (isInner || 296 (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}} 297 check(NoReturnDtor()) || 298 testRecursiveFrames(true)) { 299 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 300 } 301 } 302 void testRecursiveFramesStart() { testRecursiveFrames(false); } 303 304 void testLambdas() { 305 []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); 306 } 307 308 void testGnuExpressionStatements(int v) { 309 ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23; 310 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 311 312 ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23; 313 clang_analyzer_warnIfReached(); // no warning, unreachable code 314 } 315 316 void testGnuExpressionStatementsDestructionPoint(int v) { 317 // In normal context, the temporary destructor runs at the end of the full 318 // statement, thus the last statement is reached. 319 (++v, check(NoReturnDtor()), v == 42), 320 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 321 322 // GNU expression statements execute temporary destructors within the 323 // blocks, thus the last statement is not reached. 324 ({ ++v; check(NoReturnDtor()); v == 42; }), 325 clang_analyzer_warnIfReached(); // no warning, unreachable code 326 } 327 328 void testMultipleTemporaries(bool value) { 329 if (value) { 330 // FIXME: Find a way to verify construction order. 331 // ~Dtor should run before ~NoReturnDtor() because construction order is 332 // guaranteed by comma operator. 333 if (!value || check((NoReturnDtor(), Dtor())) || value) { 334 clang_analyzer_eval(true); // no warning, unreachable code 335 } 336 } 337 } 338 339 void testBinaryOperatorShortcut(bool value) { 340 if (value) { 341 if (false && false && check(NoReturnDtor()) && true) { 342 clang_analyzer_eval(true); 343 } 344 } 345 } 346 347 void testIfAtEndOfLoop() { 348 int y = 0; 349 while (true) { 350 if (y > 0) { 351 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 352 } 353 ++y; 354 // Test that the CFG gets hooked up correctly when temporary destructors 355 // are handled after a statically known branch condition. 356 if (true) (void)0; else (void)check(NoReturnDtor()); 357 } 358 } 359 360 void testTernaryAtEndOfLoop() { 361 int y = 0; 362 while (true) { 363 if (y > 0) { 364 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 365 } 366 ++y; 367 // Test that the CFG gets hooked up correctly when temporary destructors 368 // are handled after a statically known branch condition. 369 true ? (void)0 : (void)check(NoReturnDtor()); 370 } 371 } 372 373 void testNoReturnInComplexCondition() { 374 check(Dtor()) && 375 (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor()); 376 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 377 } 378 379 void testSequencingOfConditionalTempDtors(bool b) { 380 b || (check(Dtor()), check(NoReturnDtor())); 381 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 382 } 383 384 void testSequencingOfConditionalTempDtors2(bool b) { 385 (b || check(Dtor())), check(NoReturnDtor()); 386 clang_analyzer_warnIfReached(); // no warning, unreachable code 387 } 388 389 void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) { 390 b || (check(Dtor()) + check(NoReturnDtor())); 391 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 392 } 393 394 void f(Dtor d = Dtor()); 395 void testDefaultParameters() { 396 f(); 397 } 398 399 struct DefaultParam { 400 DefaultParam(int, const Dtor& d = Dtor()); 401 ~DefaultParam(); 402 }; 403 void testDefaultParamConstructorsInLoops() { 404 while (true) { 405 // FIXME: This exact pattern triggers the temporary cleanup logic 406 // to fail when adding a 'clean' state. 407 DefaultParam(42); 408 DefaultParam(42); 409 } 410 } 411 void testDefaultParamConstructorsInTernariesInLoops(bool value) { 412 while (true) { 413 // FIXME: This exact pattern triggers the temporary cleanup logic 414 // to visit the bind-temporary logic with a state that already has that 415 // temporary marked as executed. 416 value ? DefaultParam(42) : DefaultParam(42); 417 } 418 } 419 #else // !TEMPORARY_DTORS 420 421 // Test for fallback logic that conservatively stops exploration after 422 // executing a temporary constructor for a class with a no-return destructor 423 // when temporary destructors are not enabled in the CFG. 424 425 struct CtorWithNoReturnDtor { 426 CtorWithNoReturnDtor() = default; 427 428 CtorWithNoReturnDtor(int x) { 429 clang_analyzer_checkInlined(false); // no-warning 430 } 431 432 ~CtorWithNoReturnDtor() __attribute__((noreturn)); 433 }; 434 435 void testDefaultContructorWithNoReturnDtor() { 436 CtorWithNoReturnDtor(); 437 clang_analyzer_warnIfReached(); // no-warning 438 } 439 440 void testLifeExtensionWithNoReturnDtor() { 441 const CtorWithNoReturnDtor &c = CtorWithNoReturnDtor(); 442 443 // This represents an (expected) loss of coverage, since the destructor 444 // of the lifetime-exended temporary is executed at the end of 445 // scope. 446 clang_analyzer_warnIfReached(); // no-warning 447 } 448 449 #if __cplusplus >= 201103L 450 CtorWithNoReturnDtor returnNoReturnDtor() { 451 return {1}; // no-crash 452 } 453 #endif 454 455 #endif // TEMPORARY_DTORS 456 } 457 458 void testStaticMaterializeTemporaryExpr() { 459 static const Trivial &ref = getTrivial(); 460 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 461 462 static const Trivial &directRef = Trivial(42); 463 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 464 465 #if __has_feature(cxx_thread_local) 466 thread_local static const Trivial &threadRef = getTrivial(); 467 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 468 469 thread_local static const Trivial &threadDirectRef = Trivial(42); 470 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 471 #endif 472 } 473 474 namespace PR16629 { 475 struct A { 476 explicit A(int* p_) : p(p_) {} 477 int* p; 478 }; 479 480 extern void escape(const A*[]); 481 extern void check(int); 482 483 void callEscape(const A& a) { 484 const A* args[] = { &a }; 485 escape(args); 486 } 487 488 void testNoWarning() { 489 int x; 490 callEscape(A(&x)); 491 check(x); // Analyzer used to give a "x is uninitialized warning" here 492 } 493 494 void set(const A*a[]) { 495 *a[0]->p = 47; 496 } 497 498 void callSet(const A& a) { 499 const A* args[] = { &a }; 500 set(args); 501 } 502 503 void testConsistency() { 504 int x; 505 callSet(A(&x)); 506 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 507 } 508 } 509 510 namespace PR32088 { 511 void testReturnFromStmtExprInitializer() { 512 // We shouldn't try to destroy the object pointed to by `obj' upon return. 513 const NonTrivial &obj = ({ 514 return; // no-crash 515 NonTrivial(42); 516 }); 517 } 518 } 519 520 namespace CopyToTemporaryCorrectly { 521 class Super { 522 public: 523 void m() { 524 mImpl(); 525 } 526 virtual void mImpl() = 0; 527 }; 528 class Sub : public Super { 529 public: 530 Sub(const int &p) : j(p) {} 531 virtual void mImpl() override { 532 // Used to be undefined pointer dereference because we didn't copy 533 // the subclass data (j) to the temporary object properly. 534 (void)(j + 1); // no-warning 535 if (j != 22) { 536 clang_analyzer_warnIfReached(); // no-warning 537 } 538 } 539 const int &j; 540 }; 541 void run() { 542 int i = 22; 543 Sub(i).m(); 544 } 545 } 546 547 namespace test_return_temporary { 548 class C { 549 int x, y; 550 551 public: 552 C(int x, int y) : x(x), y(y) {} 553 int getX() const { return x; } 554 int getY() const { return y; } 555 ~C() {} 556 }; 557 558 class D: public C { 559 public: 560 D() : C(1, 2) {} 561 D(const D &d): C(d.getX(), d.getY()) {} 562 }; 563 564 C returnTemporaryWithVariable() { C c(1, 2); return c; } 565 C returnTemporaryWithAnotherFunctionWithVariable() { 566 return returnTemporaryWithVariable(); 567 } 568 C returnTemporaryWithCopyConstructionWithVariable() { 569 return C(returnTemporaryWithVariable()); 570 } 571 572 C returnTemporaryWithConstruction() { return C(1, 2); } 573 C returnTemporaryWithAnotherFunctionWithConstruction() { 574 return returnTemporaryWithConstruction(); 575 } 576 C returnTemporaryWithCopyConstructionWithConstruction() { 577 return C(returnTemporaryWithConstruction()); 578 } 579 580 D returnTemporaryWithVariableAndNonTrivialCopy() { D d; return d; } 581 D returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy() { 582 return returnTemporaryWithVariableAndNonTrivialCopy(); 583 } 584 D returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy() { 585 return D(returnTemporaryWithVariableAndNonTrivialCopy()); 586 } 587 588 #if __cplusplus >= 201103L 589 C returnTemporaryWithBraces() { return {1, 2}; } 590 C returnTemporaryWithAnotherFunctionWithBraces() { 591 return returnTemporaryWithBraces(); 592 } 593 C returnTemporaryWithCopyConstructionWithBraces() { 594 return C(returnTemporaryWithBraces()); 595 } 596 #endif // C++11 597 598 void test() { 599 C c1 = returnTemporaryWithVariable(); 600 clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} 601 clang_analyzer_eval(c1.getY() == 2); // expected-warning{{TRUE}} 602 603 C c2 = returnTemporaryWithAnotherFunctionWithVariable(); 604 clang_analyzer_eval(c2.getX() == 1); // expected-warning{{TRUE}} 605 clang_analyzer_eval(c2.getY() == 2); // expected-warning{{TRUE}} 606 607 C c3 = returnTemporaryWithCopyConstructionWithVariable(); 608 clang_analyzer_eval(c3.getX() == 1); // expected-warning{{TRUE}} 609 clang_analyzer_eval(c3.getY() == 2); // expected-warning{{TRUE}} 610 611 C c4 = returnTemporaryWithConstruction(); 612 clang_analyzer_eval(c4.getX() == 1); 613 clang_analyzer_eval(c4.getY() == 2); 614 #ifdef TEMPORARY_DTORS 615 // expected-warning@-3{{TRUE}} 616 // expected-warning@-3{{TRUE}} 617 #else 618 // expected-warning@-6{{UNKNOWN}} 619 // expected-warning@-6{{UNKNOWN}} 620 #endif 621 622 C c5 = returnTemporaryWithAnotherFunctionWithConstruction(); 623 clang_analyzer_eval(c5.getX() == 1); 624 clang_analyzer_eval(c5.getY() == 2); 625 #ifdef TEMPORARY_DTORS 626 // expected-warning@-3{{TRUE}} 627 // expected-warning@-3{{TRUE}} 628 #else 629 // expected-warning@-6{{UNKNOWN}} 630 // expected-warning@-6{{UNKNOWN}} 631 #endif 632 633 C c6 = returnTemporaryWithCopyConstructionWithConstruction(); 634 clang_analyzer_eval(c5.getX() == 1); 635 clang_analyzer_eval(c5.getY() == 2); 636 #ifdef TEMPORARY_DTORS 637 // expected-warning@-3{{TRUE}} 638 // expected-warning@-3{{TRUE}} 639 #else 640 // expected-warning@-6{{UNKNOWN}} 641 // expected-warning@-6{{UNKNOWN}} 642 #endif 643 644 #if __cplusplus >= 201103L 645 646 C c7 = returnTemporaryWithBraces(); 647 clang_analyzer_eval(c7.getX() == 1); 648 clang_analyzer_eval(c7.getY() == 2); 649 #ifdef TEMPORARY_DTORS 650 // expected-warning@-3{{TRUE}} 651 // expected-warning@-3{{TRUE}} 652 #else 653 // expected-warning@-6{{UNKNOWN}} 654 // expected-warning@-6{{UNKNOWN}} 655 #endif 656 657 C c8 = returnTemporaryWithAnotherFunctionWithBraces(); 658 clang_analyzer_eval(c8.getX() == 1); 659 clang_analyzer_eval(c8.getY() == 2); 660 #ifdef TEMPORARY_DTORS 661 // expected-warning@-3{{TRUE}} 662 // expected-warning@-3{{TRUE}} 663 #else 664 // expected-warning@-6{{UNKNOWN}} 665 // expected-warning@-6{{UNKNOWN}} 666 #endif 667 668 C c9 = returnTemporaryWithCopyConstructionWithBraces(); 669 clang_analyzer_eval(c9.getX() == 1); 670 clang_analyzer_eval(c9.getY() == 2); 671 #ifdef TEMPORARY_DTORS 672 // expected-warning@-3{{TRUE}} 673 // expected-warning@-3{{TRUE}} 674 #else 675 // expected-warning@-6{{UNKNOWN}} 676 // expected-warning@-6{{UNKNOWN}} 677 #endif 678 679 #endif // C++11 680 681 D d1 = returnTemporaryWithVariableAndNonTrivialCopy(); 682 clang_analyzer_eval(d1.getX() == 1); 683 clang_analyzer_eval(d1.getY() == 2); 684 #ifdef TEMPORARY_DTORS 685 // expected-warning@-3{{TRUE}} 686 // expected-warning@-3{{TRUE}} 687 #else 688 // expected-warning@-6{{UNKNOWN}} 689 // expected-warning@-6{{UNKNOWN}} 690 #endif 691 692 D d2 = returnTemporaryWithAnotherFunctionWithVariableAndNonTrivialCopy(); 693 clang_analyzer_eval(d2.getX() == 1); 694 clang_analyzer_eval(d2.getY() == 2); 695 #ifdef TEMPORARY_DTORS 696 // expected-warning@-3{{TRUE}} 697 // expected-warning@-3{{TRUE}} 698 #else 699 // expected-warning@-6{{UNKNOWN}} 700 // expected-warning@-6{{UNKNOWN}} 701 #endif 702 703 D d3 = returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy(); 704 clang_analyzer_eval(d3.getX() == 1); 705 clang_analyzer_eval(d3.getY() == 2); 706 #ifdef TEMPORARY_DTORS 707 // expected-warning@-3{{TRUE}} 708 // expected-warning@-3{{TRUE}} 709 #else 710 // expected-warning@-6{{UNKNOWN}} 711 // expected-warning@-6{{UNKNOWN}} 712 #endif 713 } 714 } // namespace test_return_temporary 715 716 717 namespace test_temporary_object_expr_without_dtor { 718 class C { 719 int x; 720 public: 721 C(int x) : x(x) {} 722 int getX() const { return x; } 723 }; 724 725 void test() { 726 clang_analyzer_eval(C(3).getX() == 3); // expected-warning{{TRUE}} 727 }; 728 } 729 730 namespace test_temporary_object_expr_with_dtor { 731 class C { 732 int x; 733 734 public: 735 C(int x) : x(x) {} 736 ~C() {} 737 int getX() const { return x; } 738 }; 739 740 void test(int coin) { 741 clang_analyzer_eval(C(3).getX() == 3); 742 #ifdef TEMPORARY_DTORS 743 // expected-warning@-2{{TRUE}} 744 #else 745 // expected-warning@-4{{UNKNOWN}} 746 #endif 747 748 const C &c1 = coin ? C(1) : C(2); 749 if (coin) { 750 clang_analyzer_eval(c1.getX() == 1); 751 #ifdef TEMPORARY_DTORS 752 // expected-warning@-2{{TRUE}} 753 #else 754 // expected-warning@-4{{UNKNOWN}} 755 #endif 756 } else { 757 clang_analyzer_eval(c1.getX() == 2); 758 #ifdef TEMPORARY_DTORS 759 // expected-warning@-2{{TRUE}} 760 #else 761 // expected-warning@-4{{UNKNOWN}} 762 #endif 763 } 764 765 C c2 = coin ? C(1) : C(2); 766 if (coin) { 767 clang_analyzer_eval(c2.getX() == 1); 768 #ifdef TEMPORARY_DTORS 769 // expected-warning@-2{{TRUE}} 770 #else 771 // expected-warning@-4{{UNKNOWN}} 772 #endif 773 } else { 774 clang_analyzer_eval(c2.getX() == 2); 775 #ifdef TEMPORARY_DTORS 776 // expected-warning@-2{{TRUE}} 777 #else 778 // expected-warning@-4{{UNKNOWN}} 779 #endif 780 } 781 } 782 783 } // namespace test_temporary_object_expr 784 785 namespace test_match_constructors_and_destructors { 786 class C { 787 public: 788 int &x, &y; 789 C(int &_x, int &_y) : x(_x), y(_y) { ++x; } 790 C(const C &c): x(c.x), y(c.y) { ++x; } 791 ~C() { ++y; } 792 }; 793 794 void test_simple_temporary() { 795 int x = 0, y = 0; 796 { 797 const C &c = C(x, y); 798 } 799 // One constructor and one destructor. 800 clang_analyzer_eval(x == 1); 801 clang_analyzer_eval(y == 1); 802 #ifdef TEMPORARY_DTORS 803 // expected-warning@-3{{TRUE}} 804 // expected-warning@-3{{TRUE}} 805 #else 806 // expected-warning@-6{{UNKNOWN}} 807 // expected-warning@-6{{UNKNOWN}} 808 #endif 809 } 810 811 void test_simple_temporary_with_copy() { 812 int x = 0, y = 0; 813 { 814 C c = C(x, y); 815 } 816 // Two constructors (temporary object expr and copy) and two destructors. 817 clang_analyzer_eval(x == 2); 818 clang_analyzer_eval(y == 2); 819 #ifdef TEMPORARY_DTORS 820 // expected-warning@-3{{TRUE}} 821 // expected-warning@-3{{TRUE}} 822 #else 823 // expected-warning@-6{{UNKNOWN}} 824 // expected-warning@-6{{UNKNOWN}} 825 #endif 826 } 827 828 void test_ternary_temporary(int coin) { 829 int x = 0, y = 0, z = 0, w = 0; 830 { 831 const C &c = coin ? C(x, y) : C(z, w); 832 } 833 // This time each branch contains an additional elidable copy constructor. 834 if (coin) { 835 clang_analyzer_eval(x == 2); 836 clang_analyzer_eval(y == 2); 837 #ifdef TEMPORARY_DTORS 838 // expected-warning@-3{{TRUE}} 839 // expected-warning@-3{{TRUE}} 840 #else 841 // expected-warning@-6{{UNKNOWN}} 842 // expected-warning@-6{{UNKNOWN}} 843 #endif 844 clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} 845 clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} 846 847 } else { 848 clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} 849 clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} 850 clang_analyzer_eval(z == 2); 851 clang_analyzer_eval(w == 2); 852 #ifdef TEMPORARY_DTORS 853 // expected-warning@-3{{TRUE}} 854 // expected-warning@-3{{TRUE}} 855 #else 856 // expected-warning@-6{{UNKNOWN}} 857 // expected-warning@-6{{UNKNOWN}} 858 #endif 859 } 860 } 861 862 void test_ternary_temporary_with_copy(int coin) { 863 int x = 0, y = 0, z = 0, w = 0; 864 { 865 C c = coin ? C(x, y) : C(z, w); 866 } 867 // Temporary expression, elidable copy within branch, 868 // constructor for variable - 3 total. 869 if (coin) { 870 clang_analyzer_eval(x == 3); 871 clang_analyzer_eval(y == 3); 872 #ifdef TEMPORARY_DTORS 873 // expected-warning@-3{{TRUE}} 874 // expected-warning@-3{{TRUE}} 875 #else 876 // expected-warning@-6{{UNKNOWN}} 877 // expected-warning@-6{{UNKNOWN}} 878 #endif 879 clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} 880 clang_analyzer_eval(w == 0); // expected-warning{{TRUE}} 881 882 } else { 883 clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} 884 clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} 885 clang_analyzer_eval(z == 3); 886 clang_analyzer_eval(w == 3); 887 #ifdef TEMPORARY_DTORS 888 // expected-warning@-3{{TRUE}} 889 // expected-warning@-3{{TRUE}} 890 #else 891 // expected-warning@-6{{UNKNOWN}} 892 // expected-warning@-6{{UNKNOWN}} 893 #endif 894 } 895 } 896 } // namespace test_match_constructors_and_destructors 897 898 #if __cplusplus >= 201103L 899 namespace temporary_list_crash { 900 class C { 901 public: 902 C() {} 903 ~C() {} 904 }; 905 906 void test() { 907 std::initializer_list<C>{C(), C()}; // no-crash 908 } 909 } // namespace temporary_list_crash 910 #endif // C++11 911