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 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 void 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 106 void 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 121 class 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 139 class 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 163 void inc(int &x) { 164 ++x; 165 } 166 167 void 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 177 // Test inline defensive checks 178 int getNum(); 179 180 void inlineDefensiveChecks() { 181 int i = getNum(); 182 [=]() { 183 if (i == 0) 184 ; 185 }(); 186 int p = 5/i; 187 (void)p; 188 } 189 190 191 template<typename T> 192 void callLambda(T t) { 193 t(); 194 } 195 196 struct DontCrash { 197 int x; 198 void f() { 199 callLambda([&](){ ++x; }); 200 callLambdaFromStatic([&](){ ++x; }); 201 } 202 203 template<typename T> 204 static void callLambdaFromStatic(T t) { 205 t(); 206 } 207 }; 208 209 210 // Capture constants 211 212 void captureConstants() { 213 const int i = 5; 214 [=]() { 215 if (i != 5) 216 clang_analyzer_warnIfReached(); 217 }(); 218 [&] { 219 if (i != 5) 220 clang_analyzer_warnIfReached(); 221 }(); 222 } 223 224 void captureReferenceByCopy(int &p) { 225 int v = 7; 226 p = 8; 227 228 // p is a reference captured by copy 229 [&v,p]() mutable { 230 v = p; 231 p = 22; 232 }(); 233 234 clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} 235 clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} 236 } 237 238 void captureReferenceByReference(int &p) { 239 int v = 7; 240 p = 8; 241 242 // p is a reference captured by reference 243 [&v,&p]() { 244 v = p; 245 p = 22; 246 }(); 247 248 clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} 249 clang_analyzer_eval(p == 22); // expected-warning{{TRUE}} 250 } 251 252 void callMutableLambdaMultipleTimes(int &p) { 253 int v = 0; 254 p = 8; 255 256 auto l = [&v, p]() mutable { 257 v = p; 258 p++; 259 }; 260 261 l(); 262 263 clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} 264 clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} 265 266 l(); 267 268 clang_analyzer_eval(v == 9); // expected-warning{{TRUE}} 269 clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} 270 } 271 272 // PR 24914 273 struct StructPR24914{ 274 int x; 275 }; 276 277 void takesConstStructArgument(const StructPR24914&); 278 void captureStructReference(const StructPR24914& s) { 279 [s]() { 280 takesConstStructArgument(s); 281 }(); 282 } 283 284 // Lambda capture counts as use for dead-store checking. 285 286 int returnsValue(); 287 288 void captureByCopyCausesUse() { 289 int local1 = returnsValue(); // no-warning 290 int local2 = returnsValue(); // no-warning 291 int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}} 292 293 (void)[local1, local2]() { }; // Explicit capture by copy counts as use. 294 295 int local4 = returnsValue(); // no-warning 296 int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}} 297 298 (void)[=]() { 299 (void)local4; // Implicit capture by copy counts as use 300 }; 301 } 302 303 void captureByReference() { 304 int local1 = returnsValue(); // no-warning 305 306 auto lambda1 = [&local1]() { // Explicit capture by reference 307 local1++; 308 }; 309 310 // Don't treat as a dead store because local1 was was captured by reference. 311 local1 = 7; // no-warning 312 313 lambda1(); 314 315 int local2 = returnsValue(); // no-warning 316 317 auto lambda2 = [&]() { 318 local2++; // Implicit capture by reference 319 }; 320 321 // Don't treat as a dead store because local2 was was captured by reference. 322 local2 = 7; // no-warning 323 324 lambda2(); 325 } 326 327 328 // CHECK: [B2 (ENTRY)] 329 // CHECK: Succs (1): B1 330 // CHECK: [B1] 331 // CHECK: 1: x 332 // CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X) 333 // CHECK: 3: [B1.2] (CXXConstructExpr, struct X) 334 // CHECK: 4: [x] { 335 // CHECK: } 336 // CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void) 337 // CHECK: Preds (1): B2 338 // CHECK: Succs (1): B0 339 // CHECK: [B0 (EXIT)] 340 // CHECK: Preds (1): B1 341 342