clang 23.0.0git
Checker.cpp
Go to the documentation of this file.
1//===- Checker.cpp - C++ Lifetime Safety Checker ----------------*- 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 implements the LifetimeChecker, which detects use-after-free
10// errors by checking if live origins hold loans that have expired.
11//
12//===----------------------------------------------------------------------===//
13
15#include "clang/AST/Decl.h"
16#include "clang/AST/Expr.h"
26#include "llvm/ADT/DenseMap.h"
27#include "llvm/Support/ErrorHandling.h"
28#include "llvm/Support/TimeProfiler.h"
29
31
33 switch (K) {
35 return true;
38 return false;
39 }
40 llvm_unreachable("unknown liveness kind");
41}
42
43namespace {
44
45/// Struct to store the complete context for a potential lifetime violation.
46struct PendingWarning {
47 SourceLocation ExpiryLoc; // Where the loan expired.
48 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
49 const Expr *MovedExpr;
50 const Expr *InvalidatedByExpr;
51 bool CausingFactDominatesExpiry;
52};
53
54using AnnotationTarget =
55 llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *>;
56using EscapingTarget = LifetimeSafetySemaHelper::EscapingTarget;
57
58class LifetimeChecker {
59private:
60 llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
61 llvm::DenseMap<AnnotationTarget, EscapingTarget> AnnotationWarningsMap;
62 llvm::DenseMap<const ParmVarDecl *, EscapingTarget> NoescapeWarningsMap;
63 llvm::DenseSet<const Decl *> VerifiedLiftimeboundEscapes;
64 const LoanPropagationAnalysis &LoanPropagation;
65 const MovedLoansAnalysis &MovedLoans;
66 const LiveOriginsAnalysis &LiveOrigins;
67 FactManager &FactMgr;
68 LifetimeSafetySemaHelper *SemaHelper;
69 ASTContext &AST;
70 const Decl *FD;
71
72 static SourceLocation
73 GetFactLoc(llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) {
74 if (const auto *UF = F.dyn_cast<const UseFact *>())
75 return UF->getUseExpr()->getExprLoc();
76 if (const auto *OEF = F.dyn_cast<const OriginEscapesFact *>()) {
77 if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
78 return ReturnEsc->getReturnExpr()->getExprLoc();
79 if (auto *FieldEsc = dyn_cast<FieldEscapeFact>(OEF))
80 return FieldEsc->getFieldDecl()->getLocation();
81 }
82 llvm_unreachable("unhandled causing fact in PointerUnion");
83 }
84
85public:
86 LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
87 const MovedLoansAnalysis &MovedLoans,
88 const LiveOriginsAnalysis &LiveOrigins, FactManager &FM,
89 AnalysisDeclContext &ADC,
90 LifetimeSafetySemaHelper *SemaHelper)
91 : LoanPropagation(LoanPropagation), MovedLoans(MovedLoans),
92 LiveOrigins(LiveOrigins), FactMgr(FM), SemaHelper(SemaHelper),
93 AST(ADC.getASTContext()), FD(ADC.getDecl()) {
94 for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
95 for (const Fact *F : FactMgr.getFacts(B))
96 if (const auto *EF = F->getAs<ExpireFact>())
97 checkExpiry(EF);
98 else if (const auto *IOF = F->getAs<InvalidateOriginFact>())
99 checkInvalidation(IOF);
100 else if (const auto *OEF = F->getAs<OriginEscapesFact>())
101 checkAnnotations(OEF);
102 issuePendingWarnings();
103 suggestAnnotations();
104 reportNoescapeViolations();
105 reportLifetimeboundViolations();
106 reportMisplacedLifetimebound();
107 // Annotation inference is currently guarded by a frontend flag. In the
108 // future, this might be replaced by a design that differentiates between
109 // explicit and inferred findings with separate warning groups.
110 if (AST.getLangOpts().EnableLifetimeSafetyInference)
111 inferAnnotations();
112 }
113
114 /// Checks if an escaping origin holds a placeholder loan, indicating a
115 /// missing [[clang::lifetimebound]] annotation or a violation of
116 /// [[clang::noescape]].
117 void checkAnnotations(const OriginEscapesFact *OEF) {
118 OriginID EscapedOID = OEF->getEscapedOriginID();
119 LoanSet EscapedLoans = LoanPropagation.getLoans(EscapedOID, OEF);
120 auto CheckParam = [&](const ParmVarDecl *PVD, bool IsMoved) {
121 // NoEscape param should not escape.
122 if (PVD->hasAttr<NoEscapeAttr>()) {
123 if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
124 NoescapeWarningsMap.try_emplace(PVD, ReturnEsc->getReturnExpr());
125 if (auto *FieldEsc = dyn_cast<FieldEscapeFact>(OEF))
126 NoescapeWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
127 if (auto *GlobalEsc = dyn_cast<GlobalEscapeFact>(OEF))
128 NoescapeWarningsMap.try_emplace(PVD, GlobalEsc->getGlobal());
129 return;
130 }
131 // Skip annotation suggestion for moved loans, as ownership transfer
132 // obscures the lifetime relationship (e.g., shared_ptr from unique_ptr).
133 if (IsMoved)
134 return;
135 if (PVD->hasAttr<LifetimeBoundAttr>()) {
136 // Track that this lifetimebound parameter correctly escapes.
137 if (isa<ReturnEscapeFact>(OEF))
138 VerifiedLiftimeboundEscapes.insert(PVD);
139 } else {
140 // Otherwise, suggest lifetimebound for parameter escaping through
141 // return or a field in constructor.
142 if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
143 AnnotationWarningsMap.try_emplace(PVD, ReturnEsc->getReturnExpr());
144 else if (auto *FieldEsc = dyn_cast<FieldEscapeFact>(OEF);
145 FieldEsc && isa<CXXConstructorDecl>(FD))
146 AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
147 }
148 // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
149 // field!
150 };
151 auto CheckImplicitThis = [&](const CXXMethodDecl *MD) {
152 if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF)) {
154 VerifiedLiftimeboundEscapes.insert(MD);
155 else
156 AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
157 }
158 };
159 auto MovedAtEscape = MovedLoans.getMovedLoans(OEF);
160 for (LoanID LID : EscapedLoans) {
161 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
162 const AccessPath &AP = L->getAccessPath();
163 if (const auto *PVD = AP.getAsPlaceholderParam())
164 CheckParam(PVD, /*IsMoved=*/MovedAtEscape.lookup(LID));
165 else if (const auto *MD = AP.getAsPlaceholderThis())
166 CheckImplicitThis(MD);
167 }
168 }
169
170 /// Checks for use-after-free & use-after-return errors when an access path
171 /// expires (e.g., a variable goes out of scope).
172 ///
173 /// When a path expires, all loans having this path expires.
174 /// This method examines all live origins and reports warnings for loans they
175 /// hold that are prefixed by the expired path.
176 void checkExpiry(const ExpireFact *EF) {
177 const AccessPath &ExpiredPath = EF->getAccessPath();
178 LivenessMap Origins = LiveOrigins.getLiveOriginsAt(EF);
179 for (auto &[OID, LiveInfo] : Origins) {
180 LoanSet HeldLoans = LoanPropagation.getLoans(OID, EF);
181 for (LoanID HeldLoanID : HeldLoans) {
182 const Loan *HeldLoan = FactMgr.getLoanMgr().getLoan(HeldLoanID);
183 if (ExpiredPath != HeldLoan->getAccessPath())
184 continue;
185 // HeldLoan is expired because its AccessPath is expired.
186 PendingWarning &CurWarning = FinalWarningsMap[HeldLoan->getID()];
187 const Expr *MovedExpr = nullptr;
188 if (auto *ME = MovedLoans.getMovedLoans(EF).lookup(HeldLoanID))
189 MovedExpr = *ME;
190 // Skip if we already have a dominating causing fact.
191 if (CurWarning.CausingFactDominatesExpiry)
192 continue;
193 if (causingFactDominatesExpiry(LiveInfo.Kind))
194 CurWarning.CausingFactDominatesExpiry = true;
195 CurWarning.CausingFact = LiveInfo.CausingFact;
196 CurWarning.ExpiryLoc = EF->getExpiryLoc();
197 CurWarning.MovedExpr = MovedExpr;
198 CurWarning.InvalidatedByExpr = nullptr;
199 }
200 }
201 }
202
203 /// Checks for use-after-invalidation errors when a container is modified.
204 ///
205 /// This method identifies origins that are live at the point of invalidation
206 /// and checks if they hold loans that are invalidated by the operation
207 /// (e.g., iterators into a vector that is being pushed to).
208 void checkInvalidation(const InvalidateOriginFact *IOF) {
209 OriginID InvalidatedOrigin = IOF->getInvalidatedOrigin();
210 /// Get loans directly pointing to the invalidated container
211 LoanSet DirectlyInvalidatedLoans =
212 LoanPropagation.getLoans(InvalidatedOrigin, IOF);
213 auto IsInvalidated = [&](const Loan *L) {
214 for (LoanID InvalidID : DirectlyInvalidatedLoans) {
215 const Loan *InvalidL = FactMgr.getLoanMgr().getLoan(InvalidID);
216 if (InvalidL->getAccessPath() == L->getAccessPath())
217 return true;
218 }
219 return false;
220 };
221 // For each live origin, check if it holds an invalidated loan and report.
222 LivenessMap Origins = LiveOrigins.getLiveOriginsAt(IOF);
223 for (auto &[OID, LiveInfo] : Origins) {
224 LoanSet HeldLoans = LoanPropagation.getLoans(OID, IOF);
225 for (LoanID LiveLoanID : HeldLoans)
226 if (IsInvalidated(FactMgr.getLoanMgr().getLoan(LiveLoanID))) {
227 bool CurDomination = causingFactDominatesExpiry(LiveInfo.Kind);
228 bool LastDomination =
229 FinalWarningsMap.lookup(LiveLoanID).CausingFactDominatesExpiry;
230 if (!LastDomination) {
231 FinalWarningsMap[LiveLoanID] = {
232 /*ExpiryLoc=*/{},
233 /*CausingFact=*/LiveInfo.CausingFact,
234 /*MovedExpr=*/nullptr,
235 /*InvalidatedByExpr=*/IOF->getInvalidationExpr(),
236 /*CausingFactDominatesExpiry=*/CurDomination};
237 }
238 }
239 }
240 }
241
242 void issuePendingWarnings() {
243 if (!SemaHelper)
244 return;
245 for (const auto &[LID, Warning] : FinalWarningsMap) {
246 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
247 const Expr *IssueExpr = L->getIssuingExpr();
248 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
249 CausingFact = Warning.CausingFact;
250 const ParmVarDecl *InvalidatedPVD =
251 L->getAccessPath().getAsPlaceholderParam();
252 const Expr *MovedExpr = Warning.MovedExpr;
253 SourceLocation ExpiryLoc = Warning.ExpiryLoc;
254
255 if (const auto *UF = CausingFact.dyn_cast<const UseFact *>()) {
256 if (Warning.InvalidatedByExpr) {
257 if (IssueExpr)
258 // Use-after-invalidation of an object on stack.
259 SemaHelper->reportUseAfterInvalidation(IssueExpr, UF->getUseExpr(),
260 Warning.InvalidatedByExpr);
261 else if (InvalidatedPVD)
262 // Use-after-invalidation of a parameter.
263 SemaHelper->reportUseAfterInvalidation(
264 InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
265
266 } else
267 // Scope-based expiry (use-after-scope).
268 SemaHelper->reportUseAfterScope(IssueExpr, UF->getUseExpr(),
269 MovedExpr, ExpiryLoc);
270 } else if (const auto *OEF =
271 CausingFact.dyn_cast<const OriginEscapesFact *>()) {
272 if (Warning.InvalidatedByExpr) {
273 if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF)) {
274 // Invalidated object escapes to a field.
275 if (IssueExpr)
276 // Invalidated object on stack escapes to a field.
277 SemaHelper->reportInvalidatedField(IssueExpr,
278 FieldEscape->getFieldDecl(),
279 Warning.InvalidatedByExpr);
280 else if (InvalidatedPVD)
281 // Invalidated parameter escapes to a field.
282 SemaHelper->reportInvalidatedField(InvalidatedPVD,
283 FieldEscape->getFieldDecl(),
284 Warning.InvalidatedByExpr);
285 } else if (const auto *GlobalEscape =
286 dyn_cast<GlobalEscapeFact>(OEF)) {
287 // Invalidated object escapes to global or static storage.
288 if (IssueExpr)
289 // Invalidated object on stack escapes to global or static
290 // storage.
291 SemaHelper->reportInvalidatedGlobal(IssueExpr,
292 GlobalEscape->getGlobal(),
293 Warning.InvalidatedByExpr);
294 else if (InvalidatedPVD)
295 // Invalidated parameter escapes to global or static storage.
296 SemaHelper->reportInvalidatedGlobal(InvalidatedPVD,
297 GlobalEscape->getGlobal(),
298 Warning.InvalidatedByExpr);
299 } else if (isa<ReturnEscapeFact>(OEF)) {
300 // FIXME: Diagnose invalidated return escapes separately.
301 } else
302 llvm_unreachable("Unhandled OriginEscapesFact type");
303 } else if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF))
304 // Return stack address.
305 SemaHelper->reportUseAfterReturn(
306 IssueExpr, RetEscape->getReturnExpr(), MovedExpr);
307 else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF))
308 // Dangling field.
309 SemaHelper->reportDanglingField(
310 IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, ExpiryLoc);
311 else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF))
312 // Global escape.
313 SemaHelper->reportDanglingGlobal(IssueExpr, GlobalEscape->getGlobal(),
314 MovedExpr, ExpiryLoc);
315 else
316 llvm_unreachable("Unhandled OriginEscapesFact type");
317 } else
318 llvm_unreachable("Unhandled CausingFact type");
319 }
320 }
321
322 // Returns declarations that should be annotated with lifetime attributes
323 // in order to annotate FDef: the canonical declaration and the earliest
324 // redeclarations in each other file. This defines the placement policy for
325 // lifetime annotations. Each target is paired with its corresponding warning
326 // scope.
327 llvm::SmallVector<std::pair<const FunctionDecl *, WarningScope>, 2>
328 getTargetDeclsForAttr(const FunctionDecl *FDef) {
329 if (!FDef)
330 return {};
331
332 assert(FDef->isThisDeclarationADefinition() &&
333 "Expected FunctionDecl to be a definition");
334
335 const auto &SM = FDef->getASTContext().getSourceManager();
336
337 auto GetFile = [&SM](const FunctionDecl *FD) {
338 return SM.getFileID(SM.getExpansionLoc(FD->getLocation()));
339 };
340
341 const FileID DefFile = GetFile(FDef);
342 const FunctionDecl *CanonicalDecl = FDef->getCanonicalDecl();
343 llvm::SmallVector<std::pair<const FunctionDecl *, WarningScope>, 2> Targets{
344 {CanonicalDecl, GetFile(CanonicalDecl) == DefFile
347
348 // Find the earliest redeclaration in each file other than the definition
349 // file.
350 auto AddCrossTUDecl = [&](const FunctionDecl *FD) {
351 FileID File = GetFile(FD);
352 if (File == DefFile)
353 return;
354 for (auto [SeenFD, _] : Targets)
355 if (GetFile(SeenFD) == File)
356 return;
357 Targets.push_back({FD, WarningScope::CrossTU});
358 };
359
360 // We iterate in reverse order (from most recent to oldest) to find
361 // the first declaration in each file.
362
363 // Store in temporary variable to manually extend lifetime
364 auto redecls = llvm::to_vector(FDef->redecls());
365
366 for (const FunctionDecl *Redecl : llvm::reverse(redecls))
367 AddCrossTUDecl(Redecl);
368
369 return Targets;
370 }
371
372 void suggestWithScopeForParmVar(const ParmVarDecl *PVD,
373 EscapingTarget EscapeTarget) {
374 if (llvm::isa<const VarDecl *>(EscapeTarget))
375 return;
376
377 for (auto [Decl, Scope] : getTargetDeclsForAttr(cast<FunctionDecl>(FD))) {
378 const auto *ParmToAnnotate =
379 Decl->getParamDecl(PVD->getFunctionScopeIndex());
380 SemaHelper->suggestLifetimeboundToParmVar(Scope, ParmToAnnotate,
381 EscapeTarget);
382 }
383 }
384
385 void suggestWithScopeForImplicitThis(const CXXMethodDecl *MD,
386 const Expr *EscapeExpr) {
387 for (auto [Decl, Scope] : getTargetDeclsForAttr(MD)) {
388 SemaHelper->suggestLifetimeboundToImplicitThis(
389 Scope, cast<CXXMethodDecl>(Decl), EscapeExpr);
390 }
391 }
392
393 void suggestAnnotations() {
394 if (!SemaHelper)
395 return;
396 for (auto [Target, EscapeTarget] : AnnotationWarningsMap) {
397 if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
398 suggestWithScopeForParmVar(PVD, EscapeTarget);
399 else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
400 if (const auto *EscapeExpr = EscapeTarget.dyn_cast<const Expr *>())
401 suggestWithScopeForImplicitThis(MD, EscapeExpr);
402 else
403 llvm_unreachable("Implicit this can only escape via Expr (return)");
404 }
405 }
406 }
407
408 void reportNoescapeViolations() {
409 for (auto [PVD, EscapeTarget] : NoescapeWarningsMap) {
410 if (const auto *E = EscapeTarget.dyn_cast<const Expr *>())
411 SemaHelper->reportNoescapeViolation(PVD, E);
412 else if (const auto *FD = EscapeTarget.dyn_cast<const FieldDecl *>())
413 SemaHelper->reportNoescapeViolation(PVD, FD);
414 else if (const auto *G = EscapeTarget.dyn_cast<const VarDecl *>())
415 SemaHelper->reportNoescapeViolation(PVD, G);
416 else
417 llvm_unreachable("Unhandled EscapingTarget type");
418 }
419 }
420
421 void reportLifetimeboundViolations() {
422 if (!isa<FunctionDecl>(FD))
423 return;
424 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
426 !VerifiedLiftimeboundEscapes.contains(MD))
427 SemaHelper->reportLifetimeboundViolation(MD);
428 for (const ParmVarDecl *PVD : cast<FunctionDecl>(FD)->parameters()) {
429 if (!PVD->hasAttr<LifetimeBoundAttr>())
430 continue;
431 bool isImplicit = PVD->getAttr<LifetimeBoundAttr>()->isImplicit();
432 bool Escapes = VerifiedLiftimeboundEscapes.contains(PVD);
433 assert((!isImplicit || Escapes || isInStlNamespace(FD)) &&
434 "Implicit lifetimebound parameters "
435 "should escape through return");
436 if (!isImplicit && !Escapes)
437 SemaHelper->reportLifetimeboundViolation(PVD);
438 }
439 }
440
441 // Reports lifetimebound attributes that are placed on a function definition
442 // but not on the corresponding declaration.
443 void reportMisplacedLifetimebound() {
444 const FunctionDecl *FDef = dyn_cast<FunctionDecl>(FD);
445 if (!FDef)
446 return;
447
448 auto TargetDecls = getTargetDeclsForAttr(FDef);
449 // Check if implicit 'this' has lifetimebound on definition but not on
450 // declaration.
451 if (const auto *MDef = dyn_cast<CXXMethodDecl>(FDef);
453 for (auto [Decl, Scope] : TargetDecls) {
454 const auto *MDecl = cast<CXXMethodDecl>(Decl);
456 SemaHelper->reportMisplacedLifetimebound(Scope, MDef, MDecl);
457 }
458
459 // Check each parameter for explicit lifetimebound on definition but not on
460 // declaration.
461 for (const auto *PDef : FDef->parameters()) {
462 const auto *Attr = PDef->getAttr<LifetimeBoundAttr>();
463 if (!Attr || Attr->isImplicit())
464 continue;
465 for (auto [Decl, Scope] : TargetDecls) {
466 const auto *PDecl = Decl->getParamDecl(PDef->getFunctionScopeIndex());
467 if (!PDecl->hasAttr<LifetimeBoundAttr>())
468 SemaHelper->reportMisplacedLifetimebound(Scope, PDef, PDecl);
469 }
470 }
471 }
472
473 void inferAnnotations() {
474 for (auto [Target, EscapeTarget] : AnnotationWarningsMap) {
475 if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
477 SemaHelper->addLifetimeBoundToImplicitThis(cast<CXXMethodDecl>(MD));
478 } else if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>()) {
479 const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
480 if (!FD)
481 continue;
482 // Propagates inferred attributes via the most recent declaration to
483 // ensure visibility for callers in post-order analysis.
485 ParmVarDecl *InferredPVD = const_cast<ParmVarDecl *>(
486 FD->getParamDecl(PVD->getFunctionScopeIndex()));
487 if (!InferredPVD->hasAttr<LifetimeBoundAttr>())
488 InferredPVD->addAttr(
489 LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
490 }
491 }
492 }
493};
494} // namespace
495
497 const MovedLoansAnalysis &MovedLoans,
498 const LiveOriginsAnalysis &LO, FactManager &FactMgr,
500 LifetimeSafetySemaHelper *SemaHelper) {
501 llvm::TimeTraceScope TimeProfile("LifetimeChecker");
502 LifetimeChecker Checker(LP, MovedLoans, LO, FactMgr, ADC, SemaHelper);
503}
504
505} // namespace clang::lifetimes::internal
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
#define SM(sm)
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
This represents one expression.
Definition Expr.h:112
Encodes a location in the source.
Abstract interface for operations requiring Sema access.
llvm::PointerUnion< const Expr *, const FieldDecl *, const VarDecl * > EscapingTarget
llvm::ImmutableSet< LoanID > LoanSet
utils::ID< struct LoanTag > LoanID
Definition Loans.h:25
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
static bool causingFactDominatesExpiry(LivenessKind K)
Definition Checker.cpp:32
llvm::ImmutableMap< OriginID, LivenessInfo > LivenessMap
Definition LiveOrigins.h:76
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const MovedLoansAnalysis &MovedLoans, const LiveOriginsAnalysis &LiveOrigins, FactManager &FactMgr, AnalysisDeclContext &ADC, LifetimeSafetySemaHelper *SemaHelper)
Runs the lifetime checker, which detects use-after-free errors by examining loan expiration points an...
Definition Checker.cpp:496
const LifetimeBoundAttr * getDirectImplicitObjectLifetimeBoundAttr(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const LifetimeBoundAttr * getImplicitObjectParamLifetimeBoundAttr(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isInStlNamespace(const Decl *D)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
bool isa(CodeGen::Address addr)
Definition Address.h:330
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
for(const auto &A :T->param_types())
U cast(CodeGen::Address addr)
Definition Address.h:327