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&); };
__anon597162750102null9 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