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