[clang] 83c2bfd - [clang][dataflow] Handle this-capturing lambdas in field initializers. (#99519)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 22 07:22:26 PDT 2024
Author: Samira Bazuzi
Date: 2024-07-22T10:22:23-04:00
New Revision: 83c2bfdacb0593b3a72e93098a55afdcd93d865f
URL: https://github.com/llvm/llvm-project/commit/83c2bfdacb0593b3a72e93098a55afdcd93d865f
DIFF: https://github.com/llvm/llvm-project/commit/83c2bfdacb0593b3a72e93098a55afdcd93d865f.diff
LOG: [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.
Added:
Modified:
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index f734168e647bd..8d7fe18488217 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -524,12 +524,21 @@ void Environment::initialize() {
assert(VarDecl != nullptr);
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
} else if (Capture.capturesThis()) {
- const auto *SurroundingMethodDecl =
- cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
- QualType ThisPointeeType =
- SurroundingMethodDecl->getFunctionObjectParameterType();
- setThisPointeeStorageLocation(
- cast<RecordStorageLocation>(createObject(ThisPointeeType)));
+ if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
+ const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
+ QualType ThisPointeeType =
+ SurroundingMethodDecl->getFunctionObjectParameterType();
+ setThisPointeeStorageLocation(
+ cast<RecordStorageLocation>(createObject(ThisPointeeType)));
+ } else if (auto *FieldBeingInitialized =
+ dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
+ // This is in a field initializer, rather than a method.
+ setThisPointeeStorageLocation(
+ cast<RecordStorageLocation>(createObject(QualType(
+ FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
+ } else {
+ assert(false && "Unexpected this-capturing lambda context.");
+ }
}
}
} else if (MethodDecl->isImplicitObjectMemberFunction()) {
diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
index a4ac597bb06d6..41fca6bf6eba2 100644
--- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -473,4 +473,32 @@ TEST_F(EnvironmentTest, Stmt) {
Env.getResultObjectLocation(*Init);
}
+// This is a crash repro.
+TEST_F(EnvironmentTest, LambdaCapturingThisInFieldInitializer) {
+ using namespace ast_matchers;
+ std::string Code = R"cc(
+ struct S {
+ int f{[this]() { return 1; }()};
+ };
+ )cc";
+
+ auto Unit =
+ tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
+ auto &Context = Unit->getASTContext();
+
+ ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+ auto *LambdaCallOperator = selectFirst<CXXMethodDecl>(
+ "method", match(cxxMethodDecl(hasName("operator()"),
+ ofClass(cxxRecordDecl(isLambda())))
+ .bind("method"),
+ Context));
+
+ Environment Env(DAContext, *LambdaCallOperator);
+ // Don't crash when initializing.
+ Env.initialize();
+ // And initialize the captured `this` pointee.
+ ASSERT_NE(nullptr, Env.getThisPointeeStorageLocation());
+}
+
} // namespace
More information about the cfe-commits
mailing list