Skip to content

Commit 11d4fc0

Browse files
committed
SILGen: Clean up partially-initialized array elements when lowering ArrayExpr
1 parent 66204f4 commit 11d4fc0

File tree

3 files changed

+42
-3
lines changed

3 files changed

+42
-3
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3663,6 +3663,9 @@ RValue RValueEmitter::visitArrayExpr(ArrayExpr *E, SGFContext C) {
36633663
emitBeginVarargs(SGF, loc, elementType, arrayTy,
36643664
E->getNumElements(), {});
36653665

3666+
// Cleanups for any elements that have been initialized so far.
3667+
SmallVector<CleanupHandle, 8> cleanups;
3668+
36663669
for (unsigned index : range(E->getNumElements())) {
36673670
auto destAddr = varargsInfo.getBaseAddress();
36683671
if (index != 0) {
@@ -3671,14 +3674,27 @@ RValue RValueEmitter::visitArrayExpr(ArrayExpr *E, SGFContext C) {
36713674
destAddr = SGF.B.createIndexAddr(loc, destAddr, indexValue);
36723675
}
36733676
auto &destTL = varargsInfo.getBaseTypeLowering();
3674-
// Use an invalid cleanup here because we're relying on the cleanup for
3675-
// the Array constructed inside emitBeginVarargs to destroy these values.
3676-
TemporaryInitialization init(destAddr, CleanupHandle::invalid());
3677+
// Create a dormant cleanup for the value in case we exit before the
3678+
// full array has been constructed.
3679+
3680+
CleanupHandle destCleanup = CleanupHandle::invalid();
3681+
if (!destTL.isTrivial()) {
3682+
destCleanup = SGF.enterDestroyCleanup(destAddr);
3683+
SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dormant);
3684+
cleanups.push_back(destCleanup);
3685+
}
3686+
3687+
TemporaryInitialization init(destAddr, destCleanup);
3688+
36773689
ArgumentSource(E->getElements()[index])
36783690
.forwardInto(SGF, varargsInfo.getBaseAbstractionPattern(), &init,
36793691
destTL);
36803692
}
36813693

3694+
// Kill the per-element cleanups. The array will take ownership of them.
3695+
for (auto destCleanup : cleanups)
3696+
SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead);
3697+
36823698
RValue arg(SGF, loc, arrayTy,
36833699
emitEndVarargs(SGF, loc, std::move(varargsInfo)));
36843700

test/Interpreter/arrays.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,25 @@ test()
161161
let mdaPerf = [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]]
162162
print(mdaPerf)
163163
// CHECK: {{\[}}[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]]
164+
165+
class Deinitable {
166+
deinit {
167+
print("deinit called")
168+
}
169+
}
170+
171+
enum E : Error {
172+
case error
173+
}
174+
175+
func throwingFunc() throws -> Deinitable {
176+
throw E.error
177+
}
178+
179+
do {
180+
let array = try [Deinitable(), throwingFunc()]
181+
} catch {
182+
// CHECK: deinit called
183+
// CHECK: error thrown
184+
print("error thrown")
185+
}

test/SILGen/literals.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ func makeBasic<T : FooProtocol>() -> T { return T() }
248248
// CHECK: return [[ARR]]
249249

250250
// CHECK: bb2([[ERR:%.*]] : @owned $Error):
251+
// CHECK: destroy_addr [[POINTER]] : $*T
251252
// CHECK: [[DEALLOC:%.*]] = function_ref @$ss29_deallocateUninitializedArrayyySayxGnlF
252253
// CHECK: [[TMP:%.*]] = apply [[DEALLOC]]<T>([[ARR]])
253254
// CHECK: throw [[ERR]] : $Error

0 commit comments

Comments
 (0)