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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits