@@ -478,6 +478,25 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
478
478
}
479
479
}
480
480
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
+
481
500
void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
482
501
// / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
483
502
// / pointers can use the same type of loan.
@@ -530,8 +549,27 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
530
549
void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
531
550
// Check if this is a test point marker. If so, we are done with this
532
551
// expression.
533
- if (VisitTestPoint (FCE))
552
+ if (handleTestPoint (FCE))
534
553
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 ());
535
573
}
536
574
537
575
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
@@ -557,10 +595,21 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
557
595
}
558
596
559
597
private:
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 ;
562
608
}
563
609
610
+ static bool isPointerType (QualType QT) {
611
+ return QT->isPointerOrReferenceType () || isGslPointerType (QT);
612
+ }
564
613
// Check if a type has an origin.
565
614
static bool hasOrigin (const Expr *E) {
566
615
return E->isGLValue () || isPointerType (E->getType ());
@@ -570,6 +619,41 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
570
619
return isPointerType (VD->getType ());
571
620
}
572
621
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
+
573
657
// / Creates a loan for the storage path of a given declaration reference.
574
658
// / This function should be called whenever a DeclRefExpr represents a borrow.
575
659
// / \param DRE The declaration reference expression that initiates the borrow.
@@ -593,7 +677,7 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
593
677
594
678
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
595
679
// / If so, creates a `TestPointFact` and returns true.
596
- bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
680
+ bool handleTestPoint (const CXXFunctionalCastExpr *FCE) {
597
681
if (!FCE->getType ()->isVoidType ())
598
682
return false ;
599
683
@@ -641,6 +725,8 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
641
725
}
642
726
643
727
void markUseAsWrite (const DeclRefExpr *DRE) {
728
+ if (!isPointerType (DRE->getType ()))
729
+ return ;
644
730
assert (UseFacts.contains (DRE));
645
731
UseFacts[DRE]->markAsWritten ();
646
732
}
0 commit comments