diff options
-rw-r--r-- | clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | 10 | ||||
-rw-r--r-- | clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp | 37 |
2 files changed, 45 insertions, 2 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 7c88917..f734168 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 @@ public: // lowest-level AST node that initializes a given object, and nothing // below them can initialize the same object (or part of it). if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) || - isa<CXXDefaultArgExpr>(E) || isa<CXXDefaultInitExpr>(E) || - isa<CXXStdInitializerListExpr>(E) || isa<AtomicExpr>(E) || + isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) || + isa<AtomicExpr>(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 @@ public: return; } + if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) { + PropagateResultObject(DIE->getExpr(), Loc); + return; + } + // All other expression nodes that propagate a record prvalue should have // exactly one child. SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end()); diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index bd710a0..a4ac597 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 <memory> +#include <string> 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<CXXConstructorDecl>("ctor", Results); + const auto *DefaultInit = + selectFirst<CXXDefaultInitExpr>("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; |