mirror of
https://github.com/apple/swift.git
synced 2026-10-16 16:50:49 +02:00
An unconditional cast can recover a different object with an independent reference count. Compute its ownership-preservation flag from the source and destination types, as for checked_cast_br, instead of unconditionally allowing guaranteed forwarding. Keep the source copy and result destruction distinct when the cast does not preserve reference counts, and account for the foreign code and releases it can execute in the instruction and function effects.
89 lines
4.0 KiB
Plaintext
89 lines
4.0 KiB
Plaintext
// RUN: %empty-directory(%t)
|
|
// RUN: %target-swift-frontend -enable-experimental-com-interop -module-name COM -emit-module-path %t/COM.swiftmodule %S/../Inputs/COM.swift
|
|
// RUN: %target-sil-opt -enable-experimental-com-interop -I %t -enable-sil-verify-all -copy-propagation -simplification -simplify-instruction=destroy_value %s | %FileCheck %s
|
|
// RUN: %target-sil-opt -enable-experimental-com-interop -I %t -compute-side-effects %s | %FileCheck %s --check-prefix=EFFECTS
|
|
|
|
sil_stage canonical
|
|
import Swift
|
|
|
|
@com(interface: "10000000-0000-0000-0000-000000000001")
|
|
public protocol ISource: AnyObject {}
|
|
public class NativeBase {}
|
|
public class NativeDerived: NativeBase {}
|
|
|
|
// The cast consumes an interface reference and returns an independent native
|
|
// reference. Destroying the result must not destroy the borrowed source.
|
|
// CHECK-LABEL: sil {{.*}}@recover
|
|
// CHECK: [[COPY:%.*]] = copy_value %0
|
|
// CHECK: [[NATIVE:%.*]] = unconditional_checked_cast [[COPY]]
|
|
// CHECK: destroy_value [[NATIVE]]
|
|
// CHECK: return
|
|
// EFFECTS-LABEL: sil {{.*}}@recover
|
|
// EFFECTS-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.**, destroy v**.c*.v**]
|
|
// EFFECTS-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
sil [ossa] @recover : $@convention(thin) (@guaranteed any ISource) -> () {
|
|
bb0(%source : @guaranteed $any ISource):
|
|
%copy = copy_value %source : $any ISource
|
|
%native = unconditional_checked_cast %copy : $any ISource to NativeBase
|
|
destroy_value %native : $NativeBase
|
|
%unit = tuple ()
|
|
return %unit : $()
|
|
}
|
|
|
|
// Native class casts can continue forwarding a guaranteed reference.
|
|
// CHECK-LABEL: sil {{.*}}@native
|
|
// CHECK-NOT: copy_value
|
|
// CHECK: unconditional_checked_cast
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: return
|
|
sil [ossa] @native : $@convention(thin) (@guaranteed NativeBase) -> () {
|
|
bb0(%source : @guaranteed $NativeBase):
|
|
%copy = copy_value %source : $NativeBase
|
|
%derived = unconditional_checked_cast %copy : $NativeBase to NativeDerived
|
|
destroy_value %derived : $NativeDerived
|
|
%unit = tuple ()
|
|
return %unit : $()
|
|
}
|
|
|
|
// AnyObject can hide a boxed value. Like COM identity recovery, unwrapping it
|
|
// cannot assume the result shares the source's reference count.
|
|
// CHECK-LABEL: sil {{.*}}@unwrap_anyobject
|
|
// CHECK: [[COPY:%.*]] = copy_value %0
|
|
// CHECK: [[NATIVE:%.*]] = unconditional_checked_cast [[COPY]]
|
|
// CHECK: destroy_value [[NATIVE]]
|
|
// CHECK: return
|
|
// EFFECTS-LABEL: sil {{.*}}@unwrap_anyobject
|
|
// EFFECTS-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.**, destroy v**.c*.v**]
|
|
// EFFECTS-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
sil [ossa] @unwrap_anyobject : $@convention(thin) (@guaranteed AnyObject) -> () {
|
|
bb0(%source : @guaranteed $AnyObject):
|
|
%copy = copy_value %source : $AnyObject
|
|
%native = unconditional_checked_cast %copy : $AnyObject to NativeBase
|
|
destroy_value %native : $NativeBase
|
|
%unit = tuple ()
|
|
return %unit : $()
|
|
}
|
|
|
|
// Attribute the cast effects to the field containing the interface, rather
|
|
// than treating the entire argument as having escaped to an unknown user.
|
|
// EFFECTS-LABEL: sil {{.*}}@recover_tuple_element
|
|
// EFFECTS-NEXT: [%0: read 0.v**.c*.v**, write 0.v**.c*.v**, copy 0.v**.**, destroy 0.v**.c*.v**]
|
|
// EFFECTS-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
sil [ossa] @recover_tuple_element : $@convention(thin) (@guaranteed (any ISource, NativeBase)) -> @owned NativeBase {
|
|
bb0(%pair : @guaranteed $(any ISource, NativeBase)):
|
|
%source = tuple_extract %pair : $(any ISource, NativeBase), 0
|
|
%copy = copy_value %source : $any ISource
|
|
%native = unconditional_checked_cast %copy : $any ISource to NativeBase
|
|
return %native : $NativeBase
|
|
}
|
|
|
|
// A native class cast that preserves reference counts has no such effects.
|
|
// EFFECTS-LABEL: sil {{.*}}@borrow_native
|
|
// EFFECTS-NEXT: [global: ]
|
|
sil [ossa] @borrow_native : $@convention(thin) (@guaranteed NativeBase) -> () {
|
|
bb0(%source : @guaranteed $NativeBase):
|
|
%derived = unconditional_checked_cast %source : $NativeBase to NativeDerived
|
|
%unit = tuple ()
|
|
return %unit : $()
|
|
}
|