xref: /aosp_15_r20/external/clang/test/Analysis/lambdas.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
2*67e74705SXin Li // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
3*67e74705SXin Li // RUN: FileCheck --input-file=%t %s
4*67e74705SXin Li 
5*67e74705SXin Li void clang_analyzer_warnIfReached();
6*67e74705SXin Li void clang_analyzer_eval(int);
7*67e74705SXin Li 
8*67e74705SXin Li struct X { X(const X&); };
__anoncb3f37620102null9*67e74705SXin Li void f(X x) { (void) [x]{}; }
10*67e74705SXin Li 
11*67e74705SXin Li 
12*67e74705SXin Li // Lambda semantics tests.
13*67e74705SXin Li 
basicCapture()14*67e74705SXin Li void basicCapture() {
15*67e74705SXin Li   int i = 5;
16*67e74705SXin Li   [i]() mutable {
17*67e74705SXin Li     // clang_analyzer_eval does nothing in inlined functions.
18*67e74705SXin Li     if (i != 5)
19*67e74705SXin Li       clang_analyzer_warnIfReached();
20*67e74705SXin Li     ++i;
21*67e74705SXin Li   }();
22*67e74705SXin Li   [&i] {
23*67e74705SXin Li     if (i != 5)
24*67e74705SXin Li       clang_analyzer_warnIfReached();
25*67e74705SXin Li   }();
26*67e74705SXin Li   [&i] {
27*67e74705SXin Li     if (i != 5)
28*67e74705SXin Li       clang_analyzer_warnIfReached();
29*67e74705SXin Li     i++;
30*67e74705SXin Li   }();
31*67e74705SXin Li   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
32*67e74705SXin Li }
33*67e74705SXin Li 
deferredLambdaCall()34*67e74705SXin Li void deferredLambdaCall() {
35*67e74705SXin Li   int i = 5;
36*67e74705SXin Li   auto l1 = [i]() mutable {
37*67e74705SXin Li     if (i != 5)
38*67e74705SXin Li       clang_analyzer_warnIfReached();
39*67e74705SXin Li     ++i;
40*67e74705SXin Li   };
41*67e74705SXin Li   auto l2 = [&i] {
42*67e74705SXin Li     if (i != 5)
43*67e74705SXin Li       clang_analyzer_warnIfReached();
44*67e74705SXin Li   };
45*67e74705SXin Li   auto l3 = [&i] {
46*67e74705SXin Li     if (i != 5)
47*67e74705SXin Li       clang_analyzer_warnIfReached();
48*67e74705SXin Li     i++;
49*67e74705SXin Li   };
50*67e74705SXin Li   l1();
51*67e74705SXin Li   l2();
52*67e74705SXin Li   l3();
53*67e74705SXin Li   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
54*67e74705SXin Li }
55*67e74705SXin Li 
multipleCaptures()56*67e74705SXin Li void multipleCaptures() {
57*67e74705SXin Li   int i = 5, j = 5;
58*67e74705SXin Li   [i, &j]() mutable {
59*67e74705SXin Li     if (i != 5 && j != 5)
60*67e74705SXin Li       clang_analyzer_warnIfReached();
61*67e74705SXin Li     ++i;
62*67e74705SXin Li     ++j;
63*67e74705SXin Li   }();
64*67e74705SXin Li   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
65*67e74705SXin Li   clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
66*67e74705SXin Li   [=]() mutable {
67*67e74705SXin Li     if (i != 5 && j != 6)
68*67e74705SXin Li       clang_analyzer_warnIfReached();
69*67e74705SXin Li     ++i;
70*67e74705SXin Li     ++j;
71*67e74705SXin Li   }();
72*67e74705SXin Li   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
73*67e74705SXin Li   clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
74*67e74705SXin Li   [&]() mutable {
75*67e74705SXin Li     if (i != 5 && j != 6)
76*67e74705SXin Li       clang_analyzer_warnIfReached();
77*67e74705SXin Li     ++i;
78*67e74705SXin Li     ++j;
79*67e74705SXin Li   }();
80*67e74705SXin Li   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
81*67e74705SXin Li   clang_analyzer_eval(j == 7); // expected-warning{{TRUE}}
82*67e74705SXin Li }
83*67e74705SXin Li 
testReturnValue()84*67e74705SXin Li void testReturnValue() {
85*67e74705SXin Li   int i = 5;
86*67e74705SXin Li   auto l = [i] (int a) {
87*67e74705SXin Li     return i + a;
88*67e74705SXin Li   };
89*67e74705SXin Li   int b = l(3);
90*67e74705SXin Li   clang_analyzer_eval(b == 8); // expected-warning{{TRUE}}
91*67e74705SXin Li }
92*67e74705SXin Li 
testAliasingBetweenParameterAndCapture()93*67e74705SXin Li void testAliasingBetweenParameterAndCapture() {
94*67e74705SXin Li   int i = 5;
95*67e74705SXin Li 
96*67e74705SXin Li   auto l = [&i](int &p) {
97*67e74705SXin Li     i++;
98*67e74705SXin Li     p++;
99*67e74705SXin Li   };
100*67e74705SXin Li   l(i);
101*67e74705SXin Li   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
102*67e74705SXin Li }
103*67e74705SXin Li 
104*67e74705SXin Li // Nested lambdas.
105*67e74705SXin Li 
testNestedLambdas()106*67e74705SXin Li void testNestedLambdas() {
107*67e74705SXin Li   int i = 5;
108*67e74705SXin Li   auto l = [i]() mutable {
109*67e74705SXin Li     [&i]() {
110*67e74705SXin Li       ++i;
111*67e74705SXin Li     }();
112*67e74705SXin Li     if (i != 6)
113*67e74705SXin Li       clang_analyzer_warnIfReached();
114*67e74705SXin Li   };
115*67e74705SXin Li   l();
116*67e74705SXin Li   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
117*67e74705SXin Li }
118*67e74705SXin Li 
119*67e74705SXin Li // Captured this.
120*67e74705SXin Li 
121*67e74705SXin Li class RandomClass {
122*67e74705SXin Li   int i;
123*67e74705SXin Li 
captureFields()124*67e74705SXin Li   void captureFields() {
125*67e74705SXin Li     i = 5;
126*67e74705SXin Li     [this]() {
127*67e74705SXin Li       // clang_analyzer_eval does nothing in inlined functions.
128*67e74705SXin Li       if (i != 5)
129*67e74705SXin Li         clang_analyzer_warnIfReached();
130*67e74705SXin Li       ++i;
131*67e74705SXin Li     }();
132*67e74705SXin Li     clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
133*67e74705SXin Li   }
134*67e74705SXin Li };
135*67e74705SXin Li 
136*67e74705SXin Li 
137*67e74705SXin Li // Nested this capture.
138*67e74705SXin Li 
139*67e74705SXin Li class RandomClass2 {
140*67e74705SXin Li   int i;
141*67e74705SXin Li 
captureFields()142*67e74705SXin Li   void captureFields() {
143*67e74705SXin Li     i = 5;
144*67e74705SXin Li     [this]() {
145*67e74705SXin Li       // clang_analyzer_eval does nothing in inlined functions.
146*67e74705SXin Li       if (i != 5)
147*67e74705SXin Li         clang_analyzer_warnIfReached();
148*67e74705SXin Li       ++i;
149*67e74705SXin Li       [this]() {
150*67e74705SXin Li         // clang_analyzer_eval does nothing in inlined functions.
151*67e74705SXin Li         if (i != 6)
152*67e74705SXin Li           clang_analyzer_warnIfReached();
153*67e74705SXin Li         ++i;
154*67e74705SXin Li       }();
155*67e74705SXin Li     }();
156*67e74705SXin Li     clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
157*67e74705SXin Li   }
158*67e74705SXin Li };
159*67e74705SXin Li 
160*67e74705SXin Li 
161*67e74705SXin Li // Captured function pointers.
162*67e74705SXin Li 
inc(int & x)163*67e74705SXin Li void inc(int &x) {
164*67e74705SXin Li   ++x;
165*67e74705SXin Li }
166*67e74705SXin Li 
testFunctionPointerCapture()167*67e74705SXin Li void testFunctionPointerCapture() {
168*67e74705SXin Li   void (*func)(int &) = inc;
169*67e74705SXin Li   int i = 5;
170*67e74705SXin Li   [&i, func] {
171*67e74705SXin Li     func(i);
172*67e74705SXin Li   }();
173*67e74705SXin Li   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
174*67e74705SXin Li }
175*67e74705SXin Li 
176*67e74705SXin Li // Captured variable-length array.
177*67e74705SXin Li 
testVariableLengthArrayCaptured()178*67e74705SXin Li void testVariableLengthArrayCaptured() {
179*67e74705SXin Li   int n = 2;
180*67e74705SXin Li   int array[n];
181*67e74705SXin Li   array[0] = 7;
182*67e74705SXin Li 
183*67e74705SXin Li   int i = [&]{
184*67e74705SXin Li     return array[0];
185*67e74705SXin Li   }();
186*67e74705SXin Li 
187*67e74705SXin Li   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
188*67e74705SXin Li }
189*67e74705SXin Li 
190*67e74705SXin Li // Test inline defensive checks
191*67e74705SXin Li int getNum();
192*67e74705SXin Li 
inlineDefensiveChecks()193*67e74705SXin Li void inlineDefensiveChecks() {
194*67e74705SXin Li   int i = getNum();
195*67e74705SXin Li   [=]() {
196*67e74705SXin Li     if (i == 0)
197*67e74705SXin Li       ;
198*67e74705SXin Li   }();
199*67e74705SXin Li   int p = 5/i;
200*67e74705SXin Li   (void)p;
201*67e74705SXin Li }
202*67e74705SXin Li 
203*67e74705SXin Li 
204*67e74705SXin Li template<typename T>
callLambda(T t)205*67e74705SXin Li void callLambda(T t) {
206*67e74705SXin Li   t();
207*67e74705SXin Li }
208*67e74705SXin Li 
209*67e74705SXin Li struct DontCrash {
210*67e74705SXin Li   int x;
fDontCrash211*67e74705SXin Li   void f() {
212*67e74705SXin Li     callLambda([&](){ ++x; });
213*67e74705SXin Li     callLambdaFromStatic([&](){ ++x; });
214*67e74705SXin Li   }
215*67e74705SXin Li 
216*67e74705SXin Li   template<typename T>
callLambdaFromStaticDontCrash217*67e74705SXin Li   static void callLambdaFromStatic(T t) {
218*67e74705SXin Li     t();
219*67e74705SXin Li   }
220*67e74705SXin Li };
221*67e74705SXin Li 
222*67e74705SXin Li 
223*67e74705SXin Li // Capture constants
224*67e74705SXin Li 
captureConstants()225*67e74705SXin Li void captureConstants() {
226*67e74705SXin Li   const int i = 5;
227*67e74705SXin Li   [=]() {
228*67e74705SXin Li     if (i != 5)
229*67e74705SXin Li       clang_analyzer_warnIfReached();
230*67e74705SXin Li   }();
231*67e74705SXin Li   [&] {
232*67e74705SXin Li     if (i != 5)
233*67e74705SXin Li       clang_analyzer_warnIfReached();
234*67e74705SXin Li   }();
235*67e74705SXin Li }
236*67e74705SXin Li 
captureReferenceByCopy(int & p)237*67e74705SXin Li void captureReferenceByCopy(int &p) {
238*67e74705SXin Li   int v = 7;
239*67e74705SXin Li   p = 8;
240*67e74705SXin Li 
241*67e74705SXin Li   // p is a reference captured by copy
242*67e74705SXin Li   [&v,p]() mutable {
243*67e74705SXin Li     v = p;
244*67e74705SXin Li     p = 22;
245*67e74705SXin Li   }();
246*67e74705SXin Li 
247*67e74705SXin Li   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
248*67e74705SXin Li   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
249*67e74705SXin Li }
250*67e74705SXin Li 
captureReferenceByReference(int & p)251*67e74705SXin Li void captureReferenceByReference(int &p) {
252*67e74705SXin Li   int v = 7;
253*67e74705SXin Li   p = 8;
254*67e74705SXin Li 
255*67e74705SXin Li   // p is a reference captured by reference
256*67e74705SXin Li   [&v,&p]() {
257*67e74705SXin Li     v = p;
258*67e74705SXin Li     p = 22;
259*67e74705SXin Li   }();
260*67e74705SXin Li 
261*67e74705SXin Li   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
262*67e74705SXin Li   clang_analyzer_eval(p == 22); // expected-warning{{TRUE}}
263*67e74705SXin Li }
264*67e74705SXin Li 
callMutableLambdaMultipleTimes(int & p)265*67e74705SXin Li void callMutableLambdaMultipleTimes(int &p) {
266*67e74705SXin Li   int v = 0;
267*67e74705SXin Li   p = 8;
268*67e74705SXin Li 
269*67e74705SXin Li   auto l = [&v, p]() mutable {
270*67e74705SXin Li     v = p;
271*67e74705SXin Li     p++;
272*67e74705SXin Li   };
273*67e74705SXin Li 
274*67e74705SXin Li   l();
275*67e74705SXin Li 
276*67e74705SXin Li   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
277*67e74705SXin Li   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
278*67e74705SXin Li 
279*67e74705SXin Li   l();
280*67e74705SXin Li 
281*67e74705SXin Li   clang_analyzer_eval(v == 9); // expected-warning{{TRUE}}
282*67e74705SXin Li   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
283*67e74705SXin Li }
284*67e74705SXin Li 
285*67e74705SXin Li // PR 24914
286*67e74705SXin Li struct StructPR24914{
287*67e74705SXin Li   int x;
288*67e74705SXin Li };
289*67e74705SXin Li 
290*67e74705SXin Li void takesConstStructArgument(const StructPR24914&);
captureStructReference(const StructPR24914 & s)291*67e74705SXin Li void captureStructReference(const StructPR24914& s) {
292*67e74705SXin Li   [s]() {
293*67e74705SXin Li     takesConstStructArgument(s);
294*67e74705SXin Li   }();
295*67e74705SXin Li }
296*67e74705SXin Li 
297*67e74705SXin Li // Lambda capture counts as use for dead-store checking.
298*67e74705SXin Li 
299*67e74705SXin Li int returnsValue();
300*67e74705SXin Li 
captureByCopyCausesUse()301*67e74705SXin Li void captureByCopyCausesUse() {
302*67e74705SXin Li   int local1 = returnsValue(); // no-warning
303*67e74705SXin Li   int local2 = returnsValue(); // no-warning
304*67e74705SXin Li   int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
305*67e74705SXin Li 
306*67e74705SXin Li   (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
307*67e74705SXin Li 
308*67e74705SXin Li   int local4 = returnsValue(); // no-warning
309*67e74705SXin Li   int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
310*67e74705SXin Li 
311*67e74705SXin Li   (void)[=]() {
312*67e74705SXin Li     (void)local4; // Implicit capture by copy counts as use
313*67e74705SXin Li   };
314*67e74705SXin Li }
315*67e74705SXin Li 
captureByReference()316*67e74705SXin Li void captureByReference() {
317*67e74705SXin Li   int local1 = returnsValue(); // no-warning
318*67e74705SXin Li 
319*67e74705SXin Li   auto lambda1 = [&local1]() { // Explicit capture by reference
320*67e74705SXin Li     local1++;
321*67e74705SXin Li   };
322*67e74705SXin Li 
323*67e74705SXin Li   // Don't treat as a dead store because local1 was was captured by reference.
324*67e74705SXin Li   local1 = 7; // no-warning
325*67e74705SXin Li 
326*67e74705SXin Li   lambda1();
327*67e74705SXin Li 
328*67e74705SXin Li   int local2 = returnsValue(); // no-warning
329*67e74705SXin Li 
330*67e74705SXin Li   auto lambda2 = [&]() {
331*67e74705SXin Li     local2++; // Implicit capture by reference
332*67e74705SXin Li   };
333*67e74705SXin Li 
334*67e74705SXin Li   // Don't treat as a dead store because local2 was was captured by reference.
335*67e74705SXin Li   local2 = 7; // no-warning
336*67e74705SXin Li 
337*67e74705SXin Li   lambda2();
338*67e74705SXin Li }
339*67e74705SXin Li 
340*67e74705SXin Li 
341*67e74705SXin Li // CHECK: [B2 (ENTRY)]
342*67e74705SXin Li // CHECK:   Succs (1): B1
343*67e74705SXin Li // CHECK: [B1]
344*67e74705SXin Li // CHECK:   1: x
345*67e74705SXin Li // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
346*67e74705SXin Li // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
347*67e74705SXin Li // CHECK:   4: [x]     {
348*67e74705SXin Li // CHECK:    }
349*67e74705SXin Li // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
350*67e74705SXin Li // CHECK:   Preds (1): B2
351*67e74705SXin Li // CHECK:   Succs (1): B0
352*67e74705SXin Li // CHECK: [B0 (EXIT)]
353*67e74705SXin Li // CHECK:   Preds (1): B1
354*67e74705SXin Li 
355