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