Skip to content

Commit 0bf0acd

Browse files
committed
[ownership-verifier] Make unchecked_enum_data a propagating instruction.
This allows for an unchecked_enum_data to be either a consumed instruction or a borrowed instruction. The reason why this makes sense in contrast to other value projection operations like struct_extract and tuple_extract is that an enum payload is essentially a tuple. This means that we are extracting the entire value when we perform a struct_extract. So forwarding is viable from a semantic perspective since if we destroy the payload, there is nothing left to destroy. This contrasts with struct_extract and tuple_extract where we may have other parts of the struct/tuple to destroy. rdar://29791263
1 parent d539b67 commit 0bf0acd

File tree

9 files changed

+52
-13
lines changed

9 files changed

+52
-13
lines changed

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ FORWARD_ANY_OWNERSHIP_INST(RefToBridgeObject)
456456
FORWARD_ANY_OWNERSHIP_INST(BridgeObjectToRef)
457457
FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCast)
458458
FORWARD_ANY_OWNERSHIP_INST(MarkUninitialized)
459+
FORWARD_ANY_OWNERSHIP_INST(UncheckedEnumData)
459460
#undef FORWARD_ANY_OWNERSHIP_INST
460461

461462
// An instruction that forwards a constant ownership or trivial ownership.
@@ -482,7 +483,6 @@ FORWARD_ANY_OWNERSHIP_INST(MarkUninitialized)
482483
}
483484
FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false, TupleExtract)
484485
FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false, StructExtract)
485-
FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false, UncheckedEnumData)
486486
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
487487

488488
OwnershipUseCheckerResult

lib/SIL/SILValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ CONSTANT_OWNERSHIP_INST(Unowned, UnownedToRef)
283283
}
284284
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, StructExtract)
285285
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract)
286-
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, UncheckedEnumData)
287286
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
288287

289288
// These are instructions that do not have any result, so we should never reach
@@ -418,6 +417,7 @@ FORWARDING_OWNERSHIP_INST(UncheckedRefCast)
418417
FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast)
419418
FORWARDING_OWNERSHIP_INST(Upcast)
420419
FORWARDING_OWNERSHIP_INST(MarkUninitialized)
420+
FORWARDING_OWNERSHIP_INST(UncheckedEnumData)
421421
#undef FORWARDING_OWNERSHIP_INST
422422

423423
ValueOwnershipKind

test/ClangImporter/optional.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ class A {
2222
// Something branch: project value, translate, inject into result.
2323
// CHECK: [[STR:%.*]] = unchecked_enum_data [[T1]]
2424
// CHECK: [[T0:%.*]] = function_ref @_T0SS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
25-
// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[STR]])
25+
// CHECK-NEXT: [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
26+
// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[BORROWED_STR]])
2627
// CHECK-NEXT: enum $Optional<NSString>, #Optional.some!enumelt.1, [[T1]]
28+
// CHECK-NEXT: end_borrow [[BORROWED_STR:%.*]] from [[STR]]
2729
// CHECK-NEXT: destroy_value [[STR]]
2830
// CHECK-NEXT: br
2931
// Nothing branch: inject nothing into result.

test/SIL/ownership-verifier/over_consume.sil

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ class RefWithInt {
1717
init()
1818
}
1919

20+
enum Optional<T> {
21+
case some(T)
22+
case none
23+
}
24+
2025
///////////
2126
// Tests //
2227
///////////
@@ -150,4 +155,20 @@ bb0(%0 : @owned $RefWithInt):
150155
destroy_value %0 : $RefWithInt
151156
%9999 = tuple()
152157
return %9999 : $()
153-
}
158+
}
159+
160+
// Make sure that we catch that in the case where unchecked_enum_data is
161+
// propagating forward @owned ownership, that we catch a double consumed.
162+
//
163+
// CHECK-LABEL: Function: 'unchecked_enum_data_propagates_ownership'
164+
// CHECK: Found over consume?!
165+
// CHECK: Value: %0 = argument of bb0 : $Optional<Builtin.NativeObject>
166+
// CHECK: User: destroy_value %0 : $Optional<Builtin.NativeObject>
167+
// CHECK: Block: bb0
168+
sil @unchecked_enum_data_propagates_ownership : $@convention(thin) (@owned Optional<Builtin.NativeObject>) -> () {
169+
bb0(%0 : @owned $Optional<Builtin.NativeObject>):
170+
%1 = unchecked_enum_data %0 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
171+
destroy_value %0 : $Optional<Builtin.NativeObject>
172+
%9999 = tuple()
173+
return %9999 : $()
174+
}

test/SIL/ownership-verifier/use_verifier.sil

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ bb0(%0 : @owned $Ref):
298298
return %9999 : $()
299299
}
300300

301+
sil @unchecked_enum_data_propagates_ownership : $@convention(thin) (@owned Optional<Builtin.NativeObject>) -> @owned Builtin.NativeObject {
302+
bb0(%0 : @owned $Optional<Builtin.NativeObject>):
303+
%1 = begin_borrow %0 : $Optional<Builtin.NativeObject>
304+
unchecked_enum_data %1 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
305+
unchecked_enum_data %1 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
306+
unchecked_enum_data %1 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
307+
end_borrow %1 from %0 : $Optional<Builtin.NativeObject>, $Optional<Builtin.NativeObject>
308+
%2 = unchecked_enum_data %0 : $Optional<Builtin.NativeObject>, #Optional.some!enumelt.1
309+
return %2 : $Builtin.NativeObject
310+
}
311+
301312
//////////////////////
302313
// Terminator Tests //
303314
//////////////////////

