Skip to content

Commit 4e30159

Browse files
authored
Merge pull request #73093 from jckarter/silgen-loadable-error-cleanup-order-6.0
[6.0] SILGen: Move error values into indirect error returns in proper order with cleanups
2 parents 1c97cc3 + 9367d23 commit 4e30159

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

lib/SILGen/Cleanup.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,28 @@ bool CleanupManager::hasAnyActiveCleanups(CleanupsDepth from) {
162162
/// emitBranchAndCleanups - Emit a branch to the given jump destination,
163163
/// threading out through any cleanups we might need to run. This does not
164164
/// pop the cleanup stack.
165-
void CleanupManager::emitBranchAndCleanups(JumpDest dest, SILLocation branchLoc,
165+
void CleanupManager::emitBranchAndCleanups(JumpDest dest,
166+
SILLocation branchLoc,
167+
ArrayRef<SILValue> args,
168+
ForUnwind_t forUnwind) {
169+
emitCleanupsForBranch(dest, branchLoc, args, forUnwind);
170+
SGF.getBuilder().createBranch(branchLoc, dest.getBlock(), args);
171+
}
172+
173+
/// emitBranchAndCleanups - Emit the cleanups necessary before branching to
174+
/// the given jump destination. This does not pop the cleanup stack, nor does
175+
/// it emit the actual branch.
176+
void CleanupManager::emitCleanupsForBranch(JumpDest dest,
177+
SILLocation branchLoc,
166178
ArrayRef<SILValue> args,
167179
ForUnwind_t forUnwind) {
168180
SILGenBuilder &builder = SGF.getBuilder();
169181
assert(builder.hasValidInsertionPoint() && "Emitting branch in invalid spot");
170182
emitCleanups(dest.getDepth(), dest.getCleanupLocation(),
171183
forUnwind, /*popCleanups=*/false);
172-
builder.createBranch(branchLoc, dest.getBlock(), args);
173184
}
174185

186+
175187
void CleanupManager::emitCleanupsForReturn(CleanupLocation loc,
176188
ForUnwind_t forUnwind) {
177189
SILGenBuilder &builder = SGF.getBuilder();

lib/SILGen/Cleanup.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
221221
ArrayRef<SILValue> args = {},
222222
ForUnwind_t forUnwind = NotForUnwind);
223223

224+
/// Emit a branch to the given jump destination,
225+
/// threading out through any cleanups we need to run. This does not pop the
226+
/// cleanup stack.
227+
///
228+
/// \param dest The destination scope and block.
229+
/// \param branchLoc The location of the branch instruction.
230+
/// \param args Arguments to pass to the destination block.
231+
void emitCleanupsForBranch(JumpDest dest, SILLocation branchLoc,
232+
ArrayRef<SILValue> args = {},
233+
ForUnwind_t forUnwind = NotForUnwind);
234+
224235
/// emitCleanupsForReturn - Emit the top-level cleanups needed prior to a
225236
/// return from the function.
226237
void emitCleanupsForReturn(CleanupLocation loc, ForUnwind_t forUnwind);

lib/SILGen/SILGenStmt.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,11 +1656,12 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
16561656
if (exn->getType().isAddress()) {
16571657
B.createCopyAddr(loc, exn, indirectErrorAddr,
16581658
IsTake, IsInitialization);
1659-
} else {
1660-
// An indirect error is written into the destination error address.
1661-
emitSemanticStore(loc, exn, indirectErrorAddr,
1662-
getTypeLowering(destErrorType), IsInitialization);
16631659
}
1660+
1661+
// If the error is represented as a value, then we should forward it into
1662+
// the indirect error return slot. We have to wait to do that until after
1663+
// we pop cleanups, though, since the value may have a borrow active in
1664+
// scope that won't be released until the cleanups pop.
16641665
} else if (!throwBB.getArguments().empty()) {
16651666
// Load if we need to.
16661667
if (exn->getType().isAddress()) {
@@ -1676,5 +1677,16 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
16761677
}
16771678

16781679
// Branch to the cleanup destination.
1679-
Cleanups.emitBranchAndCleanups(ThrowDest, loc, args, IsForUnwind);
1680+
Cleanups.emitCleanupsForBranch(ThrowDest, loc, args, IsForUnwind);
1681+
1682+
if (indirectErrorAddr && !exn->getType().isAddress()) {
1683+
// Forward the error value into the return slot now. This has to happen
1684+
// after emitting cleanups because the active scope may be borrowing the
1685+
// error value, and we can't forward ownership until those borrows are
1686+
// released.
1687+
emitSemanticStore(loc, exn, indirectErrorAddr,
1688+
getTypeLowering(destErrorType), IsInitialization);
1689+
}
1690+
1691+
getBuilder().createBranch(loc, ThrowDest.getBlock(), args);
16801692
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
func test2() throws { // Not OK
3+
// The literal closure below is in a generic error context, even though
4+
// it statically throws `any Error`, leading it to be emitted with an
5+
// indirect `any Error` out parameter.
6+
try call { () throws in
7+
// CHECK-LABEL: sil{{.*}} @{{.*}}5test2{{.*}}fU_
8+
do {
9+
try gorble()
10+
}
11+
// Make sure we stop borrowing the error value before forwarding it into
12+
// the error return slot.
13+
// CHECK: bb{{.*}}([[ERROR:%.*]] : @owned $any Error):
14+
// CHECK: [[ERROR_BORROW:%.*]] = begin_borrow [[ERROR]]
15+
// CHECK: bb{{[0-9]+}}:
16+
// CHECK: bb{{[0-9]+}}:
17+
// CHECK: end_borrow [[ERROR_BORROW]]
18+
// CHECK-NEXT: store [[ERROR]] to [init]
19+
// CHECK-NEXT: throw_addr
20+
21+
catch is E1 { /* ignore */ }
22+
}
23+
}
24+
25+
func call<E: Error, R>(
26+
_ body: () throws(E) -> R
27+
) throws(E) -> R {
28+
try body()
29+
}
30+
31+
struct E1: Error {}
32+
33+
func gorble() throws {}
34+
35+
func test1() throws { // OK
36+
try call { () throws in
37+
try gorble()
38+
}
39+
}

0 commit comments

Comments
 (0)