clang 23.0.0git
Facts.h
Go to the documentation of this file.
1//===- Facts.h - Lifetime Analysis Facts and Fact Manager ------*- 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 Facts, which are atomic lifetime-relevant events (such as
10// loan issuance, loan expiration, origin flow, and use), and the FactManager,
11// which manages the storage and retrieval of facts for each CFG block.
12//
13//===----------------------------------------------------------------------===//
14#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
15#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
16
17#include "clang/AST/Decl.h"
22#include "clang/Analysis/CFG.h"
23#include "llvm/ADT/STLFunctionalExtras.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/raw_ostream.h"
27#include <cstdint>
28#include <optional>
29
31
33
35
36/// An abstract base class for a single, atomic lifetime-relevant event.
37class Fact {
38
39public:
40 enum class Kind : uint8_t {
41 /// A new loan is issued from a borrow expression (e.g., &x).
43 /// A loan expires as its underlying storage is freed (e.g., variable goes
44 /// out of scope).
46 /// An origin is propagated from a source to a destination (e.g., p = q).
47 /// This can also optionally kill the destination origin before flowing into
48 /// it. Otherwise, the source's loan set is merged into the destination's
49 /// loan set.
51 /// An origin is used (eg. appears as l-value expression like DeclRefExpr).
53 /// An origin that is moved (e.g., passed to an rvalue reference parameter).
55 /// A marker for a specific point in the code, for testing.
57 /// An origin that escapes the function scope (e.g., via return).
59 /// An origin is invalidated (e.g. vector resized, `delete` called).
61 /// All loans of an origin are cleared.
63 };
64
65private:
66 Kind K;
67 FactID ID;
68
69protected:
70 Fact(Kind K) : K(K) {}
71
72public:
73 virtual ~Fact() = default;
74 Kind getKind() const { return K; }
75
76 void setID(FactID ID) { this->ID = ID; }
77 FactID getID() const { return ID; }
78
79 template <typename T> const T *getAs() const {
80 if (T::classof(this))
81 return static_cast<const T *>(this);
82 return nullptr;
83 }
84
85 virtual void dump(llvm::raw_ostream &OS, const LoanManager &,
86 const OriginManager &,
87 const LoanPropagationAnalysis *LPA = nullptr) const;
88};
89
90/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
91/// `Fact`. identified by a lifetime-related event (`Fact`).
92///
93/// A `ProgramPoint` has "after" semantics: it represents the location
94/// immediately after its corresponding `Fact`.
95using ProgramPoint = const Fact *;
96
97class IssueFact : public Fact {
98 LoanID LID;
99 OriginID OID;
100
101public:
102 static bool classof(const Fact *F) { return F->getKind() == Kind::Issue; }
103
104 IssueFact(LoanID LID, OriginID OID) : Fact(Kind::Issue), LID(LID), OID(OID) {}
105 LoanID getLoanID() const { return LID; }
106 OriginID getOriginID() const { return OID; }
107 void dump(llvm::raw_ostream &OS, const LoanManager &LM,
108 const OriginManager &OM,
109 const LoanPropagationAnalysis *LPA = nullptr) const override;
110};
111
112/// When an AccessPath expires (e.g., a variable goes out of scope), all loans
113/// that are associated with this path expire. For example, if `x` expires, then
114/// the loan to `x` expires.
115class ExpireFact : public Fact {
116 // The access path that expires.
117 AccessPath AP;
118
119 // Expired origin (e.g., its variable goes out of scope).
120 std::optional<OriginID> OID;
121 SourceLocation ExpiryLoc;
122
123public:
124 static bool classof(const Fact *F) { return F->getKind() == Kind::Expire; }
125
127 std::optional<OriginID> OID = std::nullopt)
128 : Fact(Kind::Expire), AP(AP), OID(OID), ExpiryLoc(ExpiryLoc) {}
129
130 const AccessPath &getAccessPath() const { return AP; }
131 std::optional<OriginID> getOriginID() const { return OID; }
132 SourceLocation getExpiryLoc() const { return ExpiryLoc; }
133
134 void dump(llvm::raw_ostream &OS, const LoanManager &LM,
135 const OriginManager &OM,
136 const LoanPropagationAnalysis *LPA = nullptr) const override;
137};
138
139class OriginFlowFact : public Fact {
140 OriginID OIDDest;
141 OriginID OIDSrc;
142 // True if the destination origin should be killed (i.e., its current loans
143 // cleared) before the source origin's loans are flowed into it.
144 bool KillDest;
145
146public:
147 static bool classof(const Fact *F) {
148 return F->getKind() == Kind::OriginFlow;
149 }
150
151 OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
152 : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc),
153 KillDest(KillDest) {}
154
155 OriginID getDestOriginID() const { return OIDDest; }
156 OriginID getSrcOriginID() const { return OIDSrc; }
157 bool getKillDest() const { return KillDest; }
158
159 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
160 const LoanPropagationAnalysis *LPA = nullptr) const override;
161};
162
163/// Represents that an origin escapes the current scope through various means.
164/// This is the base class for different escape scenarios.
165class OriginEscapesFact : public Fact {
166 OriginID OID;
167
168public:
169 /// The way an origin can escape the current scope.
170 enum class EscapeKind : uint8_t {
171 Return, /// Escapes via return statement.
172 Field, /// Escapes via assignment to a field.
173 Global, /// Escapes via assignment to global storage.
175
176 static bool classof(const Fact *F) {
177 return F->getKind() == Kind::OriginEscapes;
178 }
179
182 OriginID getEscapedOriginID() const { return OID; }
183 EscapeKind getEscapeKind() const { return EscKind; }
184};
185
186/// Represents that an origin escapes via a return statement.
188 const Expr *ReturnExpr;
189
190public:
191 ReturnEscapeFact(OriginID OID, const Expr *ReturnExpr)
192 : OriginEscapesFact(OID, EscapeKind::Return), ReturnExpr(ReturnExpr) {}
193
194 static bool classof(const Fact *F) {
195 return F->getKind() == Kind::OriginEscapes &&
196 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
198 }
199 const Expr *getReturnExpr() const { return ReturnExpr; };
200 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
201 const LoanPropagationAnalysis *LPA = nullptr) const override;
202};
203
204/// Represents that an origin escapes via assignment to a field.
205/// Example: `this->view = local_var;` where local_var outlives the assignment
206/// but not the object containing the field.
208 const FieldDecl *FDecl;
209
210public:
212 : OriginEscapesFact(OID, EscapeKind::Field), FDecl(FDecl) {}
213
214 static bool classof(const Fact *F) {
215 return F->getKind() == Kind::OriginEscapes &&
216 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
218 }
219 const FieldDecl *getFieldDecl() const { return FDecl; };
220 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
221 const LoanPropagationAnalysis *LPA = nullptr) const override;
222};
223
224/// Represents that an origin escapes via assignment to global or static
225/// storage. Example: `global_storage = local_var;`
227 const VarDecl *Global;
228
229public:
231 : OriginEscapesFact(OID, EscapeKind::Global), Global(VDecl) {}
232
233 static bool classof(const Fact *F) {
234 return F->getKind() == Kind::OriginEscapes &&
235 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
237 }
238 const VarDecl *getGlobal() const { return Global; };
239 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
240 const LoanPropagationAnalysis *LPA = nullptr) const override;
241};
242
243class UseFact : public Fact {
244 const Expr *UseExpr;
245 const OriginList *OList;
246 // True if this use is a write operation (e.g., left-hand side of assignment).
247 // Write operations are exempted from use-after-free checks.
248 bool IsWritten = false;
249
250public:
251 static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
252
253 UseFact(const Expr *UseExpr, const OriginList *OList)
254 : Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
255
256 const OriginList *getUsedOrigins() const { return OList; }
257 void setUsedOrigins(const OriginList *NewList) { OList = NewList; }
258 const Expr *getUseExpr() const { return UseExpr; }
259 void markAsWritten() { IsWritten = true; }
260 bool isWritten() const { return IsWritten; }
261
262 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
263 const LoanPropagationAnalysis *LPA = nullptr) const override;
264};
265
266/// Represents that an origin's storage has been invalidated by a container
267/// operation (e.g., vector::push_back may reallocate, invalidating iterators).
268/// Created when a container method that may invalidate references/iterators
269/// is called on the container.
271 OriginID OID;
272 const Expr *InvalidationExpr;
273
274public:
275 static bool classof(const Fact *F) {
276 return F->getKind() == Kind::InvalidateOrigin;
277 }
278
279 InvalidateOriginFact(OriginID OID, const Expr *InvalidationExpr)
280 : Fact(Kind::InvalidateOrigin), OID(OID),
281 InvalidationExpr(InvalidationExpr) {}
282
283 OriginID getInvalidatedOrigin() const { return OID; }
284 const Expr *getInvalidationExpr() const { return InvalidationExpr; }
285 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
286 const LoanPropagationAnalysis *LPA = nullptr) const override;
287};
288
289/// Top-level origin of the expression which was found to be moved, e.g, when
290/// being used as an argument to an r-value reference parameter.
291class MovedOriginFact : public Fact {
292 const OriginID MovedOrigin;
293 const Expr *MoveExpr;
294
295public:
296 static bool classof(const Fact *F) {
297 return F->getKind() == Kind::MovedOrigin;
298 }
299
300 MovedOriginFact(const Expr *MoveExpr, OriginID MovedOrigin)
301 : Fact(Kind::MovedOrigin), MovedOrigin(MovedOrigin), MoveExpr(MoveExpr) {}
302
303 OriginID getMovedOrigin() const { return MovedOrigin; }
304 const Expr *getMoveExpr() const { return MoveExpr; }
305
306 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
307 const LoanPropagationAnalysis *LPA = nullptr) const override;
308};
309
310/// A dummy-fact used to mark a specific point in the code for testing.
311/// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
312class TestPointFact : public Fact {
313 StringRef Annotation;
314
315public:
316 static bool classof(const Fact *F) { return F->getKind() == Kind::TestPoint; }
317
318 explicit TestPointFact(StringRef Annotation)
319 : Fact(Kind::TestPoint), Annotation(Annotation) {}
320
321 StringRef getAnnotation() const { return Annotation; }
322
323 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &,
324 const LoanPropagationAnalysis *LPA = nullptr) const override;
325};
326
327/// All loans are cleared from an origin (e.g., assigning a callable without
328/// tracked origins to std::function).
329class KillOriginFact : public Fact {
330 OriginID OID;
331
332public:
333 static bool classof(const Fact *F) {
334 return F->getKind() == Kind::KillOrigin;
335 }
336
338
339 OriginID getKilledOrigin() const { return OID; }
340
341 void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM,
342 const LoanPropagationAnalysis *LPA = nullptr) const override;
343};
344
346public:
347 FactManager(const AnalysisDeclContext &AC, const CFG &Cfg) : OriginMgr(AC) {
348 BlockToFacts.resize(Cfg.getNumBlockIDs());
349 }
350
352 return BlockToFacts[B->getBlockID()];
353 }
354
356 if (!NewFacts.empty())
357 BlockToFacts[B->getBlockID()].assign(NewFacts.begin(), NewFacts.end());
358 }
359
360 void appendBlockFact(const CFGBlock *B, const Fact *F) {
361 BlockToFacts[B->getBlockID()].push_back(F);
362 }
363
364 template <typename FactType, typename... Args>
365 FactType *createFact(Args &&...args) {
366 void *Mem = FactAllocator.Allocate<FactType>();
367 FactType *Res = new (Mem) FactType(std::forward<Args>(args)...);
368 Res->setID(NextFactID++);
369 return Res;
370 }
371
372 void dump(const CFG &Cfg, AnalysisDeclContext &AC,
373 const LoanPropagationAnalysis *LPA = nullptr) const;
374
375 /// Retrieves program points that were specially marked in the source code
376 /// for testing.
377 ///
378 /// The analysis recognizes special function calls of the form
379 /// `void("__lifetime_test_point_<name>")` as test points. This method returns
380 /// a map from the annotation string (<name>) to the corresponding
381 /// `ProgramPoint`. This allows test harnesses to query the analysis state at
382 /// user-defined locations in the code.
383 /// \note This is intended for testing only.
384 llvm::StringMap<ProgramPoint> getTestPoints() const;
385 /// Retrieves all the facts in the block containing Program Point P.
386 /// \note This is intended for testing only.
388 size_t getBlockID(ProgramPoint P) const;
389
390 unsigned getNumFacts() const { return NextFactID.Value; }
391
392 LoanManager &getLoanMgr() { return LoanMgr; }
393 const LoanManager &getLoanMgr() const { return LoanMgr; }
394 OriginManager &getOriginMgr() { return OriginMgr; }
395 const OriginManager &getOriginMgr() const { return OriginMgr; }
396
397private:
398 FactID NextFactID{0};
399 LoanManager LoanMgr;
400 OriginManager OriginMgr;
401 /// Facts for each CFG block, indexed by block ID.
403 llvm::BumpPtrAllocator FactAllocator;
404};
405} // namespace clang::lifetimes::internal
406
407#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
unsigned getBlockID() const
Definition CFG.h:1154
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1464
This represents one expression.
Definition Expr.h:112
Represents a member of a struct/union/class.
Definition Decl.h:3179
Encodes a location in the source.
Represents a variable declaration or definition.
Definition Decl.h:932
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:45
const AccessPath & getAccessPath() const
Definition Facts.h:130
SourceLocation getExpiryLoc() const
Definition Facts.h:132
static bool classof(const Fact *F)
Definition Facts.h:124
ExpireFact(AccessPath AP, SourceLocation ExpiryLoc, std::optional< OriginID > OID=std::nullopt)
Definition Facts.h:126
std::optional< OriginID > getOriginID() const
Definition Facts.h:131
void dump(llvm::raw_ostream &OS, const LoanManager &LM, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:31
llvm::ArrayRef< const Fact * > getFacts(const CFGBlock *B) const
Definition Facts.h:351
FactType * createFact(Args &&...args)
Definition Facts.h:365
llvm::StringMap< ProgramPoint > getTestPoints() const
Retrieves program points that were specially marked in the source code for testing.
Definition Facts.cpp:138
void dump(const CFG &Cfg, AnalysisDeclContext &AC, const LoanPropagationAnalysis *LPA=nullptr) const
Definition Facts.cpp:153
void addBlockFacts(const CFGBlock *B, llvm::ArrayRef< Fact * > NewFacts)
Definition Facts.h:355
const OriginManager & getOriginMgr() const
Definition Facts.h:395
size_t getBlockID(ProgramPoint P) const
Definition Facts.cpp:177
void appendBlockFact(const CFGBlock *B, const Fact *F)
Definition Facts.h:360
const LoanManager & getLoanMgr() const
Definition Facts.h:393
llvm::ArrayRef< const Fact * > getBlockContaining(ProgramPoint P) const
Retrieves all the facts in the block containing Program Point P.
Definition Facts.cpp:173
FactManager(const AnalysisDeclContext &AC, const CFG &Cfg)
Definition Facts.h:347
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:37
virtual void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &, const LoanPropagationAnalysis *LPA=nullptr) const
Definition Facts.cpp:16
@ InvalidateOrigin
An origin is invalidated (e.g. vector resized, delete called).
Definition Facts.h:60
@ TestPoint
A marker for a specific point in the code, for testing.
Definition Facts.h:56
@ Expire
A loan expires as its underlying storage is freed (e.g., variable goes out of scope).
Definition Facts.h:45
@ Issue
A new loan is issued from a borrow expression (e.g., &x).
Definition Facts.h:42
@ OriginFlow
An origin is propagated from a source to a destination (e.g., p = q).
Definition Facts.h:50
@ MovedOrigin
An origin that is moved (e.g., passed to an rvalue reference parameter).
Definition Facts.h:54
@ Use
An origin is used (eg. appears as l-value expression like DeclRefExpr).
Definition Facts.h:52
@ OriginEscapes
An origin that escapes the function scope (e.g., via return).
Definition Facts.h:58
@ KillOrigin
All loans of an origin are cleared.
Definition Facts.h:62
const T * getAs() const
Definition Facts.h:79
FieldEscapeFact(OriginID OID, const FieldDecl *FDecl)
Definition Facts.h:211
const FieldDecl * getFieldDecl() const
Definition Facts.h:219
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:85
static bool classof(const Fact *F)
Definition Facts.h:214
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:93
GlobalEscapeFact(OriginID OID, const VarDecl *VDecl)
Definition Facts.h:230
static bool classof(const Fact *F)
Definition Facts.h:233
const VarDecl * getGlobal() const
Definition Facts.h:238
InvalidateOriginFact(OriginID OID, const Expr *InvalidationExpr)
Definition Facts.h:279
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:116
void dump(llvm::raw_ostream &OS, const LoanManager &LM, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:21
IssueFact(LoanID LID, OriginID OID)
Definition Facts.h:104
static bool classof(const Fact *F)
Definition Facts.h:102
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:130
static bool classof(const Fact *F)
Definition Facts.h:333
Manages the creation, storage and retrieval of loans.
Definition Loans.h:139
static bool classof(const Fact *F)
Definition Facts.h:296
MovedOriginFact(const Expr *MoveExpr, OriginID MovedOrigin)
Definition Facts.h:300
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:69
enum clang::lifetimes::internal::OriginEscapesFact::EscapeKind EscKind
EscapeKind
The way an origin can escape the current scope.
Definition Facts.h:170
@ Global
Escapes via assignment to a field.
Definition Facts.h:173
static bool classof(const Fact *F)
Definition Facts.h:176
OriginEscapesFact(OriginID OID, EscapeKind EscKind)
Definition Facts.h:180
static bool classof(const Fact *F)
Definition Facts.h:147
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:43
OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
Definition Facts.h:151
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:95
Manages the creation, storage, and retrieval of origins for pointer-like variables and expressions.
Definition Origins.h:125
static bool classof(const Fact *F)
Definition Facts.h:194
ReturnEscapeFact(OriginID OID, const Expr *ReturnExpr)
Definition Facts.h:191
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:77
static bool classof(const Fact *F)
Definition Facts.h:316
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:124
TestPointFact(StringRef Annotation)
Definition Facts.h:318
void setUsedOrigins(const OriginList *NewList)
Definition Facts.h:257
const Expr * getUseExpr() const
Definition Facts.h:258
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, const LoanPropagationAnalysis *LPA=nullptr) const override
Definition Facts.cpp:101
static bool classof(const Fact *F)
Definition Facts.h:251
UseFact(const Expr *UseExpr, const OriginList *OList)
Definition Facts.h:253
const OriginList * getUsedOrigins() const
Definition Facts.h:256
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:95
utils::ID< struct LoanTag > LoanID
Definition Loans.h:25
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
utils::ID< struct FactTag > FactID
Definition Facts.h:34
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 uint8_t
A generic, type-safe wrapper for an ID, distinguished by its Tag type.
Definition Utils.h:21