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 // CHECK: [B2 (ENTRY)]
180 // CHECK:   Succs (1): B1
181 // CHECK: [B1]
182 // CHECK:   1: x
183 // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
184 // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
185 // CHECK:   4: [x]     {
186 // CHECK:    }
187 // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
188 // CHECK:   Preds (1): B2
189 // CHECK:   Succs (1): B0
190 // CHECK: [B0 (EXIT)]
191 // CHECK:   Preds (1): B1
192 
193