From: Ted Kremenek Date: Thu, 6 Sep 2012 22:32:48 +0000 (+0000) Subject: Tweak DeadStoresChecker to not warn about dead stores to variables that X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2827f5af018c515986ffb1779ec2e7246988f150;p=clang 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163353 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 510e8cd810..00bff53f99 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/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 { +public: + bool inEH; + llvm::DenseSet &S; + + bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + SaveAndRestore inFinally(inEH, true); + return ::RecursiveASTVisitor::TraverseObjCAtFinallyStmt(S); + } + + bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) { + SaveAndRestore inCatch(inEH, true); + return ::RecursiveASTVisitor::TraverseObjCAtCatchStmt(S); + } + + bool TraverseCXXCatchStmt(CXXCatchStmt *S) { + SaveAndRestore inCatch(inEH, true); + return TraverseStmt(S->getHandlerBlock()); + } + + bool VisitDeclRefExpr(DeclRefExpr *DR) { + if (inEH) + if (const VarDecl *D = dyn_cast(DR->getDecl())) + S.insert(D); + return true; + } + + EHCodeVisitor(llvm::DenseSet &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 Escaped; OwningPtr reachableCode; const CFGBlock *currentBlock; + llvm::OwningPtr > 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()); + 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()) return; - if (!Live.isLive(VD) && + if (!isLive(Live, VD) && !(VD->getAttr() || VD->getAttr())) { 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() == 0) { + if (!isLive(Live, V) && V->getAttr() == 0) { // Special case: check for initializations with constants. // // e.g. : int x = 0; diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp index 67bc8b5a23..341363afaa 100644 --- a/test/Analysis/dead-stores.cpp +++ b/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; +} +