Re: [PATCH] D12652: [Static Analyzer] Lambda support.
zaks.anna added a comment. Looks like this patch is causing regressions: https://llvm.org/bugs/show_bug.cgi?id=24914 Repository: rL LLVM http://reviews.llvm.org/D12652 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
xazax.hun added inline comments. Comment at: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h:515-517 @@ -511,1 +514,5 @@ + /// Returns true if lambdas should be inlined. Otherwise a sink node will be + /// generated each time a LambdaExpr is visited. + bool shouldInlineLambdas(); + jordan_rose wrote: > "inline" is kind of a misnomer, since we may not actually inline lambdas. I > would have suggested "model lambdas" or "lambda support". Even when this configuration option is set to false, the body of the lambda is analyzed as a top level function. For this reason I think the "lambda support" might be a misnomer too. What do you think? Comment at: lib/StaticAnalyzer/Core/MemRegion.cpp:740-741 @@ -739,3 +739,4 @@ const DeclContext *DC, - const VarDecl *VD) { + const VarDecl *VD, + MemRegionManager *Mmgr) { while (LC) { jordan_rose wrote: > Why the extra parameter? This is just a leftover from code evolution, thank you for spotting this. http://reviews.llvm.org/D12652 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
This revision was automatically updated to reflect the committed changes. Closed by commit rL247426: [Static Analyzer] Lambda support. (authored by xazax). Changed prior to commit: http://reviews.llvm.org/D12652?vs=34498=34555#toc Repository: rL LLVM http://reviews.llvm.org/D12652 Files: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp cfe/trunk/test/Analysis/dead-stores.cpp cfe/trunk/test/Analysis/lambda-notes.cpp cfe/trunk/test/Analysis/lambdas.cpp cfe/trunk/test/Analysis/temporaries.cpp Index: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h === --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -256,6 +256,9 @@ /// \sa getMaxNodesPerTopLevelFunction Optional MaxNodesPerTopLevelFunction; + /// \sa shouldInlineLambdas + Optional InlineLambdas; + /// A helper function that retrieves option for a given full-qualified /// checker name. /// Options for checkers can be specified via 'analyzer-config' command-line @@ -509,6 +512,10 @@ /// This is controlled by the 'max-nodes' config option. unsigned getMaxNodesPerTopLevelFunction(); + /// Returns true if lambdas should be inlined. Otherwise a sink node will be + /// generated each time a LambdaExpr is visited. + bool shouldInlineLambdas(); + public: AnalyzerOptions() : AnalysisStoreOpt(RegionStoreModel), Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h === --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -341,6 +341,10 @@ void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet ); + /// VisitLambdaExpr - Transfer function logic for LambdaExprs. + void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, + ExplodedNodeSet ); + /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet ); Index: cfe/trunk/test/Analysis/dead-stores.cpp === --- cfe/trunk/test/Analysis/dead-stores.cpp +++ cfe/trunk/test/Analysis/dead-stores.cpp @@ -174,3 +174,17 @@ return radar13213575_testit(5) + radar13213575_testit(3); } +//===--===// +// Dead store checking involving lambdas. +//===--===// + +int basicLambda(int i, int j) { + i = 5; // no warning + j = 6; // no warning + [i] { (void)i; }(); + [] { (void)j; }(); + i = 2; + j = 3; + return i + j; +} + Index: cfe/trunk/test/Analysis/lambda-notes.cpp === --- cfe/trunk/test/Analysis/lambda-notes.cpp +++ cfe/trunk/test/Analysis/lambda-notes.cpp @@ -0,0 +1,204 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core -analyzer-config inline-lambdas=true -analyzer-output plist -verify %s -o %t +// RUN: FileCheck --input-file=%t %s + + +// Diagnostic inside a lambda + +void diagnosticFromLambda() { + int i = 0; + [=] { +int p = 5/i; // expected-warning{{Division by zero}} +(void)p; + }(); +} + +// CHECK: +// CHECK: +// CHECK:path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK:line8 +// CHECK:col3 +// CHECK:file0 +// CHECK: +// CHECK: +// CHECK:line8 +// CHECK:col5 +// CHECK:file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK:line9 +// CHECK:col3 +// CHECK:file0 +// CHECK: +// CHECK: +// CHECK:line9 +// CHECK:col3 +// CHECK:file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line9 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line9 +// CHECK:
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
xazax.hun updated this revision to Diff 34498. xazax.hun added a comment. - Updated to latest trunk - Added test for the defensive inline check heuristic case - Added test for diagnostic within a lambda body - Added test for path notes http://reviews.llvm.org/D12652 Files: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/MemRegion.cpp test/Analysis/dead-stores.cpp test/Analysis/lambda-notes.cpp test/Analysis/lambdas.cpp test/Analysis/temporaries.cpp Index: test/Analysis/temporaries.cpp === --- test/Analysis/temporaries.cpp +++ test/Analysis/temporaries.cpp @@ -299,13 +299,7 @@ void testRecursiveFramesStart() { testRecursiveFrames(false); } void testLambdas() { -// This is the test we would like to write: -// []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); -// But currently the analyzer stops when it encounters a lambda: -[] {}; -// The CFG for this now looks correct, but we still do not reach the line -// below. -clang_analyzer_warnIfReached(); // FIXME: Should warn. +[]() { check(NoReturnDtor()); } != nullptr || check(Dtor()); } void testGnuExpressionStatements(int v) { Index: test/Analysis/lambdas.cpp === --- test/Analysis/lambdas.cpp +++ test/Analysis/lambdas.cpp @@ -1,9 +1,181 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1 +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -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; + }(); + [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }(); + [] { +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 = [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }; + auto l3 = [] { +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, ]() 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}} +} + +// Nested lambdas. + +void testNestedLambdas() { + int i = 5; + auto l = [i]() mutable { +[]() { + ++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; + }(); +}(); +
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
jordan_rose added a comment. A few comments coming late… Comment at: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h:515-517 @@ -511,1 +514,5 @@ + /// Returns true if lambdas should be inlined. Otherwise a sink node will be + /// generated each time a LambdaExpr is visited. + bool shouldInlineLambdas(); + "inline" is kind of a misnomer, since we may not actually inline lambdas. I would have suggested "model lambdas" or "lambda support". Comment at: lib/StaticAnalyzer/Core/MemRegion.cpp:740-741 @@ -739,3 +739,4 @@ const DeclContext *DC, - const VarDecl *VD) { + const VarDecl *VD, + MemRegionManager *Mmgr) { while (LC) { Why the extra parameter? http://reviews.llvm.org/D12652 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
zaks.anna added a comment. Have you tested this on a large codebase that uses lambdas? When do you think we should turn this on by default? Please, add test cases that demonstrate what happens when an issue is reported within a lambda and to check if inlined defensive checks work. (As a follow up to this patch, we may need to teach LiveVariables.cpp and UninitializedValues.cpp about lambdas. For example, to address issues like this one: https://llvm.org/bugs/show_bug.cgi?id=22834) http://reviews.llvm.org/D12652 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
zaks.anna accepted this revision. zaks.anna added a comment. This revision is now accepted and ready to land. Please, do turn on by default. LGTM http://reviews.llvm.org/D12652 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12652: [Static Analyzer] Lambda support.
xazax.hun updated this revision to Diff 34285. xazax.hun added a comment. - Updated to newest trunk. - Moved the feature behind an option. - Fixed a crash when an operator() of a lambda is analyzed as a top level function, and a ThisExpr is referring to the this in the enclosing scope (this can only happen when lambda support is turned off). - Added a new test case for nested lambdas capturing 'this'. http://reviews.llvm.org/D12652 Files: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/MemRegion.cpp test/Analysis/dead-stores.cpp test/Analysis/lambdas.cpp test/Analysis/temporaries.cpp Index: test/Analysis/temporaries.cpp === --- test/Analysis/temporaries.cpp +++ test/Analysis/temporaries.cpp @@ -299,13 +299,7 @@ void testRecursiveFramesStart() { testRecursiveFrames(false); } void testLambdas() { -// This is the test we would like to write: -// []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); -// But currently the analyzer stops when it encounters a lambda: -[] {}; -// The CFG for this now looks correct, but we still do not reach the line -// below. -clang_analyzer_warnIfReached(); // FIXME: Should warn. +[]() { check(NoReturnDtor()); } != nullptr || check(Dtor()); } void testGnuExpressionStatements(int v) { Index: test/Analysis/lambdas.cpp === --- test/Analysis/lambdas.cpp +++ test/Analysis/lambdas.cpp @@ -1,9 +1,167 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1 +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -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; + }(); + [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }(); + [] { +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 = [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }; + auto l3 = [] { +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, ]() 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}} +} + +// Nested lambdas. + +void testNestedLambdas() { + int i = 5; + auto l = [i]() mutable { +[]() { + ++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
[PATCH] D12652: [Static Analyzer] Lambda support.
xazax.hun created this revision. xazax.hun added reviewers: dcoughlin, zaks.anna, jordan_rose, ted. xazax.hun added a subscriber: cfe-commits. This patch adds lambda support for the static analyzer. All of my initial tests are passed. Before this patch each time a LambdaExpr was encountered a sink node was generated. This also reduced the coverage of code that is actually not inside a lambda operator(). Also the lack of lambda support is a known cause of some false positives (for example in the dead store checker). This is a work in progress version of this patch, I will move this feature behind a flag and run it on LLVM to make sure it is also tested with real world code. http://reviews.llvm.org/D12652 Files: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/MemRegion.cpp test/Analysis/dead-stores.cpp test/Analysis/lambdas.cpp test/Analysis/temporaries.cpp Index: test/Analysis/temporaries.cpp === --- test/Analysis/temporaries.cpp +++ test/Analysis/temporaries.cpp @@ -299,13 +299,7 @@ void testRecursiveFramesStart() { testRecursiveFrames(false); } void testLambdas() { -// This is the test we would like to write: -// []() { check(NoReturnDtor()); } != nullptr || check(Dtor()); -// But currently the analyzer stops when it encounters a lambda: -[] {}; -// The CFG for this now looks correct, but we still do not reach the line -// below. -clang_analyzer_warnIfReached(); // FIXME: Should warn. +[]() { check(NoReturnDtor()); } != nullptr || check(Dtor()); } void testGnuExpressionStatements(int v) { Index: test/Analysis/lambdas.cpp === --- test/Analysis/lambdas.cpp +++ test/Analysis/lambdas.cpp @@ -1,9 +1,142 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1 +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG %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; + }(); + [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }(); + [] { +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 = [] { +if (i != 5) + clang_analyzer_warnIfReached(); + }; + auto l3 = [] { +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, ]() 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}} +} + +// Nested lambdas. + +void testNestedLambdas() { + int i = 5; + auto l = [i]() mutable { +[]() { + ++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}} + } +}; + +// Captured function pointers. + +void inc(int ) { + ++x; +} + +void testFunctionPointerCapture() { + void (*func)(int &) = inc; + int i = 5; + [, func] { +func(i); + }(); +