diff options
| author | Devin Coughlin <dcoughlin@apple.com> | 2015-11-20 01:53:44 +0000 |
|---|---|---|
| committer | Devin Coughlin <dcoughlin@apple.com> | 2015-11-20 01:53:44 +0000 |
| commit | c7315b3ebfaca4e0ea234a8dd3e4194c44c92cbf (patch) | |
| tree | dd2a41276e93cf97dc2b88fbd9607822e92b83d4 /clang/lib/StaticAnalyzer | |
| parent | c85f4ced4d163442019d170282b751852b2e6500 (diff) | |
| download | bcm5719-llvm-c7315b3ebfaca4e0ea234a8dd3e4194c44c92cbf.tar.gz bcm5719-llvm-c7315b3ebfaca4e0ea234a8dd3e4194c44c92cbf.zip | |
[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
llvm-svn: 253630
Diffstat (limited to 'clang/lib/StaticAnalyzer')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 5d8baf6ba7d..f2a269a3335 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -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 |

