[clang] baa0f22 - [clang][dataflow] Update StructValue child when assigning a value
Stanislav Gatev via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 24 08:43:09 PST 2022
Author: Stanislav Gatev
Date: 2022-02-24T16:41:48Z
New Revision: baa0f221d6df2fcce10c54751cc42284e2656c31
URL: https://github.com/llvm/llvm-project/commit/baa0f221d6df2fcce10c54751cc42284e2656c31
DIFF: https://github.com/llvm/llvm-project/commit/baa0f221d6df2fcce10c54751cc42284e2656c31.diff
LOG: [clang][dataflow] Update StructValue child when assigning a value
When assigning a value to a storage location of a struct member we
need to also update the value in the corresponding `StructValue`.
This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.
Reviewed-by: ymandel, xazax.hun
Differential Revision: https://reviews.llvm.org/D120414
Added:
Modified:
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index bab20418a016a..2fb32053a11b5 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -265,6 +265,12 @@ class Environment {
llvm::DenseMap<const StorageLocation *, Value *> LocToVal;
+ // Maps locations of struct members to symbolic values of the structs that own
+ // them and the decls of the struct members.
+ llvm::DenseMap<const StorageLocation *,
+ std::pair<StructValue *, const ValueDecl *>>
+ MemberLocToStruct;
+
// FIXME: Add flow condition constraints.
};
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 0fb341fd0bb05..fc6f9aa2167b0 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -138,6 +138,9 @@ bool Environment::equivalentTo(const Environment &Other,
if (ExprToLoc != Other.ExprToLoc)
return false;
+ if (MemberLocToStruct != Other.MemberLocToStruct)
+ return false;
+
if (LocToVal.size() != Other.LocToVal.size())
return false;
@@ -176,6 +179,12 @@ LatticeJoinEffect Environment::join(const Environment &Other,
if (ExprToLocSizeBefore != ExprToLoc.size())
Effect = LatticeJoinEffect::Changed;
+ const unsigned MemberLocToStructSizeBefore = MemberLocToStruct.size();
+ MemberLocToStruct =
+ intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
+ if (MemberLocToStructSizeBefore != MemberLocToStruct.size())
+ Effect = LatticeJoinEffect::Changed;
+
// Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
// values to storage locations while this code iterates over the current
// assignments.
@@ -285,9 +294,25 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
assert(Field != nullptr);
- setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
+ StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
+ MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
+ setValue(FieldLoc, StructVal->getChild(*Field));
}
}
+
+ auto IT = MemberLocToStruct.find(&Loc);
+ if (IT != MemberLocToStruct.end()) {
+ // `Loc` is the location of a struct member so we need to also update the
+ // value of the member in the corresponding `StructValue`.
+
+ assert(IT->second.first != nullptr);
+ StructValue &StructVal = *IT->second.first;
+
+ assert(IT->second.second != nullptr);
+ const ValueDecl &Member = *IT->second.second;
+
+ StructVal.setChild(Member, Val);
+ }
}
Value *Environment::getValue(const StorageLocation &Loc) const {
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index fda4af435c4a7..4da24e0e1f75c 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2320,4 +2320,48 @@ TEST_F(TransferTest, StaticMemberRefVarDecl) {
});
}
+TEST_F(TransferTest, AssignMemberBeforeCopy) {
+ std::string Code = R"(
+ struct A {
+ int Foo;
+ };
+
+ void target() {
+ A A1;
+ A A2;
+ int Bar;
+ A1.Foo = Bar;
+ A2 = A1;
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+ ASSERT_THAT(BarDecl, NotNull());
+
+ const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
+ ASSERT_THAT(A1Decl, NotNull());
+
+ const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
+ ASSERT_THAT(A2Decl, NotNull());
+
+ const auto *BarVal =
+ cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
+
+ const auto *A2Val =
+ cast<StructValue>(Env.getValue(*A2Decl, SkipPast::None));
+ EXPECT_EQ(&A2Val->getChild(*FooDecl), BarVal);
+ });
+}
+
} // namespace
More information about the cfe-commits
mailing list