test/SILGen/objc_bridging.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ func setFoo(_ f: Foo, s: String) {
5959
// CHECK: select_enum [[OPT_NATIVE]]
6060
// CHECK: [[NATIVE:%.*]] = unchecked_enum_data [[OPT_NATIVE]]
6161
// CHECK: [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
62-
// CHECK: [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[NATIVE]])
62+
// CHECK: [[BORROWED_NATIVE:%.*]] = begin_borrow [[NATIVE]]
63+
// CHECK: [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_NATIVE]])
6364
// CHECK: = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
65+
// CHECK: end_borrow [[BORROWED_NATIVE]] from [[NATIVE]]
6466
// CHECK: bb3([[OPT_BRIDGED:%.*]] : $Optional<NSString>):
6567
// CHECK: apply [[SET_FOO]]([[OPT_BRIDGED]], %0)
6668
// CHECK: destroy_value [[OPT_BRIDGED]]
@@ -177,8 +179,10 @@ func callSetBar(_ s: String) {
177179
// CHECK: select_enum [[OPT_NATIVE]]
178180
// CHECK: [[NATIVE:%.*]] = unchecked_enum_data [[OPT_NATIVE]]
179181
// CHECK: [[STRING_TO_NSSTRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString
180-
// CHECK: [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[NATIVE]])
182+
// CHECK: [[BORROWED_NATIVE:%.*]] = begin_borrow [[NATIVE]]
183+
// CHECK: [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_NATIVE]])
181184
// CHECK: = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
185+
// CHECK: end_borrow [[BORROWED_NATIVE]] from [[NATIVE]]
182186
// CHECK: bb3([[OPT_BRIDGED:%.*]] : $Optional<NSString>):
183187
// CHECK: apply [[SET_BAR]]([[OPT_BRIDGED]])
184188
// CHECK: destroy_value [[OPT_BRIDGED]]

test/SILGen/objc_bridging_any.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,12 @@ func passingToNullableId<T: CP, U>(receiver: NSIdLover,
346346
// CHECK: cond_br
347347
// CHECK: [[STRING_DATA:%.*]] = unchecked_enum_data [[OPT_STRING_COPY]]
348348
// CHECK: [[BRIDGE_STRING:%.*]] = function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
349-
// CHECK: [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[STRING_DATA]])
349+
// CHECK: [[BORROWED_STRING_DATA:%.*]] = begin_borrow [[STRING_DATA]]
350+
// CHECK: [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_DATA]])
350351
// CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
351352
// CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
353+
// CHECK: end_borrow [[BORROWED_STRING_DATA]] from [[STRING_DATA]]
354+
// CHECK: destroy_value [[STRING_DATA]]
352355
// CHECK: br [[JOIN:bb.*]]([[OPT_ANYOBJECT]]
353356
// CHECK: [[JOIN]]([[PHI:%.*]] : $Optional<AnyObject>):
354357
// CHECK: apply [[METHOD]]([[PHI]], [[SELF]])

test/SILGen/objc_currying.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ func curry_bridged(_ x: CurryTest) -> (String!) -> String! {
5959
// CHECK: bb1:
6060
// CHECK: [[STRING:%.*]] = unchecked_enum_data [[OPT_STRING]]
6161
// CHECK: [[BRIDGING_FUNC:%.*]] = function_ref @_T0SS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
62-
// CHECK: [[NSSTRING:%.*]] = apply [[BRIDGING_FUNC]]([[STRING]])
62+
// CHECK: [[BORROWED_STRING:%.*]] = begin_borrow [[STRING]]
63+
// CHECK: [[NSSTRING:%.*]] = apply [[BRIDGING_FUNC]]([[BORROWED_STRING]])
6364
// CHECK: [[OPT_NSSTRING:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NSSTRING]] : $NSString
65+
// CHECK: end_borrow [[BORROWED_STRING]] from [[STRING]]
6466
// CHECK: destroy_value [[STRING]]
6567
// CHECK: br bb3([[OPT_NSSTRING]] : $Optional<NSString>)
6668

test/SILGen/vtable_thunks.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,9 @@ class F: D {
104104

105105
// CHECK: [[SOME_BB]]:
106106
// CHECK: [[UNWRAP_Y:%.*]] = unchecked_enum_data [[Y]]
107-
// SEMANTIC SIL TODO: The copy on the next line is not needed and should be
108-
// removed when we use switch enum arguments.
109-
// CHECK: [[COPIED_UNWRAP_Y:%.*]] = copy_value [[UNWRAP_Y]]
110107
// CHECK: [[THUNK_FUNC:%.*]] = function_ref @_T013vtable_thunks1DC3iuo{{.*}}
111-
// CHECK: [[RES:%.*]] = apply [[THUNK_FUNC]]([[WRAP_X]], [[COPIED_UNWRAP_Y]], [[Z]], [[W]])
108+
// CHECK: [[RES:%.*]] = apply [[THUNK_FUNC]]([[WRAP_X]], [[UNWRAP_Y]], [[Z]], [[W]])
112109
// CHECK: [[WRAP_RES:%.*]] = enum $Optional<B>, {{.*}} [[RES]]
113-
// CHECK: destroy_value [[UNWRAP_Y]]
114110
// CHECK: return [[WRAP_RES]]
115111

116112
// CHECK-LABEL: sil private @_T013vtable_thunks1DC1g{{[_0-9a-zA-Z]*}}FTV

0 commit comments

Comments
 (0)