From bb811cab1bfa91074f1992b154fcb0c288e6eda3 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Wed, 4 Apr 2012 19:58:03 +0000 Subject: [PATCH] Look through chains of 'x = y = z' when employing silencing heuristics in the DeadStoresChecker. Fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154040 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/DeadStoresChecker.cpp | 38 +++++++++++++++---- test/Analysis/dead-stores.c | 22 +++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 7457e44e18..510e8cd810 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -68,6 +68,21 @@ void ReachableCode::computeReachableBlocks() { } } +static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { + while (Ex) { + const BinaryOperator *BO = + dyn_cast(Ex->IgnoreParenCasts()); + if (!BO) + break; + if (BO->getOpcode() == BO_Assign) { + Ex = BO->getRHS(); + continue; + } + break; + } + return Ex; +} + namespace { class DeadStoreObs : public LiveVariables::Observer { const CFG &cfg; @@ -200,17 +215,18 @@ public: if (VarDecl *VD = dyn_cast(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. + const Expr *RHS = LookThroughTransitiveAssignments(B->getRHS()); + QualType T = VD->getType(); if (T->isPointerType() || T->isObjCObjectPointerType()) { - if (B->getRHS()->isNullPointerConstant(Ctx, - Expr::NPC_ValueDependentIsNull)) + if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) return; } - Expr *RHS = B->getRHS()->IgnoreParenCasts(); + RHS = RHS->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. - if (DeclRefExpr *RhsDR = dyn_cast(RHS)) + if (const DeclRefExpr *RhsDR = dyn_cast(RHS)) if (VD == dyn_cast(RhsDR->getDecl())) return; @@ -252,10 +268,15 @@ public: if (V->getType()->getAs()) return; - if (Expr *E = V->getInit()) { - while (ExprWithCleanups *exprClean = dyn_cast(E)) + if (const Expr *E = V->getInit()) { + while (const ExprWithCleanups *exprClean = + dyn_cast(E)) E = exprClean->getSubExpr(); + // Look through transitive assignments, e.g.: + // int x = y = 0; + E = LookThroughTransitiveAssignments(E); + // Don't warn on C++ objects (yet) until we can show that their // constructors/destructors don't have side effects. if (isa(E)) @@ -275,8 +296,9 @@ public: if (E->isEvaluatable(Ctx)) return; - if (DeclRefExpr *DRE=dyn_cast(E->IgnoreParenCasts())) - if (VarDecl *VD = dyn_cast(DRE->getDecl())) { + if (const DeclRefExpr *DRE = + dyn_cast(E->IgnoreParenCasts())) + if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { // Special case: check for initialization from constant // variables. // diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 4c0c1bc130..b8d195d05a 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -526,3 +526,25 @@ void rdar8405222() { rdar8405222_aux(i); } +// Look through chains of assignements, e.g.: int x = y = 0, when employing +// silencing heuristics. +int radar11185138_foo() { + int x, y; + x = y = 0; // expected-warning {{never read}} + return y; +} + +int rdar11185138_bar() { + int y; + int x = y = 0; // no-warning + x = 2; + y = 2; + return x + y; +} + +int *radar11185138_baz() { + int *x, *y; + x = y = 0; // no-warning + return y; +} + -- 2.40.0