2424#include  " llvm/Support/TimeProfiler.h" 
2525#include  < cstdint> 
2626
27- namespace  clang ::lifetimes {
28- namespace  internal  {
27+ namespace  clang  {
2928namespace  {
30- template  <typename  Tag>
31- inline  llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
32-   return  OS << ID.Value ;
33- }
34- } //  namespace
3529
3630// / Represents the storage location being borrowed, e.g., a specific stack
3731// / variable.
@@ -42,6 +36,32 @@ struct AccessPath {
4236  AccessPath (const  clang::ValueDecl *D) : D(D) {}
4337};
4438
39+ // / A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
40+ // / Used for giving ID to loans and origins.
41+ template  <typename  Tag> struct  ID  {
42+   uint32_t  Value = 0 ;
43+ 
44+   bool  operator ==(const  ID<Tag> &Other) const  { return  Value == Other.Value ; }
45+   bool  operator !=(const  ID<Tag> &Other) const  { return  !(*this  == Other); }
46+   bool  operator <(const  ID<Tag> &Other) const  { return  Value < Other.Value ; }
47+   ID<Tag> operator ++(int ) {
48+     ID<Tag> Tmp = *this ;
49+     ++Value;
50+     return  Tmp;
51+   }
52+   void  Profile (llvm::FoldingSetNodeID &IDBuilder) const  {
53+     IDBuilder.AddInteger (Value);
54+   }
55+ };
56+ 
57+ template  <typename  Tag>
58+ inline  llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
59+   return  OS << ID.Value ;
60+ }
61+ 
62+ using  LoanID = ID<struct  LoanTag >;
63+ using  OriginID = ID<struct  OriginTag >;
64+ 
4565// / Information about a single borrow, or "Loan". A loan is created when a
4666// / reference or pointer is created.
4767struct  Loan  {
@@ -203,9 +223,7 @@ class Fact {
203223    // / An origin is propagated from a source to a destination (e.g., p = q).
204224    AssignOrigin,
205225    // / An origin escapes the function by flowing into the return value.
206-     ReturnOfOrigin,
207-     // / A marker for a specific point in the code, for testing.
208-     TestPoint,
226+     ReturnOfOrigin
209227  };
210228
211229private: 
@@ -292,24 +310,6 @@ class ReturnOfOriginFact : public Fact {
292310  }
293311};
294312
295- // / A dummy-fact used to mark a specific point in the code for testing.
296- // / It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
297- class  TestPointFact  : public  Fact  {
298-   StringRef Annotation;
299- 
300- public: 
301-   static  bool  classof (const  Fact *F) { return  F->getKind () == Kind::TestPoint; }
302- 
303-   explicit  TestPointFact (StringRef Annotation)
304-       : Fact(Kind::TestPoint), Annotation(Annotation) {}
305- 
306-   StringRef getAnnotation () const  { return  Annotation; }
307- 
308-   void  dump (llvm::raw_ostream &OS) const  override  {
309-     OS << " TestPoint (Annotation: \" "   << getAnnotation () << " \" )\n "  ;
310-   }
311- };
312- 
313313class  FactManager  {
314314public: 
315315  llvm::ArrayRef<const  Fact *> getFacts (const  CFGBlock *B) const  {
@@ -363,7 +363,6 @@ class FactManager {
363363};
364364
365365class  FactGenerator  : public  ConstStmtVisitor <FactGenerator> {
366-   using  Base = ConstStmtVisitor<FactGenerator>;
367366
368367public: 
369368  FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
@@ -459,15 +458,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
459458    }
460459  }
461460
462-   void  VisitCXXFunctionalCastExpr (const  CXXFunctionalCastExpr *FCE) {
463-     //  Check if this is a test point marker. If so, we are done with this
464-     //  expression.
465-     if  (VisitTestPoint (FCE))
466-       return ;
467-     //  Visit as normal otherwise.
468-     Base::VisitCXXFunctionalCastExpr (FCE);
469-   }
470- 
471461private: 
472462  //  Check if a type has an origin.
473463  bool  hasOrigin (QualType QT) { return  QT->isPointerOrReferenceType (); }
@@ -501,27 +491,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
501491    }
502492  }
503493
504-   // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
505-   // / If so, creates a `TestPointFact` and returns true.
506-   bool  VisitTestPoint (const  CXXFunctionalCastExpr *FCE) {
507-     if  (!FCE->getType ()->isVoidType ())
508-       return  false ;
509- 
510-     const  auto  *SubExpr = FCE->getSubExpr ()->IgnoreParenImpCasts ();
511-     if  (const  auto  *SL = dyn_cast<StringLiteral>(SubExpr)) {
512-       llvm::StringRef LiteralValue = SL->getString ();
513-       const  std::string Prefix = " __lifetime_test_point_"  ;
514- 
515-       if  (LiteralValue.starts_with (Prefix)) {
516-         StringRef Annotation = LiteralValue.drop_front (Prefix.length ());
517-         CurrentBlockFacts.push_back (
518-             FactMgr.createFact <TestPointFact>(Annotation));
519-         return  true ;
520-       }
521-     }
522-     return  false ;
523-   }
524- 
525494  FactManager &FactMgr;
526495  AnalysisDeclContext &AC;
527496  llvm::SmallVector<Fact *> CurrentBlockFacts;
@@ -668,8 +637,6 @@ class DataflowAnalysis {
668637      return  D->transfer (In, *F->getAs <AssignOriginFact>());
669638    case  Fact::Kind::ReturnOfOrigin:
670639      return  D->transfer (In, *F->getAs <ReturnOfOriginFact>());
671-     case  Fact::Kind::TestPoint:
672-       return  D->transfer (In, *F->getAs <TestPointFact>());
673640    }
674641    llvm_unreachable (" Unknown fact kind"  );
675642  }
@@ -679,16 +646,14 @@ class DataflowAnalysis {
679646  Lattice transfer (Lattice In, const  ExpireFact &) { return  In; }
680647  Lattice transfer (Lattice In, const  AssignOriginFact &) { return  In; }
681648  Lattice transfer (Lattice In, const  ReturnOfOriginFact &) { return  In; }
682-   Lattice transfer (Lattice In, const  TestPointFact &) { return  In; }
683649};
684650
685651namespace  utils  {
686652
687653// / Computes the union of two ImmutableSets.
688654template  <typename  T>
689- static  llvm::ImmutableSet<T> join (llvm::ImmutableSet<T> A,
690-                                   llvm::ImmutableSet<T> B,
691-                                   typename  llvm::ImmutableSet<T>::Factory &F) {
655+ llvm::ImmutableSet<T> join (llvm::ImmutableSet<T> A, llvm::ImmutableSet<T> B,
656+                            typename  llvm::ImmutableSet<T>::Factory &F) {
692657  if  (A.getHeight () < B.getHeight ())
693658    std::swap (A, B);
694659  for  (const  T &E : B)
@@ -701,7 +666,7 @@ static llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A,
701666//  efficient merge could be implemented using a Patricia Trie or HAMT
702667//  instead of the current AVL-tree-based ImmutableMap.
703668template  <typename  K, typename  V, typename  Joiner>
704- static   llvm::ImmutableMap<K, V>
669+ llvm::ImmutableMap<K, V>
705670join (llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
706671     typename  llvm::ImmutableMap<K, V>::Factory &F, Joiner joinValues) {
707672  if  (A.getHeight () < B.getHeight ())
@@ -725,6 +690,10 @@ join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
725690//                           Loan Propagation Analysis
726691//  ========================================================================= //
727692
693+ //  Using LLVM's immutable collections is efficient for dataflow analysis
694+ //  as it avoids deep copies during state transitions.
695+ //  TODO(opt): Consider using a bitset to represent the set of loans.
696+ using  LoanSet = llvm::ImmutableSet<LoanID>;
728697using  OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
729698
730699// / An object to hold the factories for immutable collections, ensuring
@@ -838,28 +807,17 @@ class LoanPropagationAnalysis
838807//  - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
839808//  - Using the above three to perform the final error reporting.
840809//  ========================================================================= //
810+ } //  anonymous namespace
841811
842- //  ========================================================================= //
843- //                   LifetimeSafetyAnalysis Class Implementation
844- //  ========================================================================= //
845- 
846- //  We need this here for unique_ptr with forward declared class.
847- LifetimeSafetyAnalysis::~LifetimeSafetyAnalysis () = default ;
848- 
849- LifetimeSafetyAnalysis::LifetimeSafetyAnalysis (AnalysisDeclContext &AC)
850-     : AC(AC), Factory(std::make_unique<LifetimeFactory>()),
851-       FactMgr (std::make_unique<FactManager>()) {}
852- 
853- void  LifetimeSafetyAnalysis::run () {
812+ void  runLifetimeSafetyAnalysis (const  DeclContext &DC, const  CFG &Cfg,
813+                                AnalysisDeclContext &AC) {
854814  llvm::TimeTraceScope TimeProfile (" LifetimeSafetyAnalysis"  );
855- 
856-   const  CFG &Cfg = *AC.getCFG ();
857815  DEBUG_WITH_TYPE (" PrintCFG"  , Cfg.dump (AC.getASTContext ().getLangOpts (),
858816                                       /* ShowColors=*/ true ));
859- 
860-   FactGenerator FactGen (* FactMgr, AC);
817+   FactManager FactMgr; 
818+   FactGenerator FactGen (FactMgr, AC);
861819  FactGen.run ();
862-   DEBUG_WITH_TYPE (" LifetimeFacts"  , FactMgr-> dump (Cfg, AC));
820+   DEBUG_WITH_TYPE (" LifetimeFacts"  , FactMgr. dump (Cfg, AC));
863821
864822  // / TODO(opt): Consider optimizing individual blocks before running the
865823  // / dataflow analysis.
@@ -870,56 +828,9 @@ void LifetimeSafetyAnalysis::run() {
870828  // /    blocks; only Decls are visible.  Therefore, loans in a block that
871829  // /    never reach an Origin associated with a Decl can be safely dropped by
872830  // /    the analysis.
873-   LoanPropagation =
874-       std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
875-   LoanPropagation->run ();
876- }
877- 
878- LoanSet LifetimeSafetyAnalysis::getLoansAtPoint (OriginID OID,
879-                                                 ProgramPoint PP) const  {
880-   assert (LoanPropagation && " Analysis has not been run."  );
881-   return  LoanPropagation->getLoans (OID, PP);
882- }
883- 
884- std::optional<OriginID>
885- LifetimeSafetyAnalysis::getOriginIDForDecl (const  ValueDecl *D) const  {
886-   assert (FactMgr && " FactManager not initialized"  );
887-   //  This assumes the OriginManager's `get` can find an existing origin.
888-   //  We might need a `find` method on OriginManager to avoid `getOrCreate` logic
889-   //  in a const-query context if that becomes an issue.
890-   return  FactMgr->getOriginMgr ().get (*D);
891- }
892- 
893- std::vector<LoanID>
894- LifetimeSafetyAnalysis::getLoanIDForVar (const  VarDecl *VD) const  {
895-   assert (FactMgr && " FactManager not initialized"  );
896-   std::vector<LoanID> Result;
897-   for  (const  Loan &L : FactMgr->getLoanMgr ().getLoans ())
898-     if  (L.Path .D  == VD)
899-       Result.push_back (L.ID );
900-   return  Result;
901- }
902- 
903- llvm::StringMap<ProgramPoint> LifetimeSafetyAnalysis::getTestPoints () const  {
904-   assert (FactMgr && " FactManager not initialized"  );
905-   llvm::StringMap<ProgramPoint> AnnotationToPointMap;
906-   for  (const  CFGBlock *Block : *AC.getCFG ()) {
907-     for  (const  Fact *F : FactMgr->getFacts (Block)) {
908-       if  (const  auto  *TPF = F->getAs <TestPointFact>()) {
909-         StringRef PointName = TPF->getAnnotation ();
910-         assert (AnnotationToPointMap.find (PointName) ==
911-                    AnnotationToPointMap.end () &&
912-                " more than one test points with the same name"  );
913-         AnnotationToPointMap[PointName] = F;
914-       }
915-     }
916-   }
917-   return  AnnotationToPointMap;
918- }
919- } //  namespace internal
920- 
921- void  runLifetimeSafetyAnalysis (AnalysisDeclContext &AC) {
922-   internal::LifetimeSafetyAnalysis Analysis (AC);
923-   Analysis.run ();
831+   LifetimeFactory Factory;
832+   LoanPropagationAnalysis LoanPropagation (Cfg, AC, FactMgr, Factory);
833+   LoanPropagation.run ();
834+   DEBUG_WITH_TYPE (" LifetimeLoanPropagation"  , LoanPropagation.dump ());
924835}
925- } //  namespace clang::lifetimes 
836+ } //  namespace clang
0 commit comments