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
98 llvm::TimeTraceScope TimeProfile("FactGenerator");
99 const CFG &Cfg = *AC.getCFG();
100 llvm::SmallVector<Fact *> PlaceholderLoanFacts = issuePlaceholderLoans();
101 // Iterate through the CFG blocks in reverse post-order to ensure that
102 // initializations and destructions are processed in the correct sequence.
103 for (const CFGBlock *Block : *AC.getAnalysis<PostOrderCFGView>()) {
104 CurrentBlockFacts.clear();
105 EscapesInCurrentBlock.clear();
106 CurrentBlock = Block;
107 if (Block == &Cfg.getEntry())
108 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
109 PlaceholderLoanFacts.end());
110 for (unsigned I = 0; I < Block->size(); ++I) {
111 const CFGElement &Element = Block->Elements[I];
112 if (std::optional<CFGStmt> CS = Element.getAs<CFGStmt>())
113 Visit(CS->getStmt());
114 else if (std::optional<CFGInitializer> Initializer =
115 Element.getAs<CFGInitializer>())
116 handleCXXCtorInitializer(Initializer->getInitializer());
117 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
118 Element.getAs<CFGLifetimeEnds>())
119 handleLifetimeEnds(*LifetimeEnds);
120 else if (std::optional<CFGFullExprCleanup> FullExprCleanup =
121 Element.getAs<CFGFullExprCleanup>()) {
122 handleFullExprCleanup(*FullExprCleanup);
123 }
124 }
125 if (Block == &Cfg.getExit())
126 handleExitBlock();
127
128 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
129 EscapesInCurrentBlock.end());
130 FactMgr.addBlockFacts(Block, CurrentBlockFacts);
131 }
132}
133
134/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
135/// if the expression is a GLValue. For pointer/view GLValues, this strips
136/// the origin representing the storage location to get the origins of the
137/// pointed-to value.
138///
139/// Example: For `View& v`, returns the origin of what v points to, not v's
140/// storage.
141static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
142 if (!List)
143 return nullptr;
144 return E->isGLValue() ? List->peelOuterOrigin() : List;
145}
146
148 for (const Decl *D : DS->decls())
149 if (const auto *VD = dyn_cast<VarDecl>(D))
150 if (const Expr *InitExpr = VD->getInit()) {
151 OriginList *VDList = getOriginsList(*VD);
152 if (!VDList)
153 continue;
154 OriginList *InitList = getOriginsList(*InitExpr);
155 assert(InitList && "VarDecl had origins but InitExpr did not");
156 flow(VDList, InitList, /*Kill=*/true);
157 }
158}
159
161 // Skip function references as their lifetimes are not interesting. Skip non
162 // GLValues (like EnumConstants).
163 if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
164 return;
165 handleUse(DRE);
166 // For all declarations with storage (non-references), we issue a loan
167 // representing the borrow of the variable's storage itself.
168 //
169 // Examples:
170 // - `int x; x` issues loan to x's storage
171 // - `int* p; p` issues loan to p's storage (the pointer variable)
172 // - `View v; v` issues loan to v's storage (the view object)
173 // - `int& r = x; r` issues no loan (r has no storage, it's an alias to x)
174 if (doesDeclHaveStorage(DRE->getDecl())) {
175 const Loan *L = createLoan(FactMgr, DRE);
176 assert(L);
177 OriginList *List = getOriginsList(*DRE);
178 assert(List &&
179 "gl-value DRE of non-pointer type should have an origin list");
180 // This loan specifically tracks borrowing the variable's storage location
181 // itself and is issued to outermost origin (List->OID).
182 CurrentBlockFacts.push_back(
183 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
184 }
185}
186
188 if (isGslPointerType(CCE->getType())) {
189 handleGSLPointerConstruction(CCE);
190 return;
191 }
192 // For defaulted (implicit or `= default`) copy/move constructors, propagate
193 // origins directly. User-defined copy/move constructors are not handled here
194 // as they have opaque semantics.
196 CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
197 hasOrigins(CCE->getType())) {
198 const Expr *Arg = CCE->getArg(0);
199 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
200 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
201 return;
202 }
203 }
204 // Standard library callable wrappers (e.g., std::function) propagate the
205 // stored lambda's origins.
206 if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
207 RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
208 const Expr *Arg = CCE->getArg(0);
209 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
210 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
211 return;
212 }
213 }
214 handleFunctionCall(CCE, CCE->getConstructor(),
215 {CCE->getArgs(), CCE->getNumArgs()},
216 /*IsGslConstruction=*/false);
217}
218
220 if (const Expr *Init = DIE->getExpr())
221 killAndFlowOrigin(*DIE, *Init);
222}
223
224void FactsGenerator::handleCXXCtorInitializer(const CXXCtorInitializer *CII) {
225 // Flows origins from the initializer expression to the field.
226 // Example: `MyObj(std::string s) : view(s) {}`
227 if (const FieldDecl *FD = CII->getAnyMember())
228 killAndFlowOrigin(*FD, *CII->getInit());
229}
230
232 // Specifically for conversion operators,
233 // like `std::string_view p = std::string{};`
234 if (isGslPointerType(MCE->getType()) &&
235 isa_and_present<CXXConversionDecl>(MCE->getCalleeDecl()) &&
237 // The argument is the implicit object itself.
238 handleFunctionCall(MCE, MCE->getMethodDecl(),
239 {MCE->getImplicitObjectArgument()},
240 /*IsGslConstruction=*/true);
241 return;
242 }
243 if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
244 // Construct the argument list, with the implicit 'this' object as the
245 // first argument.
247 Args.push_back(MCE->getImplicitObjectArgument());
248 Args.append(MCE->getArgs(), MCE->getArgs() + MCE->getNumArgs());
249
250 handleFunctionCall(MCE, Method, Args, /*IsGslConstruction=*/false);
251 }
252}
253
255 auto *MD = ME->getMemberDecl();
256 if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
257 assert(ME->isGLValue() && "Field member should be GL value");
258 OriginList *Dst = getOriginsList(*ME);
259 assert(Dst && "Field member should have an origin list as it is GL value");
260 OriginList *Src = getOriginsList(*ME->getBase());
261 assert(Src && "Base expression should be a pointer/reference type");
262 // The field's glvalue (outermost origin) holds the same loans as the base
263 // expression.
264 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
265 Dst->getOuterOriginID(), Src->getOuterOriginID(),
266 /*Kill=*/true));
267 }
268}
269
271 handleFunctionCall(CE, CE->getDirectCallee(),
272 {CE->getArgs(), CE->getNumArgs()});
273}
274
276 const CXXNullPtrLiteralExpr *N) {
277 /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
278 /// pointers can use the same type of loan.
279 getOriginsList(*N);
280}
281
283 OriginList *Dest = getOriginsList(*CE);
284 if (!Dest)
285 return;
286 const Expr *SubExpr = CE->getSubExpr();
287 OriginList *Src = getOriginsList(*SubExpr);
288
289 switch (CE->getCastKind()) {
290 case CK_LValueToRValue:
291 if (!SubExpr->isGLValue())
292 return;
293
294 assert(Src && "LValue being cast to RValue has no origin list");
295 // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
296 // `int *p, *q; p = q;`) should propagate the inner origin (what the pointer
297 // points to), not the outer origin (the pointer's storage location). Strip
298 // the outer lvalue origin.
299 flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
300 /*Kill=*/true);
301 return;
302 case CK_NullToPointer:
303 getOriginsList(*CE);
304 // TODO: Flow into them a null origin.
305 return;
306 case CK_NoOp:
307 case CK_ConstructorConversion:
308 case CK_UserDefinedConversion:
309 flow(Dest, Src, /*Kill=*/true);
310 return;
311 case CK_UncheckedDerivedToBase:
312 case CK_DerivedToBase:
313 // It is possible that the derived class and base class have different
314 // gsl::Pointer annotations. Skip if their origin shape differ.
315 if (Dest && Src && Dest->getLength() == Src->getLength())
316 flow(Dest, Src, /*Kill=*/true);
317 return;
318 case CK_ArrayToPointerDecay:
319 assert(Src && "Array expression should have origins as it is GL value");
320 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
321 Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
322 return;
323 case CK_FunctionToPointerDecay:
324 case CK_BuiltinFnToFnPtr:
325 // Ignore function-to-pointer decays.
326 return;
327 default:
328 return;
329 }
330}
331
333 switch (UO->getOpcode()) {
334 case UO_AddrOf: {
335 const Expr *SubExpr = UO->getSubExpr();
336 // The origin of an address-of expression (e.g., &x) is the origin of
337 // its sub-expression (x). This fact will cause the dataflow analysis
338 // to propagate any loans held by the sub-expression's origin to the
339 // origin of this UnaryOperator expression.
340 killAndFlowOrigin(*UO, *SubExpr);
341 return;
342 }
343 case UO_Deref: {
344 const Expr *SubExpr = UO->getSubExpr();
345 killAndFlowOrigin(*UO, *SubExpr);
346 return;
347 }
348 default:
349 return;
350 }
351}
352
354 if (const Expr *RetExpr = RS->getRetValue()) {
355 if (OriginList *List = getOriginsList(*RetExpr))
356 for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
357 EscapesInCurrentBlock.push_back(FactMgr.createFact<ReturnEscapeFact>(
358 L->getOuterOriginID(), RetExpr));
359 }
360}
361
362void FactsGenerator::handleAssignment(const Expr *LHSExpr,
363 const Expr *RHSExpr) {
364 LHSExpr = LHSExpr->IgnoreParenImpCasts();
365 OriginList *LHSList = nullptr;
366
367 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
368 LHSList = getOriginsList(*DRE_LHS);
369 assert(LHSList && "LHS is a DRE and should have an origin list");
370 }
371 // Handle assignment to member fields (e.g., `this->view = s` or `view = s`).
372 // This enables detection of dangling fields when local values escape to
373 // fields.
374 if (const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
375 LHSList = getOriginsList(*ME_LHS);
376 assert(LHSList && "LHS is a MemberExpr and should have an origin list");
377 }
378 if (!LHSList)
379 return;
380 OriginList *RHSList = getOriginsList(*RHSExpr);
381 // For operator= with reference parameters (e.g.,
382 // `View& operator=(const View&)`), the RHS argument stays an lvalue,
383 // unlike built-in assignment where LValueToRValue cast strips the outer
384 // lvalue origin. Strip it manually to get the actual value origins being
385 // assigned.
386 RHSList = getRValueOrigins(RHSExpr, RHSList);
387
388 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
389 QualType QT = DRE_LHS->getDecl()->getType();
390 if (QT->isReferenceType()) {
391 if (hasOrigins(QT->getPointeeType())) {
392 // Writing through a reference uses the binding but overwrites the
393 // pointee. Model this as a Read of the outer origin (keeping the
394 // binding live) and a Write of the inner origins (killing the pointee's
395 // liveness).
396 if (UseFact *UF = UseFacts.lookup(DRE_LHS)) {
397 const OriginList *FullList = UF->getUsedOrigins();
398 assert(FullList);
399 UF->setUsedOrigins(FactMgr.getOriginMgr().createSingleOriginList(
400 FullList->getOuterOriginID()));
401 if (const OriginList *InnerList = FullList->peelOuterOrigin()) {
402 UseFact *WriteUF = FactMgr.createFact<UseFact>(DRE_LHS, InnerList);
403 WriteUF->markAsWritten();
404 CurrentBlockFacts.push_back(WriteUF);
405 }
406 }
407 }
408 } else
409 markUseAsWrite(DRE_LHS);
410 }
411 if (!RHSList) {
412 // RHS has no tracked origins (e.g., assigning a callable without origins
413 // to std::function). Clear loans of the destination.
414 for (OriginList *LHSInner = LHSList->peelOuterOrigin(); LHSInner;
415 LHSInner = LHSInner->peelOuterOrigin())
416 CurrentBlockFacts.push_back(
417 FactMgr.createFact<KillOriginFact>(LHSInner->getOuterOriginID()));
418 return;
419 }
420 // Kill the old loans of the destination origin and flow the new loans
421 // from the source origin.
422 flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
423}
424
425void FactsGenerator::handlePointerArithmetic(const BinaryOperator *BO) {
426 if (Expr *RHS = BO->getRHS(); RHS->getType()->isPointerType()) {
427 killAndFlowOrigin(*BO, *RHS);
428 return;
429 }
430 Expr *LHS = BO->getLHS();
431 assert(LHS->getType()->isPointerType() &&
432 "Pointer arithmetic must have a pointer operand");
433 killAndFlowOrigin(*BO, *LHS);
434}
435
437 if (BO->isCompoundAssignmentOp())
438 return;
439 if (BO->getType()->isPointerType() && BO->isAdditiveOp())
440 handlePointerArithmetic(BO);
441 handleUse(BO->getRHS());
442 if (BO->isAssignmentOp())
443 handleAssignment(BO->getLHS(), BO->getRHS());
444 // TODO: Handle assignments involving dereference like `*p = q`.
445}
446
448 if (!hasOrigins(CO))
449 return;
450
451 const Expr *TrueExpr = CO->getTrueExpr();
452 const Expr *FalseExpr = CO->getFalseExpr();
453
454 const auto Preds = CurrentBlock->preds();
455
456 // Skip origin flow from conditional operator arms that cannot produce the
457 // result value: throw arms and calls to noreturn functions.
458 bool TBHasEdge = true;
459 bool FBHasEdge = true;
460
461 switch (CurrentBlock->pred_size()) {
462 case 0:
463 return;
464 case 1: {
465 TBHasEdge = llvm::any_of(**Preds.begin(),
466 [ExpectedStmt = TrueExpr->IgnoreParenImpCasts()](
467 const CFGElement &Elt) {
468 if (auto CS = Elt.getAs<CFGStmt>())
469 return CS->getStmt() == ExpectedStmt;
470 return false;
471 });
472 FBHasEdge = !TBHasEdge;
473 break;
474 }
475 case 2: {
476 const auto *It = Preds.begin();
477 TBHasEdge = It->isReachable();
478 FBHasEdge = (++It)->isReachable();
479 break;
480 }
481 default:
482 llvm_unreachable("expected at most 2 predecessors");
483 return;
484 }
485
486 bool FirstFlow = true;
487 auto HandleFlow = [&](const Expr *E) {
488 if (FirstFlow) {
489 killAndFlowOrigin(*CO, *E);
490 FirstFlow = false;
491 } else {
492 flowOrigin(*CO, *E);
493 }
494 };
495
496 if (TBHasEdge)
497 HandleFlow(TrueExpr);
498 if (FBHasEdge)
499 HandleFlow(FalseExpr);
500}
501
503 // Assignment operators have special "kill-then-propagate" semantics
504 // and are handled separately.
505 if (OCE->getOperator() == OO_Equal && OCE->getNumArgs() == 2 &&
506 hasOrigins(OCE->getArg(0)->getType())) {
507 // Pointer-like types: assignment inherently propagates origins.
508 QualType LHSTy = OCE->getArg(0)->getType();
509 if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy) ||
510 isGslOwnerType(LHSTy)) {
511 handleAssignment(OCE->getArg(0), OCE->getArg(1));
512 return;
513 }
514 // Standard library callable wrappers (e.g., std::function) can propagate
515 // the stored lambda's origins.
516 if (const auto *RD = LHSTy->getAsCXXRecordDecl();
517 RD && isStdCallableWrapperType(RD)) {
518 handleAssignment(OCE->getArg(0), OCE->getArg(1));
519 return;
520 }
521 // Other tracked types: only defaulted operator= propagates origins.
522 // User-defined operator= has opaque semantics, so don't handle them now.
523 if (const auto *MD =
524 dyn_cast_or_null<CXXMethodDecl>(OCE->getDirectCallee());
525 MD && MD->isDefaulted()) {
526 handleAssignment(OCE->getArg(0), OCE->getArg(1));
527 return;
528 }
529 }
530
531 ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()};
532 // For `static operator()`, the first argument is the object argument,
533 // remove it from the argument list to avoid off-by-one errors.
534 if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic())
535 Args = Args.slice(1);
536 handleFunctionCall(OCE, OCE->getDirectCallee(), Args);
537}
538
540 const CXXFunctionalCastExpr *FCE) {
541 // Check if this is a test point marker. If so, we are done with this
542 // expression.
543 if (handleTestPoint(FCE))
544 return;
545 VisitCastExpr(FCE);
546}
547
549 if (!hasOrigins(ILE))
550 return;
551 // For list initialization with a single element, like `View{...}`, the
552 // origin of the list itself is the origin of its single element.
553 if (ILE->getNumInits() == 1)
554 killAndFlowOrigin(*ILE, *ILE->getInit(0));
555}
556
558 const CXXBindTemporaryExpr *BTE) {
559 killAndFlowOrigin(*BTE, *BTE->getSubExpr());
560}
561
563 const MaterializeTemporaryExpr *MTE) {
564 assert(MTE->isGLValue());
565 OriginList *MTEList = getOriginsList(*MTE);
566 if (!MTEList)
567 return;
568 OriginList *SubExprList = getOriginsList(*MTE->getSubExpr());
569 assert((!SubExprList ||
570 MTEList->getLength() == (SubExprList->getLength() + 1)) &&
571 "MTE top level origin should contain a loan to the MTE itself");
572
573 OriginList *RValMTEList = getRValueOrigins(MTE, MTEList);
574 flow(RValMTEList, SubExprList, /*Kill=*/true);
575 OriginID OuterMTEID = MTEList->getOuterOriginID();
577 // Issue a loan to MTE for the storage location represented by MTE.
578 const Loan *L = createLoan(FactMgr, MTE);
579 CurrentBlockFacts.push_back(
580 FactMgr.createFact<IssueFact>(L->getID(), OuterMTEID));
581 }
582}
583
585 // The lambda gets a single merged origin that aggregates all captured
586 // pointer-like origins. Currently we only need to detect whether the lambda
587 // outlives any capture.
588 OriginList *LambdaList = getOriginsList(*LE);
589 if (!LambdaList)
590 return;
591 bool Kill = true;
592 for (const Expr *Init : LE->capture_inits()) {
593 if (!Init)
594 continue;
595 OriginList *InitList = getOriginsList(*Init);
596 if (!InitList)
597 continue;
598 // FIXME: Consider flowing all origin levels once lambdas support more than
599 // one origin. Currently only the outermost origin is flowed, so by-ref
600 // captures like `[&p]` (where p is string_view) miss inner-level
601 // invalidation.
602 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
603 LambdaList->getOuterOriginID(), InitList->getOuterOriginID(), Kill));
604 Kill = false;
605 }
606}
607
609 assert(ASE->isGLValue() && "Array subscript should be a GL value");
610 OriginList *Dst = getOriginsList(*ASE);
611 assert(Dst && "Array subscript should have origins as it is a GL value");
612 OriginList *Src = getOriginsList(*ASE->getBase());
613 assert(Src && "Base of array subscript should have origins");
614 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
615 Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
616}
617
618bool FactsGenerator::escapesViaReturn(OriginID OID) const {
619 return llvm::any_of(EscapesInCurrentBlock, [OID](const Fact *F) {
620 if (const auto *EF = F->getAs<ReturnEscapeFact>())
621 return EF->getEscapedOriginID() == OID;
622 return false;
623 });
624}
625
626void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) {
627 const VarDecl *LifetimeEndsVD = LifetimeEnds.getVarDecl();
628 if (!LifetimeEndsVD)
629 return;
630 // Expire the origin when its variable's lifetime ends to ensure liveness
631 // doesn't persist through loop back-edges.
632 std::optional<OriginID> ExpiredOID;
633 if (OriginList *List = getOriginsList(*LifetimeEndsVD)) {
634 OriginID OID = List->getOuterOriginID();
635 // Skip origins that escape via return; the escape checker needs their loans
636 // to remain until the return statement is processed.
637 if (!escapesViaReturn(OID))
638 ExpiredOID = OID;
639 }
640 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
641 AccessPath(LifetimeEndsVD), LifetimeEnds.getTriggerStmt()->getEndLoc(),
642 ExpiredOID));
643}
644
645void FactsGenerator::handleFullExprCleanup(
646 const CFGFullExprCleanup &FullExprCleanup) {
647 for (const auto *MTE : FullExprCleanup.getExpiringMTEs())
648 CurrentBlockFacts.push_back(
649 FactMgr.createFact<ExpireFact>(AccessPath(MTE), MTE->getEndLoc()));
650}
651
652void FactsGenerator::handleExitBlock() {
653 for (const Origin &O : FactMgr.getOriginMgr().getOrigins())
654 if (auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
655 // Create FieldEscapeFacts for all field origins that remain live at exit.
656 EscapesInCurrentBlock.push_back(
657 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
658 else if (auto *VD = dyn_cast_if_present<VarDecl>(O.getDecl())) {
659 // Create GlobalEscapeFacts for all origins with global-storage that
660 // remain live at exit.
661 if (VD->hasGlobalStorage()) {
662 EscapesInCurrentBlock.push_back(
663 FactMgr.createFact<GlobalEscapeFact>(O.ID, VD));
664 }
665 }
666}
667
668void FactsGenerator::handleGSLPointerConstruction(const CXXConstructExpr *CCE) {
669 assert(isGslPointerType(CCE->getType()));
670 if (CCE->getNumArgs() != 1)
671 return;
672
673 const Expr *Arg = CCE->getArg(0);
674 if (isGslPointerType(Arg->getType())) {
675 OriginList *ArgList = getOriginsList(*Arg);
676 assert(ArgList && "GSL pointer argument should have an origin list");
677 // GSL pointer is constructed from another gsl pointer.
678 // Example:
679 // View(View v);
680 // View(const View &v);
681 ArgList = getRValueOrigins(Arg, ArgList);
682 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
683 } else if (Arg->getType()->isPointerType()) {
684 // GSL pointer is constructed from a raw pointer. Flow only the outermost
685 // raw pointer. Example:
686 // View(const char*);
687 // Span<int*>(const in**);
688 OriginList *ArgList = getOriginsList(*Arg);
689 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
690 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
691 /*Kill=*/true));
692 } else {
693 // This could be a new borrow.
694 // TODO: Add code example here.
695 handleFunctionCall(CCE, CCE->getConstructor(),
696 {CCE->getArgs(), CCE->getNumArgs()},
697 /*IsGslConstruction=*/true);
698 }
699}
700
701void FactsGenerator::handleMovedArgsInCall(const FunctionDecl *FD,
702 ArrayRef<const Expr *> Args) {
703 unsigned IsInstance = 0;
704 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
705 MD && MD->isInstance() && !isa<CXXConstructorDecl>(FD)) {
706 IsInstance = 1;
707 // std::unique_ptr::release() transfers ownership.
708 // Treat it as a move to prevent false-positive warnings when the unique_ptr
709 // destructor runs after ownership has been transferred.
710 if (isUniquePtrRelease(*MD)) {
711 const Expr *UniquePtrExpr = Args[0];
712 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
713 if (MovedOrigins)
714 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
715 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
716 }
717 }
718
719 // Skip 'this' arg as it cannot be moved.
720 for (unsigned I = IsInstance;
721 I < Args.size() && I < FD->getNumParams() + IsInstance; ++I) {
722 const ParmVarDecl *PVD = FD->getParamDecl(I - IsInstance);
723 if (!PVD->getType()->isRValueReferenceType())
724 continue;
725 const Expr *Arg = Args[I];
726 OriginList *MovedOrigins = getOriginsList(*Arg);
727 assert(MovedOrigins->getLength() >= 1 &&
728 "unexpected length for r-value reference param");
729 // Arg is being moved to this parameter. Mark the origin as moved.
730 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
731 Arg, MovedOrigins->getOuterOriginID()));
732 }
733}
734
735void FactsGenerator::handleInvalidatingCall(const Expr *Call,
736 const FunctionDecl *FD,
737 ArrayRef<const Expr *> Args) {
738 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
739 if (!MD || !MD->isInstance())
740 return;
741
743 return;
744 // Heuristics to turn-down false positives.
745 auto *DRE = dyn_cast<DeclRefExpr>(Args[0]);
746 if (!DRE || DRE->getDecl()->getType()->isReferenceType())
747 return;
748
749 OriginList *ThisList = getOriginsList(*Args[0]);
750 if (ThisList)
751 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
752 ThisList->getOuterOriginID(), Call));
753}
754
755void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call,
756 const FunctionDecl *FD) {
757 const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call);
758 if (!MemberCall)
759 return;
760
761 if (!isa_and_present<CXXThisExpr>(
762 MemberCall->getImplicitObjectArgument()->IgnoreImpCasts()))
763 return;
764
765 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
766 assert(MD && "Function must be a CXXMethodDecl for member calls");
767
768 const auto *ClassDecl = MD->getParent()->getDefinition();
769 if (!ClassDecl)
770 return;
771
772 const auto UseFields = [&](const CXXRecordDecl *RD) {
773 for (const auto *Field : RD->fields())
774 if (auto *FieldList = getOriginsList(*Field))
775 CurrentBlockFacts.push_back(
776 FactMgr.createFact<UseFact>(Call, FieldList));
777 };
778
779 UseFields(ClassDecl);
780
781 ClassDecl->forallBases([&](const CXXRecordDecl *Base) {
782 UseFields(Base);
783 return true;
784 });
785}
786
787void FactsGenerator::handleFunctionCall(const Expr *Call,
788 const FunctionDecl *FD,
789 ArrayRef<const Expr *> Args,
790 bool IsGslConstruction) {
791 OriginList *CallList = getOriginsList(*Call);
792 // Ignore functions returning values with no origin.
794 if (!FD)
795 return;
796 // All arguments to a function are a use of the corresponding expressions.
797 for (const Expr *Arg : Args)
798 handleUse(Arg);
799 handleInvalidatingCall(Call, FD, Args);
800 handleMovedArgsInCall(FD, Args);
801 handleImplicitObjectFieldUses(Call, FD);
802 if (!CallList)
803 return;
804 auto IsArgLifetimeBound = [FD](unsigned I) -> bool {
805 const ParmVarDecl *PVD = nullptr;
806 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
807 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
808 if (I == 0)
809 // For the 'this' argument, the attribute is on the method itself.
812 Method, /*RunningUnderLifetimeSafety=*/true);
813 if ((I - 1) < Method->getNumParams())
814 // For explicit arguments, find the corresponding parameter
815 // declaration.
816 PVD = Method->getParamDecl(I - 1);
817 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
818 return true;
819 } else if (I < FD->getNumParams()) {
820 // For free functions or static methods.
821 PVD = FD->getParamDecl(I);
822 }
823 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
824 };
825 auto shouldTrackPointerImplicitObjectArg = [FD](unsigned I) -> bool {
826 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
827 if (!Method || !Method->isInstance())
828 return false;
829 return I == 0 &&
830 isGslPointerType(Method->getFunctionObjectParameterType()) &&
832 /*RunningUnderLifetimeSafety=*/true);
833 };
834 if (Args.empty())
835 return;
836 bool KillSrc = true;
837 for (unsigned I = 0; I < Args.size(); ++I) {
838 OriginList *ArgList = getOriginsList(*Args[I]);
839 if (!ArgList)
840 continue;
841 if (IsGslConstruction) {
842 // TODO: document with code example.
843 // std::string_view(const std::string_view& from)
844 if (isGslPointerType(Args[I]->getType())) {
845 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
846 ArgList = getRValueOrigins(Args[I], ArgList);
847 }
848 if (isGslOwnerType(Args[I]->getType())) {
849 // The constructed gsl::Pointer borrows from the Owner's storage, not
850 // from what the Owner itself borrows, so only the outermost origin is
851 // needed.
852 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
853 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
854 KillSrc));
855 KillSrc = false;
856 } else if (IsArgLifetimeBound(I)) {
857 // Only flow the outer origin here. For lifetimebound args in
858 // gsl::Pointer construction, we do not have enough information to
859 // safely match inner origins, so the source and
860 // destination origin lists may have different lengths.
861 // FIXME: Handle origin-shape mismatches gracefully so we can also flow
862 // inner origins.
863 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
864 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
865 KillSrc));
866 KillSrc = false;
867 }
868 } else if (shouldTrackPointerImplicitObjectArg(I)) {
869 assert(ArgList->getLength() >= 2 &&
870 "Object arg of pointer type should have atleast two origins");
871 // See through the GSLPointer reference to see the pointer's value.
872 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
873 CallList->getOuterOriginID(),
874 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
875 KillSrc = false;
876 } else if (IsArgLifetimeBound(I)) {
877 // Lifetimebound on a non-GSL-ctor function means the returned
878 // pointer/reference itself must not outlive the arguments. This
879 // only constraints the top-level origin.
880 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
881 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
882 KillSrc = false;
883 }
884 }
885}
886
887/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
888/// If so, creates a `TestPointFact` and returns true.
889bool FactsGenerator::handleTestPoint(const CXXFunctionalCastExpr *FCE) {
890 if (!FCE->getType()->isVoidType())
891 return false;
892
893 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
894 if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
895 llvm::StringRef LiteralValue = SL->getString();
896 const std::string Prefix = "__lifetime_test_point_";
897
898 if (LiteralValue.starts_with(Prefix)) {
899 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
900 CurrentBlockFacts.push_back(
901 FactMgr.createFact<TestPointFact>(Annotation));
902 return true;
903 }
904 }
905 return false;
906}
907
908void FactsGenerator::handleUse(const Expr *E) {
909 OriginList *List = getOriginsList(*E);
910 if (!List)
911 return;
912 // For DeclRefExpr: Remove the outer layer of origin which borrows from the
913 // decl directly (e.g., when this is not a reference). This is a use of the
914 // underlying decl.
915 if (auto *DRE = dyn_cast<DeclRefExpr>(E);
916 DRE && !DRE->getDecl()->getType()->isReferenceType())
917 List = getRValueOrigins(DRE, List);
918 // Skip if there is no inner origin (e.g., when it is not a pointer type).
919 if (!List)
920 return;
921 if (!UseFacts.contains(E)) {
922 UseFact *UF = FactMgr.createFact<UseFact>(E, List);
923 CurrentBlockFacts.push_back(UF);
924 UseFacts[E] = UF;
925 }
926}
927
928void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
929 if (UseFacts.contains(DRE))
930 UseFacts[DRE]->markAsWritten();
931}
932
933// Creates an IssueFact for a new placeholder loan for each pointer or reference
934// parameter at the function's entry.
935llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
936 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
937 if (!FD)
938 return {};
939
940 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
941 if (auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
942 OriginList *List = *ThisOrigins;
943 const Loan *L = FactMgr.getLoanMgr().createLoan(
945 /*IssuingExpr=*/nullptr);
946 PlaceholderLoanFacts.push_back(
947 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
948 }
949 for (const ParmVarDecl *PVD : FD->parameters()) {
950 OriginList *List = getOriginsList(*PVD);
951 if (!List)
952 continue;
953 const Loan *L = FactMgr.getLoanMgr().createLoan(
954 AccessPath::Placeholder(PVD), /*IssuingExpr=*/nullptr);
955 PlaceholderLoanFacts.push_back(
956 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
957 }
958 return PlaceholderLoanFacts;
959}
960
961} // 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:2724
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4041
Expr * getLHS() const
Definition Expr.h:4091
Expr * getRHS() const
Definition Expr.h:4093
static bool isAdditiveOp(Opcode Opc)
Definition Expr.h:4127
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4177
static bool isCompoundAssignmentOp(Opcode Opc)
Definition Expr.h:4182
Represents a single basic block in a source-level CFG.
Definition CFG.h:632
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:110
Represents C++ base or member initializer from constructor's initialization list.
Definition CFG.h:229
Represents the point where the lifetime of an automatic object ends.
Definition CFG.h:294
const Stmt * getTriggerStmt() const
Definition CFG.h:303
const VarDecl * getVarDecl() const
Definition CFG.h:299
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1250
CFGBlock & getExit()
Definition CFG.h:1366
CFGBlock & getEntry()
Definition CFG.h:1364
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:3071
Represents a C++ base or member initializer.
Definition DeclCXX.h:2389
Expr * getInit() const
Get the initializer.
Definition DeclCXX.h:2591
FieldDecl * getAnyMember() const
Definition DeclCXX.h:2535
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:1107
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:743
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:724
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2136
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:2946
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3150
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3129
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3137
Expr ** getArgs()
Retrieve the call arguments.
Definition Expr.h:3140
Decl * getCalleeDecl()
Definition Expr.h:3123
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3679
CastKind getCastKind() const
Definition Expr.h:3723
Expr * getSubExpr()
Definition Expr.h:3729
ConditionalOperator - The ?
Definition Expr.h:4394
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4426
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4421
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1273
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
Definition Expr.h:1384
ValueDecl * getDecl()
Definition Expr.h:1341
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1637
decl_range decls()
Definition Stmt.h:1685
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:3090
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3175
bool isStatic() const
Definition Decl.h:2944
bool isDefaulted() const
Whether this function is defaulted.
Definition Decl.h:2400
Describes an C or C++ initializer list.
Definition Expr.h:5302
unsigned getNumInits() const
Definition Expr.h:5332
const Expr * getInit(unsigned Init) const
Definition Expr.h:5356
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:3367
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3450
Expr * getBase() const
Definition Expr.h:3444
A (possibly-)qualified type.
Definition TypeBase.h:937
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3166
Expr * getRetValue()
Definition Stmt.h:3193
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition StmtVisitor.h:45
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
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:8668
bool isReferenceType() const
Definition TypeBase.h:8692
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:754
bool isPointerOrReferenceType() const
Definition TypeBase.h:8672
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2247
Expr * getSubExpr() const
Definition Expr.h:2288
Opcode getOpcode() const
Definition Expr.h:2283
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:926
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:44
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 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)
Loan * createLoan(AccessPath Path, const Expr *IssueExpr)
Definition Loans.h:133
Represents lending a storage location.
Definition Loans.h:112
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:189
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:156
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 shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
bool isContainerInvalidationMethod(const CXXMethodDecl &MD)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isGslOwnerType(QualType QT)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ 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