Skip to content

Commit 49cb170

Browse files
Pask00martinboehme
andauthored
[clang][dataflow] Handle CXXInheritedCtorInitExpr in ResultObjectVisitor. (#99616)
`CXXInheritedCtorInitExpr` is another of the node kinds that should be considered an "original initializer". An assertion failure in `assert(Children.size() == 1)` happens without this fix. --------- Co-authored-by: martinboehme <[email protected]>
1 parent f2a0f97 commit 49cb170

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> {
416416
// below them can initialize the same object (or part of it).
417417
if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
418418
isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||
419-
isa<AtomicExpr>(E) ||
419+
isa<AtomicExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) ||
420420
// We treat `BuiltinBitCastExpr` as an "original initializer" too as
421421
// it may not even be casting from a record type -- and even if it is,
422422
// the two objects are in general of unrelated type.

clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,55 @@ TEST_F(EnvironmentTest, CXXDefaultInitExprResultObjIsWrappedExprResultObj) {
442442
&Env.getResultObjectLocation(*DefaultInit->getExpr()));
443443
}
444444

445+
// This test verifies the behavior of `getResultObjectLocation()` in
446+
// scenarios involving inherited constructors.
447+
// Since the specific AST node of interest `CXXConstructorDecl` is implicitly
448+
// generated, we cannot annotate any statements inside of it as we do in tests
449+
// within TransferTest. Thus, the only way to get the right `Environment` is by
450+
// explicitly initializing it as we do in tests within EnvironmentTest.
451+
// This is why this test is not inside TransferTest, where most of the tests for
452+
// `getResultObjectLocation()` are located.
453+
TEST_F(EnvironmentTest, ResultObjectLocationForInheritedCtorInitExpr) {
454+
using namespace ast_matchers;
455+
456+
std::string Code = R"(
457+
struct Base {
458+
Base(int b) {}
459+
};
460+
struct Derived : Base {
461+
using Base::Base;
462+
};
463+
464+
Derived d = Derived(0);
465+
)";
466+
467+
auto Unit =
468+
tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++20"});
469+
auto &Context = Unit->getASTContext();
470+
471+
ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
472+
473+
auto Results =
474+
match(cxxConstructorDecl(
475+
hasAnyConstructorInitializer(cxxCtorInitializer(
476+
withInitializer(expr().bind("inherited_ctor_init_expr")))))
477+
.bind("ctor"),
478+
Context);
479+
const auto *Constructor = selectFirst<CXXConstructorDecl>("ctor", Results);
480+
const auto *InheritedCtorInit = selectFirst<CXXInheritedCtorInitExpr>(
481+
"inherited_ctor_init_expr", Results);
482+
483+
EXPECT_EQ(InheritedCtorInit->child_begin(), InheritedCtorInit->child_end());
484+
485+
Environment Env(DAContext, *Constructor);
486+
Env.initialize();
487+
488+
RecordStorageLocation &Loc = Env.getResultObjectLocation(*InheritedCtorInit);
489+
EXPECT_NE(&Loc, nullptr);
490+
491+
EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation());
492+
}
493+
445494
TEST_F(EnvironmentTest, Stmt) {
446495
using namespace ast_matchers;
447496

0 commit comments

Comments
 (0)