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