2323#include " llvm/Support/Debug.h"
2424#include " llvm/Support/TimeProfiler.h"
2525#include < cstdint>
26+ #include < memory>
2627
2728namespace clang ::lifetimes {
2829namespace internal {
2930namespace {
30- template <typename Tag>
31- inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
32- return OS << ID.Value ;
33- }
31+ // template <typename Tag>
32+ // inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
33+ // return OS << ID.Value;
34+ // }
3435} // namespace
3536
3637// / Represents the storage location being borrowed, e.g., a specific stack
@@ -832,6 +833,65 @@ class LoanPropagationAnalysis
832833 }
833834};
834835
836+ // ========================================================================= //
837+ // Expired Loans Analysis
838+ // ========================================================================= //
839+
840+ // / The dataflow lattice for tracking the set of expired loans.
841+ struct ExpiredLattice {
842+ LoanSet Expired;
843+
844+ ExpiredLattice () : Expired(nullptr ) {};
845+ explicit ExpiredLattice (LoanSet S) : Expired(S) {}
846+
847+ bool operator ==(const ExpiredLattice &Other) const {
848+ return Expired == Other.Expired ;
849+ }
850+ bool operator !=(const ExpiredLattice &Other) const {
851+ return !(*this == Other);
852+ }
853+
854+ void dump (llvm::raw_ostream &OS) const {
855+ OS << " ExpiredLattice State:\n " ;
856+ if (Expired.isEmpty ())
857+ OS << " <empty>\n " ;
858+ for (const LoanID &LID : Expired)
859+ OS << " Loan " << LID << " is expired\n " ;
860+ }
861+ };
862+
863+ // / The analysis that tracks which loans have expired.
864+ class ExpiredLoansAnalysis
865+ : public DataflowAnalysis<ExpiredLoansAnalysis, ExpiredLattice,
866+ Direction::Forward> {
867+
868+ LoanSet::Factory &Factory;
869+
870+ public:
871+ ExpiredLoansAnalysis (const CFG &C, AnalysisDeclContext &AC, FactManager &F,
872+ LifetimeFactory &Factory)
873+ : DataflowAnalysis(C, AC, F), Factory(Factory.LoanSetFactory) {}
874+
875+ using Base::transfer;
876+
877+ StringRef getAnalysisName () const { return " ExpiredLoans" ; }
878+
879+ Lattice getInitialState () { return Lattice (Factory.getEmptySet ()); }
880+
881+ // / Merges two lattices by taking the union of the expired loan sets.
882+ Lattice join (Lattice L1, Lattice L2) const {
883+ return Lattice (utils::join (L1.Expired , L2.Expired , Factory));
884+ }
885+
886+ Lattice transfer (Lattice In, const ExpireFact &F) {
887+ return Lattice (Factory.add (In.Expired , F.getLoanID ()));
888+ }
889+
890+ Lattice transfer (Lattice In, const IssueFact &F) {
891+ return Lattice (Factory.remove (In.Expired , F.getLoanID ()));
892+ }
893+ };
894+
835895// ========================================================================= //
836896// TODO:
837897// - Modify loan expiry analysis to answer `bool isExpired(Loan L, Point P)`
@@ -873,6 +933,10 @@ void LifetimeSafetyAnalysis::run() {
873933 LoanPropagation =
874934 std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
875935 LoanPropagation->run ();
936+
937+ ExpiredLoans =
938+ std::make_unique<ExpiredLoansAnalysis>(Cfg, AC, *FactMgr, *Factory);
939+ ExpiredLoans->run ();
876940}
877941
878942LoanSet LifetimeSafetyAnalysis::getLoansAtPoint (OriginID OID,
@@ -881,6 +945,11 @@ LoanSet LifetimeSafetyAnalysis::getLoansAtPoint(OriginID OID,
881945 return LoanPropagation->getLoans (OID, PP);
882946}
883947
948+ LoanSet LifetimeSafetyAnalysis::getExpiredLoansAtPoint (ProgramPoint PP) const {
949+ assert (ExpiredLoans && " ExpiredLoansAnalysis has not been run." );
950+ return ExpiredLoans->getState (PP).Expired ;
951+ }
952+
884953std::optional<OriginID>
885954LifetimeSafetyAnalysis::getOriginIDForDecl (const ValueDecl *D) const {
886955 assert (FactMgr && " FactManager not initialized" );
0 commit comments