clang 24.0.0git
Loans.h
Go to the documentation of this file.
1//===- Loans.h - Loan and Access Path Definitions --------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the Loan and AccessPath structures, which represent
10// borrows of storage locations, and the LoanManager, which manages the
11// creation and retrieval of loans during lifetime analysis.
12//
13//===----------------------------------------------------------------------===//
14#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
15#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
16
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/ExprCXX.h"
21#include "llvm/ADT/FoldingSet.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/Support/raw_ostream.h"
24
26
28inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
29 return OS << ID.Value;
30}
31
32/// Represents one step in an access path: either a field access or an
33/// access to an unnamed interior region (denoted by '*').
34///
35/// Examples:
36/// - Field access: `obj.field` has PathElement 'field'
37/// - Interior access: `owner.*` has '*'
38/// - In `std::string s; std::string_view v = s;`, v has loan to s.*
39/// - Array element: `arr[i]` has PathElement '*' (same as interior access)
40class PathElement {
41public:
42 enum class Kind { Field, Interior };
43
44 static PathElement getField(const FieldDecl &FD) {
45 return PathElement(Kind::Field, &FD);
46 }
47 static PathElement getInterior() {
48 return PathElement(Kind::Interior, nullptr);
49 }
50
51 bool isField() const { return K == Kind::Field; }
52 bool isInterior() const { return K == Kind::Interior; }
53 const FieldDecl *getFieldDecl() const { return FD; }
54
55 bool operator==(const PathElement &Other) const {
56 return K == Other.K && FD == Other.FD;
57 }
58 bool operator!=(const PathElement &Other) const { return !(*this == Other); }
59
60 void dump(llvm::raw_ostream &OS) const {
61 if (isField())
62 OS << "." << FD->getNameAsString();
63 else
64 OS << ".*";
65 }
66
67private:
68 PathElement(Kind K, const FieldDecl *FD) : K(K), FD(FD) {}
69 Kind K;
70 const FieldDecl *FD;
71};
72
73/// Represents the base of a placeholder access path, which is a function
74/// parameter, the implicit 'this' object of an instance method, or a field of
75/// the enclosing class. Placeholder paths never expire within the function
76/// scope, as they represent storage from the caller's or object's scope.
77class PlaceholderBase : public llvm::FoldingSetNode {
78 llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *,
79 const FieldDecl *>
80 ParamMethodOrField;
81
82public:
83 PlaceholderBase(const ParmVarDecl *PVD) : ParamMethodOrField(PVD) {}
84 PlaceholderBase(const CXXMethodDecl *MD) : ParamMethodOrField(MD) {}
85 PlaceholderBase(const FieldDecl *FD) : ParamMethodOrField(FD) {}
86
87 const ParmVarDecl *getParmVarDecl() const {
88 return dyn_cast<const ParmVarDecl *>(ParamMethodOrField);
89 }
90
92 return dyn_cast<const CXXMethodDecl *>(ParamMethodOrField);
93 }
94
95 const FieldDecl *getFieldDecl() const {
96 return dyn_cast<const FieldDecl *>(ParamMethodOrField);
97 }
98
99 using KeyTy = llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *,
100 const FieldDecl *>;
101
102 static void Profile(llvm::FoldingSetNodeID &ID, KeyTy ParamMethodOrField) {
103 ID.AddPointer(ParamMethodOrField.getOpaqueValue());
104 }
105
106 void Profile(llvm::FoldingSetNodeID &ID) const {
107 Profile(ID, ParamMethodOrField);
108 }
109};
110
111/// Represents the storage location being borrowed, e.g., a specific stack
112/// variable or a field within it: var.field.*
113///
114/// An AccessPath consists of:
115/// - A base: either a ValueDecl, MaterializeTemporaryExpr, or PlaceholderBase
116/// - A sequence of PathElements representing field accesses or interior
117/// regions
118///
119/// Examples:
120/// - `x` -> Base=x, Elements=[]
121/// - `x.field` -> Base=x, Elements=[.field]
122/// - `x.*` (e.g., string_view from string) -> Base=x, Elements=[.*]
123/// - `x.field.*` -> Base=x, Elements=[.field, .*]
124/// - `$param.field` -> Base=$param, Elements=[.field]
125///
126/// TODO: Model access paths of other types, e.g. heap and globals.
128 /// The base of the access path: a variable, temporary, or placeholder.
129 const llvm::PointerUnion<const clang::ValueDecl *,
131 const PlaceholderBase *, const clang::CXXNewExpr *>
132 Base;
133 /// The path elements representing field accesses and access to unnamed
134 /// interior regions.
136
137public:
138 AccessPath(const clang::ValueDecl *D) : Base(D) {}
140 AccessPath(const PlaceholderBase *PB) : Base(PB) {}
142
143 /// Creates an extended access path by appending a path element.
144 /// Example: AccessPath(x_path, field) creates path to `x.field`.
146 : Base(Other.Base), Elements(Other.Elements) {
147 Elements.push_back(E);
148 }
149
151 return dyn_cast<const clang::ValueDecl *>(Base);
152 }
153
155 return dyn_cast<const clang::MaterializeTemporaryExpr *>(Base);
156 }
157
159 return dyn_cast<const PlaceholderBase *>(Base);
160 }
161
163 return dyn_cast<const clang::CXXNewExpr *>(Base);
164 }
165
166 bool operator==(const AccessPath &RHS) const {
167 return Base == RHS.Base && Elements == RHS.Elements;
168 }
169 bool operator!=(const AccessPath &RHS) const { return !(*this == RHS); }
170
171 /// Returns true if this path is a prefix of Other (or same as Other).
172 /// Examples:
173 /// - `x` is a prefix of `x`, `x.field`, `x.field.*`
174 /// - `x.field` is a prefix of `x.field` and `x.field.nested`
175 /// - `x.field` is NOT a prefix of `x.other_field`
176 bool isPrefixOf(const AccessPath &Other) const {
177 if (Base != Other.Base || Elements.size() > Other.Elements.size())
178 return false;
179 return std::equal(Elements.begin(), Elements.end(), Other.Elements.begin());
180 }
181
182 /// Returns true if this path is a strict prefix of Other.
183 /// Example:
184 /// - `x` is a strict prefix of `x.field` but NOT of `x`
185 bool isStrictPrefixOf(const AccessPath &Other) const {
186 return Elements.size() < Other.Elements.size() && isPrefixOf(Other);
187 }
188 llvm::ArrayRef<PathElement> getElements() const { return Elements; }
189
190 void dump(llvm::raw_ostream &OS) const;
191};
192
193/// Represents a component of an access path: either a named field access or an
194/// abstract unnamed interior region (denoted by '*').
195///
196/// The interior access (`*`) represents the borrowable content of an object
197/// without exposing its internal implementation details. It may abstract over
198/// multiple underlying fields or memory regions.
199///
200/// Examples:
201/// - `int* p = &x;` creates a loan to `x`
202/// - `std::string_view v = s;` creates a loan to `s.*` (interior)
203/// - `int* p = &obj.field;` creates a loan to `obj.field`
204/// - Parameter loans have no IssueExpr (created at function entry)
205class Loan {
206 const LoanID ID;
207 const AccessPath Path;
208 /// The expression that creates the loan, e.g., &x. Optional for placeholder
209 /// loans.
210 const Expr *IssueExpr;
211
212public:
213 Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr = nullptr)
214 : ID(ID), Path(Path), IssueExpr(IssueExpr) {}
215
216 LoanID getID() const { return ID; }
217 const AccessPath &getAccessPath() const { return Path; }
218 const Expr *getIssueExpr() const { return IssueExpr; }
219
220 void dump(llvm::raw_ostream &OS) const;
221};
222
223/// Manages the creation, storage and retrieval of loans.
225
226public:
227 LoanManager() = default;
228
229 Loan *createLoan(AccessPath Path, const Expr *IssueExpr = nullptr) {
230 void *Mem = LoanAllocator.Allocate<Loan>();
231 auto *NewLoan = new (Mem) Loan(getNextLoanID(), Path, IssueExpr);
232 AllLoans.push_back(NewLoan);
233 return NewLoan;
234 }
235
237 return createLoan(AccessPath(getOrCreatePlaceholderBase(PVD)));
238 }
240 return createLoan(AccessPath(getOrCreatePlaceholderBase(MD)));
241 }
243 return createLoan(AccessPath(getOrCreatePlaceholderBase(FD)));
244 }
245
246 const Loan *getLoan(LoanID ID) const {
247 assert(ID.Value < AllLoans.size());
248 return AllLoans[ID.Value];
249 }
250
251 llvm::ArrayRef<const Loan *> getLoans() const { return AllLoans; }
252
253private:
254 LoanID getNextLoanID() { return NextLoanID++; }
255
256 /// Gets or creates a placeholder base for a given parameter, method, or
257 /// field.
258 const PlaceholderBase *getOrCreatePlaceholderBase(const ParmVarDecl *PVD);
259 const PlaceholderBase *getOrCreatePlaceholderBase(const CXXMethodDecl *MD);
260 const PlaceholderBase *getOrCreatePlaceholderBase(const FieldDecl *FD);
261
262 LoanID NextLoanID{0};
263
264 llvm::FoldingSet<PlaceholderBase> PlaceholderBases;
265
266 /// TODO(opt): Profile and evaluate the usefullness of small buffer
267 /// optimisation.
269 llvm::BumpPtrAllocator LoanAllocator;
270};
271} // namespace clang::lifetimes::internal
272
273#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOANS_H
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2360
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3299
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4974
Represents a parameter to a function.
Definition Decl.h:1820
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:127
bool isStrictPrefixOf(const AccessPath &Other) const
Returns true if this path is a strict prefix of Other.
Definition Loans.h:185
const clang::CXXNewExpr * getAsNewAllocation() const
Definition Loans.h:162
bool isPrefixOf(const AccessPath &Other) const
Returns true if this path is a prefix of Other (or same as Other).
Definition Loans.h:176
bool operator!=(const AccessPath &RHS) const
Definition Loans.h:169
AccessPath(const clang::ValueDecl *D)
Definition Loans.h:138
const clang::ValueDecl * getAsValueDecl() const
Definition Loans.h:150
bool operator==(const AccessPath &RHS) const
Definition Loans.h:166
AccessPath(const clang::MaterializeTemporaryExpr *MTE)
Definition Loans.h:139
const clang::MaterializeTemporaryExpr * getAsMaterializeTemporaryExpr() const
Definition Loans.h:154
llvm::ArrayRef< PathElement > getElements() const
Definition Loans.h:188
const PlaceholderBase * getAsPlaceholderBase() const
Definition Loans.h:158
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:13
AccessPath(const PlaceholderBase *PB)
Definition Loans.h:140
AccessPath(const AccessPath &Other, PathElement E)
Creates an extended access path by appending a path element.
Definition Loans.h:145
AccessPath(const clang::CXXNewExpr *New)
Definition Loans.h:141
Loan * createPlaceholderLoan(const ParmVarDecl *PVD)
Definition Loans.h:236
llvm::ArrayRef< const Loan * > getLoans() const
Definition Loans.h:251
const Loan * getLoan(LoanID ID) const
Definition Loans.h:246
Loan * createLoan(AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:229
Loan * createPlaceholderLoan(const FieldDecl *FD)
Definition Loans.h:242
Loan * createPlaceholderLoan(const CXXMethodDecl *MD)
Definition Loans.h:239
Represents a component of an access path: either a named field access or an abstract unnamed interior...
Definition Loans.h:205
const Expr * getIssueExpr() const
Definition Loans.h:218
Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:213
const AccessPath & getAccessPath() const
Definition Loans.h:217
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:34
Represents one step in an access path: either a field access or an access to an unnamed interior regi...
Definition Loans.h:40
static PathElement getInterior()
Definition Loans.h:47
const FieldDecl * getFieldDecl() const
Definition Loans.h:53
void dump(llvm::raw_ostream &OS) const
Definition Loans.h:60
bool operator==(const PathElement &Other) const
Definition Loans.h:55
bool operator!=(const PathElement &Other) const
Definition Loans.h:58
static PathElement getField(const FieldDecl &FD)
Definition Loans.h:44
Represents the base of a placeholder access path, which is a function parameter, the implicit 'this' ...
Definition Loans.h:77
static void Profile(llvm::FoldingSetNodeID &ID, KeyTy ParamMethodOrField)
Definition Loans.h:102
PlaceholderBase(const ParmVarDecl *PVD)
Definition Loans.h:83
llvm::PointerUnion< const ParmVarDecl *, const CXXMethodDecl *, const FieldDecl * > KeyTy
Definition Loans.h:99
PlaceholderBase(const CXXMethodDecl *MD)
Definition Loans.h:84
PlaceholderBase(const FieldDecl *FD)
Definition Loans.h:85
const ParmVarDecl * getParmVarDecl() const
Definition Loans.h:87
const CXXMethodDecl * getImplicitThisParent() const
Definition Loans.h:91
const FieldDecl * getFieldDecl() const
Definition Loans.h:95
void Profile(llvm::FoldingSetNodeID &ID) const
Definition Loans.h:106
utils::ID< struct LoanTag > LoanID
Definition Loans.h:27
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, LoanID ID)
Definition Loans.h:28
@ Other
Other implicit parameter.
Definition Decl.h:1775
A generic, type-safe wrapper for an ID, distinguished by its Tag type.
Definition Utils.h:21