diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 7c88917faf9c65..f734168e647bd9 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -15,6 +15,7 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/Type.h" @@ -414,8 +415,8 @@ class ResultObjectVisitor : public AnalysisASTVisitor { // lowest-level AST node that initializes a given object, and nothing // below them can initialize the same object (or part of it). if (isa(E) || isa(E) || isa(E) || - isa(E) || isa(E) || - isa(E) || isa(E) || + isa(E) || isa(E) || + isa(E) || // We treat `BuiltinBitCastExpr` as an "original initializer" too as // it may not even be casting from a record type -- and even if it is, // the two objects are in general of unrelated type. @@ -463,6 +464,11 @@ class ResultObjectVisitor : public AnalysisASTVisitor { return; } + if (auto *DIE = dyn_cast(E)) { + PropagateResultObject(DIE->getExpr(), Loc); + return; + } + // All other expression nodes that propagate a record prvalue should have // exactly one child. SmallVector Children(E->child_begin(), E->child_end()); diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index bd710a00c47ce7..a4ac597bb06d62 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -21,6 +21,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include namespace { @@ -405,6 +406,42 @@ TEST_F(EnvironmentTest, Contains(Member)); } +// This is a repro of a failure case seen in the wild. +TEST_F(EnvironmentTest, CXXDefaultInitExprResultObjIsWrappedExprResultObj) { + using namespace ast_matchers; + + std::string Code = R"cc( + struct Inner {}; + + struct S { + S() {} + + Inner i = {}; + }; + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = + match(cxxConstructorDecl( + hasAnyConstructorInitializer(cxxCtorInitializer( + withInitializer(expr().bind("default_init_expr"))))) + .bind("ctor"), + Context); + const auto *Constructor = selectFirst("ctor", Results); + const auto *DefaultInit = + selectFirst("default_init_expr", Results); + + Environment Env(DAContext, *Constructor); + Env.initialize(); + EXPECT_EQ(&Env.getResultObjectLocation(*DefaultInit), + &Env.getResultObjectLocation(*DefaultInit->getExpr())); +} + TEST_F(EnvironmentTest, Stmt) { using namespace ast_matchers;