Clang Project

clang_source_code/test/Analysis/lambdas.cpp
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
6void clang_analyzer_warnIfReached();
7void clang_analyzer_eval(int);
8
9#ifdef NO_INLINING
10
11// expected-no-diagnostics
12
13int& 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
24struct X { X(const X&); };
25void f(X x) { (void) [x]{}; }
26
27
28// Lambda semantics tests.
29
30void 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
50void 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
72void 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
100void 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
109void 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
122void 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
137class RandomClass {
138  int i;
139
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
155class RandomClass2 {
156  int i;
157
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
179void inc(int &x) {
180  ++x;
181}
182
183void 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
194void 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
207int getNum();
208
209void inlineDefensiveChecks() {
210  int i = getNum();
211  [=]() {
212    if (i == 0)
213      ;
214  }();
215  int p = 5/i;
216  (void)p;
217}
218
219
220template<typename T>
221void callLambda(T t) {
222  t();
223}
224
225struct DontCrash {
226  int x;
227  void f() {
228    callLambda([&](){ ++x; });
229    callLambdaFromStatic([&](){ ++x; });
230  }
231
232  template<typename T>
233  static void callLambdaFromStatic(T t) {
234    t();
235  }
236};
237
238
239// Capture constants
240
241void 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
253void 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
267void 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
281void 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
302struct StructPR24914{
303  int x;
304};
305
306void takesConstStructArgument(const StructPR24914&);
307void captureStructReference(const StructPR24914& s) {
308  [s]() {
309    takesConstStructArgument(s);
310  }();
311}
312
313// Lambda capture counts as use for dead-store checking.
314
315int returnsValue();
316
317void 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
332void 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
356void 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
367void escape(void*);
368
369int& 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
380static int b = 0;
381
382int 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