clang 23.0.0git
FactsGenerator.cpp
Go to the documentation of this file.
1//===- FactsGenerator.cpp - Lifetime Facts Generation -----------*- 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#include <cassert>
10#include <string>
11
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
22#include "clang/Analysis/CFG.h"
24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/STLExtras.h"
26#include "llvm/Support/Casting.h"
27#include "llvm/Support/Signals.h"
28#include "llvm/Support/TimeProfiler.h"
29
31using llvm::isa_and_present;
32
33OriginList *FactsGenerator::getOriginsList(const ValueDecl &D) {
34 return FactMgr.getOriginMgr().getOrCreateList(&D);
35}
36OriginList *FactsGenerator::getOriginsList(const Expr &E) {
37 return FactMgr.getOriginMgr().getOrCreateList(&E);
38}
39
40bool FactsGenerator::hasOrigins(QualType QT) const {
41 return FactMgr.getOriginMgr().hasOrigins(QT);
42}
43
44bool FactsGenerator::hasOrigins(const Expr *E) const {
45 return FactMgr.getOriginMgr().hasOrigins(E);
46}
47
48/// Propagates origin information from Src to Dst through all levels of
49/// indirection, creating OriginFlowFacts at each level.
50///
51/// This function enforces a critical type-safety invariant: both lists must
52/// have the same shape (same depth/structure). This invariant ensures that
53/// origins flow only between compatible types during expression evaluation.
54///
55/// Examples:
56/// - `int* p = &x;` flows origins from `&x` (depth 1) to `p` (depth 1)
57/// - `int** pp = &p;` flows origins from `&p` (depth 2) to `pp` (depth 2)
58/// * Level 1: pp <- p's address
59/// * Level 2: (*pp) <- what p points to (i.e., &x)
60/// - `View v = obj;` flows origins from `obj` (depth 1) to `v` (depth 1)
61void FactsGenerator::flow(OriginList *Dst, OriginList *Src, bool Kill) {
62 if (!Dst)
63 return;
64 assert(Src &&
65 "Dst is non-null but Src is null. List must have the same length");
66 assert(Dst->getLength() == Src->getLength() &&
67 "Lists must have the same length");
68
69 while (Dst && Src) {
70 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
71 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
72 Dst = Dst->peelOuterOrigin();
73 Src = Src->peelOuterOrigin();
74 }
75}
76
77/// Creates a loan for the storage path of a given declaration reference.
78/// This function should be called whenever a DeclRefExpr represents a borrow.
79/// \param DRE The declaration reference expression that initiates the borrow.
80/// \return The new Loan on success, nullptr otherwise.
81static const Loan *createLoan(FactManager &FactMgr, const DeclRefExpr *DRE) {
82 const ValueDecl *VD = DRE->getDecl();
83 AccessPath Path(VD);
84 // The loan is created at the location of the DeclRefExpr.
85 return FactMgr.getLoanMgr().createLoan(Path, DRE);
86}
87
88/// Creates a loan for the storage location of a temporary object.
89/// \param MTE The MaterializeTemporaryExpr that represents the temporary
90/// binding. \return The new Loan.
91static const Loan *createLoan(FactManager &FactMgr,
92 const MaterializeTemporaryExpr *MTE) {
93 AccessPath Path(MTE);
94 return FactMgr.getLoanMgr().createLoan(Path, MTE);
95}
96
97/// Creates a loan for an allocation through 'new'
98/// \param NE The CXXNewExpr that represents the allocation
99/// \return The new Loan on success, nullptr otherwise
100static const Loan *createLoan(FactManager &FactMgr, const CXXNewExpr *NE) {
101 AccessPath Path(NE);
102 return FactMgr.getLoanMgr().createLoan(Path, NE);
103}
104
106 llvm::TimeTraceScope TimeProfile("FactGenerator");
107 const CFG &Cfg = *AC.getCFG();
108 llvm::SmallVector<Fact *> PlaceholderLoanFacts = issuePlaceholderLoans();
109 // Iterate through the CFG blocks in reverse post-order to ensure that
110 // initializations and destructions are processed in the correct sequence.
111 for (const CFGBlock *Block : *AC.getAnalysis<PostOrderCFGView>()) {
112 CurrentBlockFacts.clear();
113 EscapesInCurrentBlock.clear();
114 CurrentBlock = Block;
115 if (Block == &Cfg.getEntry())
116 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
117 PlaceholderLoanFacts.end());
118 for (unsigned I = 0; I < Block->size(); ++I) {
119 const CFGElement &Element = Block->Elements[I];
120 if (std::optional<CFGStmt> CS = Element.getAs<CFGStmt>())
121 Visit(CS->getStmt());
122 else if (std::optional<CFGInitializer> Initializer =
123 Element.getAs<CFGInitializer>())
124 handleCXXCtorInitializer(Initializer->getInitializer());
125 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
126 Element.getAs<CFGLifetimeEnds>())
127 handleLifetimeEnds(*LifetimeEnds);
128 else if (std::optional<CFGFullExprCleanup> FullExprCleanup =
129 Element.getAs<CFGFullExprCleanup>()) {
130 handleFullExprCleanup(*FullExprCleanup);
131 }
132 }
133 if (Block == &Cfg.getExit())
134 handleExitBlock();
135
136 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
137 EscapesInCurrentBlock.end());
138 FactMgr.addBlockFacts(Block, CurrentBlockFacts);
139 }
140}
141
142/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
143/// if the expression is a GLValue. For pointer/view GLValues, this strips
144/// the origin representing the storage location to get the origins of the
145/// pointed-to value.
146///
147/// Example: For `View& v`, returns the origin of what v points to, not v's
148/// storage.
149static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
150 if (!List)
151 return nullptr;
152 return E->isGLValue() ? List->peelOuterOrigin() : List;
153}
154
156 for (const Decl *D : DS->decls())
157 if (const auto *VD = dyn_cast<VarDecl>(D))
158 if (const Expr *InitExpr = VD->getInit()) {
159 OriginList *VDList = getOriginsList(*VD);
160 if (!VDList)
161 continue;
162 OriginList *InitList = getOriginsList(*InitExpr);
163 assert(InitList && "VarDecl had origins but InitExpr did not");
164 flow(VDList, InitList, /*Kill=*/true);
165 }
166}
167
169 // Skip function references as their lifetimes are not interesting. Skip non
170 // GLValues (like EnumConstants).
171 if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
172 return;
173 handleUse(DRE);
174 // For all declarations with storage (non-references), we issue a loan
175 // representing the borrow of the variable's storage itself.
176 //
177 // Examples:
178 // - `int x; x` issues loan to x's storage
179 // - `int* p; p` issues loan to p's storage (the pointer variable)
180 // - `View v; v` issues loan to v's storage (the view object)
181 // - `int& r = x; r` issues no loan (r has no storage, it's an alias to x)
182 if (doesDeclHaveStorage(DRE->getDecl())) {
183 const Loan *L = createLoan(FactMgr, DRE);
184 assert(L);
185 OriginList *List = getOriginsList(*DRE);
186 assert(List &&
187 "gl-value DRE of non-pointer type should have an origin list");
188 // This loan specifically tracks borrowing the variable's storage location
189 // itself and is issued to outermost origin (List->OID).
190 CurrentBlockFacts.push_back(
191 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
192 }
193}
194
196 if (isGslPointerType(CCE->getType())) {
197 handleGSLPointerConstruction(CCE);
198 return;
199 }
200 // For defaulted (implicit or `= default`) copy/move constructors, propagate
201 // origins directly. User-defined copy/move constructors are not handled here
202 // as they have opaque semantics.
204 CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
205 hasOrigins(CCE->getType())) {
206 const Expr *Arg = CCE->getArg(0);
207 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
208 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
209 return;
210 }
211 }
212 // Standard library callable wrappers (e.g., std::function) propagate the
213 // stored lambda's origins.
214 if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
215 RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
216 const Expr *Arg = CCE->getArg(0);
217 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
218 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
219 return;
220 }
221 }
222 handleFunctionCall(CCE, CCE->getConstructor(),
223 {CCE->getArgs(), CCE->getNumArgs()},
224 /*IsGslConstruction=*/false);
225}
226
228 if (const Expr *Init = DIE->getExpr())
229 killAndFlowOrigin(*DIE, *Init);
230}
231
232void FactsGenerator::handleCXXCtorInitializer(const CXXCtorInitializer *CII) {
233 // Flows origins from the initializer expression to the field.
234 // Example: `MyObj(std::string s) : view(s) {}`
235 if (const FieldDecl *FD = CII->getAnyMember())
236 killAndFlowOrigin(*FD, *CII->getInit());
237}
238
240 // Specifically for conversion operators,
241 // like `std::string_view p = std::string{};`
242 if (isGslPointerType(MCE->getType()) &&
243 isa_and_present<CXXConversionDecl>(MCE->getCalleeDecl()) &&
245 // The argument is the implicit object itself.
246 handleFunctionCall(MCE, MCE->getMethodDecl(),
247 {MCE->getImplicitObjectArgument()},
248 /*IsGslConstruction=*/true);
249 return;
250 }
251 if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
252 // Construct the argument list, with the implicit 'this' object as the
253 // first argument.
255 Args.push_back(MCE->getImplicitObjectArgument());
256 Args.append(MCE->getArgs(), MCE->getArgs() + MCE->getNumArgs());
257
258 handleFunctionCall(MCE, Method, Args, /*IsGslConstruction=*/false);
259 }
260}
261
263 auto *MD = ME->getMemberDecl();
264 if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
265 assert(ME->isGLValue() && "Field member should be GL value");
266 OriginList *Dst = getOriginsList(*ME);
267 assert(Dst && "Field member should have an origin list as it is GL value");
268 OriginList *Src = getOriginsList(*ME->getBase());
269 assert(Src && "Base expression should be a pointer/reference type");
270 // The field's glvalue (outermost origin) holds the same loans as the base
271 // expression.
272 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
273 Dst->getOuterOriginID(), Src->getOuterOriginID(),
274 /*Kill=*/true));
275 }
276}
277
279 handleFunctionCall(CE, CE->getDirectCallee(),
280 {CE->getArgs(), CE->getNumArgs()});
281}
282
284 const CXXNullPtrLiteralExpr *N) {
285 /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
286 /// pointers can use the same type of loan.
287 getOriginsList(*N);
288}
289
291 OriginList *Dest = getOriginsList(*CE);
292 if (!Dest)
293 return;
294 const Expr *SubExpr = CE->getSubExpr();
295 OriginList *Src = getOriginsList(*SubExpr);
296
297 switch (CE->getCastKind()) {
298 case CK_LValueToRValue:
299 if (!SubExpr->isGLValue())
300 return;
301
302 assert(Src && "LValue being cast to RValue has no origin list");
303 // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
304 // `int *p, *q; p = q;`) should propagate the inner origin (what the pointer
305 // points to), not the outer origin (the pointer's storage location). Strip
306 // the outer lvalue origin.
307 flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
308 /*Kill=*/true);
309 return;
310 case CK_NullToPointer:
311 getOriginsList(*CE);
312 // TODO: Flow into them a null origin.
313 return;
314 case CK_NoOp:
315 case CK_ConstructorConversion:
316 case CK_UserDefinedConversion:
317 flow(Dest, Src, /*Kill=*/true);
318 return;
319 case CK_UncheckedDerivedToBase:
320 case CK_DerivedToBase:
321 // It is possible that the derived class and base class have different
322 // gsl::Pointer annotations. Skip if their origin shape differ.
323 if (Dest && Src && Dest->getLength() == Src->getLength())
324 flow(Dest, Src, /*Kill=*/true);
325 return;
326 case CK_ArrayToPointerDecay:
327 // va_arg(ap, array_type) is UB and does not provide addressable array
328 // storage to model.
329 if (isa<VAArgExpr>(SubExpr->IgnoreParens()))
330 return;
331 assert(Src && "Array expression should have origins as it is GL value");
332 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
333 Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
334 return;
335 case CK_FunctionToPointerDecay:
336 case CK_BuiltinFnToFnPtr:
337 // Ignore function-to-pointer decays.
338 return;
339 case CK_BitCast:
340 // OriginLists for Src and Dst may differ here. For example when casting
341 // from int** to void*
342 if (Src && Dest && Dest->getLength() == Src->getLength())
343 flow(Dest, Src, /*Kill=*/true);
344 return;
345 default:
346 return;
347 }
348}
349
351 switch (UO->getOpcode()) {
352 case UO_AddrOf: {
353 const Expr *SubExpr = UO->getSubExpr();
354 // Function addresses do not need lifetime tracking.
355 if (SubExpr->getType()->isFunctionType())
356 return;
357 // Skip address-of on void expressions: GNU C permits them, but void itself
358 // has no origins to track.
359 if (IsCMode && SubExpr->getType()->isVoidType())
360 return;
361 assert(!SubExpr->getType()->isVoidType() &&
362 "Taking address of void is not valid in C++");
363 // The origin of an address-of expression (e.g., &x) is the origin of
364 // its sub-expression (x). This fact will cause the dataflow analysis
365 // to propagate any loans held by the sub-expression's origin to the
366 // origin of this UnaryOperator expression.
367 killAndFlowOrigin(*UO, *SubExpr);
368 return;
369 }
370 case UO_Deref: {
371 const Expr *SubExpr = UO->getSubExpr();
372 killAndFlowOrigin(*UO, *SubExpr);
373 return;
374 }
375 default:
376 return;
377 }
378}
379
381 if (const Expr *RetExpr = RS->getRetValue()) {
382 if (OriginList *List = getOriginsList(*RetExpr))
383 for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
384 EscapesInCurrentBlock.push_back(FactMgr.createFact<ReturnEscapeFact>(
385 L->getOuterOriginID(), RetExpr));
386 }
387}
388
389void FactsGenerator::handleAssignment(const Expr *TargetExpr,
390 const Expr *LHSExpr,
391 const Expr *RHSExpr) {
392 LHSExpr = LHSExpr->IgnoreParenImpCasts();
393 OriginList *LHSList = nullptr;
394
395 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
396 LHSList = getOriginsList(*DRE_LHS);
397 assert(LHSList && "LHS is a DRE and should have an origin list");
398 }
399 // Handle assignment to member fields (e.g., `this->view = s` or `view = s`).
400 // This enables detection of dangling fields when local values escape to
401 // fields.
402 if (const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
403 LHSList = getOriginsList(*ME_LHS);
404 assert(LHSList && "LHS is a MemberExpr and should have an origin list");
405 }
406 if (!LHSList)
407 return;
408 OriginList *RHSList = getOriginsList(*RHSExpr);
409 // For operator= with reference parameters (e.g.,
410 // `View& operator=(const View&)`), the RHS argument stays an lvalue,
411 // unlike built-in assignment where LValueToRValue cast strips the outer
412 // lvalue origin. Strip it manually to get the actual value origins being
413 // assigned.
414 RHSList = getRValueOrigins(RHSExpr, RHSList);
415
416 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
417 QualType QT = DRE_LHS->getDecl()->getType();
418 if (QT->isReferenceType()) {
419 if (hasOrigins(QT->getPointeeType())) {
420 // Writing through a reference uses the binding but overwrites the
421 // pointee. Model this as a Read of the outer origin (keeping the
422 // binding live) and a Write of the inner origins (killing the pointee's
423 // liveness).
424 if (UseFact *UF = UseFacts.lookup(DRE_LHS)) {
425 const OriginList *FullList = UF->getUsedOrigins();
426 assert(FullList);
427 UF->setUsedOrigins(FactMgr.getOriginMgr().createSingleOriginList(
428 FullList->getOuterOriginID()));
429 if (const OriginList *InnerList = FullList->peelOuterOrigin()) {
430 UseFact *WriteUF = FactMgr.createFact<UseFact>(DRE_LHS, InnerList);
431 WriteUF->markAsWritten();
432 CurrentBlockFacts.push_back(WriteUF);
433 }
434 }
435 }
436 } else
437 markUseAsWrite(DRE_LHS);
438 }
439 if (!RHSList) {
440 // RHS has no tracked origins (e.g., assigning a callable without origins
441 // to std::function). Clear loans of the destination.
442 for (OriginList *LHSInner = LHSList->peelOuterOrigin(); LHSInner;
443 LHSInner = LHSInner->peelOuterOrigin())
444 CurrentBlockFacts.push_back(
445 FactMgr.createFact<KillOriginFact>(LHSInner->getOuterOriginID()));
446 return;
447 }
448 // Kill the old loans of the destination origin and flow the new loans
449 // from the source origin.
450 flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
451
452 // In C, assignment expressions are not GLValues, so the assignment result has
453 // the assigned value origins, not the LHS storage origin.
454 if (IsCMode)
455 LHSList = getRValueOrigins(LHSExpr, LHSList);
456 flow(getOriginsList(*TargetExpr), LHSList, /*Kill=*/true);
457}
458
459void FactsGenerator::handlePointerArithmetic(const BinaryOperator *BO) {
460 if (Expr *RHS = BO->getRHS(); RHS->getType()->isPointerType()) {
461 killAndFlowOrigin(*BO, *RHS);
462 return;
463 }
464 Expr *LHS = BO->getLHS();
465 assert(LHS->getType()->isPointerType() &&
466 "Pointer arithmetic must have a pointer operand");
467 killAndFlowOrigin(*BO, *LHS);
468}
469
471 if (BO->getOpcode() == BO_Comma) {
472 killAndFlowOrigin(*BO, *BO->getRHS());
473 return;
474 }
475 if (BO->isCompoundAssignmentOp())
476 return;
477 if (BO->getType()->isPointerType() && BO->isAdditiveOp())
478 handlePointerArithmetic(BO);
479 handleUse(BO->getRHS());
480 if (BO->isAssignmentOp())
481 handleAssignment(BO, BO->getLHS(), BO->getRHS());
482 // TODO: Handle assignments involving dereference like `*p = q`.
483}
484
486 if (!hasOrigins(CO))
487 return;
488
489 const Expr *TrueExpr = CO->getTrueExpr();
490 const Expr *FalseExpr = CO->getFalseExpr();
491
492 const auto Preds = CurrentBlock->preds();
493
494 // Skip origin flow from conditional operator arms that cannot produce the
495 // result value: throw arms and calls to noreturn functions.
496 bool TBHasEdge = true;
497 bool FBHasEdge = true;
498
499 switch (CurrentBlock->pred_size()) {
500 case 0:
501 return;
502 case 1: {
503 TBHasEdge = llvm::any_of(**Preds.begin(),
504 [ExpectedStmt = TrueExpr->IgnoreParenImpCasts()](
505 const CFGElement &Elt) {
506 if (auto CS = Elt.getAs<CFGStmt>())
507 return CS->getStmt() == ExpectedStmt;
508 return false;
509 });
510 FBHasEdge = !TBHasEdge;
511 break;
512 }
513 case 2: {
514 const auto *It = Preds.begin();
515 TBHasEdge = It->isReachable();
516 FBHasEdge = (++It)->isReachable();
517 break;
518 }
519 default:
520 llvm_unreachable("expected at most 2 predecessors");
521 return;
522 }
523
524 bool FirstFlow = true;
525 auto HandleFlow = [&](const Expr *E) {
526 if (FirstFlow) {
527 killAndFlowOrigin(*CO, *E);
528 FirstFlow = false;
529 } else {
530 flowOrigin(*CO, *E);
531 }
532 };
533
534 if (TBHasEdge)
535 HandleFlow(TrueExpr);
536 if (FBHasEdge)
537 HandleFlow(FalseExpr);
538}
539
541 // Assignment operators have special "kill-then-propagate" semantics
542 // and are handled separately.
543 if (OCE->getOperator() == OO_Equal && OCE->getNumArgs() == 2 &&
544 hasOrigins(OCE->getArg(0)->getType())) {
545 // Pointer-like types: assignment inherently propagates origins.
546 QualType LHSTy = OCE->getArg(0)->getType();
547 if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy) ||
548 isGslOwnerType(LHSTy)) {
549 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
550 return;
551 }
552 // Standard library callable wrappers (e.g., std::function) can propagate
553 // the stored lambda's origins.
554 if (const auto *RD = LHSTy->getAsCXXRecordDecl();
555 RD && isStdCallableWrapperType(RD)) {
556 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
557 return;
558 }
559 // Other tracked types: only defaulted operator= propagates origins.
560 // User-defined operator= has opaque semantics, so don't handle them now.
561 if (const auto *MD =
562 dyn_cast_or_null<CXXMethodDecl>(OCE->getDirectCallee());
563 MD && MD->isDefaulted()) {
564 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
565 return;
566 }
567 }
568
569 ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()};
570 // For `static operator()`, the first argument is the object argument,
571 // remove it from the argument list to avoid off-by-one errors.
572 if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic())
573 Args = Args.slice(1);
574 handleFunctionCall(OCE, OCE->getDirectCallee(), Args);
575}
576
578 const CXXFunctionalCastExpr *FCE) {
579 // Check if this is a test point marker. If so, we are done with this
580 // expression.
581 if (handleTestPoint(FCE))
582 return;
583 VisitCastExpr(FCE);
584}
585
587 if (!hasOrigins(ILE))
588 return;
589 // For list initialization with a single element, like `View{...}`, the
590 // origin of the list itself is the origin of its single element.
591 if (ILE->getNumInits() == 1) {
592 // A type with origins may be list-initialized from an element with none
593 // (e.g., an int). Only flow if the element carries any.
594 if (!hasOrigins(ILE->getInit(0)))
595 return;
596 killAndFlowOrigin(*ILE, *ILE->getInit(0));
597 }
598}
599
601 const CXXBindTemporaryExpr *BTE) {
602 killAndFlowOrigin(*BTE, *BTE->getSubExpr());
603}
604
606 const MaterializeTemporaryExpr *MTE) {
607 assert(MTE->isGLValue());
608 OriginList *MTEList = getOriginsList(*MTE);
609 if (!MTEList)
610 return;
611 OriginList *SubExprList = getOriginsList(*MTE->getSubExpr());
612 assert((!SubExprList ||
613 MTEList->getLength() == (SubExprList->getLength() + 1)) &&
614 "MTE top level origin should contain a loan to the MTE itself");
615
616 OriginList *RValMTEList = getRValueOrigins(MTE, MTEList);
617 flow(RValMTEList, SubExprList, /*Kill=*/true);
618 OriginID OuterMTEID = MTEList->getOuterOriginID();
620 // Issue a loan to MTE for the storage location represented by MTE.
621 const Loan *L = createLoan(FactMgr, MTE);
622 CurrentBlockFacts.push_back(
623 FactMgr.createFact<IssueFact>(L->getID(), OuterMTEID));
624 }
625}
626
628 // The lambda gets a single merged origin that aggregates all captured
629 // pointer-like origins. Currently we only need to detect whether the lambda
630 // outlives any capture.
631 OriginList *LambdaList = getOriginsList(*LE);
632 if (!LambdaList)
633 return;
634 bool Kill = true;
635 for (const Expr *Init : LE->capture_inits()) {
636 if (!Init)
637 continue;
638 OriginList *InitList = getOriginsList(*Init);
639 if (!InitList)
640 continue;
641 // FIXME: Consider flowing all origin levels once lambdas support more than
642 // one origin. Currently only the outermost origin is flowed, so by-ref
643 // captures like `[&p]` (where p is string_view) miss inner-level
644 // invalidation.
645 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
646 LambdaList->getOuterOriginID(), InitList->getOuterOriginID(), Kill));
647 Kill = false;
648 }
649}
650
652 // Some C subscripts do not refer to addressable storage with origins, such as
653 // GNU void-pointer subscripts and vector element extraction from rvalues.
654 if (IsCMode && !ASE->isGLValue())
655 return;
656 assert(ASE->isGLValue() && "Array subscript should be a GL value");
657 OriginList *Dst = getOriginsList(*ASE);
658 assert(Dst && "Array subscript should have origins as it is a GL value");
659 OriginList *Src = getOriginsList(*ASE->getBase());
660 assert(Src && "Base of array subscript should have origins");
661 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
662 Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
663}
664
665bool FactsGenerator::handlePlacementNew(const CXXNewExpr *NE,
666 OriginList *NewList) {
667 // Model only the standard single-argument placement new form, where the
668 // placement argument corresponds to a void* allocation-function parameter.
669 // Other placement forms, such as std::nothrow, are not modeled as providing
670 // storage for the returned pointer.
671 if (NE->getNumPlacementArgs() != 1)
672 return false;
673
674 const FunctionDecl *OperatorNew = NE->getOperatorNew();
675 if (OperatorNew->getNumParams() <= 1)
676 return false;
677
678 const auto *Arg =
679 OperatorNew->getParamDecl(1)->getType()->getAs<PointerType>();
680 if (!Arg || !Arg->isVoidPointerType())
681 return false;
682
683 // Use the placement argument before the implicit conversion to void*, so
684 // inner origins are still available.
685 const Expr *PlacementArg = NE->getPlacementArg(0);
686 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PlacementArg);
687 ICE && ICE->getCastKind() == CK_BitCast &&
688 PlacementArg->getType()->isVoidPointerType())
689 PlacementArg = ICE->getSubExpr();
690 OriginList *PlacementList = getOriginsList(*PlacementArg);
691 // FIXME: General placement arguments need separate handling to overwrite
692 // the right origins.
693
694 // The pointer returned by placement new comes from the placement
695 // argument.
696 if (PlacementList)
697 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
698 NewList->getOuterOriginID(), PlacementList->getOuterOriginID(), true));
699 return true;
700}
701
703 OriginList *NewList = getOriginsList(*NE);
704 const Expr *Init = NE->getInitializer();
705
706 bool HandledAsPlacementNew = false;
707 if (NE->getNumPlacementArgs() == 1)
708 HandledAsPlacementNew = handlePlacementNew(NE, NewList);
709
710 // Treat ordinary new and replaceable global allocation forms as heap
711 // allocations.
712 const FunctionDecl *OperatorNew = NE->getOperatorNew();
713 if (!HandledAsPlacementNew &&
714 (NE->getNumPlacementArgs() == 0 ||
715 (OperatorNew && OperatorNew->isReplaceableGlobalAllocationFunction()))) {
716 const Loan *L = createLoan(FactMgr, NE);
717 CurrentBlockFacts.push_back(
718 FactMgr.createFact<IssueFact>(L->getID(), NewList->getOuterOriginID()));
719 }
720
721 NewList = NewList->peelOuterOrigin();
722
723 if (!NewList || !Init)
724 return;
725
726 // FIXME: OriginList is null for `new[]` initializers. Remove this `Init`
727 // check once array origins are supported.
728 if (OriginList *InitList = getOriginsList(*Init); InitList)
729 flow(NewList, InitList, true);
730}
731
733 OriginList *List = getOriginsList(*DE->getArgument());
734 CurrentBlockFacts.push_back(
735 FactMgr.createFact<InvalidateOriginFact>(List->getOuterOriginID(), DE));
736}
737
738bool FactsGenerator::escapesViaReturn(OriginID OID) const {
739 return llvm::any_of(EscapesInCurrentBlock, [OID](const Fact *F) {
740 if (const auto *EF = F->getAs<ReturnEscapeFact>())
741 return EF->getEscapedOriginID() == OID;
742 return false;
743 });
744}
745
746void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) {
747 const VarDecl *LifetimeEndsVD = LifetimeEnds.getVarDecl();
748 if (!LifetimeEndsVD)
749 return;
750 // Expire the origin when its variable's lifetime ends to ensure liveness
751 // doesn't persist through loop back-edges.
752 std::optional<OriginID> ExpiredOID;
753 if (OriginList *List = getOriginsList(*LifetimeEndsVD)) {
754 OriginID OID = List->getOuterOriginID();
755 // Skip origins that escape via return; the escape checker needs their loans
756 // to remain until the return statement is processed.
757 if (!escapesViaReturn(OID))
758 ExpiredOID = OID;
759 }
760 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
761 AccessPath(LifetimeEndsVD), LifetimeEnds.getTriggerStmt()->getEndLoc(),
762 ExpiredOID));
763}
764
765void FactsGenerator::handleFullExprCleanup(
766 const CFGFullExprCleanup &FullExprCleanup) {
767 for (const auto *MTE : FullExprCleanup.getExpiringMTEs())
768 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
769 AccessPath(MTE), FullExprCleanup.getCleanupLoc()));
770}
771
772void FactsGenerator::handleExitBlock() {
773 for (const Origin &O : FactMgr.getOriginMgr().getOrigins())
774 if (auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
775 // Create FieldEscapeFacts for all field origins that remain live at exit.
776 EscapesInCurrentBlock.push_back(
777 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
778 else if (auto *VD = dyn_cast_if_present<VarDecl>(O.getDecl())) {
779 // Create GlobalEscapeFacts for all origins with global-storage that
780 // remain live at exit.
781 if (VD->hasGlobalStorage()) {
782 EscapesInCurrentBlock.push_back(
783 FactMgr.createFact<GlobalEscapeFact>(O.ID, VD));
784 }
785 }
786}
787
788void FactsGenerator::handleGSLPointerConstruction(const CXXConstructExpr *CCE) {
789 assert(isGslPointerType(CCE->getType()));
790 if (CCE->getNumArgs() != 1)
791 return;
792
793 const Expr *Arg = CCE->getArg(0);
794 if (isGslPointerType(Arg->getType())) {
795 OriginList *ArgList = getOriginsList(*Arg);
796 assert(ArgList && "GSL pointer argument should have an origin list");
797 // GSL pointer is constructed from another gsl pointer.
798 // Example:
799 // View(View v);
800 // View(const View &v);
801 ArgList = getRValueOrigins(Arg, ArgList);
802 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
803 } else if (Arg->getType()->isPointerType()) {
804 // GSL pointer is constructed from a raw pointer. Flow only the outermost
805 // raw pointer. Example:
806 // View(const char*);
807 // Span<int*>(const in**);
808 OriginList *ArgList = getOriginsList(*Arg);
809 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
810 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
811 /*Kill=*/true));
812 } else {
813 // This could be a new borrow.
814 // TODO: Add code example here.
815 handleFunctionCall(CCE, CCE->getConstructor(),
816 {CCE->getArgs(), CCE->getNumArgs()},
817 /*IsGslConstruction=*/true);
818 }
819}
820
821void FactsGenerator::handleMovedArgsInCall(const FunctionDecl *FD,
822 ArrayRef<const Expr *> Args) {
823 unsigned IsInstance = 0;
824 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
825 MD && MD->isInstance() && !isa<CXXConstructorDecl>(FD)) {
826 IsInstance = 1;
827 // std::unique_ptr::release() transfers ownership.
828 // Treat it as a move to prevent false-positive warnings when the unique_ptr
829 // destructor runs after ownership has been transferred.
830 if (isUniquePtrRelease(*MD)) {
831 const Expr *UniquePtrExpr = Args[0];
832 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
833 if (MovedOrigins)
834 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
835 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
836 }
837 }
838
839 // Skip 'this' arg as it cannot be moved.
840 for (unsigned I = IsInstance;
841 I < Args.size() && I < FD->getNumParams() + IsInstance; ++I) {
842 const ParmVarDecl *PVD = FD->getParamDecl(I - IsInstance);
843 if (!PVD->getType()->isRValueReferenceType())
844 continue;
845 const Expr *Arg = Args[I];
846 OriginList *MovedOrigins = getOriginsList(*Arg);
847 assert(MovedOrigins->getLength() >= 1 &&
848 "unexpected length for r-value reference param");
849 // Arg is being moved to this parameter. Mark the origin as moved.
850 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
851 Arg, MovedOrigins->getOuterOriginID()));
852 }
853}
854
855void FactsGenerator::handleInvalidatingCall(const Expr *Call,
856 const FunctionDecl *FD,
857 ArrayRef<const Expr *> Args) {
858 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
859 if (!MD || !MD->isInstance())
860 return;
861
862 if (!isInvalidationMethod(*MD))
863 return;
864
865 // Heuristics to turn-down false positives. Skip member field expressions for
866 // now. This is not a perfect filter and will still surface some false
867 // positives (e.g. `auto& r = s.v`).
868 if (!isa<DeclRefExpr>(Args[0]->IgnoreImpCasts()))
869 return;
870
871 OriginList *ThisList = getOriginsList(*Args[0]);
872 if (ThisList)
873 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
874 ThisList->getOuterOriginID(), Call));
875}
876
877void FactsGenerator::handleDestructiveCall(const Expr *Call,
878 const FunctionDecl *FD,
879 ArrayRef<const Expr *> Args) {
880 if (!destructsFirstArg(*FD))
881 return;
882 OriginList *ArgList = getOriginsList(*Args[0]);
883 if (ArgList)
884 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
885 ArgList->getOuterOriginID(), Call));
886}
887
888void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call,
889 const FunctionDecl *FD) {
890 const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call);
891 if (!MemberCall)
892 return;
893
894 if (!isa_and_present<CXXThisExpr>(
895 MemberCall->getImplicitObjectArgument()->IgnoreImpCasts()))
896 return;
897
898 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
899 assert(MD && "Function must be a CXXMethodDecl for member calls");
900
901 const auto *ClassDecl = MD->getParent()->getDefinition();
902 if (!ClassDecl)
903 return;
904
905 const auto UseFields = [&](const CXXRecordDecl *RD) {
906 for (const auto *Field : RD->fields())
907 if (auto *FieldList = getOriginsList(*Field))
908 CurrentBlockFacts.push_back(
909 FactMgr.createFact<UseFact>(Call, FieldList));
910 };
911
912 UseFields(ClassDecl);
913
914 ClassDecl->forallBases([&](const CXXRecordDecl *Base) {
915 UseFields(Base);
916 return true;
917 });
918}
919
920void FactsGenerator::handleLifetimeCaptureBy(const FunctionDecl *FD,
921 ArrayRef<const Expr *> Args) {
922 if (Args.empty())
923 return;
924 // FIXME: Add support for capture_by on constructors.
926 return;
927 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
928 bool IsInstance =
929 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD);
930 auto getArgCaptureBy = [FD,
931 IsInstance](unsigned I) -> LifetimeCaptureByAttr * {
932 const ParmVarDecl *PVD = nullptr;
933 if (IsInstance) {
934 // FIXME: Add support for I == 0 i.e. capture_by on function declarations
935 if (I > 0 && I - 1 < FD->getNumParams())
936 PVD = FD->getParamDecl(I - 1);
937 } else {
938 if (I < FD->getNumParams())
939 PVD = FD->getParamDecl(I);
940 }
941 return PVD ? PVD->getAttr<LifetimeCaptureByAttr>() : nullptr;
942 };
943 for (unsigned I = 0; I < Args.size(); ++I) {
944 const LifetimeCaptureByAttr *Attr = getArgCaptureBy(I);
945 if (!Attr)
946 continue;
947 OriginList *CapturedOriginList = getOriginsList(*Args[I]);
948 if (!CapturedOriginList)
949 continue;
950 if (!CapturedOriginList)
951 continue;
952 for (int CapturingArgIdx : Attr->params()) {
953 // FIXME: Add support for capturing to Global/unknown.
954 if (CapturingArgIdx == LifetimeCaptureByAttr::Global ||
955 CapturingArgIdx == LifetimeCaptureByAttr::Unknown ||
956 CapturingArgIdx == LifetimeCaptureByAttr::Invalid)
957 continue;
958 ArrayRef<const Expr *> CallArgs = IsInstance ? Args.drop_front() : Args;
959 const Expr *CapturedByArg =
960 (CapturingArgIdx == LifetimeCaptureByAttr::This)
961 ? Args[0]
962 : CallArgs[CapturingArgIdx];
963 assert(CapturedByArg && "Capturer expression must be valid");
964
965 OriginList *CapturingOriginList = getOriginsList(*CapturedByArg);
966 OriginList *Dest = getRValueOrigins(CapturedByArg, CapturingOriginList);
967 if (!Dest)
968 continue;
969 // KillDest=false because we cannot know if previous captures are being
970 // replaced or accumulated. Multiple successive captures into the same
971 // destination must all be tracked, so captured lifetimes are always
972 // merged.
973 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
974 Dest->getOuterOriginID(), CapturedOriginList->getOuterOriginID(),
975 /*KillDest=*/false));
976 }
977 }
978}
979
980void FactsGenerator::handleFunctionCall(const Expr *Call,
981 const FunctionDecl *FD,
982 ArrayRef<const Expr *> Args,
983 bool IsGslConstruction) {
984 OriginList *CallList = getOriginsList(*Call);
985 // Ignore functions returning values with no origin.
987 if (!FD)
988 return;
989 // All arguments to a function are a use of the corresponding expressions.
990 for (const Expr *Arg : Args)
991 handleUse(Arg);
992 handleInvalidatingCall(Call, FD, Args);
993 handleDestructiveCall(Call, FD, Args);
994 handleMovedArgsInCall(FD, Args);
995 handleImplicitObjectFieldUses(Call, FD);
996 handleLifetimeCaptureBy(FD, Args);
997 if (!CallList)
998 return;
999 if (isStdReferenceCast(FD)) {
1000 assert(Args.size() == 1 &&
1001 "std reference cast builtins take exactly one argument");
1002 // std reference-cast functions like std::move return a result that refers
1003 // to the same object as the argument, so propagate the full origins.
1004 flow(CallList, getOriginsList(*Args[0]), /*Kill=*/true);
1005 return;
1006 }
1007 auto IsArgLifetimeBound = [FD, &Args](unsigned I) -> bool {
1008 const ParmVarDecl *PVD = nullptr;
1009 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1010 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
1011 if (I == 0)
1012 // For the 'this' argument, the attribute is on the method itself.
1015 *Args[0], Method, /*RunningUnderLifetimeSafety=*/true);
1016 if ((I - 1) < Method->getNumParams())
1017 // For explicit arguments, find the corresponding parameter
1018 // declaration.
1019 PVD = Method->getParamDecl(I - 1);
1020 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
1021 return true;
1022 } else if (I == 1 && shouldTrackSecondArgument(FD)) {
1023 return true;
1024 } else if (I < FD->getNumParams()) {
1025 // For free functions or static methods.
1026 PVD = FD->getParamDecl(I);
1027 }
1028 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
1029 };
1030 auto shouldTrackPointerImplicitObjectArg = [FD, &Args](unsigned I) -> bool {
1031 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1032 if (!Method || !Method->isInstance())
1033 return false;
1034 return I == 0 &&
1035 isGslPointerType(Method->getFunctionObjectParameterType()) &&
1037 /*RunningUnderLifetimeSafety=*/true);
1038 };
1039 if (Args.empty())
1040 return;
1041 bool KillSrc = true;
1042 for (unsigned I = 0; I < Args.size(); ++I) {
1043 OriginList *ArgList = getOriginsList(*Args[I]);
1044 if (!ArgList)
1045 continue;
1046 if (IsGslConstruction) {
1047 // TODO: document with code example.
1048 // std::string_view(const std::string_view& from)
1049 if (isGslPointerType(Args[I]->getType())) {
1050 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
1051 ArgList = getRValueOrigins(Args[I], ArgList);
1052 }
1053 if (isGslOwnerType(Args[I]->getType())) {
1054 // The constructed gsl::Pointer borrows from the Owner's storage, not
1055 // from what the Owner itself borrows, so only the outermost origin is
1056 // needed.
1057 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1058 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1059 KillSrc));
1060 KillSrc = false;
1061 } else if (IsArgLifetimeBound(I)) {
1062 // Only flow the outer origin here. For lifetimebound args in
1063 // gsl::Pointer construction, we do not have enough information to
1064 // safely match inner origins, so the source and
1065 // destination origin lists may have different lengths.
1066 // FIXME: Handle origin-shape mismatches gracefully so we can also flow
1067 // inner origins.
1068 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1069 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1070 KillSrc));
1071 KillSrc = false;
1072 }
1073 } else if (shouldTrackPointerImplicitObjectArg(I)) {
1074 assert(ArgList->getLength() >= 2 &&
1075 "Object arg of pointer type should have at least two origins");
1076 // See through the GSLPointer reference to see the pointer's value.
1077 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1078 CallList->getOuterOriginID(),
1079 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
1080 KillSrc = false;
1081 } else if (IsArgLifetimeBound(I)) {
1082 // Lifetimebound on a non-GSL-ctor function means the returned
1083 // pointer/reference itself must not outlive the arguments. This
1084 // only constrains the top-level origin.
1085 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1086 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
1087 KillSrc = false;
1088 }
1089 }
1090}
1091
1092/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
1093/// If so, creates a `TestPointFact` and returns true.
1094bool FactsGenerator::handleTestPoint(const CXXFunctionalCastExpr *FCE) {
1095 if (!FCE->getType()->isVoidType())
1096 return false;
1097
1098 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
1099 if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
1100 llvm::StringRef LiteralValue = SL->getString();
1101 const std::string Prefix = "__lifetime_test_point_";
1102
1103 if (LiteralValue.starts_with(Prefix)) {
1104 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
1105 CurrentBlockFacts.push_back(
1106 FactMgr.createFact<TestPointFact>(Annotation));
1107 return true;
1108 }
1109 }
1110 return false;
1111}
1112
1113void FactsGenerator::handleUse(const Expr *E) {
1114 OriginList *List = getOriginsList(*E);
1115 if (!List)
1116 return;
1117 // For DeclRefExpr: Remove the outer layer of origin which borrows from the
1118 // decl directly (e.g., when this is not a reference). This is a use of the
1119 // underlying decl.
1120 if (auto *DRE = dyn_cast<DeclRefExpr>(E);
1121 DRE && !DRE->getDecl()->getType()->isReferenceType())
1122 List = getRValueOrigins(DRE, List);
1123 // Skip if there is no inner origin (e.g., when it is not a pointer type).
1124 if (!List)
1125 return;
1126 if (!UseFacts.contains(E)) {
1127 UseFact *UF = FactMgr.createFact<UseFact>(E, List);
1128 CurrentBlockFacts.push_back(UF);
1129 UseFacts[E] = UF;
1130 }
1131}
1132
1133void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
1134 if (UseFacts.contains(DRE))
1135 UseFacts[DRE]->markAsWritten();
1136}
1137
1138// Creates an IssueFact for a new placeholder loan for each pointer or reference
1139// parameter at the function's entry.
1140llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
1141 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
1142 if (!FD)
1143 return {};
1144
1145 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
1146 if (auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
1147 OriginList *List = *ThisOrigins;
1148 const Loan *L = FactMgr.getLoanMgr().createLoan(
1150 /*IssuingExpr=*/nullptr);
1151 PlaceholderLoanFacts.push_back(
1152 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1153 }
1154 for (const ParmVarDecl *PVD : FD->parameters()) {
1155 OriginList *List = getOriginsList(*PVD);
1156 if (!List)
1157 continue;
1158 const Loan *L = FactMgr.getLoanMgr().createLoan(
1159 AccessPath::Placeholder(PVD), /*IssuingExpr=*/nullptr);
1160 PlaceholderLoanFacts.push_back(
1161 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1162 }
1163 return PlaceholderLoanFacts;
1164}
1165
1166} // namespace clang::lifetimes::internal
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
TokenType getType() const
Returns the token's type, e.g.
Defines an enumeration for C++ overloaded operators.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2727
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4044
Expr * getLHS() const
Definition Expr.h:4094
Expr * getRHS() const
Definition Expr.h:4096
static bool isAdditiveOp(Opcode Opc)
Definition Expr.h:4130
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4180
static bool isCompoundAssignmentOp(Opcode Opc)
Definition Expr.h:4185
Opcode getOpcode() const
Definition Expr.h:4089
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
Represents a top-level expression in a basic block.
Definition CFG.h:55
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Definition CFG.h:113
Represents C++ base or member initializer from constructor's initialization list.
Definition CFG.h:232
Represents the point where the lifetime of an automatic object ends.
Definition CFG.h:321
const VarDecl * getVarDecl() const
Definition CFG.h:326
LLVM_ATTRIBUTE_RETURNS_NONNULL const Stmt * getTriggerStmt() const
Definition CFG.h:300
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
CFGBlock & getExit()
Definition CFG.h:1387
CFGBlock & getEntry()
Definition CFG.h:1385
Represents binding an expression to a temporary.
Definition ExprCXX.h:1497
const Expr * getSubExpr() const
Definition ExprCXX.h:1519
Represents a call to a C++ constructor.
Definition ExprCXX.h:1552
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1695
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1615
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1692
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const
Determine whether this is a copy or move constructor.
Definition DeclCXX.cpp:3067
Represents a C++ base or member initializer.
Definition DeclCXX.h:2398
Expr * getInit() const
Get the initializer.
Definition DeclCXX.h:2600
FieldDecl * getAnyMember() const
Definition DeclCXX.h:2544
A use of a default initializer in a constructor or in aggregate initialization.
Definition ExprCXX.h:1381
Expr * getExpr()
Get the initialization expression that will be used.
Definition ExprCXX.cpp:1112
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition ExprCXX.h:2630
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Definition ExprCXX.h:1835
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:183
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition ExprCXX.cpp:748
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:729
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2359
The null pointer literal (C++11 [lex.nullptr])
Definition ExprCXX.h:772
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:85
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Definition ExprCXX.h:115
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
Expr ** getArgs()
Retrieve the call arguments.
Definition Expr.h:3143
Decl * getCalleeDecl()
Definition Expr.h:3126
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3682
CastKind getCastKind() const
Definition Expr.h:3726
Expr * getSubExpr()
Definition Expr.h:3732
ConditionalOperator - The ?
Definition Expr.h:4397
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4429
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4424
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
Definition Expr.h:1387
ValueDecl * getDecl()
Definition Expr.h:1344
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1641
decl_range decls()
Definition Stmt.h:1689
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isFunctionOrFunctionTemplate() const
Whether this declaration is a function or function template.
Definition DeclBase.h:1132
This represents one expression.
Definition Expr.h:112
bool isGLValue() const
Definition Expr.h:287
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3099
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3095
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3182
Represents a function declaration or definition.
Definition Decl.h:2018
bool isStatic() const
Definition Decl.h:2947
bool isDefaulted() const
Whether this function is defaulted.
Definition Decl.h:2403
Describes an C or C++ initializer list.
Definition Expr.h:5305
unsigned getNumInits() const
Definition Expr.h:5338
const Expr * getInit(unsigned Init) const
Definition Expr.h:5360
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Definition ExprCXX.h:1972
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4920
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition ExprCXX.h:4945
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4937
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3370
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3453
Expr * getBase() const
Definition Expr.h:3447
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3392
A (possibly-)qualified type.
Definition TypeBase.h:937
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3170
Expr * getRetValue()
Definition Stmt.h:3197
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition StmtVisitor.h:45
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
bool isVoidType() const
Definition TypeBase.h:9050
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isPointerType() const
Definition TypeBase.h:8684
bool isReferenceType() const
Definition TypeBase.h:8708
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isPointerOrReferenceType() const
Definition TypeBase.h:8688
bool isFunctionType() const
Definition TypeBase.h:8680
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2250
Expr * getSubExpr() const
Definition Expr.h:2291
Opcode getOpcode() const
Definition Expr.h:2286
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
Represents a variable declaration or definition.
Definition Decl.h:924
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:45
static AccessPath Placeholder(const ParmVarDecl *PVD)
Definition Loans.h:64
FactType * createFact(Args &&...args)
Definition Facts.h:355
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:34
const T * getAs() const
Definition Facts.h:76
void VisitDeclRefExpr(const DeclRefExpr *DRE)
void VisitBinaryOperator(const BinaryOperator *BO)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE)
void VisitCXXConstructExpr(const CXXConstructExpr *CCE)
void VisitCXXDeleteExpr(const CXXDeleteExpr *DE)
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE)
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *DIE)
void VisitInitListExpr(const InitListExpr *ILE)
void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)
void VisitUnaryOperator(const UnaryOperator *UO)
void VisitConditionalOperator(const ConditionalOperator *CO)
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)
Represents that an origin's storage has been invalidated by a container operation (e....
Definition Facts.h:264
Loan * createLoan(AccessPath Path, const Expr *IssueExpr)
Definition Loans.h:143
Represents lending a storage location.
Definition Loans.h:122
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:95
OriginList * peelOuterOrigin() const
Definition Origins.h:99
OriginList * createSingleOriginList(OriginID OID)
Wraps an existing OriginID in a new single-element OriginList, so a fact can refer to a single level ...
Definition Origins.cpp:190
Represents that an origin escapes via a return statement.
Definition Facts.h:181
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
static OriginList * getRValueOrigins(const Expr *E, OriginList *List)
Simulates LValueToRValue conversion by peeling the outer lvalue origin if the expression is a GLValue...
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
Definition Origins.cpp:157
static const Loan * createLoan(FactManager &FactMgr, const DeclRefExpr *DRE)
Creates a loan for the storage path of a given declaration reference.
bool isGslPointerType(QualType QT)
bool isStdCallableWrapperType(const CXXRecordDecl *RD)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument, const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
bool isStdReferenceCast(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isInvalidationMethod(const CXXMethodDecl &MD)
bool destructsFirstArg(const FunctionDecl &FD)
bool isGslOwnerType(QualType QT)
bool shouldTrackSecondArgument(const FunctionDecl *FD)
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition Specifiers.h:341
U cast(CodeGen::Address addr)
Definition Address.h:327
llvm::Expected< Stmt * > ExpectedStmt
#define false
Definition stdbool.h:26