diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -89,8 +89,12 @@ if (ExprToLocSizeBefore != ExprToLoc.size()) Effect = LatticeJoinEffect::Changed; - llvm::DenseMap MergedLocToVal; - for (auto &Entry : LocToVal) { + // Move `LocToVal` so that `Environment::Merger::merge` can safely assign + // values to storage locations while this code iterates over the current + // assignments. + llvm::DenseMap OldLocToVal = + std::move(LocToVal); + for (auto &Entry : OldLocToVal) { const StorageLocation *Loc = Entry.first; assert(Loc != nullptr); @@ -103,19 +107,25 @@ assert(It->second != nullptr); if (It->second == Val) { - MergedLocToVal.insert({Loc, Val}); + LocToVal.insert({Loc, Val}); continue; } + if (auto *FirstVal = dyn_cast(Val)) { + auto *SecondVal = cast(It->second); + if (&FirstVal->getPointeeLoc() == &SecondVal->getPointeeLoc()) { + LocToVal.insert({Loc, FirstVal}); + continue; + } + } + // FIXME: Consider destroying `MergedValue` immediately if `Merger::merge` // returns false to avoid storing unneeded values in `DACtx`. if (Value *MergedVal = createValue(Loc->getType())) if (Merger.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this)) - MergedLocToVal.insert({Loc, MergedVal}); + LocToVal.insert({Loc, MergedVal}); } - const unsigned LocToValSizeBefore = LocToVal.size(); - LocToVal = std::move(MergedLocToVal); - if (LocToValSizeBefore != LocToVal.size()) + if (OldLocToVal.size() != LocToVal.size()) Effect = LatticeJoinEffect::Changed; return Effect; diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -494,4 +494,37 @@ }); } +TEST_F(WideningTest, DistinctPointersToTheSameLocation) { + std::string Code = R"( + void target(int Foo, bool Cond) { + int *Bar = &Foo; + while (Cond) { + Bar = &Foo; + } + (void)0; + // [[p]] + } + )"; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + 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 auto *FooLoc = cast( + Env.getStorageLocation(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + }); +} + } // namespace