@@ -433,6 +433,31 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
433433
434434 void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
435435
436+ void VisitCXXConstructExpr (const CXXConstructExpr *CCE) {
437+ if (!isGslPointerType (CCE->getType ()))
438+ return ;
439+
440+ if (CCE->getNumArgs () > 0 && hasOrigin (CCE->getArg (0 )->getType ()))
441+ // This is a propagation.
442+ addAssignOriginFact (*CCE, *CCE->getArg (0 ));
443+ else
444+ // This could be a new borrow.
445+ checkForBorrows (CCE, CCE->getConstructor (),
446+ {CCE->getArgs (), CCE->getNumArgs ()});
447+ }
448+
449+ void VisitCXXMemberCallExpr (const CXXMemberCallExpr *MCE) {
450+ if (!isGslPointerType (MCE->getImplicitObjectArgument ()->getType ()))
451+ return ;
452+ // Specifically for conversion operators, like `std::string_view p = a;`
453+ if (isa<CXXConversionDecl>(MCE->getCalleeDecl ())) {
454+ // The argument is the implicit object itself.
455+ checkForBorrows (MCE, MCE->getMethodDecl (),
456+ {MCE->getImplicitObjectArgument ()});
457+ }
458+ // Note: A more general VisitCallExpr could also be used here.
459+ }
460+
436461 void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
437462 // / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
438463 // / pointers can use the same type of loan.
@@ -492,10 +517,27 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
492517 void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
493518 // Check if this is a test point marker. If so, we are done with this
494519 // expression.
495- if (VisitTestPoint (FCE))
520+ if (handleTestPoint (FCE))
496521 return ;
497- // Visit as normal otherwise.
498- Base::VisitCXXFunctionalCastExpr (FCE);
522+ if (isGslPointerType (FCE->getType ()))
523+ addAssignOriginFact (*FCE, *FCE->getSubExpr ());
524+ }
525+
526+ void VisitInitListExpr (const InitListExpr *ILE) {
527+ if (!hasOrigin (ILE->getType ()))
528+ return ;
529+ // For list initialization with a single element, like `View{...}`, the
530+ // origin of the list itself is the origin of its single element.
531+ if (ILE->getNumInits () == 1 )
532+ addAssignOriginFact (*ILE, *ILE->getInit (0 ));
533+ }
534+
535+ void VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *MTE) {
536+ if (!hasOrigin (MTE->getType ()))
537+ return ;
538+ // A temporary object's origin is the same as the origin of the
539+ // expression that initializes it.
540+ addAssignOriginFact (*MTE, *MTE->getSubExpr ());
499541 }
500542
501543 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
@@ -521,8 +563,75 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
521563 }
522564
523565private:
566+ static bool isGslPointerType (QualType QT) {
567+ if (const auto *RD = QT->getAsCXXRecordDecl ()) {
568+ // We need to check the template definition for specializations.
569+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
570+ return CTSD->getSpecializedTemplate ()
571+ ->getTemplatedDecl ()
572+ ->hasAttr <PointerAttr>();
573+ return RD->hasAttr <PointerAttr>();
574+ }
575+ return false ;
576+ }
577+
524578 // Check if a type has an origin.
525- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
579+ static bool hasOrigin (QualType QT) {
580+ if (QT->isFunctionPointerType ())
581+ return false ;
582+ return QT->isPointerOrReferenceType () || isGslPointerType (QT);
583+ }
584+
585+ // / Checks if a call-like expression creates a borrow by passing a local
586+ // / value to a reference parameter, creating an IssueFact if it does.
587+ void checkForBorrows (const Expr *Call, const FunctionDecl *FD,
588+ ArrayRef<const Expr *> Args) {
589+ if (!FD)
590+ return ;
591+
592+ for (unsigned I = 0 ; I < Args.size (); ++I) {
593+ if (I >= FD->getNumParams ())
594+ break ;
595+
596+ const ParmVarDecl *Param = FD->getParamDecl (I);
597+ const Expr *Arg = Args[I];
598+
599+ // This is the core condition for a new borrow: a value type (no origin)
600+ // is passed to a reference parameter.
601+ if (Param->getType ()->isReferenceType () && !hasOrigin (Arg->getType ())) {
602+ if (const Loan *L = createLoanFrom (Arg, Call)) {
603+ OriginID OID = FactMgr.getOriginMgr ().getOrCreate (*Call);
604+ CurrentBlockFacts.push_back (
605+ FactMgr.createFact <IssueFact>(L->ID , OID));
606+ // For view creation, we assume the first borrow is the significant
607+ // one.
608+ return ;
609+ }
610+ }
611+ }
612+ }
613+
614+ // / Attempts to create a loan by analyzing the source expression of a borrow.
615+ // / This method is the single point for creating loans, allowing for future
616+ // / expansion to handle temporaries, field members, etc.
617+ // / \param SourceExpr The expression representing the object being borrowed
618+ // / from.
619+ // / \param IssueExpr The expression that triggers the borrow (e.g., a
620+ // / constructor call).
621+ // / \return The new Loan on success, nullptr on failure.
622+ const Loan *createLoanFrom (const Expr *SourceExpr, const Expr *IssueExpr) {
623+ // For now, we only handle direct borrows from local variables.
624+ // In the future, this can be extended to handle MaterializeTemporaryExpr,
625+ // etc.
626+ if (const auto *DRE =
627+ dyn_cast<DeclRefExpr>(SourceExpr->IgnoreParenImpCasts ())) {
628+ if (const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl ())) {
629+ AccessPath Path (VD);
630+ return &FactMgr.getLoanMgr ().addLoan (Path, IssueExpr);
631+ }
632+ }
633+ return nullptr ;
634+ }
526635
527636 template <typename Destination, typename Source>
528637 void addAssignOriginFact (const Destination &D, const Source &S) {
@@ -534,7 +643,7 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
534643
535644 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
536645 // / If so, creates a `TestPointFact` and returns true.
537- bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
646+ bool handleTestPoint (const CXXFunctionalCastExpr *FCE) {
538647 if (!FCE->getType ()->isVoidType ())
539648 return false ;
540649
@@ -612,10 +721,13 @@ class FactGenerator : public RecursiveASTVisitor<FactGenerator> {
612721 for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
613722 FactGeneratorBlockRAII BlockGenerator (FG, Block);
614723 for (const CFGElement &Element : *Block) {
615- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
724+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>()) {
725+ DEBUG_WITH_TYPE (" PrintCFG" , llvm::dbgs () << " ================== \n " );
726+ DEBUG_WITH_TYPE (" PrintCFG" , CS->dump ());
727+ DEBUG_WITH_TYPE (" PrintCFG" , CS->getStmt ()->dumpColor ());
616728 TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
617- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
618- Element.getAs <CFGAutomaticObjDtor>())
729+ } else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
730+ Element.getAs <CFGAutomaticObjDtor>())
619731 FG.handleDestructor (*DtorOpt);
620732 }
621733 }
0 commit comments