forked from OSchip/llvm-project
[clang][dataflow] Fix incorrect CXXThisExpr pointee for lambdas
When constructing the `Environment`, the `this` pointee is established for a `CXXMethodDecl` by looking at its parent. However, inside of lambdas, a `CXXThisExpr` refers to the captured `this` coming from the enclosing member function. When establishing the `this` pointee for a function, we check whether the function is a lambda, and check for an enclosing member function to establish the `this` pointee storage location. Differential Revision: https://reviews.llvm.org/D126413
This commit is contained in:
parent
33b598a808
commit
5520c58390
|
@ -216,7 +216,12 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
|
|||
}
|
||||
|
||||
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
|
||||
if (!MethodDecl->isStatic()) {
|
||||
auto *Parent = MethodDecl->getParent();
|
||||
assert(Parent != nullptr);
|
||||
if (Parent->isLambda())
|
||||
MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
|
||||
|
||||
if (MethodDecl && !MethodDecl->isStatic()) {
|
||||
QualType ThisPointeeType = MethodDecl->getThisObjectType();
|
||||
// FIXME: Add support for union types.
|
||||
if (!ThisPointeeType->isUnionType()) {
|
||||
|
|
|
@ -1476,6 +1476,112 @@ TEST_F(TransferTest, ClassThisMember) {
|
|||
});
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, StructThisInLambda) {
|
||||
std::string ThisCaptureCode = R"(
|
||||
struct A {
|
||||
void frob() {
|
||||
[this]() {
|
||||
int Foo = Bar;
|
||||
// [[p1]]
|
||||
}();
|
||||
}
|
||||
|
||||
int Bar;
|
||||
};
|
||||
)";
|
||||
runDataflow(
|
||||
ThisCaptureCode,
|
||||
[](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p1", _)));
|
||||
const Environment &Env = Results[0].second.Env;
|
||||
|
||||
const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
|
||||
Env.getThisPointeeStorageLocation());
|
||||
ASSERT_THAT(ThisLoc, NotNull());
|
||||
|
||||
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
const auto *BarLoc =
|
||||
cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
|
||||
ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
|
||||
|
||||
const Value *BarVal = Env.getValue(*BarLoc);
|
||||
ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
|
||||
|
||||
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
|
||||
ASSERT_THAT(FooDecl, NotNull());
|
||||
EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
|
||||
},
|
||||
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
|
||||
|
||||
std::string RefCaptureDefaultCode = R"(
|
||||
struct A {
|
||||
void frob() {
|
||||
[&]() {
|
||||
int Foo = Bar;
|
||||
// [[p2]]
|
||||
}();
|
||||
}
|
||||
|
||||
int Bar;
|
||||
};
|
||||
)";
|
||||
runDataflow(
|
||||
RefCaptureDefaultCode,
|
||||
[](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p2", _)));
|
||||
const Environment &Env = Results[0].second.Env;
|
||||
|
||||
const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
|
||||
Env.getThisPointeeStorageLocation());
|
||||
ASSERT_THAT(ThisLoc, NotNull());
|
||||
|
||||
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
const auto *BarLoc =
|
||||
cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
|
||||
ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
|
||||
|
||||
const Value *BarVal = Env.getValue(*BarLoc);
|
||||
ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
|
||||
|
||||
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
|
||||
ASSERT_THAT(FooDecl, NotNull());
|
||||
EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
|
||||
},
|
||||
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
|
||||
|
||||
std::string FreeFunctionLambdaCode = R"(
|
||||
void foo() {
|
||||
int Bar;
|
||||
[&]() {
|
||||
int Foo = Bar;
|
||||
// [[p3]]
|
||||
}();
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
FreeFunctionLambdaCode,
|
||||
[](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p3", _)));
|
||||
const Environment &Env = Results[0].second.Env;
|
||||
|
||||
EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());
|
||||
},
|
||||
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, ConstructorInitializer) {
|
||||
std::string Code = R"(
|
||||
struct target {
|
||||
|
|
Loading…
Reference in New Issue