From 7f5fce7200fdbf03f7d70134a57271e584fcb766 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 20 Jan 2009 00:47:45 +0000 Subject: [PATCH] Dead stores checker: Fix 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 --- include/clang/AST/ParentMap.h | 2 -- lib/AST/ParentMap.cpp | 8 ------ lib/Analysis/CheckDeadStores.cpp | 49 ++++++++++++++++++++++++++++---- 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(S)) - return false; - - Stmt* P = getParent(S); - return P ? !isa(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(E) || isa(E))) { + DirectChild = P; + P = Parents.getParent(P); + } + + if (!P) + return false; + + switch (P->getStmtClass()) { + default: + return isa(P); + case Stmt::BinaryOperatorClass: { + BinaryOperator *BE = cast(P); + return BE->getOpcode()==BinaryOperator::Comma && DirectChild==BE->getLHS(); + } + case Stmt::ForStmtClass: + return DirectChild == cast(P)->getCond(); + case Stmt::WhileStmtClass: + return DirectChild == cast(P)->getCond(); + case Stmt::DoStmtClass: + return DirectChild == cast(P)->getCond(); + case Stmt::IfStmtClass: + return DirectChild == cast(P)->getCond(); + case Stmt::IndirectGotoStmtClass: + return DirectChild == cast(P)->getTarget(); + case Stmt::SwitchStmtClass: + return DirectChild == cast(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 } + +// +// 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'}} +} -- 2.40.0