Skip to content

Commit c4e97bc

Browse files
committed
Handle non-existential errors in do..catch blocks
1 parent 9bfca45 commit c4e97bc

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

Diff for: lib/SILGen/SILGenPattern.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -3189,13 +3189,14 @@ void SILGenFunction::emitCatchDispatch(DoCatchStmt *S, ManagedValue exn,
31893189

31903190
Scope stmtScope(Cleanups, CleanupLocation(S));
31913191

3192-
assert(exn.getType().isObject() &&
3193-
"Error is special and should always be an object");
3192+
auto consumptionKind = exn.getType().isObject()
3193+
? CastConsumptionKind::BorrowAlways
3194+
: CastConsumptionKind::CopyOnSuccess;
3195+
31943196
// Our model is that sub-cases get the exception at +0 and the throw (if we
31953197
// need to rethrow the exception) gets the exception at +1 since we need to
31963198
// trampoline it's ownership to our caller.
3197-
ConsumableManagedValue subject = {exn.borrow(*this, S),
3198-
CastConsumptionKind::BorrowAlways};
3199+
ConsumableManagedValue subject = {exn.borrow(*this, S), consumptionKind};
31993200

32003201
auto failure = [&](SILLocation location) {
32013202
// If we fail to match anything, just rethrow the exception.

Diff for: test/SILGen/typed_throws.swift

+35
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,41 @@ func passesClosureWithReabstractionToRethrowing(count: Int) {
203203
}
204204

205205

206+
// CHECK-LABEL: sil hidden [ossa] @$s12typed_throws13throwAndCatchyyyyxYKXExYKs5ErrorRzlF : $@convention(thin) <E where E : Error> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>) -> @error_indirect E {
207+
func throwAndCatch<E: Error>(_ body: () throws(E) -> Void) throws(E) {
208+
do {
209+
// CHECK: [[OUTER_ERR:%.*]] = alloc_stack $E
210+
// CHECK: try_apply [[FN:%.*]]([[ERROR_ARG:%.*]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>, normal [[NORMAL_BB:bb.*]], error [[ERROR_BB:bb.*]] //
211+
try body()
212+
} catch {
213+
// CHECK: [[ERROR_BB]]:
214+
// CHECK-NEXT: copy_addr [take] [[ERROR_ARG]] to [init] [[OUTER_ERR]] : $*E
215+
// CHECK: dealloc_stack [[ERROR_ARG]] : $*E
216+
print(error)
217+
}
218+
}
219+
220+
enum HomeworkError: Error {
221+
case dogAteIt
222+
case forgot
223+
}
224+
225+
// CHECK-LABEL: sil hidden [ossa] @$s12typed_throws25throwAndPatternMatchCatchyyyyxYKXExYKs5ErrorRzlF : $@convention(thin) <E where E : Error> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>) -> @error_indirect E {
226+
func throwAndPatternMatchCatch<E: Error>(_ body: () throws(E) -> Void) throws(E) {
227+
do {
228+
// CHECK: [[OUTER_ERR:%.*]] = alloc_stack $E
229+
// CHECK: try_apply [[FN:%.*]]([[ERROR_ARG:%.*]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>, normal [[NORMAL_BB:bb.*]], error [[ERROR_BB:bb.*]] //
230+
try body()
231+
} catch let he as HomeworkError where he == .dogAteIt {
232+
// CHECK: copy_addr [take] [[ERROR_ARG]] to [init] [[OUTER_ERR]] : $*E
233+
// CHECK: [[HOMEWORK_ERR:%.*]] = alloc_stack $HomeworkError
234+
// CHECK: checked_cast_addr_br copy_on_success E in [[OUTER_ERR]] : $*E to HomeworkError in [[HOMEWORK_ERR]] : $*HomeworkError
235+
236+
// bad dog
237+
} catch {
238+
}
239+
}
240+
206241
// CHECK-LABEL: sil_vtable MySubclass {
207242
// CHECK-NEXT: #MyClass.init!allocator: <E where E : Error> (MyClass.Type) -> (() throws(E) -> ()) throws(E) -> MyClass : @$s12typed_throws10MySubclassC4bodyACyyxYKXE_txYKcs5ErrorRzlufC [override]
208243
// CHECK-NEXT: #MyClass.f: (MyClass) -> () throws -> () : @$s12typed_throws10MySubclassC1fyyAA0C5ErrorOYKFAA0C5ClassCADyyKFTV [override]

0 commit comments

Comments
 (0)