[clang] [clang][dataflow] Add support for lambda captures (PR #68558)
Stanislav Gatev via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 10 13:40:41 PDT 2023
================
@@ -5987,4 +6018,204 @@ TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {
ASTContext &ASTCtx) {});
}
+TEST(TransferTest, LambdaCaptureByCopy) {
+ std::string Code = R"(
+ void target(int Foo, int Bar) {
+ [Foo]() {
+ (void)0;
+ // [[p]]
+ }();
+ }
+ )";
+ runDataflowOnLambda(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
+ EXPECT_THAT(BarLoc, IsNull());
+ });
+}
+
+TEST(TransferTest, LambdaCaptureByReference) {
+ std::string Code = R"(
+ void target(int Foo, int Bar) {
+ [&Foo]() {
+ (void)0;
+ // [[p]]
+ }();
+ }
+ )";
+ runDataflowOnLambda(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
+ EXPECT_THAT(BarLoc, IsNull());
+ });
+}
+
+TEST(TransferTest, LambdaCaptureWithInitializer) {
+ std::string Code = R"(
+ void target(int Bar) {
+ [Foo=Bar]() {
+ (void)0;
+ // [[p]]
+ }();
+ }
+ )";
+ runDataflowOnLambda(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
+ EXPECT_THAT(BarLoc, IsNull());
+ });
+}
+
+TEST(TransferTest, LambdaCaptureByCopyImplicit) {
+ std::string Code = R"(
+ void target(int Foo, int Bar) {
+ [=]() {
+ Foo;
+ // [[p]]
+ }();
+ }
+ )";
+ runDataflowOnLambda(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
+ EXPECT_THAT(BarLoc, IsNull());
+ });
+}
+
+TEST(TransferTest, LambdaCaptureByReferenceImplicit) {
+ std::string Code = R"(
+ void target(int Foo, int Bar) {
+ [&]() {
+ Foo;
+ // [[p]]
+ }();
+ }
+ )";
+ runDataflowOnLambda(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
+ ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
+
+ const Value *FooVal = Env.getValue(*FooLoc);
+ EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
+ EXPECT_THAT(BarLoc, IsNull());
----------------
sgatev wrote:
It's null because `Bar` isn't used in the body of the lambda. I added a comment to make this clear.
https://github.com/llvm/llvm-project/pull/68558
More information about the cfe-commits
mailing list