Skip to content

Commit 83c2bfd

Browse files
authored
[clang][dataflow] Handle this-capturing lambdas in field initializers. (#99519)
We previously would assume these lambdas appeared inside a method definition and end up crashing.
1 parent 32cd189 commit 83c2bfd

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,21 @@ void Environment::initialize() {
524524
assert(VarDecl != nullptr);
525525
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
526526
} else if (Capture.capturesThis()) {
527-
const auto *SurroundingMethodDecl =
528-
cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
529-
QualType ThisPointeeType =
530-
SurroundingMethodDecl->getFunctionObjectParameterType();
531-
setThisPointeeStorageLocation(
532-
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
527+
if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
528+
const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
529+
QualType ThisPointeeType =
530+
SurroundingMethodDecl->getFunctionObjectParameterType();
531+
setThisPointeeStorageLocation(
532+
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
533+
} else if (auto *FieldBeingInitialized =
534+
dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
535+
// This is in a field initializer, rather than a method.
536+
setThisPointeeStorageLocation(
537+
cast<RecordStorageLocation>(createObject(QualType(
538+
FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
539+
} else {
540+
assert(false && "Unexpected this-capturing lambda context.");
541+
}
533542
}
534543
}
535544
} else if (MethodDecl->isImplicitObjectMemberFunction()) {

clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,32 @@ TEST_F(EnvironmentTest, Stmt) {
473473
Env.getResultObjectLocation(*Init);
474474
}
475475

476+
// This is a crash repro.
477+
TEST_F(EnvironmentTest, LambdaCapturingThisInFieldInitializer) {
478+
using namespace ast_matchers;
479+
std::string Code = R"cc(
480+
struct S {
481+
int f{[this]() { return 1; }()};
482+
};
483+
)cc";
484+
485+
auto Unit =
486+
tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
487+
auto &Context = Unit->getASTContext();
488+
489+
ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
490+
491+
auto *LambdaCallOperator = selectFirst<CXXMethodDecl>(
492+
"method", match(cxxMethodDecl(hasName("operator()"),
493+
ofClass(cxxRecordDecl(isLambda())))
494+
.bind("method"),
495+
Context));
496+
497+
Environment Env(DAContext, *LambdaCallOperator);
498+
// Don't crash when initializing.
499+
Env.initialize();
500+
// And initialize the captured `this` pointee.
501+
ASSERT_NE(nullptr, Env.getThisPointeeStorageLocation());
502+
}
503+
476504
} // namespace

0 commit comments

Comments
 (0)