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 @@ -11,17 +11,18 @@ // //===----------------------------------------------------------------------===// -#include "clang/Lex/Lexer.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Lex/Lexer.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/SaveAndRestore.h" @@ -415,6 +416,14 @@ if (E->isEvaluatable(Ctx)) return; + // We should also allow defensive initialization of structs. + if (const auto *ILE = + dyn_cast(E->IgnoreParenCasts())) + if (llvm::all_of(ILE->inits(), [this](const Expr *Init) { + return Init->isEvaluatable(Ctx); + })) + return; + if (const DeclRefExpr *DRE = dyn_cast(E->IgnoreParenCasts())) if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { diff --git a/clang/test/Analysis/dead-stores.c b/clang/test/Analysis/dead-stores.c --- a/clang/test/Analysis/dead-stores.c +++ b/clang/test/Analysis/dead-stores.c @@ -635,3 +635,21 @@ volatile int v; v = 0; // no warning } + +struct Foo { + int x; + int y; +}; + +struct Foo rdar34122265_getFoo(void); + +int rdar34122265_test_struct(int input) { + // This is allowed for defensive programming. + struct Foo foo = {0, 0}; + if (input > 0) { + foo = rdar34122265_getFoo(); + } else { + return 0; + } + return foo.x + foo.y; +}