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