xref: /minix3/external/bsd/llvm/dist/clang/test/Analysis/temporaries.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
2f4a2713aSLionel Sambuc // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
3*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s -std=c++11
4f4a2713aSLionel Sambuc 
5f4a2713aSLionel Sambuc extern bool clang_analyzer_eval(bool);
6*0a6a1f1dSLionel Sambuc extern bool clang_analyzer_warnIfReached();
7f4a2713aSLionel Sambuc 
8f4a2713aSLionel Sambuc struct Trivial {
TrivialTrivial9f4a2713aSLionel Sambuc   Trivial(int x) : value(x) {}
10f4a2713aSLionel Sambuc   int value;
11f4a2713aSLionel Sambuc };
12f4a2713aSLionel Sambuc 
13f4a2713aSLionel Sambuc struct NonTrivial : public Trivial {
NonTrivialNonTrivial14f4a2713aSLionel Sambuc   NonTrivial(int x) : Trivial(x) {}
15f4a2713aSLionel Sambuc   ~NonTrivial();
16f4a2713aSLionel Sambuc };
17f4a2713aSLionel Sambuc 
18f4a2713aSLionel Sambuc 
getTrivial()19f4a2713aSLionel Sambuc Trivial getTrivial() {
20f4a2713aSLionel Sambuc   return Trivial(42); // no-warning
21f4a2713aSLionel Sambuc }
22f4a2713aSLionel Sambuc 
getTrivialRef()23f4a2713aSLionel Sambuc const Trivial &getTrivialRef() {
24f4a2713aSLionel Sambuc   return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}}
25f4a2713aSLionel Sambuc }
26f4a2713aSLionel Sambuc 
27f4a2713aSLionel Sambuc 
getNonTrivial()28f4a2713aSLionel Sambuc NonTrivial getNonTrivial() {
29f4a2713aSLionel Sambuc   return NonTrivial(42); // no-warning
30f4a2713aSLionel Sambuc }
31f4a2713aSLionel Sambuc 
getNonTrivialRef()32f4a2713aSLionel Sambuc const NonTrivial &getNonTrivialRef() {
33f4a2713aSLionel Sambuc   return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
34f4a2713aSLionel Sambuc }
35f4a2713aSLionel Sambuc 
36f4a2713aSLionel Sambuc namespace rdar13265460 {
37f4a2713aSLionel Sambuc   struct TrivialSubclass : public Trivial {
TrivialSubclassrdar13265460::TrivialSubclass38f4a2713aSLionel Sambuc     TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
39f4a2713aSLionel Sambuc     int anotherValue;
40f4a2713aSLionel Sambuc   };
41f4a2713aSLionel Sambuc 
getTrivialSub()42f4a2713aSLionel Sambuc   TrivialSubclass getTrivialSub() {
43f4a2713aSLionel Sambuc     TrivialSubclass obj(1);
44f4a2713aSLionel Sambuc     obj.value = 42;
45f4a2713aSLionel Sambuc     obj.anotherValue = -42;
46f4a2713aSLionel Sambuc     return obj;
47f4a2713aSLionel Sambuc   }
48f4a2713aSLionel Sambuc 
testImmediate()49f4a2713aSLionel Sambuc   void testImmediate() {
50f4a2713aSLionel Sambuc     TrivialSubclass obj = getTrivialSub();
51f4a2713aSLionel Sambuc 
52f4a2713aSLionel Sambuc     clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
53f4a2713aSLionel Sambuc     clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
54f4a2713aSLionel Sambuc 
55f4a2713aSLionel Sambuc     clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
56f4a2713aSLionel Sambuc     clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
57f4a2713aSLionel Sambuc   }
58f4a2713aSLionel Sambuc 
testMaterializeTemporaryExpr()59f4a2713aSLionel Sambuc   void testMaterializeTemporaryExpr() {
60f4a2713aSLionel Sambuc     const TrivialSubclass &ref = getTrivialSub();
61f4a2713aSLionel Sambuc     clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
62f4a2713aSLionel Sambuc 
63f4a2713aSLionel Sambuc     const Trivial &baseRef = getTrivialSub();
64f4a2713aSLionel Sambuc     clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}}
65f4a2713aSLionel Sambuc   }
66f4a2713aSLionel Sambuc }
67f4a2713aSLionel Sambuc 
68f4a2713aSLionel Sambuc namespace rdar13281951 {
69f4a2713aSLionel Sambuc   struct Derived : public Trivial {
Derivedrdar13281951::Derived70f4a2713aSLionel Sambuc     Derived(int value) : Trivial(value), value2(-value) {}
71f4a2713aSLionel Sambuc     int value2;
72f4a2713aSLionel Sambuc   };
73f4a2713aSLionel Sambuc 
test()74f4a2713aSLionel Sambuc   void test() {
75f4a2713aSLionel Sambuc     Derived obj(1);
76f4a2713aSLionel Sambuc     obj.value = 42;
77f4a2713aSLionel Sambuc     const Trivial * const &pointerRef = &obj;
78f4a2713aSLionel Sambuc     clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}}
79f4a2713aSLionel Sambuc   }
80f4a2713aSLionel Sambuc }
81f4a2713aSLionel Sambuc 
82f4a2713aSLionel Sambuc namespace compound_literals {
83f4a2713aSLionel Sambuc   struct POD {
84f4a2713aSLionel Sambuc     int x, y;
85f4a2713aSLionel Sambuc   };
86f4a2713aSLionel Sambuc   struct HasCtor {
HasCtorcompound_literals::HasCtor87f4a2713aSLionel Sambuc     HasCtor(int x, int y) : x(x), y(y) {}
88f4a2713aSLionel Sambuc     int x, y;
89f4a2713aSLionel Sambuc   };
90f4a2713aSLionel Sambuc   struct HasDtor {
91f4a2713aSLionel Sambuc     int x, y;
92f4a2713aSLionel Sambuc     ~HasDtor();
93f4a2713aSLionel Sambuc   };
94f4a2713aSLionel Sambuc   struct HasCtorDtor {
HasCtorDtorcompound_literals::HasCtorDtor95f4a2713aSLionel Sambuc     HasCtorDtor(int x, int y) : x(x), y(y) {}
96f4a2713aSLionel Sambuc     ~HasCtorDtor();
97f4a2713aSLionel Sambuc     int x, y;
98f4a2713aSLionel Sambuc   };
99f4a2713aSLionel Sambuc 
test()100f4a2713aSLionel Sambuc   void test() {
101f4a2713aSLionel Sambuc     clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}}
102f4a2713aSLionel Sambuc     clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}}
103f4a2713aSLionel Sambuc 
104f4a2713aSLionel Sambuc #if __cplusplus >= 201103L
105f4a2713aSLionel Sambuc     clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}}
106f4a2713aSLionel Sambuc 
107f4a2713aSLionel Sambuc     // FIXME: should be TRUE, but we don't inline the constructors of
108f4a2713aSLionel Sambuc     // temporaries because we can't model their destructors yet.
109f4a2713aSLionel Sambuc     clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}}
110f4a2713aSLionel Sambuc #endif
111f4a2713aSLionel Sambuc   }
112f4a2713aSLionel Sambuc }
113f4a2713aSLionel Sambuc 
114f4a2713aSLionel Sambuc namespace destructors {
115f4a2713aSLionel Sambuc   struct Dtor {
116f4a2713aSLionel Sambuc     ~Dtor();
117f4a2713aSLionel Sambuc   };
118f4a2713aSLionel Sambuc   extern bool coin();
119f4a2713aSLionel Sambuc   extern bool check(const Dtor &);
120f4a2713aSLionel Sambuc 
testPR16664andPR18159Crash()121*0a6a1f1dSLionel Sambuc   void testPR16664andPR18159Crash() {
122*0a6a1f1dSLionel Sambuc     // Regression test: we used to assert here when tmp dtors are enabled.
123*0a6a1f1dSLionel Sambuc     // PR16664 and PR18159
124f4a2713aSLionel Sambuc     if (coin() && (coin() || coin() || check(Dtor()))) {
125f4a2713aSLionel Sambuc       Dtor();
126f4a2713aSLionel Sambuc     }
127f4a2713aSLionel Sambuc   }
128f4a2713aSLionel Sambuc 
129f4a2713aSLionel Sambuc #ifdef TEMPORARY_DTORS
130f4a2713aSLionel Sambuc   struct NoReturnDtor {
131f4a2713aSLionel Sambuc     ~NoReturnDtor() __attribute__((noreturn));
132f4a2713aSLionel Sambuc   };
133f4a2713aSLionel Sambuc 
noReturnTemp(int * x)134f4a2713aSLionel Sambuc   void noReturnTemp(int *x) {
135f4a2713aSLionel Sambuc     if (! x) NoReturnDtor();
136f4a2713aSLionel Sambuc     *x = 47; // no warning
137f4a2713aSLionel Sambuc   }
138f4a2713aSLionel Sambuc 
noReturnInline(int ** x)139f4a2713aSLionel Sambuc   void noReturnInline(int **x) {
140f4a2713aSLionel Sambuc     NoReturnDtor();
141f4a2713aSLionel Sambuc   }
142f4a2713aSLionel Sambuc 
callNoReturn()143f4a2713aSLionel Sambuc   void callNoReturn() {
144f4a2713aSLionel Sambuc     int *x;
145f4a2713aSLionel Sambuc     noReturnInline(&x);
146f4a2713aSLionel Sambuc     *x = 47; // no warning
147f4a2713aSLionel Sambuc   }
148f4a2713aSLionel Sambuc 
149f4a2713aSLionel Sambuc   extern bool check(const NoReturnDtor &);
150f4a2713aSLionel Sambuc 
testConsistencyIf(int i)151f4a2713aSLionel Sambuc   void testConsistencyIf(int i) {
152f4a2713aSLionel Sambuc     if (i != 5)
153f4a2713aSLionel Sambuc       return;
154f4a2713aSLionel Sambuc     if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
155f4a2713aSLionel Sambuc       clang_analyzer_eval(true); // no warning, unreachable code
156f4a2713aSLionel Sambuc     }
157f4a2713aSLionel Sambuc   }
158f4a2713aSLionel Sambuc 
testConsistencyTernary(int i)159f4a2713aSLionel Sambuc   void testConsistencyTernary(int i) {
160f4a2713aSLionel Sambuc     (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
161f4a2713aSLionel Sambuc 
162f4a2713aSLionel Sambuc     clang_analyzer_eval(true);  // expected-warning{{TRUE}}
163f4a2713aSLionel Sambuc 
164f4a2713aSLionel Sambuc     if (i != 5)
165f4a2713aSLionel Sambuc       return;
166f4a2713aSLionel Sambuc 
167f4a2713aSLionel Sambuc     (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
168f4a2713aSLionel Sambuc 
169f4a2713aSLionel Sambuc     clang_analyzer_eval(true); // no warning, unreachable code
170f4a2713aSLionel Sambuc   }
171f4a2713aSLionel Sambuc 
172*0a6a1f1dSLionel Sambuc   // Regression test: we used to assert here.
173*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNested(int i)174f4a2713aSLionel Sambuc   void testConsistencyNested(int i) {
175f4a2713aSLionel Sambuc     extern bool compute(bool);
176f4a2713aSLionel Sambuc 
177f4a2713aSLionel Sambuc     if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
178f4a2713aSLionel Sambuc       clang_analyzer_eval(true);  // expected-warning{{TRUE}}
179f4a2713aSLionel Sambuc 
180*0a6a1f1dSLionel Sambuc     if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
181*0a6a1f1dSLionel Sambuc       clang_analyzer_eval(true);  // expected-warning{{TRUE}}
182*0a6a1f1dSLionel Sambuc 
183f4a2713aSLionel Sambuc     if (i != 5)
184f4a2713aSLionel Sambuc       return;
185f4a2713aSLionel Sambuc 
186f4a2713aSLionel Sambuc     if (compute(i == 5 &&
187f4a2713aSLionel Sambuc                 (i == 4 || compute(true) ||
188f4a2713aSLionel Sambuc                  compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
189f4a2713aSLionel Sambuc         i != 4) {
190f4a2713aSLionel Sambuc       clang_analyzer_eval(true);  // expected-warning{{TRUE}}
191f4a2713aSLionel Sambuc     }
192f4a2713aSLionel Sambuc 
193f4a2713aSLionel Sambuc     if (compute(i == 5 &&
194f4a2713aSLionel Sambuc                 (i == 4 || i == 4 ||
195f4a2713aSLionel Sambuc                  compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
196f4a2713aSLionel Sambuc         i != 4) {
197f4a2713aSLionel Sambuc       clang_analyzer_eval(true);  // no warning, unreachable code
198f4a2713aSLionel Sambuc     }
199f4a2713aSLionel Sambuc   }
200*0a6a1f1dSLionel Sambuc 
201*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedSimple(bool value)202*0a6a1f1dSLionel Sambuc   void testConsistencyNestedSimple(bool value) {
203*0a6a1f1dSLionel Sambuc     if (value) {
204*0a6a1f1dSLionel Sambuc       if (!value || check(NoReturnDtor())) {
205*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true); // no warning, unreachable code
206*0a6a1f1dSLionel Sambuc       }
207*0a6a1f1dSLionel Sambuc     }
208*0a6a1f1dSLionel Sambuc   }
209*0a6a1f1dSLionel Sambuc 
210*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedComplex(bool value)211*0a6a1f1dSLionel Sambuc   void testConsistencyNestedComplex(bool value) {
212*0a6a1f1dSLionel Sambuc     if (value) {
213*0a6a1f1dSLionel Sambuc       if (!value || !value || check(NoReturnDtor())) {
214*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
215*0a6a1f1dSLionel Sambuc       }
216*0a6a1f1dSLionel Sambuc     }
217*0a6a1f1dSLionel Sambuc   }
218*0a6a1f1dSLionel Sambuc 
219*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedWarning(bool value)220*0a6a1f1dSLionel Sambuc   void testConsistencyNestedWarning(bool value) {
221*0a6a1f1dSLionel Sambuc     if (value) {
222*0a6a1f1dSLionel Sambuc       if (!value || value || check(NoReturnDtor())) {
223*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true); // expected-warning{{TRUE}}
224*0a6a1f1dSLionel Sambuc       }
225*0a6a1f1dSLionel Sambuc     }
226*0a6a1f1dSLionel Sambuc   }
227*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedComplexMidBranch(bool value)228*0a6a1f1dSLionel Sambuc   void testConsistencyNestedComplexMidBranch(bool value) {
229*0a6a1f1dSLionel Sambuc     if (value) {
230*0a6a1f1dSLionel Sambuc       if (!value || !value || check(NoReturnDtor()) || value) {
231*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
232*0a6a1f1dSLionel Sambuc       }
233*0a6a1f1dSLionel Sambuc     }
234*0a6a1f1dSLionel Sambuc   }
235*0a6a1f1dSLionel Sambuc 
236*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedComplexNestedBranch(bool value)237*0a6a1f1dSLionel Sambuc   void testConsistencyNestedComplexNestedBranch(bool value) {
238*0a6a1f1dSLionel Sambuc     if (value) {
239*0a6a1f1dSLionel Sambuc       if (!value || (!value || check(NoReturnDtor()) || value)) {
240*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
241*0a6a1f1dSLionel Sambuc       }
242*0a6a1f1dSLionel Sambuc     }
243*0a6a1f1dSLionel Sambuc   }
244*0a6a1f1dSLionel Sambuc 
245*0a6a1f1dSLionel Sambuc   // PR16664 and PR18159
testConsistencyNestedVariableModification(bool value)246*0a6a1f1dSLionel Sambuc   void testConsistencyNestedVariableModification(bool value) {
247*0a6a1f1dSLionel Sambuc     bool other = true;
248*0a6a1f1dSLionel Sambuc     if (value) {
249*0a6a1f1dSLionel Sambuc       if (!other || !value || (other = false) || check(NoReturnDtor()) ||
250*0a6a1f1dSLionel Sambuc           !other) {
251*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
252*0a6a1f1dSLionel Sambuc       }
253*0a6a1f1dSLionel Sambuc     }
254*0a6a1f1dSLionel Sambuc   }
255*0a6a1f1dSLionel Sambuc 
testTernaryNoReturnTrueBranch(bool value)256*0a6a1f1dSLionel Sambuc   void testTernaryNoReturnTrueBranch(bool value) {
257*0a6a1f1dSLionel Sambuc     if (value) {
258*0a6a1f1dSLionel Sambuc       bool b = value && (value ? check(NoReturnDtor()) : true);
259*0a6a1f1dSLionel Sambuc       clang_analyzer_eval(true);  // no warning, unreachable code
260*0a6a1f1dSLionel Sambuc     }
261*0a6a1f1dSLionel Sambuc   }
testTernaryNoReturnFalseBranch(bool value)262*0a6a1f1dSLionel Sambuc   void testTernaryNoReturnFalseBranch(bool value) {
263*0a6a1f1dSLionel Sambuc     if (value) {
264*0a6a1f1dSLionel Sambuc       bool b = !value && !value ? true : check(NoReturnDtor());
265*0a6a1f1dSLionel Sambuc       clang_analyzer_eval(true);  // no warning, unreachable code
266*0a6a1f1dSLionel Sambuc     }
267*0a6a1f1dSLionel Sambuc   }
testTernaryIgnoreNoreturnBranch(bool value)268*0a6a1f1dSLionel Sambuc   void testTernaryIgnoreNoreturnBranch(bool value) {
269*0a6a1f1dSLionel Sambuc     if (value) {
270*0a6a1f1dSLionel Sambuc       bool b = !value && !value ? check(NoReturnDtor()) : true;
271*0a6a1f1dSLionel Sambuc       clang_analyzer_eval(true);  // expected-warning{{TRUE}}
272*0a6a1f1dSLionel Sambuc     }
273*0a6a1f1dSLionel Sambuc   }
testTernaryTrueBranchReached(bool value)274*0a6a1f1dSLionel Sambuc   void testTernaryTrueBranchReached(bool value) {
275*0a6a1f1dSLionel Sambuc     value ? clang_analyzer_warnIfReached() : // expected-warning{{REACHABLE}}
276*0a6a1f1dSLionel Sambuc             check(NoReturnDtor());
277*0a6a1f1dSLionel Sambuc   }
testTernaryFalseBranchReached(bool value)278*0a6a1f1dSLionel Sambuc   void testTernaryFalseBranchReached(bool value) {
279*0a6a1f1dSLionel Sambuc     value ? check(NoReturnDtor()) :
280*0a6a1f1dSLionel Sambuc             clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
281*0a6a1f1dSLionel Sambuc   }
282*0a6a1f1dSLionel Sambuc 
testLoop()283*0a6a1f1dSLionel Sambuc   void testLoop() {
284*0a6a1f1dSLionel Sambuc     for (int i = 0; i < 10; ++i) {
285*0a6a1f1dSLionel Sambuc       if (i < 3 && (i >= 2 || check(NoReturnDtor()))) {
286*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
287*0a6a1f1dSLionel Sambuc       }
288*0a6a1f1dSLionel Sambuc     }
289*0a6a1f1dSLionel Sambuc   }
290*0a6a1f1dSLionel Sambuc 
testRecursiveFrames(bool isInner)291*0a6a1f1dSLionel Sambuc   bool testRecursiveFrames(bool isInner) {
292*0a6a1f1dSLionel Sambuc     if (isInner ||
293*0a6a1f1dSLionel Sambuc         (clang_analyzer_warnIfReached(), false) || // expected-warning{{REACHABLE}}
294*0a6a1f1dSLionel Sambuc         check(NoReturnDtor()) ||
295*0a6a1f1dSLionel Sambuc         testRecursiveFrames(true)) {
296*0a6a1f1dSLionel Sambuc       clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
297*0a6a1f1dSLionel Sambuc     }
298*0a6a1f1dSLionel Sambuc   }
testRecursiveFramesStart()299*0a6a1f1dSLionel Sambuc   void testRecursiveFramesStart() { testRecursiveFrames(false); }
300*0a6a1f1dSLionel Sambuc 
testLambdas()301*0a6a1f1dSLionel Sambuc   void testLambdas() {
302*0a6a1f1dSLionel Sambuc     // This is the test we would like to write:
303*0a6a1f1dSLionel Sambuc     // []() { check(NoReturnDtor()); } != nullptr || check(Dtor());
304*0a6a1f1dSLionel Sambuc     // But currently the analyzer stops when it encounters a lambda:
305*0a6a1f1dSLionel Sambuc     [] {};
306*0a6a1f1dSLionel Sambuc     // The CFG for this now looks correct, but we still do not reach the line
307*0a6a1f1dSLionel Sambuc     // below.
308*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached(); // FIXME: Should warn.
309*0a6a1f1dSLionel Sambuc   }
310*0a6a1f1dSLionel Sambuc 
testGnuExpressionStatements(int v)311*0a6a1f1dSLionel Sambuc   void testGnuExpressionStatements(int v) {
312*0a6a1f1dSLionel Sambuc     ({ ++v; v == 10 || check(NoReturnDtor()); v == 42; }) || v == 23;
313*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
314*0a6a1f1dSLionel Sambuc 
315*0a6a1f1dSLionel Sambuc     ({ ++v; check(NoReturnDtor()); v == 42; }) || v == 23;
316*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // no warning, unreachable code
317*0a6a1f1dSLionel Sambuc   }
318*0a6a1f1dSLionel Sambuc 
testGnuExpressionStatementsDestructionPoint(int v)319*0a6a1f1dSLionel Sambuc   void testGnuExpressionStatementsDestructionPoint(int v) {
320*0a6a1f1dSLionel Sambuc     // In normal context, the temporary destructor runs at the end of the full
321*0a6a1f1dSLionel Sambuc     // statement, thus the last statement is reached.
322*0a6a1f1dSLionel Sambuc     (++v, check(NoReturnDtor()), v == 42),
323*0a6a1f1dSLionel Sambuc         clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
324*0a6a1f1dSLionel Sambuc 
325*0a6a1f1dSLionel Sambuc     // GNU expression statements execute temporary destructors within the
326*0a6a1f1dSLionel Sambuc     // blocks, thus the last statement is not reached.
327*0a6a1f1dSLionel Sambuc     ({ ++v; check(NoReturnDtor()); v == 42; }),
328*0a6a1f1dSLionel Sambuc         clang_analyzer_warnIfReached();  // no warning, unreachable code
329*0a6a1f1dSLionel Sambuc   }
330*0a6a1f1dSLionel Sambuc 
testMultipleTemporaries(bool value)331*0a6a1f1dSLionel Sambuc   void testMultipleTemporaries(bool value) {
332*0a6a1f1dSLionel Sambuc     if (value) {
333*0a6a1f1dSLionel Sambuc       // FIXME: Find a way to verify construction order.
334*0a6a1f1dSLionel Sambuc       // ~Dtor should run before ~NoReturnDtor() because construction order is
335*0a6a1f1dSLionel Sambuc       // guaranteed by comma operator.
336*0a6a1f1dSLionel Sambuc       if (!value || check((NoReturnDtor(), Dtor())) || value) {
337*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);  // no warning, unreachable code
338*0a6a1f1dSLionel Sambuc       }
339*0a6a1f1dSLionel Sambuc     }
340*0a6a1f1dSLionel Sambuc   }
341*0a6a1f1dSLionel Sambuc 
testBinaryOperatorShortcut(bool value)342*0a6a1f1dSLionel Sambuc   void testBinaryOperatorShortcut(bool value) {
343*0a6a1f1dSLionel Sambuc     if (value) {
344*0a6a1f1dSLionel Sambuc       if (false && false && check(NoReturnDtor()) && true) {
345*0a6a1f1dSLionel Sambuc         clang_analyzer_eval(true);
346*0a6a1f1dSLionel Sambuc       }
347*0a6a1f1dSLionel Sambuc     }
348*0a6a1f1dSLionel Sambuc   }
349*0a6a1f1dSLionel Sambuc 
testIfAtEndOfLoop()350*0a6a1f1dSLionel Sambuc   void testIfAtEndOfLoop() {
351*0a6a1f1dSLionel Sambuc     int y = 0;
352*0a6a1f1dSLionel Sambuc     while (true) {
353*0a6a1f1dSLionel Sambuc       if (y > 0) {
354*0a6a1f1dSLionel Sambuc         clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
355*0a6a1f1dSLionel Sambuc       }
356*0a6a1f1dSLionel Sambuc       ++y;
357*0a6a1f1dSLionel Sambuc       // Test that the CFG gets hooked up correctly when temporary destructors
358*0a6a1f1dSLionel Sambuc       // are handled after a statically known branch condition.
359*0a6a1f1dSLionel Sambuc       if (true) (void)0; else (void)check(NoReturnDtor());
360*0a6a1f1dSLionel Sambuc     }
361*0a6a1f1dSLionel Sambuc   }
362*0a6a1f1dSLionel Sambuc 
testTernaryAtEndOfLoop()363*0a6a1f1dSLionel Sambuc   void testTernaryAtEndOfLoop() {
364*0a6a1f1dSLionel Sambuc     int y = 0;
365*0a6a1f1dSLionel Sambuc     while (true) {
366*0a6a1f1dSLionel Sambuc       if (y > 0) {
367*0a6a1f1dSLionel Sambuc         clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
368*0a6a1f1dSLionel Sambuc       }
369*0a6a1f1dSLionel Sambuc       ++y;
370*0a6a1f1dSLionel Sambuc       // Test that the CFG gets hooked up correctly when temporary destructors
371*0a6a1f1dSLionel Sambuc       // are handled after a statically known branch condition.
372*0a6a1f1dSLionel Sambuc       true ? (void)0 : (void)check(NoReturnDtor());
373*0a6a1f1dSLionel Sambuc     }
374*0a6a1f1dSLionel Sambuc   }
375*0a6a1f1dSLionel Sambuc 
testNoReturnInComplexCondition()376*0a6a1f1dSLionel Sambuc   void testNoReturnInComplexCondition() {
377*0a6a1f1dSLionel Sambuc     check(Dtor()) &&
378*0a6a1f1dSLionel Sambuc         (check(NoReturnDtor()) || check(NoReturnDtor())) && check(Dtor());
379*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
380*0a6a1f1dSLionel Sambuc   }
381*0a6a1f1dSLionel Sambuc 
testSequencingOfConditionalTempDtors(bool b)382*0a6a1f1dSLionel Sambuc   void testSequencingOfConditionalTempDtors(bool b) {
383*0a6a1f1dSLionel Sambuc     b || (check(Dtor()), check(NoReturnDtor()));
384*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
385*0a6a1f1dSLionel Sambuc   }
386*0a6a1f1dSLionel Sambuc 
testSequencingOfConditionalTempDtors2(bool b)387*0a6a1f1dSLionel Sambuc   void testSequencingOfConditionalTempDtors2(bool b) {
388*0a6a1f1dSLionel Sambuc     (b || check(Dtor())), check(NoReturnDtor());
389*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // no warning, unreachable code
390*0a6a1f1dSLionel Sambuc   }
391*0a6a1f1dSLionel Sambuc 
testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b)392*0a6a1f1dSLionel Sambuc   void testSequencingOfConditionalTempDtorsWithinBinaryOperators(bool b) {
393*0a6a1f1dSLionel Sambuc     b || (check(Dtor()) + check(NoReturnDtor()));
394*0a6a1f1dSLionel Sambuc     clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
395*0a6a1f1dSLionel Sambuc   }
396*0a6a1f1dSLionel Sambuc 
397*0a6a1f1dSLionel Sambuc   void f(Dtor d = Dtor());
testDefaultParameters()398*0a6a1f1dSLionel Sambuc   void testDefaultParameters() {
399*0a6a1f1dSLionel Sambuc     f();
400*0a6a1f1dSLionel Sambuc   }
401*0a6a1f1dSLionel Sambuc 
402*0a6a1f1dSLionel Sambuc   struct DefaultParam {
403*0a6a1f1dSLionel Sambuc     DefaultParam(int, const Dtor& d = Dtor());
404*0a6a1f1dSLionel Sambuc     ~DefaultParam();
405*0a6a1f1dSLionel Sambuc   };
testDefaultParamConstructorsInLoops()406*0a6a1f1dSLionel Sambuc   void testDefaultParamConstructorsInLoops() {
407*0a6a1f1dSLionel Sambuc     while (true) {
408*0a6a1f1dSLionel Sambuc       // FIXME: This exact pattern triggers the temporary cleanup logic
409*0a6a1f1dSLionel Sambuc       // to fail when adding a 'clean' state.
410*0a6a1f1dSLionel Sambuc       DefaultParam(42);
411*0a6a1f1dSLionel Sambuc       DefaultParam(42);
412*0a6a1f1dSLionel Sambuc     }
413*0a6a1f1dSLionel Sambuc   }
testDefaultParamConstructorsInTernariesInLoops(bool value)414*0a6a1f1dSLionel Sambuc   void testDefaultParamConstructorsInTernariesInLoops(bool value) {
415*0a6a1f1dSLionel Sambuc     while (true) {
416*0a6a1f1dSLionel Sambuc       // FIXME: This exact pattern triggers the temporary cleanup logic
417*0a6a1f1dSLionel Sambuc       // to visit the bind-temporary logic with a state that already has that
418*0a6a1f1dSLionel Sambuc       // temporary marked as executed.
419*0a6a1f1dSLionel Sambuc       value ? DefaultParam(42) : DefaultParam(42);
420*0a6a1f1dSLionel Sambuc     }
421*0a6a1f1dSLionel Sambuc   }
422f4a2713aSLionel Sambuc #endif // TEMPORARY_DTORS
423f4a2713aSLionel Sambuc }
424f4a2713aSLionel Sambuc 
testStaticMaterializeTemporaryExpr()425f4a2713aSLionel Sambuc void testStaticMaterializeTemporaryExpr() {
426f4a2713aSLionel Sambuc   static const Trivial &ref = getTrivial();
427f4a2713aSLionel Sambuc   clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
428f4a2713aSLionel Sambuc 
429f4a2713aSLionel Sambuc   static const Trivial &directRef = Trivial(42);
430f4a2713aSLionel Sambuc   clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
431f4a2713aSLionel Sambuc 
432f4a2713aSLionel Sambuc #if __has_feature(cxx_thread_local)
433f4a2713aSLionel Sambuc   thread_local static const Trivial &threadRef = getTrivial();
434f4a2713aSLionel Sambuc   clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
435f4a2713aSLionel Sambuc 
436f4a2713aSLionel Sambuc   thread_local static const Trivial &threadDirectRef = Trivial(42);
437f4a2713aSLionel Sambuc   clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
438f4a2713aSLionel Sambuc #endif
439f4a2713aSLionel Sambuc }
440f4a2713aSLionel Sambuc 
441f4a2713aSLionel Sambuc namespace PR16629 {
442f4a2713aSLionel Sambuc   struct A {
APR16629::A443f4a2713aSLionel Sambuc     explicit A(int* p_) : p(p_) {}
444f4a2713aSLionel Sambuc     int* p;
445f4a2713aSLionel Sambuc   };
446f4a2713aSLionel Sambuc 
447f4a2713aSLionel Sambuc   extern void escape(const A*[]);
448f4a2713aSLionel Sambuc   extern void check(int);
449f4a2713aSLionel Sambuc 
callEscape(const A & a)450f4a2713aSLionel Sambuc   void callEscape(const A& a) {
451f4a2713aSLionel Sambuc     const A* args[] = { &a };
452f4a2713aSLionel Sambuc     escape(args);
453f4a2713aSLionel Sambuc   }
454f4a2713aSLionel Sambuc 
testNoWarning()455f4a2713aSLionel Sambuc   void testNoWarning() {
456f4a2713aSLionel Sambuc     int x;
457f4a2713aSLionel Sambuc     callEscape(A(&x));
458f4a2713aSLionel Sambuc     check(x); // Analyzer used to give a "x is uninitialized warning" here
459f4a2713aSLionel Sambuc   }
460f4a2713aSLionel Sambuc 
set(const A * a[])461f4a2713aSLionel Sambuc   void set(const A*a[]) {
462f4a2713aSLionel Sambuc     *a[0]->p = 47;
463f4a2713aSLionel Sambuc   }
464f4a2713aSLionel Sambuc 
callSet(const A & a)465f4a2713aSLionel Sambuc   void callSet(const A& a) {
466f4a2713aSLionel Sambuc     const A* args[] = { &a };
467f4a2713aSLionel Sambuc     set(args);
468f4a2713aSLionel Sambuc   }
469f4a2713aSLionel Sambuc 
testConsistency()470f4a2713aSLionel Sambuc   void testConsistency() {
471f4a2713aSLionel Sambuc     int x;
472f4a2713aSLionel Sambuc     callSet(A(&x));
473f4a2713aSLionel Sambuc     clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
474f4a2713aSLionel Sambuc   }
475f4a2713aSLionel Sambuc }
476