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