@@ -738,35 +738,26 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
738
738
}
739
739
} else if (F.getConventions ().hasGuaranteedResult () ||
740
740
F.getConventions ().hasGuaranteedAddressResult ()) {
741
- // If the return expression is a literal, emit as a regular return
742
- // expression/
741
+ auto *afd = cast<AbstractFunctionDecl>(FunctionDC->getAsDecl ());
743
742
if (isa<LiteralExpr>(ret)) {
743
+ // If the return expression is a literal, emit as a regular return
744
+ // expression.
744
745
auto RV = emitRValue (ret);
745
746
std::move (RV).forwardAll (*this , directResults);
746
747
} else {
747
- // If the return expression is not a projection, diagnose as error.
748
748
FormalEvaluationScope scope (*this );
749
749
auto storageRefResult =
750
750
StorageRefResult::findStorageReferenceExprForBorrow (ret);
751
751
auto lvExpr = storageRefResult.getTransitiveRoot ();
752
+ // If the return expression is not an lvalue, diagnose.
752
753
if (!lvExpr) {
753
754
diagnose (getASTContext (), ret->getStartLoc (),
754
755
diag::invalid_borrow_accessor_return);
755
756
diagnose (getASTContext (), ret->getStartLoc (),
756
757
diag::borrow_accessor_not_a_projection_note);
757
758
return ;
758
759
}
759
- // If the return expression is not a projection of self, diagnose as
760
- // error.
761
- auto *baseExpr = lookThroughProjections (storageRefResult.getStorageRef ());
762
- if (!baseExpr->isSelfExprOf (
763
- cast<AbstractFunctionDecl>(FunctionDC->getAsDecl ()))) {
764
- diagnose (getASTContext (), ret->getStartLoc (),
765
- diag::invalid_borrow_accessor_return);
766
- diagnose (getASTContext (), ret->getStartLoc (),
767
- diag::borrow_accessor_not_a_projection_note);
768
- return ;
769
- }
760
+
770
761
// Emit return value at +0.
771
762
LValueOptions options;
772
763
auto lvalue = emitLValue (ret,
@@ -776,34 +767,71 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
776
767
F.getConventions ().hasGuaranteedResult ()
777
768
? options.forGuaranteedReturn (true )
778
769
: options.forGuaranteedAddressReturn (true ));
779
- auto result =
780
- tryEmitProjectedLValue (ret, std::move (lvalue), TSanKind::None);
781
- if (!result) {
782
- diagnose (getASTContext (), ret->getStartLoc (),
783
- diag::invalid_borrow_accessor_return);
784
- diagnose (getASTContext (), ret->getStartLoc (),
785
- diag::borrow_accessor_not_a_projection_note);
786
- return ;
787
- }
788
- // For now diagnose multiple return statements in borrow/mutate accessors.
789
- // We need additional support for this.
790
- // 1. Address phis are banned in SIL.
791
- // 2. borrowed from is not inserted in SILGenCleanup.
792
- if (!ReturnDest.getBlock ()->getPredecessorBlocks ().empty ()) {
793
- diagnose (getASTContext (), ret->getStartLoc (),
794
- diag::invalid_multiple_return_borrow_accessor);
795
- return ;
796
- }
797
770
798
- auto resultValue = result->getValue ();
799
- SILType selfType = F.getSelfArgument ()->getType ();
800
- if (selfType.isMoveOnly () && F.getConventions ().hasGuaranteedResult ()) {
801
- // If we are returning the result of borrow accessor, strip the
802
- // unnecessary copy_value + mark_unresolved_non_copyable_value
803
- // instructions.
804
- resultValue = lookThroughMoveOnlyCheckerPattern (resultValue);
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);
805
834
}
806
- directResults.push_back (resultValue);
807
835
}
808
836
} else {
809
837
// SILValue return.
0 commit comments