1 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,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&); };
9 void f(X x) { (void) [x]{}; }
10 
11 
12 // Lambda semantics tests.
13 
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 
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 
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 
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 
93 // Nested lambdas.
94 
95 void testNestedLambdas() {
96   int i = 5;
97   auto l = [i]() mutable {
98     [&i]() {
99       ++i;
100     }();
101     if (i != 6)
102       clang_analyzer_warnIfReached();
103   };
104   l();
105   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
106 }
107 
108 // Captured this.
109 
110 class RandomClass {
111   int i;
112 
113   void captureFields() {
114     i = 5;
115     [this]() {
116       // clang_analyzer_eval does nothing in inlined functions.
117       if (i != 5)
118         clang_analyzer_warnIfReached();
119       ++i;
120     }();
121     clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
122   }
123 };
124 
125 
126 // Nested this capture.
127 
128 class RandomClass2 {
129   int i;
130 
131   void captureFields() {
132     i = 5;
133     [this]() {
134       // clang_analyzer_eval does nothing in inlined functions.
135       if (i != 5)
136         clang_analyzer_warnIfReached();
137       ++i;
138       [this]() {
139         // clang_analyzer_eval does nothing in inlined functions.
140         if (i != 6)
141           clang_analyzer_warnIfReached();
142         ++i;
143       }();
144     }();
145     clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
146   }
147 };
148 
149 
150 // Captured function pointers.
151 
152 void inc(int &x) {
153   ++x;
154 }
155 
156 void testFunctionPointerCapture() {
157   void (*func)(int &) = inc;
158   int i = 5;
159   [&i, func] {
160     func(i);
161   }();
162   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
163 }
164 
165 
166 // Test inline defensive checks
167 int getNum();
168 
169 void inlineDefensiveChecks() {
170   int i = getNum();
171   [=]() {
172     if (i == 0)
173       ;
174   }();
175   int p = 5/i;
176   (void)p;
177 }
178 
179 
180 template<typename T>
181 void callLambda(T t) {
182   t();
183 }
184 
185 struct DontCrash {
186   int x;
187   void f() {
188     callLambda([&](){ ++x; });
189     callLambdaFromStatic([&](){ ++x; });
190   }
191 
192   template<typename T>
193   static void callLambdaFromStatic(T t) {
194     t();
195   }
196 };
197 
198 
199 // Capture constants
200 
201 void captureConstants() {
202   const int i = 5;
203   [=]() {
204     if (i != 5)
205       clang_analyzer_warnIfReached();
206   }();
207   [&] {
208     if (i != 5)
209       clang_analyzer_warnIfReached();
210   }();
211 }
212 
213 // CHECK: [B2 (ENTRY)]
214 // CHECK:   Succs (1): B1
215 // CHECK: [B1]
216 // CHECK:   1: x
217 // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
218 // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
219 // CHECK:   4: [x]     {
220 // CHECK:    }
221 // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
222 // CHECK:   Preds (1): B2
223 // CHECK:   Succs (1): B0
224 // CHECK: [B0 (EXIT)]
225 // CHECK:   Preds (1): B1
226 
227