1 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
2 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core -analyzer-config inline-lambdas=false -DNO_INLINING=1 -verify %s
3 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
4 // RUN: FileCheck --input-file=%t %s
5 
6 void clang_analyzer_warnIfReached();
7 void clang_analyzer_eval(int);
8 
9 #ifdef NO_INLINING
10 
11 // expected-no-diagnostics
12 
invalidate_static_on_unknown_lambda()13 int& invalidate_static_on_unknown_lambda() {
14   static int* z;
15   auto f = [] {
16     z = nullptr;
17   }; // should invalidate "z" when inlining is disabled.
18   f();
19   return *z; // no-warning
20 }
21 
22 #else
23 
24 struct X { X(const X&); };
f(X x)25 void f(X x) { (void) [x]{}; }
26 
27 
28 // Lambda semantics tests.
29 
basicCapture()30 void basicCapture() {
31   int i = 5;
32   [i]() mutable {
33     // clang_analyzer_eval does nothing in inlined functions.
34     if (i != 5)
35       clang_analyzer_warnIfReached();
36     ++i;
37   }();
38   [&i] {
39     if (i != 5)
40       clang_analyzer_warnIfReached();
41   }();
42   [&i] {
43     if (i != 5)
44       clang_analyzer_warnIfReached();
45     i++;
46   }();
47   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
48 }
49 
deferredLambdaCall()50 void deferredLambdaCall() {
51   int i = 5;
52   auto l1 = [i]() mutable {
53     if (i != 5)
54       clang_analyzer_warnIfReached();
55     ++i;
56   };
57   auto l2 = [&i] {
58     if (i != 5)
59       clang_analyzer_warnIfReached();
60   };
61   auto l3 = [&i] {
62     if (i != 5)
63       clang_analyzer_warnIfReached();
64     i++;
65   };
66   l1();
67   l2();
68   l3();
69   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
70 }
71 
multipleCaptures()72 void multipleCaptures() {
73   int i = 5, j = 5;
74   [i, &j]() mutable {
75     if (i != 5 && j != 5)
76       clang_analyzer_warnIfReached();
77     ++i;
78     ++j;
79   }();
80   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
81   clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
82   [=]() mutable {
83     if (i != 5 && j != 6)
84       clang_analyzer_warnIfReached();
85     ++i;
86     ++j;
87   }();
88   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
89   clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
90   [&]() mutable {
91     if (i != 5 && j != 6)
92       clang_analyzer_warnIfReached();
93     ++i;
94     ++j;
95   }();
96   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
97   clang_analyzer_eval(j == 7); // expected-warning{{TRUE}}
98 }
99 
testReturnValue()100 void testReturnValue() {
101   int i = 5;
102   auto l = [i] (int a) {
103     return i + a;
104   };
105   int b = l(3);
106   clang_analyzer_eval(b == 8); // expected-warning{{TRUE}}
107 }
108 
testAliasingBetweenParameterAndCapture()109 void testAliasingBetweenParameterAndCapture() {
110   int i = 5;
111 
112   auto l = [&i](int &p) {
113     i++;
114     p++;
115   };
116   l(i);
117   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
118 }
119 
120 // Nested lambdas.
121 
testNestedLambdas()122 void testNestedLambdas() {
123   int i = 5;
124   auto l = [i]() mutable {
125     [&i]() {
126       ++i;
127     }();
128     if (i != 6)
129       clang_analyzer_warnIfReached();
130   };
131   l();
132   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
133 }
134 
135 // Captured this.
136 
137 class RandomClass {
138   int i;
139 
captureFields()140   void captureFields() {
141     i = 5;
142     [this]() {
143       // clang_analyzer_eval does nothing in inlined functions.
144       if (i != 5)
145         clang_analyzer_warnIfReached();
146       ++i;
147     }();
148     clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
149   }
150 };
151 
152 
153 // Nested this capture.
154 
155 class RandomClass2 {
156   int i;
157 
captureFields()158   void captureFields() {
159     i = 5;
160     [this]() {
161       // clang_analyzer_eval does nothing in inlined functions.
162       if (i != 5)
163         clang_analyzer_warnIfReached();
164       ++i;
165       [this]() {
166         // clang_analyzer_eval does nothing in inlined functions.
167         if (i != 6)
168           clang_analyzer_warnIfReached();
169         ++i;
170       }();
171     }();
172     clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
173   }
174 };
175 
176 
177 // Captured function pointers.
178 
inc(int & x)179 void inc(int &x) {
180   ++x;
181 }
182 
testFunctionPointerCapture()183 void testFunctionPointerCapture() {
184   void (*func)(int &) = inc;
185   int i = 5;
186   [&i, func] {
187     func(i);
188   }();
189   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
190 }
191 
192 // Captured variable-length array.
193 
testVariableLengthArrayCaptured()194 void testVariableLengthArrayCaptured() {
195   int n = 2;
196   int array[n];
197   array[0] = 7;
198 
199   int i = [&]{
200     return array[0];
201   }();
202 
203   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
204 }
205 
206 // Test inline defensive checks
207 int getNum();
208 
inlineDefensiveChecks()209 void inlineDefensiveChecks() {
210   int i = getNum();
211   [=]() {
212     if (i == 0)
213       ;
214   }();
215   int p = 5/i;
216   (void)p;
217 }
218 
219 
220 template<typename T>
callLambda(T t)221 void callLambda(T t) {
222   t();
223 }
224 
225 struct DontCrash {
226   int x;
fDontCrash227   void f() {
228     callLambda([&](){ ++x; });
229     callLambdaFromStatic([&](){ ++x; });
230   }
231 
232   template<typename T>
callLambdaFromStaticDontCrash233   static void callLambdaFromStatic(T t) {
234     t();
235   }
236 };
237 
238 
239 // Capture constants
240 
captureConstants()241 void captureConstants() {
242   const int i = 5;
243   [=]() {
244     if (i != 5)
245       clang_analyzer_warnIfReached();
246   }();
247   [&] {
248     if (i != 5)
249       clang_analyzer_warnIfReached();
250   }();
251 }
252 
captureReferenceByCopy(int & p)253 void captureReferenceByCopy(int &p) {
254   int v = 7;
255   p = 8;
256 
257   // p is a reference captured by copy
258   [&v,p]() mutable {
259     v = p;
260     p = 22;
261   }();
262 
263   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
264   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
265 }
266 
captureReferenceByReference(int & p)267 void captureReferenceByReference(int &p) {
268   int v = 7;
269   p = 8;
270 
271   // p is a reference captured by reference
272   [&v,&p]() {
273     v = p;
274     p = 22;
275   }();
276 
277   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
278   clang_analyzer_eval(p == 22); // expected-warning{{TRUE}}
279 }
280 
callMutableLambdaMultipleTimes(int & p)281 void callMutableLambdaMultipleTimes(int &p) {
282   int v = 0;
283   p = 8;
284 
285   auto l = [&v, p]() mutable {
286     v = p;
287     p++;
288   };
289 
290   l();
291 
292   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
293   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
294 
295   l();
296 
297   clang_analyzer_eval(v == 9); // expected-warning{{TRUE}}
298   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
299 }
300 
301 // PR 24914
302 struct StructPR24914{
303   int x;
304 };
305 
306 void takesConstStructArgument(const StructPR24914&);
captureStructReference(const StructPR24914 & s)307 void captureStructReference(const StructPR24914& s) {
308   [s]() {
309     takesConstStructArgument(s);
310   }();
311 }
312 
313 // Lambda capture counts as use for dead-store checking.
314 
315 int returnsValue();
316 
captureByCopyCausesUse()317 void captureByCopyCausesUse() {
318   int local1 = returnsValue(); // no-warning
319   int local2 = returnsValue(); // no-warning
320   int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
321 
322   (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
323 
324   int local4 = returnsValue(); // no-warning
325   int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
326 
327   (void)[=]() {
328     (void)local4; // Implicit capture by copy counts as use
329   };
330 }
331 
captureByReference()332 void captureByReference() {
333   int local1 = returnsValue(); // no-warning
334 
335   auto lambda1 = [&local1]() { // Explicit capture by reference
336     local1++;
337   };
338 
339   // Don't treat as a dead store because local1 was was captured by reference.
340   local1 = 7; // no-warning
341 
342   lambda1();
343 
344   int local2 = returnsValue(); // no-warning
345 
346   auto lambda2 = [&]() {
347     local2++; // Implicit capture by reference
348   };
349 
350   // Don't treat as a dead store because local2 was was captured by reference.
351   local2 = 7; // no-warning
352 
353   lambda2();
354 }
355 
testCapturedConstExprFloat()356 void testCapturedConstExprFloat() {
357   constexpr float localConstant = 4.0;
358   auto lambda = []{
359     // Don't treat localConstant as containing a garbage value
360     float copy = localConstant; // no-warning
361     (void)copy;
362   };
363 
364   lambda();
365 }
366 
367 void escape(void*);
368 
invalidate_static_on_unknown_lambda()369 int& invalidate_static_on_unknown_lambda() {
370   static int* z;
371   auto lambda = [] {
372     static float zz;
373     z = new int(120);
374   };
375   escape(&lambda);
376   return *z; // no-warning
377 }
378 
379 
380 static int b = 0;
381 
f()382 int f() {
383   b = 0;
384   auto &bm = b;
385   [&] {
386     bm++;
387     bm++;
388   }();
389   if (bm != 2) {
390     int *y = 0;
391     return *y; // no-warning
392   }
393   return 0;
394 }
395 
396 #endif
397 
398 // CHECK: [B2 (ENTRY)]
399 // CHECK:   Succs (1): B1
400 // CHECK: [B1]
401 // CHECK:   1: x
402 // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
403 // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
404 // CHECK:   4: [x]     {
405 // CHECK:    }
406 // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
407 // CHECK:   Preds (1): B2
408 // CHECK:   Succs (1): B0
409 // CHECK: [B0 (EXIT)]
410 // CHECK:   Preds (1): B1
411 
412