Skip to content

Commit f126b71

Browse files
committed
MoveOnlyChecker: Properly insert cleanup for dead try_apply def.
When a address-only noncopyable value is dead-def'ed by an indirect return from a `try_apply`, the cleanup should be inserted on the normal return successor block. Fixes rdar://118255228.
1 parent 89bda71 commit f126b71

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,8 +2984,14 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary(
29842984
InitableButNotConsumable)
29852985
continue;
29862986

2987-
auto *insertPt = inst->getNextInstruction();
2988-
assert(insertPt && "def instruction was a terminator");
2987+
SILInstruction *insertPt;
2988+
if (auto tryApply = dyn_cast<TryApplyInst>(inst)) {
2989+
// The dead def is only valid on the success return path.
2990+
insertPt = &tryApply->getNormalBB()->front();
2991+
} else {
2992+
insertPt = inst->getNextInstruction();
2993+
assert(insertPt && "instruction is a terminator that wasn't handled?");
2994+
}
29892995
insertDestroyBeforeInstruction(addressUseState, insertPt,
29902996
liveness.getRootValue(), defPair.second,
29912997
consumes);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
struct MyError: Error {}
2+
3+
public struct Resilient: ~Copyable {
4+
static var nextValue: Int = 0
5+
6+
private(set) public var value: Int
7+
public init(nonthrowing: ()) {
8+
value = Self.nextValue
9+
Self.nextValue += 1
10+
}
11+
deinit { print("resilient deinit \(value)") }
12+
13+
public init(throwing: Bool) throws {
14+
if throwing {
15+
throw MyError()
16+
}
17+
self = .init(nonthrowing: ())
18+
}
19+
public init(throwingAfterInit: Bool) throws {
20+
self = .init(nonthrowing: ())
21+
if throwingAfterInit {
22+
throw MyError()
23+
}
24+
}
25+
26+
public static func instanceCount() -> Int {
27+
return nextValue
28+
}
29+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -emit-module-path %t -enable-library-evolution -module-name moveonly_resilient_type -parse-as-library %S/Inputs/moveonly_resilient_type.swift -c -o %t/moveonly_resilient_type.o
3+
// RUN: %target-build-swift -enable-library-evolution -module-name moveonly_resilient_type -parse-as-library %S/Inputs/moveonly_resilient_type.swift -c -o %t/moveonly_resilient_type.o
4+
// RUN: %target-build-swift -o %t/a.out -I %t %s %t/moveonly_resilient_type.o
5+
// RUN: %target-run %t/a.out | %FileCheck %s
6+
7+
// REQUIRES: executable_test
8+
9+
// CHECK: starting
10+
11+
import moveonly_resilient_type
12+
13+
func makeItem1() throws -> Resilient {
14+
return Resilient(nonthrowing: ())
15+
}
16+
17+
func test1a() throws {
18+
// CHECK-NEXT: resilient deinit 0
19+
_ = try makeItem1()
20+
}
21+
func test1b() throws {
22+
// CHECK-NEXT: resilient deinit 1
23+
let x = try makeItem1()
24+
}
25+
26+
func makeItem2(throwing: Bool) throws -> Resilient {
27+
return try Resilient(throwing: throwing)
28+
}
29+
30+
func test2aa() throws {
31+
// CHECK-NEXT: resilient deinit 2
32+
_ = try makeItem2(throwing: false)
33+
}
34+
35+
func test2ab() throws {
36+
_ = try makeItem2(throwing: true)
37+
}
38+
39+
func test2ba() throws {
40+
// CHECK-NEXT: resilient deinit 3
41+
let x = try makeItem2(throwing: false)
42+
}
43+
44+
func test2bb() throws {
45+
let x = try makeItem2(throwing: true)
46+
}
47+
48+
func makeItem3(throwing: Bool) throws -> Resilient {
49+
return try Resilient(throwingAfterInit: throwing)
50+
}
51+
52+
func test3aa() throws {
53+
// CHECK-NEXT: resilient deinit 4
54+
_ = try makeItem3(throwing: false)
55+
}
56+
57+
func test3ab() throws {
58+
// CHECK-NEXT: resilient deinit 5
59+
_ = try makeItem3(throwing: true)
60+
}
61+
62+
func test3ba() throws {
63+
// CHECK-NEXT: resilient deinit 6
64+
let x = try makeItem3(throwing: false)
65+
}
66+
67+
func test3bb() throws {
68+
// CHECK-NEXT: resilient deinit 7
69+
let x = try makeItem3(throwing: true)
70+
}
71+
72+
func main() {
73+
print("starting")
74+
_ = try? test1a()
75+
_ = try? test1b()
76+
_ = try? test2aa()
77+
_ = try? test2ab()
78+
_ = try? test2ba()
79+
_ = try? test2bb()
80+
_ = try? test3aa()
81+
_ = try? test3ab()
82+
_ = try? test3ba()
83+
_ = try? test3bb()
84+
85+
// CHECK-NEXT: 8 instances in total
86+
print("\(Resilient.instanceCount()) instances in total")
87+
}
88+
main()

0 commit comments

Comments
 (0)