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, placeholder, or an
129 /// allocation expression (a `CXXNewExpr` or an allocating `CallExpr`).
130 ///
131 /// NOTE: Keep the number of alternatives low; PointerUnion packs the
132 /// discriminator in the low bits of the pointer, so more alternatives
133 /// require more alignment than 32-bit builds can always provide.
134 const llvm::PointerUnion<const clang::ValueDecl *, const PlaceholderBase *,
135 const clang::Expr *>
136 Base;
137 /// The path elements representing field accesses and access to unnamed
138 /// interior regions.
140
141public:
142 AccessPath(const clang::ValueDecl *D) : Base(D) {}
144 AccessPath(const PlaceholderBase *PB) : Base(PB) {}
146 AccessPath(const clang::CallExpr *CE) : Base(CE) {}
147
148 /// Creates an extended access path by appending a path element.
149 /// Example: AccessPath(x_path, field) creates path to `x.field`.
151 : Base(Other.Base), Elements(Other.Elements) {
152 Elements.push_back(E);
153 }
154
156 return dyn_cast<const clang::ValueDecl *>(Base);
157 }
158
160 return dyn_cast_or_null<clang::MaterializeTemporaryExpr>(
161 dyn_cast<const clang::Expr *>(Base));
162 }
163
165 return dyn_cast<const PlaceholderBase *>(Base);
166 }
167
168 /// Returns the allocation expression that created this loan: a
169 /// `CXXNewExpr` or an allocating `CallExpr`.
171 const auto *E = dyn_cast<const clang::Expr *>(Base);
172 return isa_and_nonnull<clang::CXXNewExpr, clang::CallExpr>(E) ? E : nullptr;
173 }
174
175 bool operator==(const AccessPath &RHS) const {
176 return Base == RHS.Base && Elements == RHS.Elements;
177 }
178 bool operator!=(const AccessPath &RHS) const { return !(*this == RHS); }
179
180 /// Returns true if this path is a prefix of Other (or same as Other).
181 /// Examples:
182 /// - `x` is a prefix of `x`, `x.field`, `x.field.*`
183 /// - `x.field` is a prefix of `x.field` and `x.field.nested`
184 /// - `x.field` is NOT a prefix of `x.other_field`
185 bool isPrefixOf(const AccessPath &Other) const {
186 if (Base != Other.Base || Elements.size() > Other.Elements.size())
187 return false;
188 return std::equal(Elements.begin(), Elements.end(), Other.Elements.begin());
189 }
190
191 /// Returns true if this path is a strict prefix of Other.
192 /// Example:
193 /// - `x` is a strict prefix of `x.field` but NOT of `x`
194 bool isStrictPrefixOf(const AccessPath &Other) const {
195 return Elements.size() < Other.Elements.size() && isPrefixOf(Other);
196 }
197 llvm::ArrayRef<PathElement> getElements() const { return Elements; }
198
199 void dump(llvm::raw_ostream &OS) const;
200};
201
202/// Represents a component of an access path: either a named field access or an
203/// abstract unnamed interior region (denoted by '*').
204///
205/// The interior access (`*`) represents the borrowable content of an object
206/// without exposing its internal implementation details. It may abstract over
207/// multiple underlying fields or memory regions.
208///
209/// Examples:
210/// - `int* p = &x;` creates a loan to `x`
211/// - `std::string_view v = s;` creates a loan to `s.*` (interior)
212/// - `int* p = &obj.field;` creates a loan to `obj.field`
213/// - Parameter loans have no IssueExpr (created at function entry)
214class Loan {
215 const LoanID ID;
216 const AccessPath Path;
217 /// The expression that creates the loan, e.g., &x. Optional for placeholder
218 /// loans.
219 const Expr *IssueExpr;
220
221public:
222 Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr = nullptr)
223 : ID(ID), Path(Path), IssueExpr(IssueExpr) {}
224
225 LoanID getID() const { return ID; }
226 const AccessPath &getAccessPath() const { return Path; }
227 const Expr *getIssueExpr() const { return IssueExpr; }
228
229 void dump(llvm::raw_ostream &OS) const;
230};
231
232/// Manages the creation, storage and retrieval of loans.
234
235public:
236 LoanManager() = default;
237
238 Loan *createLoan(AccessPath Path, const Expr *IssueExpr = nullptr) {
239 void *Mem = LoanAllocator.Allocate<Loan>();
240 auto *NewLoan = new (Mem) Loan(getNextLoanID(), Path, IssueExpr);
241 AllLoans.push_back(NewLoan);
242 return NewLoan;
243 }
244
246 return createLoan(AccessPath(getOrCreatePlaceholderBase(PVD)));
247 }
249 return createLoan(AccessPath(getOrCreatePlaceholderBase(MD)));
250 }
252 return createLoan(AccessPath(getOrCreatePlaceholderBase(FD)));
253 }
254
255 const Loan *getLoan(LoanID ID) const {
256 assert(ID.Value < AllLoans.size());
257 return AllLoans[ID.Value];
258 }
259
260 llvm::ArrayRef<const Loan *> getLoans() const { return AllLoans; }
261
262private:
263 LoanID getNextLoanID() { return NextLoanID++; }
264
265 /// Gets or creates a placeholder base for a given parameter, method, or
266 /// field.
267 const PlaceholderBase *getOrCreatePlaceholderBase(const ParmVarDecl *PVD);
268 const PlaceholderBase *getOrCreatePlaceholderBase(const CXXMethodDecl *MD);
269 const PlaceholderBase *getOrCreatePlaceholderBase(const FieldDecl *FD);
270
271 LoanID NextLoanID{0};
272
273 llvm::FoldingSet<PlaceholderBase> PlaceholderBases;
274
275 /// TODO(opt): Profile and evaluate the usefullness of small buffer
276 /// optimisation.
278 llvm::BumpPtrAllocator LoanAllocator;
279};
280} // namespace clang::lifetimes::internal
281
282#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:2153
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2360
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:3012
This represents one expression.
Definition Expr.h:114
Represents a member of a struct/union/class.
Definition Decl.h:3341
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:1832
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
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:194
AccessPath(const clang::CallExpr *CE)
Definition Loans.h:146
bool isPrefixOf(const AccessPath &Other) const
Returns true if this path is a prefix of Other (or same as Other).
Definition Loans.h:185
bool operator!=(const AccessPath &RHS) const
Definition Loans.h:178
AccessPath(const clang::ValueDecl *D)
Definition Loans.h:142
const clang::ValueDecl * getAsValueDecl() const
Definition Loans.h:155
bool operator==(const AccessPath &RHS) const
Definition Loans.h:175
AccessPath(const clang::MaterializeTemporaryExpr *MTE)
Definition Loans.h:143
const clang::MaterializeTemporaryExpr * getAsMaterializeTemporaryExpr() const
Definition Loans.h:159
llvm::ArrayRef< PathElement > getElements() const
Definition Loans.h:197
const PlaceholderBase * getAsPlaceholderBase() const
Definition Loans.h:164
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:13
AccessPath(const PlaceholderBase *PB)
Definition Loans.h:144
const clang::Expr * getAsAllocation() const
Returns the allocation expression that created this loan: a CXXNewExpr or an allocating CallExpr.
Definition Loans.h:170
AccessPath(const AccessPath &Other, PathElement E)
Creates an extended access path by appending a path element.
Definition Loans.h:150
AccessPath(const clang::CXXNewExpr *New)
Definition Loans.h:145
Loan * createPlaceholderLoan(const ParmVarDecl *PVD)
Definition Loans.h:245
llvm::ArrayRef< const Loan * > getLoans() const
Definition Loans.h:260
const Loan * getLoan(LoanID ID) const
Definition Loans.h:255
Loan * createLoan(AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:238
Loan * createPlaceholderLoan(const FieldDecl *FD)
Definition Loans.h:251
Loan * createPlaceholderLoan(const CXXMethodDecl *MD)
Definition Loans.h:248
Represents a component of an access path: either a named field access or an abstract unnamed interior...
Definition Loans.h:214
const Expr * getIssueExpr() const
Definition Loans.h:227
Loan(LoanID ID, AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:222
const AccessPath & getAccessPath() const
Definition Loans.h:226
void dump(llvm::raw_ostream &OS) const
Definition Loans.cpp:39
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:1787
A generic, type-safe wrapper for an ID, distinguished by its Tag type.
Definition Utils.h:21