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&); };
9 void f(X x) { (void) [x]{}; }
10 
11 
12 // Lambda semantics tests.
13 
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 
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 
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 
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 
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 
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 
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 
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 
163 void inc(int &x) {
164   ++x;
165 }
166 
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 
177 // Test inline defensive checks
178 int getNum();
179 
180 void inlineDefensiveChecks() {
181   int i = getNum();
182   [=]() {
183     if (i == 0)
184       ;
185   }();
186   int p = 5/i;
187   (void)p;
188 }
189 
190 
191 template<typename T>
192 void callLambda(T t) {
193   t();
194 }
195 
196 struct DontCrash {
197   int x;
198   void f() {
199     callLambda([&](){ ++x; });
200     callLambdaFromStatic([&](){ ++x; });
201   }
202 
203   template<typename T>
204   static void callLambdaFromStatic(T t) {
205     t();
206   }
207 };
208 
209 
210 // Capture constants
211 
212 void captureConstants() {
213   const int i = 5;
214   [=]() {
215     if (i != 5)
216       clang_analyzer_warnIfReached();
217   }();
218   [&] {
219     if (i != 5)
220       clang_analyzer_warnIfReached();
221   }();
222 }
223 
224 void captureReferenceByCopy(int &p) {
225   int v = 7;
226   p = 8;
227 
228   // p is a reference captured by copy
229   [&v,p]() mutable {
230     v = p;
231     p = 22;
232   }();
233 
234   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
235   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
236 }
237 
238 void captureReferenceByReference(int &p) {
239   int v = 7;
240   p = 8;
241 
242   // p is a reference captured by reference
243   [&v,&p]() {
244     v = p;
245     p = 22;
246   }();
247 
248   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
249   clang_analyzer_eval(p == 22); // expected-warning{{TRUE}}
250 }
251 
252 void callMutableLambdaMultipleTimes(int &p) {
253   int v = 0;
254   p = 8;
255 
256   auto l = [&v, p]() mutable {
257     v = p;
258     p++;
259   };
260 
261   l();
262 
263   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
264   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
265 
266   l();
267 
268   clang_analyzer_eval(v == 9); // expected-warning{{TRUE}}
269   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
270 }
271 
272 // PR 24914
273 struct StructPR24914{
274   int x;
275 };
276 
277 void takesConstStructArgument(const StructPR24914&);
278 void captureStructReference(const StructPR24914& s) {
279   [s]() {
280     takesConstStructArgument(s);
281   }();
282 }
283 
284 // Lambda capture counts as use for dead-store checking.
285 
286 int returnsValue();
287 
288 void captureByCopyCausesUse() {
289   int local1 = returnsValue(); // no-warning
290   int local2 = returnsValue(); // no-warning
291   int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
292 
293   (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
294 
295   int local4 = returnsValue(); // no-warning
296   int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
297 
298   (void)[=]() {
299     (void)local4; // Implicit capture by copy counts as use
300   };
301 }
302 
303 void captureByReference() {
304   int local1 = returnsValue(); // no-warning
305 
306   auto lambda1 = [&local1]() { // Explicit capture by reference
307     local1++;
308   };
309 
310   // Don't treat as a dead store because local1 was was captured by reference.
311   local1 = 7; // no-warning
312 
313   lambda1();
314 
315   int local2 = returnsValue(); // no-warning
316 
317   auto lambda2 = [&]() {
318     local2++; // Implicit capture by reference
319   };
320 
321   // Don't treat as a dead store because local2 was was captured by reference.
322   local2 = 7; // no-warning
323 
324   lambda2();
325 }
326 
327 
328 // CHECK: [B2 (ENTRY)]
329 // CHECK:   Succs (1): B1
330 // CHECK: [B1]
331 // CHECK:   1: x
332 // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
333 // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
334 // CHECK:   4: [x]     {
335 // CHECK:    }
336 // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
337 // CHECK:   Preds (1): B2
338 // CHECK:   Succs (1): B0
339 // CHECK: [B0 (EXIT)]
340 // CHECK:   Preds (1): B1
341 
342