Index: clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ 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); } Index: clang/test/Analysis/dead-stores.cpp =================================================================== --- clang/test/Analysis/dead-stores.cpp +++ 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). @@ -52,6 +56,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 //===----------------------------------------------------------------------===//