Skip to content

Commit b6c8f89

Browse files
committed
[NFC] Move SILGen of ReturnExpr in borrow accessors to a new function
1 parent fa7281d commit b6c8f89

File tree

2 files changed

+111
-94
lines changed

2 files changed

+111
-94
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
22732273

22742274
void emitReturnExpr(SILLocation loc, Expr *ret);
22752275

2276+
bool emitGuaranteedReturn(SILLocation loc, Expr *ret,
2277+
SmallVectorImpl<SILValue> &directResults);
2278+
22762279
void emitYield(SILLocation loc, MutableArrayRef<ArgumentSource> yieldValues,
22772280
ArrayRef<AbstractionPattern> origTypes,
22782281
JumpDest unwindDest);

lib/SILGen/SILGenStmt.cpp

Lines changed: 108 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
711815
void 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

Comments
 (0)