r253630 - [analyzer] DeadStoresChecker: Treat locals captured by reference in C++ lambdas as escaped.
Devin Coughlin via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 19 17:53:45 PST 2015
Author: dcoughlin
Date: Thu Nov 19 19:53:44 2015
New Revision: 253630
URL: http://llvm.org/viewvc/llvm-project?rev=253630&view=rev
Log:
[analyzer] DeadStoresChecker: Treat locals captured by reference in C++ lambdas as escaped.
The analyzer currently reports dead store false positives when a local variable
is captured by reference in a C++ lambda.
For example:
int local = 0; auto lambda = [&local]() {
local++;
};
local = 7; // False Positive: Value stored to 'local' is never read
lambda();
In this case, the assignment setting `local` to 7 is not a dead store because
the called lambda will later read that assigned value.
This commit silences this source of false positives by treating locals captured
by reference in C++ lambdas as escaped, similarly to how the DeadStoresChecker
deals with locals whose address is taken.
rdar://problem/22165179
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
cfe/trunk/test/Analysis/lambdas.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp?rev=253630&r1=253629&r2=253630&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp Thu Nov 19 19:53:44 2015
@@ -401,6 +401,11 @@ public:
// Check for '&'. Any VarDecl whose address has been taken we treat as
// escaped.
// FIXME: What about references?
+ if (auto *LE = dyn_cast<LambdaExpr>(S)) {
+ findLambdaReferenceCaptures(LE);
+ return;
+ }
+
const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
if (!U)
return;
@@ -412,6 +417,28 @@ public:
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
Escaped.insert(VD);
}
+
+ // Treat local variables captured by reference in C++ lambdas as escaped.
+ void findLambdaReferenceCaptures(const LambdaExpr *LE) {
+ const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
+ llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+ FieldDecl *ThisCaptureField;
+ LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
+
+ for (const LambdaCapture &C : LE->captures()) {
+ if (!C.capturesVariable())
+ continue;
+
+ VarDecl *VD = C.getCapturedVar();
+ const FieldDecl *FD = CaptureFields[VD];
+ if (!FD)
+ continue;
+
+ // If the capture field is a reference type, it is capture-by-reference.
+ if (FD->getType()->isReferenceType())
+ Escaped.insert(VD);
+ }
+ }
};
} // end anonymous namespace
Modified: cfe/trunk/test/Analysis/lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lambdas.cpp?rev=253630&r1=253629&r2=253630&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/lambdas.cpp (original)
+++ cfe/trunk/test/Analysis/lambdas.cpp Thu Nov 19 19:53:44 2015
@@ -1,4 +1,4 @@
-// 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,deadcode,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
@@ -281,6 +281,49 @@ void captureStructReference(const Struct
}();
}
+// 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
More information about the cfe-commits
mailing list