@@ -478,6 +478,25 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
478478 }
479479 }
480480
481+ void VisitCXXConstructExpr (const CXXConstructExpr *CCE) {
482+ if (isGslPointerType (CCE->getType ())) {
483+ handleGSLPointerConstruction (CCE);
484+ return ;
485+ }
486+ }
487+
488+ void VisitCXXMemberCallExpr (const CXXMemberCallExpr *MCE) {
489+ // Specifically for conversion operators,
490+ // like `std::string_view p = std::string{};`
491+ if (isGslPointerType (MCE->getType ()) &&
492+ isa<CXXConversionDecl>(MCE->getCalleeDecl ())) {
493+ // The argument is the implicit object itself.
494+ handleFunctionCall (MCE, MCE->getMethodDecl (),
495+ {MCE->getImplicitObjectArgument ()});
496+ }
497+ // FIXME: A more general VisitCallExpr could also be used here.
498+ }
499+
481500 void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
482501 // / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
483502 // / pointers can use the same type of loan.
@@ -530,8 +549,27 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
530549 void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
531550 // Check if this is a test point marker. If so, we are done with this
532551 // expression.
533- if (VisitTestPoint (FCE))
552+ if (handleTestPoint (FCE))
534553 return ;
554+ if (isGslPointerType (FCE->getType ()))
555+ addAssignOriginFact (*FCE, *FCE->getSubExpr ());
556+ }
557+
558+ void VisitInitListExpr (const InitListExpr *ILE) {
559+ if (!hasOrigin (ILE))
560+ return ;
561+ // For list initialization with a single element, like `View{...}`, the
562+ // origin of the list itself is the origin of its single element.
563+ if (ILE->getNumInits () == 1 )
564+ addAssignOriginFact (*ILE, *ILE->getInit (0 ));
565+ }
566+
567+ void VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *MTE) {
568+ if (!hasOrigin (MTE))
569+ return ;
570+ // A temporary object's origin is the same as the origin of the
571+ // expression that initializes it.
572+ addAssignOriginFact (*MTE, *MTE->getSubExpr ());
535573 }
536574
537575 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
@@ -557,10 +595,21 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
557595 }
558596
559597private:
560- static bool isPointerType (QualType QT) {
561- return QT->isPointerOrReferenceType ();
598+ static bool isGslPointerType (QualType QT) {
599+ if (const auto *RD = QT->getAsCXXRecordDecl ()) {
600+ // We need to check the template definition for specializations.
601+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
602+ return CTSD->getSpecializedTemplate ()
603+ ->getTemplatedDecl ()
604+ ->hasAttr <PointerAttr>();
605+ return RD->hasAttr <PointerAttr>();
606+ }
607+ return false ;
562608 }
563609
610+ static bool isPointerType (QualType QT) {
611+ return QT->isPointerOrReferenceType () || isGslPointerType (QT);
612+ }
564613 // Check if a type has an origin.
565614 static bool hasOrigin (const Expr *E) {
566615 return E->isGLValue () || isPointerType (E->getType ());
@@ -570,6 +619,41 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
570619 return isPointerType (VD->getType ());
571620 }
572621
622+ void handleGSLPointerConstruction (const CXXConstructExpr *CCE) {
623+ assert (isGslPointerType (CCE->getType ()));
624+ if (CCE->getNumArgs () != 1 )
625+ return ;
626+ if (hasOrigin (CCE->getArg (0 )))
627+ addAssignOriginFact (*CCE, *CCE->getArg (0 ));
628+ else
629+ // This could be a new borrow.
630+ handleFunctionCall (CCE, CCE->getConstructor (),
631+ {CCE->getArgs (), CCE->getNumArgs ()});
632+ }
633+
634+ // / Checks if a call-like expression creates a borrow by passing a value to a
635+ // / reference parameter, creating an IssueFact if it does.
636+ void handleFunctionCall (const Expr *Call, const FunctionDecl *FD,
637+ ArrayRef<const Expr *> Args) {
638+ if (!FD)
639+ return ;
640+ // TODO: Handle more than one arguments.
641+ for (unsigned I = 0 ; I <= 0 /* Args.size()*/ ; ++I) {
642+ const Expr *ArgExpr = Args[I];
643+
644+ // Propagate origins for CXX this.
645+ if (FD->isCXXClassMember () && I == 0 ) {
646+ addAssignOriginFact (*Call, *ArgExpr);
647+ continue ;
648+ }
649+ // The parameter is a pointer, reference, or gsl::Pointer.
650+ // This is a borrow. We propagate the origin from the argument expression
651+ // at the call site to the parameter declaration in the callee.
652+ if (hasOrigin (ArgExpr))
653+ addAssignOriginFact (*Call, *ArgExpr);
654+ }
655+ }
656+
573657 // / Creates a loan for the storage path of a given declaration reference.
574658 // / This function should be called whenever a DeclRefExpr represents a borrow.
575659 // / \param DRE The declaration reference expression that initiates the borrow.
@@ -593,7 +677,7 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
593677
594678 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
595679 // / If so, creates a `TestPointFact` and returns true.
596- bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
680+ bool handleTestPoint (const CXXFunctionalCastExpr *FCE) {
597681 if (!FCE->getType ()->isVoidType ())
598682 return false ;
599683
@@ -641,6 +725,8 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
641725 }
642726
643727 void markUseAsWrite (const DeclRefExpr *DRE) {
728+ if (!isPointerType (DRE->getType ()))
729+ return ;
644730 assert (UseFacts.contains (DRE));
645731 UseFacts[DRE]->markAsWritten ();
646732 }
0 commit comments