Skip to content

Commit ad82526

Browse files
committed
RawSILInstLowering: delete dead load instructions when lowering assign_by_wrapper
If only the init-closure is used and the setter-closure is dead, the argument to the setter partial_apply also needs to be delete - in case it's a load. Otherwise it would cause a memory lifetime failure.
1 parent 9b016cb commit ad82526

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
210210
// is an inout. Therefore we cannot keep it as a dead closure to be
211211
// cleaned up later. We have to delete it in this pass.
212212
toDelete.insert(inst->getSetter());
213+
214+
// Also the argument of the closure (which usually is a "load") has to be
215+
// deleted to avoid memory lifetime violations.
216+
auto *setterPA = dyn_cast<PartialApplyInst>(inst->getSetter());
217+
if (setterPA && setterPA->getNumArguments() == 1)
218+
toDelete.insert(setterPA->getArgument(0));
213219
break;
214220
}
215221
case AssignByWrapperInst::AssignWrappedValue: {
@@ -251,6 +257,22 @@ static void deleteDeadAccessMarker(BeginAccessInst *BA) {
251257
BA->eraseFromParent();
252258
}
253259

260+
/// Delete a dead load for a dead setter-closure.
261+
static void deleteDeadClosureArg(LoadInst *load) {
262+
if (load->getOwnershipQualifier() != LoadOwnershipQualifier::Trivial &&
263+
load->getOwnershipQualifier() != LoadOwnershipQualifier::Copy)
264+
return;
265+
266+
for (Operand *use : load->getUses()) {
267+
if (!isa<DestroyValueInst>(use->getUser()))
268+
return;
269+
}
270+
while (!load->use_empty()) {
271+
load->use_begin()->getUser()->eraseFromParent();
272+
}
273+
load->eraseFromParent();
274+
}
275+
254276
/// lowerRawSILOperations - There are a variety of raw-sil instructions like
255277
/// 'assign' that are only used by this pass. Now that definite initialization
256278
/// checking is done, remove them.
@@ -311,6 +333,8 @@ static bool lowerRawSILOperations(SILFunction &fn) {
311333
for (SILValue deadVal : toDelete) {
312334
if (auto *beginAccess = dyn_cast<BeginAccessInst>(deadVal)) {
313335
deleteDeadAccessMarker(beginAccess);
336+
} else if (auto *load = dyn_cast<LoadInst>(deadVal)) {
337+
deleteDeadClosureArg(load);
314338
} else if (auto *svi = dyn_cast<SingleValueInstruction>(deadVal)) {
315339
tryDeleteDeadClosure(svi);
316340
}

test/SILOptimizer/di_property_wrappers.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,14 @@ struct NonMutatingWrapperTestStruct {
558558
}
559559
}
560560

561+
// Check if a non-trivial value passes the memory lifetime verifier.
562+
struct NonMutatingWrapperTestStructString {
563+
@NonMutatingSetterWrapper var SomeProp: String
564+
init(val: String) {
565+
SomeProp = val
566+
}
567+
}
568+
561569
func testNonMutatingSetterStruct() {
562570
// CHECK: ## NonMutatingSetterWrapper
563571
print("\n## NonMutatingSetterWrapper")

0 commit comments

Comments
 (0)