Skip to content

Commit 65ab9eb

Browse files
committed
[MoveOnlyAddressChecker] Fix empty struct repr.
An empty struct without a deinit gets a single bit which is used to track the struct's liveness. Previously, an empty struct with a deinit also only got a single bit. Consequently, when discarding the struct (i.e. dropping the deinit), there was no bit left to represent the struct. This resulted in a failure to track liveness for the value. rdar://126863003
1 parent 874971c commit 65ab9eb

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,14 @@ TypeSubElementCount::TypeSubElementCount(SILType type, SILModule &mod,
7171
type.getFieldType(fieldDecl, mod, context), mod, context);
7272
number = numElements;
7373

74+
// If we do not have any elements, just set our size to 1.
75+
if (number == 0)
76+
number = 1;
7477
if (type.isValueTypeWithDeinit()) {
7578
// 'self' has its own liveness represented as an additional field at the
7679
// end of the structure.
7780
++number;
7881
}
79-
// If we do not have any elements, just set our size to 1.
80-
if (number == 0)
81-
number = 1;
8282

8383
return;
8484
}
@@ -450,6 +450,9 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
450450
callback(newValue, TypeTreeLeafTypeRange(start, next), NeedsDestroy);
451451
start = next;
452452
}
453+
if (start == 0) {
454+
++start;
455+
}
453456
if (type.isValueTypeWithDeinit()) {
454457
// 'self' has its own liveness
455458
++start;

test/SILOptimizer/moveonly_addresschecker_unmaximized.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,36 @@ bb0(%s_addr : $*S):
203203
%retval = tuple ()
204204
return %retval : $()
205205
}
206+
207+
sil @getter : $@convention(thin) (@guaranteed M) -> @owned String
208+
sil @die : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @owned String) -> Never
209+
210+
// CHECK-LABEL: sil [ossa] @partial_apply_of_borrow_of_deinitless_empty_struct : {{.*}} {
211+
// CHECK: bb0([[M_IN:%[^,]+]] :
212+
// CHECK: [[STACK:%[^,]+]] = alloc_stack $M
213+
// CHECK: store [[M_IN]] to [init] [[STACK]]
214+
// CHECK: [[ADDR:%[^,]+]] = drop_deinit [[STACK]]
215+
// CHECK: [[MB:%[^,]+]] = load_borrow [[ADDR]]
216+
// CHECK: [[GETTER:%[^,]+]] = function_ref @getter
217+
// CHECK: [[PA:%[^,]+]] = partial_apply [callee_guaranteed] [on_stack] [[GETTER]]([[MB]])
218+
// CHECK: [[DIE:%[^,]+]] = function_ref @die
219+
// CHECK: apply [[DIE]]([[PA]])
220+
// CHECK: destroy_value [[PA]]
221+
// CHECK: end_borrow [[MB]]
222+
// CHECK: unreachable
223+
// CHECK-LABEL: } // end sil function 'partial_apply_of_borrow_of_deinitless_empty_struct'
224+
sil [ossa] @partial_apply_of_borrow_of_deinitless_empty_struct : $@convention(method) (@owned M) -> () {
225+
bb0(%m_in : @owned $M):
226+
%stack = alloc_stack $M
227+
%addr1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %stack : $*M
228+
store %m_in to [init] %addr1 : $*M
229+
%nodeinit = drop_deinit %addr1 : $*M
230+
%addr = mark_unresolved_non_copyable_value [no_consume_or_assign] %nodeinit : $*M
231+
%m = load [copy] %addr : $*M
232+
%mb = begin_borrow %m : $M
233+
%getter = function_ref @getter : $@convention(thin) (@guaranteed M) -> @owned String
234+
%pa = partial_apply [callee_guaranteed] [on_stack] %getter(%mb) : $@convention(thin) (@guaranteed M) -> @owned String
235+
%die = function_ref @die : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @owned String) -> Never
236+
apply %die(%pa) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @owned String) -> Never
237+
unreachable
238+
}

validation-test/SILOptimizer/gh68328.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// REQUIRES: executable_test
88

99
struct Example: ~Copyable {
10-
private var failureString: String = "Goodbye."
10+
private var failureString: String { "Goodbye." }
1111
deinit { fatalError("FATAL ERROR: \(failureString)") }
1212
}
1313

0 commit comments

Comments
 (0)