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