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