@@ -28,12 +28,10 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
2828
2929// / An Origin is a symbolic identifier that represents the set of possible
3030// / loans a pointer-like object could hold at any given time.
31- // / TODO: Enhance the origin model to handle complex types, pointer
32- // / indirection and reborrowing. The plan is to move from a single origin per
33- // / variable/expression to a "list of origins" governed by the Type.
34- // / For example, the type 'int**' would have two origins.
35- // / See discussion:
36- // / https://github.com/llvm/llvm-project/pull/142313/commits/0cd187b01e61b200d92ca0b640789c1586075142#r2137644238
31+ // /
32+ // / Each Origin corresponds to a single level of indirection. For complex types
33+ // / with multiple levels of indirection (e.g., `int**`), multiple Origins are
34+ // / organized into an OriginTree structure (see below).
3735struct Origin {
3836 OriginID ID;
3937 // / A pointer to the AST node that this origin represents. This union
@@ -52,41 +50,110 @@ struct Origin {
5250 }
5351};
5452
53+ // / A tree of origins representing levels of indirection for pointer-like types.
54+ // /
55+ // / Each node in the tree contains an OriginID representing a level of
56+ // / indirection. The tree structure captures the multi-level nature of
57+ // / pointer and reference types in the lifetime analysis.
58+ // /
59+ // / Examples:
60+ // / - For `int& x`, the tree has depth 2:
61+ // / * Root: origin for the reference storage itself (the lvalue `x`)
62+ // / * Pointee: origin for what `x` refers to
63+ // /
64+ // / - For `int* p`, the tree has depth 2:
65+ // / * Root: origin for the pointer variable `p`
66+ // / * Pointee: origin for what `p` points to
67+ // /
68+ // / - For `View v` (where View is gsl::Pointer), the tree has depth 2:
69+ // / * Root: origin for the view object itself
70+ // / * Pointee: origin for what the view refers to
71+ // /
72+ // / - For `int** pp`, the tree has depth 3:
73+ // / * Root: origin for `pp` itself
74+ // / * Pointee: origin for `*pp` (what `pp` points to)
75+ // / * Pointee->Pointee: origin for `**pp` (what `*pp` points to)
76+ // /
77+ // / The tree structure enables the analysis to track how loans flow through
78+ // / different levels of indirection when assignments and dereferences occur.
79+ struct OriginTree {
80+ OriginID OID;
81+ OriginTree *Pointee = nullptr ;
82+
83+ OriginTree (OriginID OID) : OID(OID) {}
84+
85+ size_t getDepth () const {
86+ size_t Depth = 1 ;
87+ const OriginTree *T = this ;
88+ while (T->Pointee ) {
89+ T = T->Pointee ;
90+ Depth++;
91+ }
92+ return Depth;
93+ }
94+ };
95+
96+ bool isPointerLikeType (QualType QT);
97+
5598// / Manages the creation, storage, and retrieval of origins for pointer-like
5699// / variables and expressions.
57100class OriginManager {
58101public:
59- OriginManager () = default ;
60-
61- Origin &addOrigin (OriginID ID, const clang::ValueDecl &D);
62- Origin &addOrigin (OriginID ID, const clang::Expr &E);
63-
64- // TODO: Mark this method as const once we remove the call to getOrCreate.
65- OriginID get (const Expr &E);
66-
67- OriginID get (const ValueDecl &D);
68102
69- OriginID getOrCreate (const Expr &E);
103+ explicit OriginManager (ASTContext& AST) : AST(AST) {}
104+
105+ // / Gets or creates the OriginTree for a given ValueDecl.
106+ // /
107+ // / Creates a tree structure mirroring the levels of indirection in the
108+ // / declaration's type (e.g., `int** p` creates depth 2).
109+ // /
110+ // / \returns The OriginTree, or nullptr if the type is not pointer-like.
111+ OriginTree *getOrCreateTree (const ValueDecl *D);
112+
113+ // / Gets or creates the OriginTree for a given Expr.
114+ // /
115+ // / Creates a tree based on the expression's type and value category:
116+ // / - Lvalues get an implicit reference level (modeling addressability)
117+ // / - Rvalues of non-pointer type return nullptr (no trackable origin)
118+ // / - DeclRefExpr may reuse the underlying declaration's tree
119+ // /
120+ // / \returns The OriginTree, or nullptr for non-pointer rvalues.
121+ OriginTree *getOrCreateTree (const Expr *E);
70122
71123 const Origin &getOrigin (OriginID ID) const ;
72124
73125 llvm::ArrayRef<Origin> getOrigins () const { return AllOrigins; }
74126
75- OriginID getOrCreate (const ValueDecl &D);
76-
77127 unsigned getNumOrigins () const { return NextOriginID.Value ; }
78128
79129 void dump (OriginID OID, llvm::raw_ostream &OS) const ;
80130
81131private:
82132 OriginID getNextOriginID () { return NextOriginID++; }
83133
134+ OriginTree *createNode (const ValueDecl *D) {
135+ OriginID NewID = getNextOriginID ();
136+ AllOrigins.emplace_back (NewID, D);
137+ return new (TreeAllocator.Allocate <OriginTree>()) OriginTree (NewID);
138+ }
139+
140+ OriginTree *createNode (const Expr *E) {
141+ OriginID NewID = getNextOriginID ();
142+ AllOrigins.emplace_back (NewID, E);
143+ return new (TreeAllocator.Allocate <OriginTree>()) OriginTree (NewID);
144+ }
145+
146+ template <typename T>
147+ OriginTree *buildTreeForType (QualType QT, const T *Node);
148+
149+ ASTContext& AST;
84150 OriginID NextOriginID{0 };
85- // / TODO(opt): Profile and evaluate the usefullness of small buffer
151+ // / TODO(opt): Profile and evaluate the usefulness of small buffer
86152 // / optimisation.
87153 llvm::SmallVector<Origin> AllOrigins;
88- llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID;
89- llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID;
154+ llvm::BumpPtrAllocator TreeAllocator;
155+ llvm::DenseMap<const clang::ValueDecl *, OriginTree *> DeclToTree;
156+ llvm::DenseMap<const clang::Expr *, OriginTree *> ExprToTree;
90157};
91158} // namespace clang::lifetimes::internal
92159
0 commit comments