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
5void clang_analyzer_warnIfReached();
6void clang_analyzer_eval(int);
7
8struct X { X(const X&); };
9void f(X x) { (void) [x]{}; }
10
11
12// Lambda semantics tests.
13
14void 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
34void 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
56void 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
84void 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
93void 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
106void 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
121class 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
139class 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
163void inc(int &x) {
164  ++x;
165}
166
167void 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
178void 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
191int getNum();
192
193void inlineDefensiveChecks() {
194  int i = getNum();
195  [=]() {
196    if (i == 0)
197      ;
198  }();
199  int p = 5/i;
200  (void)p;
201}
202
203
204template<typename T>
205void callLambda(T t) {
206  t();
207}
208
209struct DontCrash {
210  int x;
211  void f() {
212    callLambda([&](){ ++x; });
213    callLambdaFromStatic([&](){ ++x; });
214  }
215
216  template<typename T>
217  static void callLambdaFromStatic(T t) {
218    t();
219  }
220};
221
222
223// Capture constants
224
225void 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
237void 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
251void 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
265void 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
286struct StructPR24914{
287  int x;
288};
289
290void takesConstStructArgument(const StructPR24914&);
291void captureStructReference(const StructPR24914& s) {
292  [s]() {
293    takesConstStructArgument(s);
294  }();
295}
296
297// Lambda capture counts as use for dead-store checking.
298
299int returnsValue();
300
301void 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
316void 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