diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-01-20 00:47:45 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-01-20 00:47:45 +0000 |
commit | 7f5fce7200fdbf03f7d70134a57271e584fcb766 (patch) | |
tree | bac91a77f940d3ecc6e2d0bb9262754a990592dd | |
parent | 06172d680766ffb96a22c48c390ec3e0fd41625b (diff) |
Dead stores checker: Fix <rdar://problem/6506065> by being more selective when say that a store is dead even though the computed value is used in the enclosing expression.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62552 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ParentMap.h | 2 | ||||
-rw-r--r-- | lib/AST/ParentMap.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/CheckDeadStores.cpp | 49 | ||||
-rw-r--r-- | test/Analysis/dead-stores.c | 19 |
4 files changed, 61 insertions, 17 deletions
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index 7443f91573..5fb96f54b4 100644 --- a/include/clang/AST/ParentMap.h +++ b/include/clang/AST/ParentMap.h @@ -28,8 +28,6 @@ public: bool hasParent(Stmt* S) const { return !getParent(S); } - - bool isSubExpr(Stmt *S) const; }; } // end clang namespace diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 82341c78f8..54472ecb96 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -45,11 +45,3 @@ Stmt* ParentMap::getParent(Stmt* S) const { MapTy::iterator I = M->find(S); return I == M->end() ? 0 : I->second; } - -bool ParentMap::isSubExpr(Stmt* S) const { - if (!isa<Expr>(S)) - return false; - - Stmt* P = getParent(S); - return P ? !isa<CompoundStmt>(P) : false; -} diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index cad19f4f93..4f51cd8d9a 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -39,6 +39,9 @@ public: virtual ~DeadStoreObs() {} + bool isConsumedExpr(Expr* E) const; + + void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) { std::string name = V->getNameAsString(); @@ -145,10 +148,9 @@ public: return; // Otherwise, issue a warning. - DeadStoreKind dsk = - Parents.isSubExpr(B) - ? Enclosing - : (isIncrement(VD,B) ? DeadIncrement : Standard); + DeadStoreKind dsk = isConsumedExpr(B) + ? Enclosing + : (isIncrement(VD,B) ? DeadIncrement : Standard); CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live); } @@ -161,7 +163,7 @@ public: // about preincrements to dead variables when the preincrement occurs // as a subexpression. This can lead to false negatives, e.g. "(++x);" // A generalized dead code checker should find such issues. - if (U->isPrefix() && Parents.isSubExpr(U)) + if (U->isPrefix() && isConsumedExpr(U)) return; Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); @@ -203,6 +205,43 @@ public: } // end anonymous namespace +bool DeadStoreObs::isConsumedExpr(Expr* E) const { + Stmt *P = Parents.getParent(E); + Stmt *DirectChild = E; + + // Ignore parents that are parentheses or casts. + while (P && (isa<ParenExpr>(E) || isa<CastExpr>(E))) { + DirectChild = P; + P = Parents.getParent(P); + } + + if (!P) + return false; + + switch (P->getStmtClass()) { + default: + return isa<Expr>(P); + case Stmt::BinaryOperatorClass: { + BinaryOperator *BE = cast<BinaryOperator>(P); + return BE->getOpcode()==BinaryOperator::Comma && DirectChild==BE->getLHS(); + } + case Stmt::ForStmtClass: + return DirectChild == cast<ForStmt>(P)->getCond(); + case Stmt::WhileStmtClass: + return DirectChild == cast<WhileStmt>(P)->getCond(); + case Stmt::DoStmtClass: + return DirectChild == cast<DoStmt>(P)->getCond(); + case Stmt::IfStmtClass: + return DirectChild == cast<IfStmt>(P)->getCond(); + case Stmt::IndirectGotoStmtClass: + return DirectChild == cast<IndirectGotoStmt>(P)->getTarget(); + case Stmt::SwitchStmtClass: + return DirectChild == cast<SwitchStmt>(P)->getCond(); + case Stmt::ReturnStmtClass: + return true; + } +} + //===----------------------------------------------------------------------===// // Driver function to invoke the Dead-Stores checker on a CFG. //===----------------------------------------------------------------------===// diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 7f99499aab..92dfdf712c 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -79,10 +79,9 @@ int f11() { int f11b() { int x = 4; - return ++x; // no-warning + return ((((++x)))); // no-warning } - int f12a(int y) { int x = y; // expected-warning{{never read}} return 1; @@ -132,3 +131,19 @@ int f17() { int x = 1; x = x; // no-warning } + +// <rdar://problem/6506065> +// The values of dead stores are only "consumed" in an enclosing expression +// what that value is actually used. In other words, don't say "Although the value stored to 'x' is used...". +int f18() { + int x = 0; // no-warning + if (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} + while (1) + x = 10; // expected-warning{{Value stored to 'x' is never read}} + do + x = 10; // expected-warning{{Value stored to 'x' is never read}} + while (1); + + return (x = 10); // expected-warning{{Although the value stored to 'x' is used in the enclosing expression, the value is never actually read from 'x'}} +} |