// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1 // RUN: FileCheck --input-file=%t %s void clang_analyzer_warnIfReached(); void clang_analyzer_eval(int); struct X { X(const X&); }; void f(X x) { (void) [x]{}; } // Lambda semantics tests. void basicCapture() { int i = 5; [i]() mutable { // clang_analyzer_eval does nothing in inlined functions. if (i != 5) clang_analyzer_warnIfReached(); ++i; }(); [&i] { if (i != 5) clang_analyzer_warnIfReached(); }(); [&i] { if (i != 5) clang_analyzer_warnIfReached(); i++; }(); clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} } void deferredLambdaCall() { int i = 5; auto l1 = [i]() mutable { if (i != 5) clang_analyzer_warnIfReached(); ++i; }; auto l2 = [&i] { if (i != 5) clang_analyzer_warnIfReached(); }; auto l3 = [&i] { if (i != 5) clang_analyzer_warnIfReached(); i++; }; l1(); l2(); l3(); clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} } void multipleCaptures() { int i = 5, j = 5; [i, &j]() mutable { if (i != 5 && j != 5) clang_analyzer_warnIfReached(); ++i; ++j; }(); clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} clang_analyzer_eval(j == 6); // expected-warning{{TRUE}} [=]() mutable { if (i != 5 && j != 6) clang_analyzer_warnIfReached(); ++i; ++j; }(); clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} clang_analyzer_eval(j == 6); // expected-warning{{TRUE}} [&]() mutable { if (i != 5 && j != 6) clang_analyzer_warnIfReached(); ++i; ++j; }(); clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} clang_analyzer_eval(j == 7); // expected-warning{{TRUE}} } void testReturnValue() { int i = 5; auto l = [i] (int a) { return i + a; }; int b = l(3); clang_analyzer_eval(b == 8); // expected-warning{{TRUE}} } void testAliasingBetweenParameterAndCapture() { int i = 5; auto l = [&i](int &p) { i++; p++; }; l(i); clang_analyzer_eval(i == 7); // expected-warning{{TRUE}} } // Nested lambdas. void testNestedLambdas() { int i = 5; auto l = [i]() mutable { [&i]() { ++i; }(); if (i != 6) clang_analyzer_warnIfReached(); }; l(); clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} } // Captured this. class RandomClass { int i; void captureFields() { i = 5; [this]() { // clang_analyzer_eval does nothing in inlined functions. if (i != 5) clang_analyzer_warnIfReached(); ++i; }(); clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} } }; // Nested this capture. class RandomClass2 { int i; void captureFields() { i = 5; [this]() { // clang_analyzer_eval does nothing in inlined functions. if (i != 5) clang_analyzer_warnIfReached(); ++i; [this]() { // clang_analyzer_eval does nothing in inlined functions. if (i != 6) clang_analyzer_warnIfReached(); ++i; }(); }(); clang_analyzer_eval(i == 7); // expected-warning{{TRUE}} } }; // Captured function pointers. void inc(int &x) { ++x; } void testFunctionPointerCapture() { void (*func)(int &) = inc; int i = 5; [&i, func] { func(i); }(); clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} } // Captured variable-length array. void testVariableLengthArrayCaptured() { int n = 2; int array[n]; array[0] = 7; int i = [&]{ return array[0]; }(); clang_analyzer_eval(i == 7); // expected-warning{{TRUE}} } // Test inline defensive checks int getNum(); void inlineDefensiveChecks() { int i = getNum(); [=]() { if (i == 0) ; }(); int p = 5/i; (void)p; } template void callLambda(T t) { t(); } struct DontCrash { int x; void f() { callLambda([&](){ ++x; }); callLambdaFromStatic([&](){ ++x; }); } template static void callLambdaFromStatic(T t) { t(); } }; // Capture constants void captureConstants() { const int i = 5; [=]() { if (i != 5) clang_analyzer_warnIfReached(); }(); [&] { if (i != 5) clang_analyzer_warnIfReached(); }(); } void captureReferenceByCopy(int &p) { int v = 7; p = 8; // p is a reference captured by copy [&v,p]() mutable { v = p; p = 22; }(); clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} } void captureReferenceByReference(int &p) { int v = 7; p = 8; // p is a reference captured by reference [&v,&p]() { v = p; p = 22; }(); clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} clang_analyzer_eval(p == 22); // expected-warning{{TRUE}} } void callMutableLambdaMultipleTimes(int &p) { int v = 0; p = 8; auto l = [&v, p]() mutable { v = p; p++; }; l(); clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} l(); clang_analyzer_eval(v == 9); // expected-warning{{TRUE}} clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} } // PR 24914 struct StructPR24914{ int x; }; void takesConstStructArgument(const StructPR24914&); void captureStructReference(const StructPR24914& s) { [s]() { takesConstStructArgument(s); }(); } // Lambda capture counts as use for dead-store checking. int returnsValue(); void captureByCopyCausesUse() { int local1 = returnsValue(); // no-warning int local2 = returnsValue(); // no-warning int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}} (void)[local1, local2]() { }; // Explicit capture by copy counts as use. int local4 = returnsValue(); // no-warning int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}} (void)[=]() { (void)local4; // Implicit capture by copy counts as use }; } void captureByReference() { int local1 = returnsValue(); // no-warning auto lambda1 = [&local1]() { // Explicit capture by reference local1++; }; // Don't treat as a dead store because local1 was was captured by reference. local1 = 7; // no-warning lambda1(); int local2 = returnsValue(); // no-warning auto lambda2 = [&]() { local2++; // Implicit capture by reference }; // Don't treat as a dead store because local2 was was captured by reference. local2 = 7; // no-warning lambda2(); } // CHECK: [B2 (ENTRY)] // CHECK: Succs (1): B1 // CHECK: [B1] // CHECK: 1: x // CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X) // CHECK: 3: [B1.2] (CXXConstructExpr, struct X) // CHECK: 4: [x] { // CHECK: } // CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] // CHECK: Preds (1): B1