diff --git a/clang/lib/Analysis/LifetimeSafety/Dataflow.h b/clang/lib/Analysis/LifetimeSafety/Dataflow.h index fc3049c8bec84..aaa2c32c400c3 100644 --- a/clang/lib/Analysis/LifetimeSafety/Dataflow.h +++ b/clang/lib/Analysis/LifetimeSafety/Dataflow.h @@ -47,6 +47,9 @@ using ProgramPoint = const Fact *; /// lifetime-relevant `Fact` transforms the lattice state. Only overloads /// for facts relevant to the analysis need to be implemented. /// +/// It may additionally override `Lattice exitBlock(Lattice);` to drop state +/// that is not visible outside the block it was computed in. +/// /// \tparam Derived The CRTP derived class that implements the specific /// analysis. /// \tparam LatticeType The dataflow lattice used by the analysis. @@ -157,7 +160,7 @@ class DataflowAnalysis { State = transferFact(State, F); } } - return State; + return static_cast(this)->exitBlock(State); } Lattice transferFact(Lattice In, const Fact *F) { @@ -187,6 +190,8 @@ class DataflowAnalysis { } public: + Lattice exitBlock(Lattice In) { return In; } + Lattice transfer(Lattice In, const IssueFact &) { return In; } Lattice transfer(Lattice In, const ExpireFact &) { return In; } Lattice transfer(Lattice In, const OriginFlowFact &) { return In; } diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp index 078892bd48c10..f028e0f06ae29 100644 --- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp @@ -148,8 +148,9 @@ class AnalysisImpl Lattice getInitialState() { return Lattice{}; } /// Merges two lattices by taking the union of loans for each origin. - /// Only persistent origins are joined; block-local origins are discarded. Lattice join(Lattice A, Lattice B) { + assert(A.BlockLocalOrigins.isEmpty() && B.BlockLocalOrigins.isEmpty() && + "block-local origins must not reach a block boundary"); OriginLoanMap JoinedOrigins = utils::join( A.PersistentOrigins, B.PersistentOrigins, OriginLoanMapFactory, [&](const LoanSet *S1, const LoanSet *S2) { @@ -166,6 +167,14 @@ class AnalysisImpl return Lattice(JoinedOrigins, OriginLoanMapFactory.getEmptyMap()); } + /// Block-local origins are not referenced outside the block that computed + /// them, so they are dropped here rather than propagated to adjacent blocks. + /// Dropping them at the boundary (instead of in `join`) also covers edges + /// where `join` is never called, such as blocks with a single predecessor. + Lattice exitBlock(Lattice L) { + return Lattice(L.PersistentOrigins, OriginLoanMapFactory.getEmptyMap()); + } + /// A new loan is issued to the origin. Old loans are erased. Lattice transfer(Lattice In, const IssueFact &F) { OriginID OID = F.getOriginID();