@@ -433,6 +433,31 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
433
433
434
434
void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
435
435
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
+
436
461
void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
437
462
// / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
438
463
// / pointers can use the same type of loan.
@@ -494,8 +519,25 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
494
519
// expression.
495
520
if (VisitTestPoint (FCE))
496
521
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 ());
499
541
}
500
542
501
543
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
@@ -521,8 +563,88 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
521
563
}
522
564
523
565
private:
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
+
524
578
// 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
+ }
635
+
636
+ void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
637
+ // Find the underlying variable declaration for the left-hand side.
638
+ if (const auto *DRE_LHS =
639
+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ()))
640
+ if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
641
+ if (hasOrigin (VD_LHS->getType ()))
642
+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
643
+ // LHS must be a pointer/reference type that can be an origin.
644
+ // RHS must also represent an origin (either another pointer/ref or an
645
+ // address-of).
646
+ addAssignOriginFact (*VD_LHS, *RHSExpr);
647
+ }
526
648
527
649
template <typename Destination, typename Source>
528
650
void addAssignOriginFact (const Destination &D, const Source &S) {
@@ -612,10 +734,13 @@ class FactGenerator : public RecursiveASTVisitor<FactGenerator> {
612
734
for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
613
735
FactGeneratorBlockRAII BlockGenerator (FG, Block);
614
736
for (const CFGElement &Element : *Block) {
615
- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
737
+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>()) {
738
+ DEBUG_WITH_TYPE (" PrintCFG" , llvm::dbgs () << " ================== \n " );
739
+ DEBUG_WITH_TYPE (" PrintCFG" , CS->dump ());
740
+ DEBUG_WITH_TYPE (" PrintCFG" , CS->getStmt ()->dumpColor ());
616
741
TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
617
- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
618
- Element.getAs <CFGAutomaticObjDtor>())
742
+ } else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
743
+ Element.getAs <CFGAutomaticObjDtor>())
619
744
FG.handleDestructor (*DtorOpt);
620
745
}
621
746
}
0 commit comments