Skip to content

Commit ebb8d73

Browse files
committed
SILGen: Fix for 'try?' leaking the error value
The error is passed in to the catch block as a +1 value but we were just dropping it on the floor. Fixes https://bugs.swift.org/browse/SR-972
1 parent 1f249f2 commit ebb8d73

File tree

4 files changed

+71
-7
lines changed

4 files changed

+71
-7
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,11 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
997997
// If control branched to the failure block, inject .None into the
998998
// result type.
999999
SGF.B.emitBlock(catchBB);
1000-
(void)catchBB->createBBArg(SILType::getExceptionType(SGF.getASTContext()));
1000+
FullExpr catchCleanups(SGF.Cleanups, E);
1001+
auto *errorArg = catchBB->createBBArg(
1002+
SILType::getExceptionType(SGF.getASTContext()));
1003+
(void) SGF.emitManagedRValueWithCleanup(errorArg);
1004+
catchCleanups.pop();
10011005

10021006
if (isByAddress) {
10031007
SGF.emitInjectOptionalNothingInto(E, optInit->getAddress(), optTL);

test/Interpreter/errors.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
//
5+
// Tests for error handling.
6+
//
7+
8+
import StdlibUnittest
9+
10+
// Also import modules which are used by StdlibUnittest internally. This
11+
// workaround is needed to link all required libraries in case we compile
12+
// StdlibUnittest with -sil-serialize-all.
13+
import SwiftPrivate
14+
#if _runtime(_ObjC)
15+
import ObjectiveC
16+
#endif
17+
18+
enum Excuse : ErrorProtocol { case CatAteHomework(LifetimeTracked) }
19+
20+
var ErrorHandlingTests = TestSuite("ErrorHandling")
21+
22+
func furball(b: Bool) throws -> LifetimeTracked {
23+
if b {
24+
throw Excuse.CatAteHomework(LifetimeTracked(0))
25+
} else {
26+
return LifetimeTracked(1)
27+
}
28+
}
29+
30+
ErrorHandlingTests.test("tryCatch") {
31+
do {
32+
try expectEqual(furball(false), LifetimeTracked(1))
33+
} catch {
34+
expectUnreachable()
35+
}
36+
37+
do {
38+
try furball(true)
39+
expectUnreachable()
40+
} catch let e {
41+
if case Excuse.CatAteHomework(let c) = e {
42+
expectEqual(c, LifetimeTracked(0))
43+
} else {
44+
expectUnreachable()
45+
}
46+
}
47+
}
48+
49+
ErrorHandlingTests.test("tryOptional") {
50+
expectEqual(LifetimeTracked(1), try? furball(false))
51+
expectEqual(Optional<LifetimeTracked>.none, try? furball(true))
52+
}
53+
54+
runAllTests()

test/SILGen/errors.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,8 @@ func testForcePeephole(f: () throws -> Int?) -> Int {
700700
// CHECK-NEXT: release_value [[RESULT]] : $Optional<Cat>
701701
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
702702
// CHECK-NEXT: return [[VOID]] : $()
703-
// CHECK: [[FAILURE:.+]]({{%.+}} : $ErrorProtocol):
703+
// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : $ErrorProtocol):
704+
// CHECK-NEXT: strong_release [[ERROR]]
704705
// CHECK-NEXT: [[NONE:%.+]] = enum $Optional<Cat>, #Optional.none!enumelt
705706
// CHECK-NEXT: br [[DONE]]([[NONE]] : $Optional<Cat>)
706707
// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : $ErrorProtocol):
@@ -725,7 +726,8 @@ func testOptionalTry() {
725726
// CHECK-NEXT: strong_release [[BOX]] : $@box Optional<Cat>
726727
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
727728
// CHECK-NEXT: return [[VOID]] : $()
728-
// CHECK: [[FAILURE:.+]]({{%.+}} : $ErrorProtocol):
729+
// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : $ErrorProtocol):
730+
// CHECK-NEXT: strong_release [[ERROR]]
729731
// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<Cat>, #Optional.none!enumelt
730732
// CHECK-NEXT: br [[DONE]]
731733
// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : $ErrorProtocol):
@@ -753,7 +755,8 @@ func testOptionalTryVar() {
753755
// CHECK-NEXT: destroy_addr %0 : $*T
754756
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
755757
// CHECK-NEXT: return [[VOID]] : $()
756-
// CHECK: [[FAILURE:.+]]({{%.+}} : $ErrorProtocol):
758+
// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : $ErrorProtocol):
759+
// CHECK-NEXT: strong_release [[ERROR]]
757760
// CHECK-NEXT: inject_enum_addr [[BOX]] : $*Optional<T>, #Optional.none!enumelt
758761
// CHECK-NEXT: br [[DONE]]
759762
// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : $ErrorProtocol):
@@ -782,7 +785,8 @@ func testOptionalTryAddressOnly<T>(obj: T) {
782785
// CHECK-NEXT: destroy_addr %0 : $*T
783786
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
784787
// CHECK-NEXT: return [[VOID]] : $()
785-
// CHECK: [[FAILURE:.+]]({{%.+}} : $ErrorProtocol):
788+
// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : $ErrorProtocol):
789+
// CHECK-NEXT: strong_release [[ERROR]]
786790
// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<T>, #Optional.none!enumelt
787791
// CHECK-NEXT: br [[DONE]]
788792
// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : $ErrorProtocol):
@@ -808,7 +812,8 @@ func testOptionalTryAddressOnlyVar<T>(obj: T) {
808812
// CHECK-NEXT: release_value [[RESULT]] : $Optional<(Cat, Cat)>
809813
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
810814
// CHECK-NEXT: return [[VOID]] : $()
811-
// CHECK: [[FAILURE:.+]]({{%.+}} : $ErrorProtocol):
815+
// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : $ErrorProtocol):
816+
// CHECK-NEXT: strong_release [[ERROR]]
812817
// CHECK-NEXT: [[NONE:%.+]] = enum $Optional<(Cat, Cat)>, #Optional.none!enumelt
813818
// CHECK-NEXT: br [[DONE]]([[NONE]] : $Optional<(Cat, Cat)>)
814819
// CHECK: [[CLEANUPS_1]]([[ERROR:%.+]] : $ErrorProtocol):

test/SILOptimizer/definite_init_failable_initializers.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,9 +521,10 @@ struct ThrowStruct {
521521
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
522522
// CHECK-NEXT: return [[NEW_SELF]] : $Optional<ThrowStruct>
523523
// CHECK: bb6:
524+
// CHECK-NEXT: strong_release [[ERROR:%.*]] : $ErrorProtocol
524525
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional<ThrowStruct>, #Optional.none!enumelt
525526
// CHECK-NEXT: br bb2([[NEW_SELF]] : $Optional<ThrowStruct>)
526-
// CHECK: bb7([[ERROR:%.*]] : $ErrorProtocol):
527+
// CHECK: bb7([[ERROR]] : $ErrorProtocol):
527528
// CHECK-NEXT: br bb6
528529
init?(throwsToOptional: Int) {
529530
try? self.init(failDuringDelegation: throwsToOptional)

0 commit comments

Comments
 (0)