Skip to content

Commit 3fed312

Browse files
authored
[clang][dataflow]Propagate the result object location for CXXDefaultInitExpr. (#98490)
These are not "original initializers"; the single node underneath represents the initializing node.
1 parent 1fe406f commit 3fed312

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
1616
#include "clang/AST/Decl.h"
1717
#include "clang/AST/DeclCXX.h"
18+
#include "clang/AST/ExprCXX.h"
1819
#include "clang/AST/RecursiveASTVisitor.h"
1920
#include "clang/AST/Stmt.h"
2021
#include "clang/AST/Type.h"
@@ -414,8 +415,8 @@ class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> {
414415
// lowest-level AST node that initializes a given object, and nothing
415416
// below them can initialize the same object (or part of it).
416417
if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
417-
isa<CXXDefaultArgExpr>(E) || isa<CXXDefaultInitExpr>(E) ||
418-
isa<CXXStdInitializerListExpr>(E) || isa<AtomicExpr>(E) ||
418+
isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||
419+
isa<AtomicExpr>(E) ||
419420
// We treat `BuiltinBitCastExpr` as an "original initializer" too as
420421
// it may not even be casting from a record type -- and even if it is,
421422
// the two objects are in general of unrelated type.
@@ -463,6 +464,11 @@ class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> {
463464
return;
464465
}
465466

467+
if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
468+
PropagateResultObject(DIE->getExpr(), Loc);
469+
return;
470+
}
471+
466472
// All other expression nodes that propagate a record prvalue should have
467473
// exactly one child.
468474
SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());

clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "gmock/gmock.h"
2222
#include "gtest/gtest.h"
2323
#include <memory>
24+
#include <string>
2425

2526
namespace {
2627

@@ -405,6 +406,42 @@ TEST_F(EnvironmentTest,
405406
Contains(Member));
406407
}
407408

409+
// This is a repro of a failure case seen in the wild.
410+
TEST_F(EnvironmentTest, CXXDefaultInitExprResultObjIsWrappedExprResultObj) {
411+
using namespace ast_matchers;
412+
413+
std::string Code = R"cc(
414+
struct Inner {};
415+
416+
struct S {
417+
S() {}
418+
419+
Inner i = {};
420+
};
421+
)cc";
422+
423+
auto Unit =
424+
tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
425+
auto &Context = Unit->getASTContext();
426+
427+
ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
428+
429+
auto Results =
430+
match(cxxConstructorDecl(
431+
hasAnyConstructorInitializer(cxxCtorInitializer(
432+
withInitializer(expr().bind("default_init_expr")))))
433+
.bind("ctor"),
434+
Context);
435+
const auto *Constructor = selectFirst<CXXConstructorDecl>("ctor", Results);
436+
const auto *DefaultInit =
437+
selectFirst<CXXDefaultInitExpr>("default_init_expr", Results);
438+
439+
Environment Env(DAContext, *Constructor);
440+
Env.initialize();
441+
EXPECT_EQ(&Env.getResultObjectLocation(*DefaultInit),
442+
&Env.getResultObjectLocation(*DefaultInit->getExpr()));
443+
}
444+
408445
TEST_F(EnvironmentTest, Stmt) {
409446
using namespace ast_matchers;
410447

0 commit comments

Comments
 (0)