@@ -708,6 +708,110 @@ static Expr *lookThroughProjections(Expr *expr) {
708708 return lookThroughProjections (lookupExpr->getBase ());
709709}
710710
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+
711815void SILGenFunction::emitReturnExpr (SILLocation branchLoc,
712816 Expr *ret) {
713817 SmallVector<SILValue, 4 > directResults;
@@ -738,101 +842,11 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
738842 }
739843 } else if (F.getConventions ().hasGuaranteedResult () ||
740844 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 ;
835848 }
849+ assert (!directResults.empty ());
836850 } else {
837851 // SILValue return.
838852 FullExpr scope (Cleanups, CleanupLocation (ret));
0 commit comments