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