1616
1717#include " clang/AST/Decl.h"
1818#include " clang/AST/Expr.h"
19+ #include " clang/AST/TypeBase.h"
1920#include " clang/Analysis/Analyses/LifetimeSafety/Utils.h"
2021
2122namespace clang ::lifetimes::internal {
@@ -28,21 +29,24 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
2829
2930// / An Origin is a symbolic identifier that represents the set of possible
3031// / 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
32+ // /
33+ // / Each Origin corresponds to a single level of indirection. For complex types
34+ // / with multiple levels of indirection (e.g., `int**`), multiple Origins are
35+ // / organized into an OriginTree structure (see below).
3736struct Origin {
3837 OriginID ID;
3938 // / A pointer to the AST node that this origin represents. This union
4039 // / distinguishes between origins from declarations (variables or parameters)
4140 // / and origins from expressions.
4241 llvm::PointerUnion<const clang::ValueDecl *, const clang::Expr *> Ptr;
4342
44- Origin (OriginID ID, const clang::ValueDecl *D) : ID(ID), Ptr(D) {}
45- Origin (OriginID ID, const clang::Expr *E) : ID(ID), Ptr(E) {}
43+ // Outermost type. TODO: Document.
44+ QualType QT;
45+
46+ Origin (OriginID ID, const clang::ValueDecl *D, QualType QT)
47+ : ID(ID), Ptr(D), QT(QT) {}
48+ Origin (OriginID ID, const clang::Expr *E, QualType QT)
49+ : ID(ID), Ptr(E), QT(QT) {}
4650
4751 const clang::ValueDecl *getDecl () const {
4852 return Ptr.dyn_cast <const clang::ValueDecl *>();
@@ -52,41 +56,111 @@ struct Origin {
5256 }
5357};
5458
59+ // / A tree of origins representing levels of indirection for pointer-like types.
60+ // /
61+ // / Each node in the tree contains an OriginID representing a level of
62+ // / indirection. The tree structure captures the multi-level nature of
63+ // / pointer and reference types in the lifetime analysis.
64+ // /
65+ // / Examples:
66+ // / - For `int& x`, the tree has depth 2:
67+ // / * Root: origin for the reference storage itself (the lvalue `x`)
68+ // / * Pointee: origin for what `x` refers to
69+ // /
70+ // / - For `int* p`, the tree has depth 2:
71+ // / * Root: origin for the pointer variable `p`
72+ // / * Pointee: origin for what `p` points to
73+ // /
74+ // / - For `View v` (where View is gsl::Pointer), the tree has depth 2:
75+ // / * Root: origin for the view object itself
76+ // / * Pointee: origin for what the view refers to
77+ // /
78+ // / - For `int** pp`, the tree has depth 3:
79+ // / * Root: origin for `pp` itself
80+ // / * Pointee: origin for `*pp` (what `pp` points to)
81+ // / * Pointee->Pointee: origin for `**pp` (what `*pp` points to)
82+ // /
83+ // / The tree structure enables the analysis to track how loans flow through
84+ // / different levels of indirection when assignments and dereferences occur.
85+ struct OriginTree {
86+ OriginID OID;
87+ OriginTree *Pointee = nullptr ;
88+
89+ OriginTree (OriginID OID) : OID(OID) {}
90+
91+ size_t getDepth () const {
92+ size_t Depth = 1 ;
93+ const OriginTree *T = this ;
94+ while (T->Pointee ) {
95+ T = T->Pointee ;
96+ Depth++;
97+ }
98+ return Depth;
99+ }
100+ };
101+
102+ bool hasOrigins (QualType QT);
103+ bool hasOrigins (const Expr *E);
104+ bool doesDeclHaveStorage (const ValueDecl *D);
105+
55106// / Manages the creation, storage, and retrieval of origins for pointer-like
56107// / variables and expressions.
57108class OriginManager {
58109public:
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);
68-
69- OriginID getOrCreate (const Expr &E);
110+ explicit OriginManager (ASTContext &AST) : AST(AST) {}
111+
112+ // / Gets or creates the OriginTree for a given ValueDecl.
113+ // /
114+ // / Creates a tree structure mirroring the levels of indirection in the
115+ // / declaration's type (e.g., `int** p` creates depth 2).
116+ // /
117+ // / \returns The OriginTree, or nullptr if the type is not pointer-like.
118+ OriginTree *getOrCreateTree (const ValueDecl *D);
119+
120+ // / Gets or creates the OriginTree for a given Expr.
121+ // /
122+ // / Creates a tree based on the expression's type and value category:
123+ // / - Lvalues get an implicit reference level (modeling addressability)
124+ // / - Rvalues of non-pointer type return nullptr (no trackable origin)
125+ // / - DeclRefExpr may reuse the underlying declaration's tree
126+ // /
127+ // / \returns The OriginTree, or nullptr for non-pointer rvalues.
128+ OriginTree *getOrCreateTree (const Expr *E, size_t Depth = 0 );
70129
71130 const Origin &getOrigin (OriginID ID) const ;
72131
73132 llvm::ArrayRef<Origin> getOrigins () const { return AllOrigins; }
74133
75- OriginID getOrCreate (const ValueDecl &D);
76-
77134 unsigned getNumOrigins () const { return NextOriginID.Value ; }
78135
79136 void dump (OriginID OID, llvm::raw_ostream &OS) const ;
80137
81138private:
82139 OriginID getNextOriginID () { return NextOriginID++; }
83140
141+ OriginTree *createNode (const ValueDecl *D, QualType QT) {
142+ OriginID NewID = getNextOriginID ();
143+ AllOrigins.emplace_back (NewID, D, QT);
144+ return new (TreeAllocator.Allocate <OriginTree>()) OriginTree (NewID);
145+ }
146+
147+ OriginTree *createNode (const Expr *E, QualType QT) {
148+ OriginID NewID = getNextOriginID ();
149+ AllOrigins.emplace_back (NewID, E, QT);
150+ return new (TreeAllocator.Allocate <OriginTree>()) OriginTree (NewID);
151+ }
152+
153+ template <typename T>
154+ OriginTree *buildTreeForType (QualType QT, const T *Node);
155+
156+ ASTContext &AST;
84157 OriginID NextOriginID{0 };
85- // / TODO(opt): Profile and evaluate the usefullness of small buffer
158+ // / TODO(opt): Profile and evaluate the usefulness of small buffer
86159 // / optimisation.
87160 llvm::SmallVector<Origin> AllOrigins;
88- llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID;
89- llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID;
161+ llvm::BumpPtrAllocator TreeAllocator;
162+ llvm::DenseMap<const clang::ValueDecl *, OriginTree *> DeclToTree;
163+ llvm::DenseMap<const clang::Expr *, OriginTree *> ExprToTree;
90164};
91165} // namespace clang::lifetimes::internal
92166
0 commit comments