@@ -708,6 +708,110 @@ static Expr *lookThroughProjections(Expr *expr) {
708
708
return lookThroughProjections (lookupExpr->getBase ());
709
709
}
710
710
711
+ bool SILGenFunction::emitGuaranteedReturn (
712
+ SILLocation loc, Expr *ret, SmallVectorImpl<SILValue> &directResults) {
713
+ auto *afd = cast<AbstractFunctionDecl>(FunctionDC->getAsDecl ());
714
+ assert (cast<AccessorDecl>(afd)->isBorrowAccessor ());
715
+
716
+ // If the return expression is a literal, emit as a regular return
717
+ // expression.
718
+ if (isa<LiteralExpr>(ret)) {
719
+ auto RV = emitRValue (ret);
720
+ std::move (RV).forwardAll (*this , directResults);
721
+ return false ;
722
+ }
723
+
724
+ auto storageRefResult =
725
+ StorageRefResult::findStorageReferenceExprForBorrow (ret);
726
+ auto lvExpr = storageRefResult.getTransitiveRoot ();
727
+ // If the return expression is not an lvalue, diagnose.
728
+ if (!lvExpr) {
729
+ diagnose (getASTContext (), ret->getStartLoc (),
730
+ diag::invalid_borrow_accessor_return);
731
+ diagnose (getASTContext (), ret->getStartLoc (),
732
+ diag::borrow_accessor_not_a_projection_note);
733
+ return true ;
734
+ }
735
+
736
+ // Emit return value at +0.
737
+ FormalEvaluationScope scope (*this );
738
+ LValueOptions options;
739
+ auto lvalue = emitLValue (ret,
740
+ F.getConventions ().hasGuaranteedResult ()
741
+ ? SGFAccessKind::BorrowedObjectRead
742
+ : SGFAccessKind::BorrowedAddressRead,
743
+ F.getConventions ().hasGuaranteedResult ()
744
+ ? options.forGuaranteedReturn (true )
745
+ : options.forGuaranteedAddressReturn (true ));
746
+
747
+ // If the accessor is annotated with @_unsafeSelfDependentResultAttr,
748
+ // disable diagnosing the return expression.
749
+ // If the accessor is annotated with @_unsafeSelfDependentResultAttr,
750
+ // disable diagnosing the return expression.
751
+ // This is needed to implement borrow accessors for Unsafe*Pointer based
752
+ // Container types where the compiler cannot analyze the safety of return
753
+ // expressions based on pointer arithmetic and unsafe addressors.
754
+ // Example:
755
+ // public struct Container<Element: ~Copyable>: ~Copyable {
756
+ // var _storage: UnsafeMutableBufferPointer<Element>
757
+ // var _count: Int
758
+ //
759
+ // public subscript(index: Int) -> Element {
760
+ // @_unsafeSelfDependentResult
761
+ // borrow {
762
+ // precondition(index >= 0 && index < _count, "Index out of bounds")
763
+ // return _storage.baseAddress.unsafelyUnwrapped.advanced(by:
764
+ // index).pointee
765
+ // }
766
+ // }
767
+ // }
768
+ if (afd->getAttrs ().hasAttribute <UnsafeSelfDependentResultAttr>()) {
769
+ auto resultValue = emitBorrowedLValue (ret, std::move (lvalue));
770
+ directResults.push_back (resultValue.getValue ());
771
+ return false ;
772
+ }
773
+
774
+ // If the return expression is not a transitive projection of self,
775
+ // diagnose.
776
+ auto *baseExpr = lookThroughProjections (storageRefResult.getStorageRef ());
777
+ if (!baseExpr->isSelfExprOf (afd)) {
778
+ diagnose (getASTContext (), ret->getStartLoc (),
779
+ diag::invalid_borrow_accessor_return);
780
+ diagnose (getASTContext (), ret->getStartLoc (),
781
+ diag::borrow_accessor_not_a_projection_note);
782
+ return true ;
783
+ }
784
+
785
+ auto result = tryEmitProjectedLValue (ret, std::move (lvalue), TSanKind::None);
786
+ if (!result) {
787
+ diagnose (getASTContext (), ret->getStartLoc (),
788
+ diag::invalid_borrow_accessor_return);
789
+ diagnose (getASTContext (), ret->getStartLoc (),
790
+ diag::borrow_accessor_not_a_projection_note);
791
+ return true ;
792
+ }
793
+ // For now diagnose multiple return statements in borrow/mutate accessors.
794
+ // We need additional support for this.
795
+ // 1. Address phis are banned in SIL.
796
+ // 2. borrowed from is not inserted in SILGenCleanup.
797
+ if (!ReturnDest.getBlock ()->getPredecessorBlocks ().empty ()) {
798
+ diagnose (getASTContext (), ret->getStartLoc (),
799
+ diag::invalid_multiple_return_borrow_accessor);
800
+ return true ;
801
+ }
802
+
803
+ auto resultValue = result->getValue ();
804
+ SILType selfType = F.getSelfArgument ()->getType ();
805
+ if (selfType.isMoveOnly () && F.getConventions ().hasGuaranteedResult ()) {
806
+ // If we are returning the result of borrow accessor, strip the
807
+ // unnecessary copy_value + mark_unresolved_non_copyable_value
808
+ // instructions.
809
+ resultValue = lookThroughMoveOnlyCheckerPattern (resultValue);
810
+ }
811
+ directResults.push_back (resultValue);
812
+ return false ;
813
+ }
814
+
711
815
void SILGenFunction::emitReturnExpr (SILLocation branchLoc,
712
816
Expr *ret) {
713
817
SmallVector<SILValue, 4 > directResults;
@@ -738,101 +842,11 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
738
842
}
739
843
} else if (F.getConventions ().hasGuaranteedResult () ||
740
844
F.getConventions ().hasGuaranteedAddressResult ()) {
741
- auto *afd = cast<AbstractFunctionDecl>(FunctionDC->getAsDecl ());
742
- if (isa<LiteralExpr>(ret)) {
743
- // If the return expression is a literal, emit as a regular return
744
- // expression.
745
- auto RV = emitRValue (ret);
746
- std::move (RV).forwardAll (*this , directResults);
747
- } else {
748
- FormalEvaluationScope scope (*this );
749
- auto storageRefResult =
750
- StorageRefResult::findStorageReferenceExprForBorrow (ret);
751
- auto lvExpr = storageRefResult.getTransitiveRoot ();
752
- // If the return expression is not an lvalue, diagnose.
753
- if (!lvExpr) {
754
- diagnose (getASTContext (), ret->getStartLoc (),
755
- diag::invalid_borrow_accessor_return);
756
- diagnose (getASTContext (), ret->getStartLoc (),
757
- diag::borrow_accessor_not_a_projection_note);
758
- return ;
759
- }
760
-
761
- // Emit return value at +0.
762
- LValueOptions options;
763
- auto lvalue = emitLValue (ret,
764
- F.getConventions ().hasGuaranteedResult ()
765
- ? SGFAccessKind::BorrowedObjectRead
766
- : SGFAccessKind::BorrowedAddressRead,
767
- F.getConventions ().hasGuaranteedResult ()
768
- ? options.forGuaranteedReturn (true )
769
- : options.forGuaranteedAddressReturn (true ));
770
-
771
- if (afd->getAttrs ().hasAttribute <UnsafeSelfDependentResultAttr>()) {
772
- // If the accessor is annotated with @_unsafeSelfDependentResultAttr,
773
- // disable diagnosing the return expression.
774
- // This is needed to implement borrow accessors for Unsafe*Pointer based
775
- // Container types where the compiler cannot analyze the safety of
776
- // return expressions based on pointer arithmetic and unsafe addressors.
777
- // Example:
778
- // public struct Container<Element: ~Copyable>: ~Copyable {
779
- // var _storage: UnsafeMutableBufferPointer<Element>
780
- // var _count: Int
781
- //
782
- // public subscript(index: Int) -> Element {
783
- // @_unsafeSelfDependentResult
784
- // borrow {
785
- // precondition(index >= 0 && index < _count, "Index out of
786
- // bounds") return
787
- // _storage.baseAddress.unsafelyUnwrapped.advanced(by:
788
- // index).pointee
789
- // }
790
- // }
791
- // }
792
- auto resultValue = emitBorrowedLValue (ret, std::move (lvalue));
793
- directResults.push_back (resultValue.getValue ());
794
- } else {
795
- // If the return expression is not a transitive projection of self,
796
- // diagnose.
797
- auto *baseExpr =
798
- lookThroughProjections (storageRefResult.getStorageRef ());
799
- if (!baseExpr->isSelfExprOf (afd)) {
800
- diagnose (getASTContext (), ret->getStartLoc (),
801
- diag::invalid_borrow_accessor_return);
802
- diagnose (getASTContext (), ret->getStartLoc (),
803
- diag::borrow_accessor_not_a_projection_note);
804
- return ;
805
- }
806
- auto result =
807
- tryEmitProjectedLValue (ret, std::move (lvalue), TSanKind::None);
808
- if (!result) {
809
- diagnose (getASTContext (), ret->getStartLoc (),
810
- diag::invalid_borrow_accessor_return);
811
- diagnose (getASTContext (), ret->getStartLoc (),
812
- diag::borrow_accessor_not_a_projection_note);
813
- return ;
814
- }
815
- // For now diagnose multiple return statements in borrow/mutate
816
- // accessors. We need additional support for this.
817
- // 1. Address phis are banned in SIL.
818
- // 2. borrowed from is not inserted in SILGenCleanup.
819
- if (!ReturnDest.getBlock ()->getPredecessorBlocks ().empty ()) {
820
- diagnose (getASTContext (), ret->getStartLoc (),
821
- diag::invalid_multiple_return_borrow_accessor);
822
- return ;
823
- }
824
-
825
- auto resultValue = result->getValue ();
826
- SILType selfType = F.getSelfArgument ()->getType ();
827
- if (selfType.isMoveOnly () && F.getConventions ().hasGuaranteedResult ()) {
828
- // If we are returning the result of borrow accessor, strip the
829
- // unnecessary copy_value + mark_unresolved_non_copyable_value
830
- // instructions.
831
- resultValue = lookThroughMoveOnlyCheckerPattern (resultValue);
832
- }
833
- directResults.push_back (resultValue);
834
- }
845
+ bool hasError = emitGuaranteedReturn (branchLoc, ret, directResults);
846
+ if (hasError) {
847
+ return ;
835
848
}
849
+ assert (!directResults.empty ());
836
850
} else {
837
851
// SILValue return.
838
852
FullExpr scope (Cleanups, CleanupLocation (ret));
0 commit comments