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