diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -103,8 +103,8 @@ static const Expr * LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) { while (Ex) { - const BinaryOperator *BO = - dyn_cast(Ex->IgnoreParenCasts()); + Ex = Ex->IgnoreParenCasts(); + const BinaryOperator *BO = dyn_cast(Ex); if (!BO) break; BinaryOperatorKind Op = BO->getOpcode(); @@ -331,8 +331,7 @@ // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. const Expr *RHS = - LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); - RHS = RHS->IgnoreParenCasts(); + LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); QualType T = VD->getType(); if (T.isVolatileQualified()) @@ -415,8 +414,7 @@ if (isConstant(E)) return; - if (const DeclRefExpr *DRE = - dyn_cast(E->IgnoreParenCasts())) + if (const DeclRefExpr *DRE = dyn_cast(E)) if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { // Special case: check for initialization from constant // variables. @@ -438,7 +436,7 @@ PathDiagnosticLocation Loc = PathDiagnosticLocation::create(V, BR.getSourceManager()); - Report(V, DeadInit, Loc, E->getSourceRange()); + Report(V, DeadInit, Loc, V->getInit()->getSourceRange()); } } } @@ -450,8 +448,9 @@ bool isConstant(const InitListExpr *Candidate) const { // We consider init list to be constant if each member of the list can be // interpreted as constant. - return llvm::all_of(Candidate->inits(), - [this](const Expr *Init) { return isConstant(Init); }); + return llvm::all_of(Candidate->inits(), [this](const Expr *Init) { + return isConstant(Init->IgnoreParenCasts()); + }); } /// Return true if the given expression can be interpreted as constant @@ -461,7 +460,7 @@ return true; // We should also allow defensive initialization of structs, i.e. { 0 } - if (const auto *ILE = dyn_cast(E->IgnoreParenCasts())) { + if (const auto *ILE = dyn_cast(E)) { return isConstant(ILE); } diff --git a/clang/test/Analysis/dead-stores.cpp b/clang/test/Analysis/dead-stores.cpp --- a/clang/test/Analysis/dead-stores.cpp +++ b/clang/test/Analysis/dead-stores.cpp @@ -11,6 +11,10 @@ // RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 \ // RUN: -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code \ // RUN: -verify=non-nested,nested %s +// +// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++17 \ +// RUN: -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code \ +// RUN: -verify=non-nested,nested %s //===----------------------------------------------------------------------===// // Basic dead store checking (but in C++ mode). @@ -33,6 +37,8 @@ (void)y; if ((y = make_int())) // nested-warning {{Although the value stored}} return; + + auto z = "text"; // non-nested-warning {{never read}} } //===----------------------------------------------------------------------===// @@ -52,6 +58,18 @@ return x; } +class TestConstructor { +public: + TestConstructor(int &y); +}; +void copy(int x) { + // All these calls might have side effects in the opaque constructor + TestConstructor tc1 = x; // no-warning potential side effects + TestConstructor tc2 = TestConstructor(x); // no-warning potential side effects + TestConstructor tc3 = (TestConstructor(x)); // no-warning potential side effects + TestConstructor tc4 = (TestConstructor)(x); // no-warning potential side effects +} + //===----------------------------------------------------------------------===// // Dead store checking involving CXXTemporaryExprs //===----------------------------------------------------------------------===//