summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2015-12-30 11:49:41 +0000
committerdim <dim@FreeBSD.org>2015-12-30 11:49:41 +0000
commit3176e97f130184ece0e1a21352c8124cc83ff24a (patch)
tree0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
parent1e9b8d38881c3213d1e67b0c47ab9b2c00721a5c (diff)
downloadFreeBSD-src-3176e97f130184ece0e1a21352c8124cc83ff24a.zip
FreeBSD-src-3176e97f130184ece0e1a21352c8124cc83ff24a.tar.gz
Vendor import of clang trunk r256633:
https://llvm.org/svn/llvm-project/cfe/trunk@256633
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp71
1 files changed, 49 insertions, 22 deletions
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index f4be5b3..f2a269a 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -28,36 +28,36 @@
using namespace clang;
using namespace ento;
-namespace {
-
+namespace {
+
/// A simple visitor to record what VarDecls occur in EH-handling code.
class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
public:
bool inEH;
llvm::DenseSet<const VarDecl *> &S;
-
+
bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
SaveAndRestore<bool> inFinally(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
}
-
+
bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
SaveAndRestore<bool> inCatch(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
}
-
+
bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
SaveAndRestore<bool> inCatch(inEH, true);
return TraverseStmt(S->getHandlerBlock());
}
-
+
bool VisitDeclRefExpr(DeclRefExpr *DR) {
if (inEH)
if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
S.insert(D);
return true;
}
-
+
EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
inEH(false), S(S) {}
};
@@ -70,9 +70,9 @@ class ReachableCode {
public:
ReachableCode(const CFG &cfg)
: cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
-
+
void computeReachableBlocks();
-
+
bool isReachable(const CFGBlock *block) const {
return reachable[block->getBlockID()];
}
@@ -82,7 +82,7 @@ public:
void ReachableCode::computeReachableBlocks() {
if (!cfg.getNumBlockIDs())
return;
-
+
SmallVector<const CFGBlock*, 10> worklist;
worklist.push_back(&cfg.getEntry());
@@ -160,19 +160,19 @@ public:
// to analyze that yet.
return InEH->count(D);
}
-
+
void Report(const VarDecl *V, DeadStoreKind dsk,
PathDiagnosticLocation L, SourceRange R) {
if (Escaped.count(V))
return;
-
+
// Compute reachable blocks within the CFG for trivial cases
// where a bogus dead store can be reported because itself is unreachable.
if (!reachableCode.get()) {
reachableCode.reset(new ReachableCode(cfg));
reachableCode->computeReachableBlocks();
}
-
+
if (!reachableCode->isReachable(currentBlock))
return;
@@ -196,7 +196,7 @@ public:
case Enclosing:
// Don't report issues in this case, e.g.: "if (x = foo())",
- // where 'x' is unused later. We have yet to see a case where
+ // where 'x' is unused later. We have yet to see a case where
// this is a real bug.
return;
}
@@ -259,7 +259,7 @@ public:
const LiveVariables::LivenessValues &Live) override {
currentBlock = block;
-
+
// Skip statements in macros.
if (S->getLocStart().isMacroID())
return;
@@ -276,7 +276,7 @@ public:
const Expr *RHS =
LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
RHS = RHS->IgnoreParenCasts();
-
+
QualType T = VD->getType();
if (T->isPointerType() || T->isObjCObjectPointerType()) {
if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
@@ -318,27 +318,27 @@ public:
if (!V)
continue;
-
- if (V->hasLocalStorage()) {
+
+ if (V->hasLocalStorage()) {
// Reference types confuse the dead stores checker. Skip them
// for now.
if (V->getType()->getAs<ReferenceType>())
return;
-
+
if (const Expr *E = V->getInit()) {
while (const ExprWithCleanups *exprClean =
dyn_cast<ExprWithCleanups>(E))
E = exprClean->getSubExpr();
-
+
// Look through transitive assignments, e.g.:
// int x = y = 0;
E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
-
+
// Don't warn on C++ objects (yet) until we can show that their
// constructors/destructors don't have side effects.
if (isa<CXXConstructExpr>(E))
return;
-
+
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused' or 'objc_precise_lifetime'.
@@ -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
OpenPOWER on IntegriCloud