Skip to content

Commit 91c7228

Browse files
committed
Fix MoveOnlyAddressChecker to handle value deinits.
Track liveness of self so we don't accidentally think that such types can be memberwise reinitialized.
1 parent 8d0232f commit 91c7228

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,13 @@ TypeSubElementCount::TypeSubElementCount(SILType type, SILModule &mod,
7070
type.getFieldType(fieldDecl, mod, context), mod, context);
7171
number = numElements;
7272

73+
if (type.isValueTypeWithDeinit()) {
74+
// 'self' has its own liveness represented as an additional field at the
75+
// end of the structure.
76+
++number;
77+
}
7378
// If we do not have any elements, just set our size to 1.
74-
if (numElements == 0)
79+
if (number == 0)
7580
number = 1;
7681

7782
return;
@@ -350,6 +355,10 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
350355
callback(newValue, TypeTreeLeafTypeRange(start, next));
351356
start = next;
352357
}
358+
if (type.isValueTypeWithDeinit()) {
359+
// 'self' has its own liveness
360+
++start;
361+
}
353362
assert(start == endEltOffset);
354363
return;
355364
}

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ static bool memInstMustConsume(Operand *memOper) {
437437

438438
SILInstruction *memInst = memOper->getUser();
439439

440+
// FIXME: drop_deinit must be handled here!
440441
switch (memInst->getKind()) {
441442
default:
442443
return false;

test/Interpreter/moveonly_discard.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,34 @@ struct SillyEmptyGeneric<T>: ~Copyable {
9191
deinit { fatalError("ran unexpectedly!") }
9292
}
9393

94+
struct SingleMutableField: ~Copyable {
95+
var value = 0
96+
97+
consuming func justDiscard() {
98+
discard self
99+
}
100+
101+
deinit {
102+
print("SingleMutableField.deinit")
103+
}
104+
}
105+
106+
// rdar://110232973 ([move-only] Checker should distinguish in between
107+
// field of single field struct vs parent field itself (was: mutation
108+
// of field in noncopyable struct should not trigger deinit))
109+
//
110+
// This test must not be in a closure.
111+
@inline(never)
112+
func testSingleMutableFieldNoMemberReinit() {
113+
var x = SingleMutableField()
114+
x.value = 20 // should not trigger deinit.
115+
// CHECK-NOT: SingleMutableField.deinit
116+
x.justDiscard()
117+
}
118+
94119
func main() {
120+
testSingleMutableFieldNoMemberReinit()
121+
95122
let _ = {
96123
let x = FileDescriptor() // 0
97124
x.close()

0 commit comments

Comments
 (0)