Skip to content

Commit f3bda1c

Browse files
authored
Merge pull request #24314 from gottesmm/pr-bc2eaca09ec955cbff0218bf32561438e41bb547
[silgen] Fix SILGenBuilder::emitDestructureValueOperation to create a…
2 parents 6352764 + ade2df1 commit f3bda1c

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

lib/SILGen/SILGenBuilder.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -819,10 +819,21 @@ void SILGenBuilder::emitDestructureValueOperation(
819819
SILLocation loc, ManagedValue value,
820820
llvm::function_ref<void(unsigned, ManagedValue)> func) {
821821
CleanupCloner cloner(*this, value);
822-
emitDestructureValueOperation(loc, value.forward(SGF),
823-
[&](unsigned index, SILValue subValue) {
824-
return func(index, cloner.clone(subValue));
825-
});
822+
823+
// NOTE: We can not directly use SILBuilder::emitDestructureValueOperation()
824+
// here since we need to create all of our cleanups before invoking \p
825+
// func. This is necessary since our func may want to emit conditional code
826+
// with an early exit, emitting unused cleanups from the current scope via the
827+
// function emitBranchAndCleanups(). If we have not yet created those
828+
// cleanups, we will introduce a leak along that path.
829+
SmallVector<ManagedValue, 8> destructuredValues;
830+
emitDestructureValueOperation(
831+
loc, value.forward(SGF), [&](unsigned index, SILValue subValue) {
832+
destructuredValues.push_back(cloner.clone(subValue));
833+
});
834+
for (auto p : llvm::enumerate(destructuredValues)) {
835+
func(p.index(), p.value());
836+
}
826837
}
827838

828839
ManagedValue SILGenBuilder::createProjectBox(SILLocation loc, ManagedValue mv,

test/Interpreter/switch.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,49 @@ SwitchTestSuite.test("Protocol Conformance Check Leaks") {
237237
}
238238
}
239239

240+
SwitchTestSuite.test("Enum Initialization Leaks") {
241+
enum Enum1 {
242+
case case1(LifetimeTracked)
243+
case case2(LifetimeTracked, Int)
244+
}
245+
246+
enum Enum2 {
247+
case case1(LifetimeTracked)
248+
case case2(Enum1, LifetimeTracked)
249+
}
250+
251+
struct Struct {
252+
var value: Enum2 = .case2(.case1(LifetimeTracked(0)), LifetimeTracked(1))
253+
254+
func doSomethingIfLet() {
255+
if case let .case2(.case2(k, _), _) = value {
256+
return
257+
}
258+
}
259+
260+
func doSomethingSwitch() {
261+
switch value {
262+
case let .case2(.case2(k, _), _):
263+
return
264+
default:
265+
return
266+
}
267+
return
268+
}
269+
270+
func doSomethingGuardLet() {
271+
guard case let .case2(.case2(k, _), _) = value else {
272+
return
273+
}
274+
}
275+
}
276+
277+
do {
278+
let s = Struct()
279+
s.doSomethingIfLet()
280+
s.doSomethingSwitch()
281+
s.doSomethingGuardLet()
282+
}
283+
}
284+
240285
runAllTests()

test/SILGen/switch.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,3 +1583,40 @@ enum Storage {
15831583
}
15841584
}
15851585

1586+
// Make sure that we do not leak tuple elements if we fail to match the first
1587+
// tuple element.
1588+
enum rdar49990484Enum1 {
1589+
case case1(Klass)
1590+
case case2(Klass, Int)
1591+
}
1592+
1593+
enum rdar49990484Enum2 {
1594+
case case1(Klass)
1595+
case case2(rdar49990484Enum1, Klass)
1596+
}
1597+
1598+
struct rdar49990484Struct {
1599+
var value: rdar49990484Enum2
1600+
1601+
func doSomethingIfLet() {
1602+
if case let .case2(.case2(k, _), _) = value {
1603+
return
1604+
}
1605+
}
1606+
1607+
func doSomethingSwitch() {
1608+
switch value {
1609+
case let .case2(.case2(k, _), _):
1610+
return
1611+
default:
1612+
return
1613+
}
1614+
return
1615+
}
1616+
1617+
func doSomethingGuardLet() {
1618+
guard case let .case2(.case2(k, _), _) = value else {
1619+
return
1620+
}
1621+
}
1622+
}

0 commit comments

Comments
 (0)