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 either a
74/// function parameter or the implicit 'this' object of an instance method.
75/// Placeholder paths never expire within the function scope, as they represent
76/// storage from the caller's scope.
77class PlaceholderBase : public llvm::FoldingSetNode {
78 llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *> ParamOrMethod;
79
80public:
81 PlaceholderBase(const ParmVarDecl *PVD) : ParamOrMethod(PVD) {}
82 PlaceholderBase(const CXXMethodDecl *MD) : ParamOrMethod(MD) {}
83
84 const ParmVarDecl *getParmVarDecl() const {
85 return ParamOrMethod.dyn_cast<const ParmVarDecl *>();
86 }
87
89 return ParamOrMethod.dyn_cast<const CXXMethodDecl *>();
90 }
91
92 using KeyTy = llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *>;
93
94 static void Profile(llvm::FoldingSetNodeID &ID, KeyTy ParamOrMethod) {
95 ID.AddPointer(ParamOrMethod.getOpaqueValue());
96 }
97
98 void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, ParamOrMethod); }
99};
100
101/// Represents the storage location being borrowed, e.g., a specific stack
102/// variable or a field within it: var.field.*
103///
104/// An AccessPath consists of:
105/// - A base: either a ValueDecl, MaterializeTemporaryExpr, or PlaceholderBase
106/// - A sequence of PathElements representing field accesses or interior
107/// regions
108///
109/// Examples:
110/// - `x` -> Base=x, Elements=[]
111/// - `x.field` -> Base=x, Elements=[.field]
112/// - `x.*` (e.g., string_view from string) -> Base=x, Elements=[.*]
113/// - `x.field.*` -> Base=x, Elements=[.field, .*]
114/// - `$param.field` -> Base=$param, Elements=[.field]
115///
116/// TODO: Model access paths of other types, e.g. heap and globals.
118 /// The base of the access path: a variable, temporary, or placeholder.
119 const llvm::PointerUnion<const clang::ValueDecl *,
121 const PlaceholderBase *, const clang::CXXNewExpr *>
122 Base;
123 /// The path elements representing field accesses and access to unnamed
124 /// interior regions.
126
127public:
128 AccessPath(const clang::ValueDecl *D) : Base(D) {}
130 AccessPath(const PlaceholderBase *PB) : Base(PB) {}
132
133 /// Creates an extended access path by appending a path element.
134 /// Example: AccessPath(x_path, field) creates path to `x.field`.
136 : Base(Other.Base), Elements(Other.Elements) {
137 Elements.push_back(E);
138 }
139
141 return Base.dyn_cast<const clang::ValueDecl *>();
142 }
143
145 return Base.dyn_cast<const clang::MaterializeTemporaryExpr *>();
146 }
147
149 return Base.dyn_cast<const PlaceholderBase *>();
150 }
151
153 return Base.dyn_cast<const clang::CXXNewExpr *>();
154 }
155
156 bool operator==(const AccessPath &RHS) const {
157 return Base == RHS.Base && Elements == RHS.Elements;
158 }
159 bool operator!=(const AccessPath &RHS) const { return !(*this == RHS); }
160
161 /// Returns true if this path is a prefix of Other (or same as Other).
162 /// Examples:
163 /// - `x` is a prefix of `x`, `x.field`, `x.field.*`
164 /// - `x.field` is a prefix of `x.field` and `x.field.nested`
165 /// - `x.field` is NOT a prefix of `x.other_field`
166 bool isPrefixOf(const AccessPath &Other) const {
167 if (Base != Other.Base || Elements.size() > Other.Elements.size())
168 return false;
169 return std::equal(Elements.begin(), Elements.end(), Other.Elements.begin());
170 }
171
172 /// Returns true if this path is a strict prefix of Other.
173 /// Example:
174 /// - `x` is a strict prefix of `x.field` but NOT of `x`
175 bool isStrictPrefixOf(const AccessPath &Other) const {
176 return Elements.size() < Other.Elements.size() && isPrefixOf(Other);
177 }
178 llvm::ArrayRef<PathElement> getElements() const { return Elements; }
179
180 void dump(llvm::raw_ostream &OS) const;
181};
182
183/// Represents a component of an access path: either a named field access or an
184/// abstract unnamed interior region (denoted by '*').
185///
186/// The interior access (`*`) represents the borrowable content of an object
187/// without exposing its internal implementation details. It may abstract over
188/// multiple underlying fields or memory regions.
189///
190/// Examples:
191/// - `int* p = &x;` creates a loan to `x`
192/// - `std::string_view v = s;` creates a loan to `s.*` (interior)
193/// - `int* p = &obj.field;` creates a loan to `obj.field`
194/// - Parameter loans have no IssueExpr (created at function entry)
195class Loan {
196 const LoanID ID;
197 const AccessPath Path;
198 /// The expression that creates the loan, e.g., &x. Optional for placeholder
199 /// loans.
200 const Expr *IssueExpr;
201
202public:
203 Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr = nullptr)
204 : ID(ID), Path(Path), IssueExpr(IssueExpr) {}
205
206 LoanID getID() const { return ID; }
207 const AccessPath &getAccessPath() const { return Path; }
208 const Expr *getIssueExpr() const { return IssueExpr; }
209
210 void dump(llvm::raw_ostream &OS) const;
211};
212
213/// Manages the creation, storage and retrieval of loans.
215
216public:
217 LoanManager() = default;
218
219 Loan *createLoan(AccessPath Path, const Expr *IssueExpr = nullptr) {
220 void *Mem = LoanAllocator.Allocate<Loan>();
221 auto *NewLoan = new (Mem) Loan(getNextLoanID(), Path, IssueExpr);
222 AllLoans.push_back(NewLoan);
223 return NewLoan;
224 }
225
227 return createLoan(AccessPath(getOrCreatePlaceholderBase(PVD)));
228 }
230 return createLoan(AccessPath(getOrCreatePlaceholderBase(MD)));
231 }
232
233 const Loan *getLoan(LoanID ID) const {
234 assert(ID.Value < AllLoans.size());
235 return AllLoans[ID.Value];
236 }
237
238 llvm::ArrayRef<const Loan *> getLoans() const { return AllLoans; }
239
240private:
241 LoanID getNextLoanID() { return NextLoanID++; }
242
243 /// Gets or creates a placeholder base for a given parameter or method.
244 const PlaceholderBase *getOrCreatePlaceholderBase(const ParmVarDecl *PVD);
245 const PlaceholderBase *getOrCreatePlaceholderBase(const CXXMethodDecl *MD);
246
247 LoanID NextLoanID{0};
248
249 llvm::FoldingSet<PlaceholderBase> PlaceholderBases;
250
251 /// TODO(opt): Profile and evaluate the usefullness of small buffer
252 /// optimisation.
254 llvm::BumpPtrAllocator LoanAllocator;
255};
256} // namespace clang::lifetimes::internal
257
258#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:2149
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2359
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3295
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4973
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:117
bool isStrictPrefixOf(const AccessPath &Other) const
Returns true if this path is a strict prefix of Other.
Definition Loans.h:175
const clang::CXXNewExpr * getAsNewAllocation() const
Definition Loans.h:152
bool isPrefixOf(const AccessPath &Other) const
Returns true if this path is a prefix of Other (or same as Other).
Definition Loans.h:166
bool operator!=(const AccessPath &RHS) const
Definition Loans.h:159
AccessPath(const clang::ValueDecl *D)
Definition Loans.h:128
const clang::ValueDecl * getAsValueDecl() const
Definition Loans.h:140
bool operator==(const AccessPath &RHS) const
Definition Loans.h:156
AccessPath(const clang::MaterializeTemporaryExpr *MTE)
Definition Loans.h:129
const clang::MaterializeTemporaryExpr * getAsMaterializeTemporaryExpr() const
Definition Loans.h:144
llvm::ArrayRef< PathElement > getElements() const
Definition Loans.h:178
const PlaceholderBase * getAsPlaceholderBase() const
Definition Loans.h:148
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:13
AccessPath(const PlaceholderBase *PB)
Definition Loans.h:130
AccessPath(const AccessPath &Other, PathElement E)
Creates an extended access path by appending a path element.
Definition Loans.h:135
AccessPath(const clang::CXXNewExpr *New)
Definition Loans.h:131
Loan * createPlaceholderLoan(const ParmVarDecl *PVD)
Definition Loans.h:226
llvm::ArrayRef< const Loan * > getLoans() const
Definition Loans.h:238
const Loan * getLoan(LoanID ID) const
Definition Loans.h:233
Loan * createLoan(AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:219
Loan * createPlaceholderLoan(const CXXMethodDecl *MD)
Definition Loans.h:229
Represents a component of an access path: either a named field access or an abstract unnamed interior...
Definition Loans.h:195
const Expr * getIssueExpr() const
Definition Loans.h:208
Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:203
const AccessPath & getAccessPath() const
Definition Loans.h:207
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:32
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 either a function parameter or the implici...
Definition Loans.h:77
PlaceholderBase(const ParmVarDecl *PVD)
Definition Loans.h:81
PlaceholderBase(const CXXMethodDecl *MD)
Definition Loans.h:82
static void Profile(llvm::FoldingSetNodeID &ID, KeyTy ParamOrMethod)
Definition Loans.h:94
llvm::PointerUnion< const ParmVarDecl *, const CXXMethodDecl * > KeyTy
Definition Loans.h:92
const ParmVarDecl * getParmVarDecl() const
Definition Loans.h:84
const CXXMethodDecl * getImplicitThisParent() const
Definition Loans.h:88
void Profile(llvm::FoldingSetNodeID &ID) const
Definition Loans.h:98
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