Skip to content

Commit 532a7de

Browse files
authored
Merge pull request #73092 from jckarter/silgen-loadable-error-cleanup-order
SILGen: Move error values into indirect error returns in proper order with cleanups.
2 parents b00b5aa + ba4f424 commit 532a7de

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
@@ -1660,11 +1660,12 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
16601660
if (exn->getType().isAddress()) {
16611661
B.createCopyAddr(loc, exn, indirectErrorAddr,
16621662
IsTake, IsInitialization);
1663-
} else {
1664-
// An indirect error is written into the destination error address.
1665-
emitSemanticStore(loc, exn, indirectErrorAddr,
1666-
getTypeLowering(destErrorType), IsInitialization);
16671663
}
1664+
1665+
// If the error is represented as a value, then we should forward it into
1666+
// the indirect error return slot. We have to wait to do that until after
1667+
// we pop cleanups, though, since the value may have a borrow active in
1668+
// scope that won't be released until the cleanups pop.
16681669
} else if (!throwBB.getArguments().empty()) {
16691670
// Load if we need to.
16701671
if (exn->getType().isAddress()) {
@@ -1680,5 +1681,16 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
16801681
}
16811682

16821683
// Branch to the cleanup destination.
1683-
Cleanups.emitBranchAndCleanups(ThrowDest, loc, args, IsForUnwind);
1684+
Cleanups.emitCleanupsForBranch(ThrowDest, loc, args, IsForUnwind);
1685+
1686+
if (indirectErrorAddr && !exn->getType().isAddress()) {
1687+
// Forward the error value into the return slot now. This has to happen
1688+
// after emitting cleanups because the active scope may be borrowing the
1689+
// error value, and we can't forward ownership until those borrows are
1690+
// released.
1691+
emitSemanticStore(loc, exn, indirectErrorAddr,
1692+
getTypeLowering(destErrorType), IsInitialization);
1693+
}
1694+
1695+
getBuilder().createBranch(loc, ThrowDest.getBlock(), args);
16841696
}
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)