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