diff options
| author | Ted Kremenek <kremenek@apple.com> | 2012-09-06 22:32:48 +0000 |
|---|---|---|
| committer | Ted Kremenek <kremenek@apple.com> | 2012-09-06 22:32:48 +0000 |
| commit | cadd9f186a4a2c6dfc510ce011b0ee59270abdce (patch) | |
| tree | 44822db5aa3b3b64aaccd4014c7084eae3b41ac5 /clang | |
| parent | c30a73adf671532c21b573a9009f20ca15e6180d (diff) | |
| download | bcm5719-llvm-cadd9f186a4a2c6dfc510ce011b0ee59270abdce.tar.gz bcm5719-llvm-cadd9f186a4a2c6dfc510ce011b0ee59270abdce.zip | |
Tweak DeadStoresChecker to not warn about dead stores to variables that
are used in EH code. Right now the CFG doesn't support exceptions well,
so we need this hack to avoid bogus dead store warnings.
Fixes <rdar://problem/12147586>
llvm-svn: 163353
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 58 | ||||
| -rw-r--r-- | clang/test/Analysis/dead-stores.cpp | 17 |
2 files changed, 72 insertions, 3 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 510e8cd8104..00bff53f993 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -22,13 +22,47 @@ #include "clang/Basic/Diagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/SaveAndRestore.h" 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) {} +}; // FIXME: Eventually migrate into its own file, and have it managed by // AnalysisManager. @@ -93,6 +127,7 @@ class DeadStoreObs : public LiveVariables::Observer { llvm::SmallPtrSet<const VarDecl*, 20> Escaped; OwningPtr<ReachableCode> reachableCode; const CFGBlock *currentBlock; + llvm::OwningPtr<llvm::DenseSet<const VarDecl *> > InEH; enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; @@ -105,6 +140,23 @@ public: virtual ~DeadStoreObs() {} + bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) { + if (Live.isLive(D)) + return true; + // Lazily construct the set that records which VarDecls are in + // EH code. + if (!InEH.get()) { + InEH.reset(new llvm::DenseSet<const VarDecl *>()); + EHCodeVisitor V(*InEH.get()); + V.TraverseStmt(AC->getBody()); + } + // Treat all VarDecls that occur in EH code as being "always live" + // when considering to suppress dead stores. Frequently stores + // are followed by reads in EH code, but we don't have the ability + // to analyze that yet. + return InEH->count(D); + } + void Report(const VarDecl *V, DeadStoreKind dsk, PathDiagnosticLocation L, SourceRange R) { if (Escaped.count(V)) @@ -159,7 +211,7 @@ public: if (VD->getType()->getAs<ReferenceType>()) return; - if (!Live.isLive(VD) && + if (!isLive(Live, VD) && !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) { PathDiagnosticLocation ExLoc = @@ -285,7 +337,7 @@ public: // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. - if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) { + if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) { // Special case: check for initializations with constants. // // e.g. : int x = 0; diff --git a/clang/test/Analysis/dead-stores.cpp b/clang/test/Analysis/dead-stores.cpp index 67bc8b5a232..341363afaa8 100644 --- a/clang/test/Analysis/dead-stores.cpp +++ b/clang/test/Analysis/dead-stores.cpp @@ -109,3 +109,20 @@ namespace foo { } } +//===----------------------------------------------------------------------===// +// Dead stores in with EH code. +//===----------------------------------------------------------------------===// + +void test_5_Aux(); +int test_5() { + int x = 0; + try { + x = 2; // no-warning + test_5_Aux(); + } + catch (int z) { + return x + z; + } + return 1; +} + |

