r247426 - [Static Analyzer] Lambda support.
Gabor Horvath via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 09:55:01 PDT 2015
Author: xazax
Date: Fri Sep 11 11:55:01 2015
New Revision: 247426
URL: http://llvm.org/viewvc/llvm-project?rev=247426&view=rev
Log:
[Static Analyzer] Lambda support.
Differential Revision: http://reviews.llvm.org/D12652
Added:
cfe/trunk/test/Analysis/lambda-notes.cpp
Modified:
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/lambdas.cpp
cfe/trunk/test/Analysis/temporaries.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Fri Sep 11 11:55:01 2015
@@ -256,6 +256,9 @@ private:
/// \sa getMaxNodesPerTopLevelFunction
Optional<unsigned> MaxNodesPerTopLevelFunction;
+ /// \sa shouldInlineLambdas
+ Optional<bool> 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 @@ public:
/// 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),
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Fri Sep 11 11:55:01 2015
@@ -341,6 +341,10 @@ public:
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// VisitLambdaExpr - Transfer function logic for LambdaExprs.
+ void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// VisitBinaryOperator - Transfer function logic for binary operators.
void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Fri Sep 11 11:55:01 2015
@@ -325,3 +325,7 @@ bool AnalyzerOptions::shouldPrunePaths()
bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
return getBooleanOption("cfg-conditional-static-initializers", true);
}
+
+bool AnalyzerOptions::shouldInlineLambdas() {
+ return getBooleanOption("inline-lambdas", /*Default=*/true);
+}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Sep 11 11:55:01 2015
@@ -769,7 +769,6 @@ void ExprEngine::Visit(const Stmt *S, Ex
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHLeaveStmtClass:
- case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
Engine.addAbortedBlock(node, currBldrCtx->getBlock());
@@ -1013,6 +1012,17 @@ void ExprEngine::Visit(const Stmt *S, Ex
Bldr.addNodes(Dst);
break;
+ case Stmt::LambdaExprClass:
+ if (AMgr.options.shouldInlineLambdas()) {
+ Bldr.takeNodes(Pred);
+ VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
+ } else {
+ const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currBldrCtx->getBlock());
+ }
+ break;
+
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
@@ -1853,11 +1863,35 @@ void ExprEngine::VisitCommonDeclRefExpr(
// C permits "extern void v", and if you cast the address to a valid type,
// you can even do things with it. We simply pretend
assert(Ex->isGLValue() || VD->getType()->isVoidType());
- SVal V = state->getLValue(VD, Pred->getLocationContext());
+ const LocationContext *LocCtxt = Pred->getLocationContext();
+ const Decl *D = LocCtxt->getDecl();
+ const auto *MD = D ? dyn_cast<CXXMethodDecl>(D) : nullptr;
+ const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
+ SVal V;
+ bool CaptureByReference = false;
+ if (AMgr.options.shouldInlineLambdas() && DeclRefEx &&
+ DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
+ MD->getParent()->isLambda()) {
+ // Lookup the field of the lambda.
+ const CXXRecordDecl *CXXRec = MD->getParent();
+ llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField;
+ CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
+ const FieldDecl *FD = LambdaCaptureFields[VD];
+ Loc CXXThis =
+ svalBuilder.getCXXThis(MD, LocCtxt->getCurrentStackFrame());
+ SVal CXXThisVal = state->getSVal(CXXThis);
+ V = state->getLValue(FD, CXXThisVal);
+ if (FD->getType()->isReferenceType() &&
+ !VD->getType()->isReferenceType())
+ CaptureByReference = true;
+ } else {
+ V = state->getLValue(VD, LocCtxt);
+ }
// For references, the 'lvalue' is the pointer address stored in the
// reference region.
- if (VD->getType()->isReferenceType()) {
+ if (VD->getType()->isReferenceType() || CaptureByReference) {
if (const MemRegion *R = V.getAsRegion())
V = state->getSVal(R);
else
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Fri Sep 11 11:55:01 2015
@@ -513,3 +513,41 @@ void ExprEngine::VisitCXXThisExpr(const
SVal V = state->getSVal(loc::MemRegionVal(R));
Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
}
+
+void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ const LocationContext *LocCtxt = Pred->getLocationContext();
+
+ // Get the region of the lambda itself.
+ const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(
+ LE, LocCtxt);
+ SVal V = loc::MemRegionVal(R);
+
+ ProgramStateRef State = Pred->getState();
+
+ // If we created a new MemRegion for the lambda, we should explicitly bind
+ // the captures.
+ CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin();
+ for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(),
+ e = LE->capture_init_end();
+ i != e; ++i, ++CurField) {
+ SVal Field = State->getLValue(*CurField, V);
+ SVal InitExpr = State->getSVal(*i, LocCtxt);
+ State = State->bindLoc(Field, InitExpr);
+ }
+
+ // Decay the Loc into an RValue, because there might be a
+ // MaterializeTemporaryExpr node above this one which expects the bound value
+ // to be an RValue.
+ SVal LambdaRVal = State->getSVal(R);
+
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
+ // FIXME: is this the right program point kind?
+ Bldr.generateNode(LE, Pred,
+ State->BindExpr(LE, LocCtxt, LambdaRVal),
+ nullptr, ProgramPoint::PostLValueKind);
+
+ // FIXME: Move all post/pre visits to ::Visit().
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
+}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp Fri Sep 11 11:55:01 2015
@@ -1013,10 +1013,21 @@ MemRegionManager::getCXXBaseObjectRegion
const CXXThisRegion*
MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
const LocationContext *LC) {
- const StackFrameContext *STC = LC->getCurrentStackFrame();
- assert(STC);
const PointerType *PT = thisPointerTy->getAs<PointerType>();
assert(PT);
+ // Inside the body of the operator() of a lambda a this expr might refer to an
+ // object in one of the parent location contexts.
+ const auto *D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+ // FIXME: when operator() of lambda is analyzed as a top level function and
+ // 'this' refers to a this to the enclosing scope, there is no right region to
+ // return.
+ while (!LC->inTopFrame() &&
+ PT != D->getThisType(getContext())->getAs<PointerType>()) {
+ LC = LC->getParent();
+ D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+ }
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
}
Modified: cfe/trunk/test/Analysis/dead-stores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dead-stores.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dead-stores.cpp (original)
+++ cfe/trunk/test/Analysis/dead-stores.cpp Fri Sep 11 11:55:01 2015
@@ -174,3 +174,17 @@ int radar_13213575() {
return radar13213575_testit<true>(5) + radar13213575_testit<false>(3);
}
+//===----------------------------------------------------------------------===//
+// Dead store checking involving lambdas.
+//===----------------------------------------------------------------------===//
+
+int basicLambda(int i, int j) {
+ i = 5; // no warning
+ j = 6; // no warning
+ [i] { (void)i; }();
+ [&j] { (void)j; }();
+ i = 2;
+ j = 3;
+ return i + j;
+}
+
Added: cfe/trunk/test/Analysis/lambda-notes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lambda-notes.cpp?rev=247426&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/lambda-notes.cpp (added)
+++ cfe/trunk/test/Analysis/lambda-notes.cpp Fri Sep 11 11:55:01 2015
@@ -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: <array>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>8</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>8</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>The value 0 is assigned to field ''</string>
+// CHECK: <key>message</key>
+// CHECK: <string>The value 0 is assigned to field ''</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling 'operator()'</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling 'operator()'</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from 'diagnosticFromLambda'</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from 'diagnosticFromLambda'</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Division by zero</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Division by zero</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Division by zero</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Division by zero</string>
+// CHECK: <key>check_name</key><string>core.DivideZero</string>
+// CHECK: <key>issue_context_kind</key><string>C++ method</string>
+// CHECK: <key>issue_context</key><string>operator()</string>
+// CHECK: <key>issue_hash</key><string>1</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: </array>
+
Modified: cfe/trunk/test/Analysis/lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lambdas.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/lambdas.cpp (original)
+++ cfe/trunk/test/Analysis/lambdas.cpp Fri Sep 11 11:55:01 2015
@@ -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;
+ }();
+ [&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}}
+}
+
+// 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}}
+}
+
+
+// Test inline defensive checks
+int getNum();
+
+void inlineDefensiveChecks() {
+ int i = getNum();
+ [=]() {
+ if (i == 0)
+ ;
+ }();
+ int p = 5/i;
+ (void)p;
+}
+
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
Modified: cfe/trunk/test/Analysis/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=247426&r1=247425&r2=247426&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temporaries.cpp (original)
+++ cfe/trunk/test/Analysis/temporaries.cpp Fri Sep 11 11:55:01 2015
@@ -299,13 +299,7 @@ namespace destructors {
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) {
More information about the cfe-commits
mailing list