mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is necessary because we need to model its stack-allocation behavior, although I'm not yet doing that in this patch because StackNesting first needs to be taught to not try to move the deallocation. I'm not convinced that `async let` *should* be doing a stack allocation, but it undoubtedly *is* doing a stack allocation, and until we have an alternative to that, we will need to model it properly.
468 lines
26 KiB
Plaintext
468 lines
26 KiB
Plaintext
// RUN: %target-sil-opt -send-non-sendable -strict-concurrency=complete %s -o /dev/null -verify
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: asserts
|
|
|
|
// PLEASE READ THIS!
|
|
//
|
|
// This test is specifically meant for small test cases that come from bugs that
|
|
// do not categorize by a specific category. If this gets too big, please split
|
|
// sections of tests out if possible.
|
|
|
|
sil_stage raw
|
|
|
|
import Swift
|
|
import Builtin
|
|
import _Concurrency
|
|
|
|
////////////////////////
|
|
// MARK: Declarations //
|
|
////////////////////////
|
|
|
|
class Klass {}
|
|
|
|
class NonSendableKlass { // expected-note 4{{}}
|
|
var klass: Klass
|
|
|
|
func asyncCall() async
|
|
|
|
@MainActor static func getValue() -> sending NonSendableKlass
|
|
}
|
|
|
|
sil @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
sil @useNonSendableKlass : $@convention(thin) (@guaranteed NonSendableKlass) -> ()
|
|
sil @useNonSendableKlassAsync : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
sil @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
|
|
sil @useUnmanagedNonSendableKlass : $@convention(thin) (@guaranteed @sil_unmanaged NonSendableKlass) -> ()
|
|
sil @constructNonSendableKlassAsync : $@convention(thin) @async () -> @owned NonSendableKlass
|
|
sil @constructNonSendableKlassAsyncSending : $@convention(thin) @async () -> @sil_sending @owned NonSendableKlass
|
|
|
|
final class SendableKlass : Sendable {}
|
|
|
|
sil @transferSendableKlass : $@convention(thin) @async (@guaranteed SendableKlass) -> ()
|
|
sil @constructSendableKlass : $@convention(thin) () -> @owned SendableKlass
|
|
|
|
final class KlassContainingKlasses {
|
|
let nsImmutable : NonSendableKlass
|
|
var nsMutable : NonSendableKlass
|
|
let sImmutable : SendableKlass
|
|
var sMutable : SendableKlass
|
|
}
|
|
|
|
sil @transferKlassContainingKlasses : $@convention(thin) @async (@guaranteed KlassContainingKlasses) -> ()
|
|
sil @useKlassContainingKlasses : $@convention(thin) (@guaranteed KlassContainingKlasses) -> ()
|
|
sil @constructKlassContainingKlasses : $@convention(thin) () -> @owned KlassContainingKlasses
|
|
|
|
struct NonSendableMoveOnlyStruct: ~Copyable {
|
|
var ns: NonSendableKlass
|
|
|
|
deinit
|
|
}
|
|
|
|
sil @constructMoveOnlyStruct : $@convention(thin) () -> @owned NonSendableMoveOnlyStruct
|
|
sil @transferMoveOnlyStruct : $@convention(thin) @async (@guaranteed NonSendableMoveOnlyStruct) -> ()
|
|
|
|
struct NonSendableStruct {
|
|
var ns: NonSendableKlass
|
|
}
|
|
|
|
sil @constructStruct : $@convention(thin) () -> @owned NonSendableStruct
|
|
sil @transferStruct : $@convention(thin) @async (@guaranteed NonSendableStruct) -> ()
|
|
|
|
sil @transferRawPointer : $@convention(thin) @async (Builtin.RawPointer) -> ()
|
|
sil @useRawPointer : $@convention(thin) (Builtin.RawPointer) -> ()
|
|
sil @initRawPointer : $@convention(thin) () -> Builtin.RawPointer
|
|
|
|
sil @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
sil @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
|
|
sil @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
sil @initIndirect : $@convention(thin) <T> () -> @out T
|
|
sil @initIndirectTransferring : $@convention(thin) @async <T> () -> @out T
|
|
sil @initIndirectTransferringError : $@convention(thin) @async <T> () -> (@out Optional<T>, @error any Error)
|
|
|
|
enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
sil @swift_asyncLet_get : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
|
|
|
|
@MainActor
|
|
struct MainActorIsolatedStruct {
|
|
let ns: NonSendableKlass
|
|
}
|
|
|
|
@MainActor
|
|
enum MainActorIsolatedEnum {
|
|
case first
|
|
case second(NonSendableKlass)
|
|
}
|
|
|
|
actor MyActor {
|
|
var klass: NonSendableKlass { get set }
|
|
}
|
|
|
|
sil @beginApplyMultipleResultCallee : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
|
|
|
|
/////////////////
|
|
// MARK: Tests //
|
|
/////////////////
|
|
|
|
// This goes through the access projection code differently from normal
|
|
// project_box since we do not see the alloc_box.
|
|
sil [ossa] @project_box_loadable_test_case : $@convention(thin) @async (@in { var NonSendableKlass }) -> () {
|
|
bb0(%0 : $*{ var NonSendableKlass }):
|
|
%1 = load [take] %0 : $*{ var NonSendableKlass }
|
|
%3 = project_box %1 : ${ var NonSendableKlass }, 0
|
|
|
|
%f = function_ref @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f<NonSendableKlass>(%3) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
// expected-warning @-1 {{}}
|
|
// expected-note @-2 {{}}
|
|
destroy_value %1 : ${ var NonSendableKlass }
|
|
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @transfer_does_not_transfer_out_parameters_1 : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $NonSendableKlass
|
|
%init = function_ref @initIndirect : $@convention(thin) <T> () -> @out T
|
|
apply %init<NonSendableKlass>(%0) : $@convention(thin) <T> () -> @out T
|
|
|
|
%1 = alloc_stack $NonSendableKlass
|
|
%f = function_ref @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f<NonSendableKlass>(%1, %0) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 // expected-warning {{}}
|
|
|
|
%useIndirect = function_ref @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
apply %useIndirect<NonSendableKlass>(%1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
|
|
destroy_addr %1 : $*NonSendableKlass
|
|
dealloc_stack %1 : $*NonSendableKlass
|
|
destroy_addr %0 : $*NonSendableKlass
|
|
dealloc_stack %0 : $*NonSendableKlass
|
|
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @transfer_does_not_transfer_out_parameters_2 : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $NonSendableKlass
|
|
%init = function_ref @initIndirect : $@convention(thin) <T> () -> @out T
|
|
apply %init<NonSendableKlass>(%0) : $@convention(thin) <T> () -> @out T
|
|
|
|
%1 = alloc_stack $NonSendableKlass
|
|
%f = function_ref @transferIndirectWithOutResult : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f<NonSendableKlass>(%1, %0) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 // expected-warning {{}}
|
|
|
|
// We do not error here on use after send since %1 is already isolated to the
|
|
// same global actor as transferIndirect which is not considered to be a
|
|
// send. We leave the actual error to be the error about returning an isolated
|
|
// value into a non-isolated context.
|
|
%f2 = function_ref @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %f2<NonSendableKlass>(%1) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
%useIndirect = function_ref @useIndirect : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
apply %useIndirect<NonSendableKlass>(%1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
|
|
destroy_addr %1 : $*NonSendableKlass
|
|
dealloc_stack %1 : $*NonSendableKlass
|
|
destroy_addr %0 : $*NonSendableKlass
|
|
dealloc_stack %0 : $*NonSendableKlass
|
|
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil @implicitClosure : $@convention(thin) @Sendable @async @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass>
|
|
|
|
sil [ossa] @asyncLetWithThinToThickFunction : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = enum $Optional<Builtin.Executor>, #Optional.none!enumelt
|
|
hop_to_executor %0 : $Optional<Builtin.Executor>
|
|
%2 = alloc_stack $NonSendableKlass
|
|
%3 = address_to_pointer %2 : $*NonSendableKlass to $Builtin.RawPointer
|
|
%4 = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
|
|
%5 = function_ref @implicitClosure : $@convention(thin) @Sendable @async @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass>
|
|
%6 = convert_function %5 : $@convention(thin) @Sendable @async @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass> to $@convention(thin) @async @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass>
|
|
%7 = thin_to_thick_function %6 : $@convention(thin) @async @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass> to $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass>
|
|
%8 = builtin "startAsyncLetWithLocalBuffer"<NonSendableKlass>(%4 : $Optional<Builtin.RawPointer>, %7 : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <NonSendableKlass>, %3 : $Builtin.RawPointer) : $Builtin.RawPointer
|
|
%9 = function_ref @swift_asyncLet_get : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
|
|
%10 = apply %9(%8, %3) : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
|
|
hop_to_executor %0 : $Optional<Builtin.Executor>
|
|
%12 = load [copy] %2 : $*NonSendableKlass
|
|
destroy_value %12 : $NonSendableKlass
|
|
%15 = builtin "finishAsyncLet"(%8, %3) : $()
|
|
hop_to_executor %0 : $Optional<Builtin.Executor>
|
|
%17 = builtin "endAsyncLetLifetime"(%8 : $Builtin.RawPointer) : $()
|
|
dealloc_stack %2 : $*NonSendableKlass
|
|
%19 = tuple ()
|
|
return %19 : $()
|
|
}
|
|
|
|
// Dead block crasher
|
|
//
|
|
// We used to crash here since we attempted to process /all/ blocks for
|
|
// diagnostic even for non-dead blocks. This is a problem since the dataflow
|
|
// uses a reverse post order traversal to get quick convergence and that skips
|
|
// dead blocks.
|
|
sil [ossa] @dead_block_crasher : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
|
|
%1 = apply %0() : $@convention(thin) () -> @owned NonSendableKlass
|
|
br bb1
|
|
|
|
bbDeadBlock:
|
|
%transfer = function_ref @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transfer(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
br bb1
|
|
|
|
bb1:
|
|
destroy_value %1 : $NonSendableKlass
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring : $@convention(method) (@guaranteed NonSendableStruct) -> @sil_sending @owned NonSendableKlass {
|
|
bb0(%0 : @guaranteed $NonSendableStruct):
|
|
debug_value %0 : $NonSendableStruct, var, name "myname"
|
|
%2 = struct_extract %0 : $NonSendableStruct, #NonSendableStruct.ns
|
|
%3 = copy_value %2 : $NonSendableKlass
|
|
return %3 : $NonSendableKlass // expected-warning {{sending 'myname.ns' risks causing data races}}
|
|
// expected-note @-1 {{task-isolated 'myname.ns' cannot be a 'sending' result. task-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring_globalactor_struct_structextract : $@convention(method) (@guaranteed MainActorIsolatedStruct) -> @sil_sending @owned NonSendableKlass {
|
|
bb0(%0 : @guaranteed $MainActorIsolatedStruct):
|
|
debug_value %0 : $MainActorIsolatedStruct, var, name "myname"
|
|
%2 = struct_extract %0 : $MainActorIsolatedStruct, #MainActorIsolatedStruct.ns
|
|
%3 = copy_value %2 : $NonSendableKlass
|
|
return %3 : $NonSendableKlass // expected-warning {{sending 'myname.ns' risks causing data races}}
|
|
// expected-note @-1 {{main actor-isolated 'myname.ns' cannot be a 'sending' result. main actor-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring_globalactor_struct_structelementaddr : $@convention(method) (@in_guaranteed MainActorIsolatedStruct) -> @sil_sending @owned NonSendableKlass {
|
|
bb0(%0 : $*MainActorIsolatedStruct):
|
|
debug_value %0 : $*MainActorIsolatedStruct, var, name "myname"
|
|
%2 = struct_element_addr %0 : $*MainActorIsolatedStruct, #MainActorIsolatedStruct.ns
|
|
%3 = load [copy] %2 : $*NonSendableKlass
|
|
return %3 : $NonSendableKlass // expected-warning {{sending 'myname.ns' risks causing data races}}
|
|
// expected-note @-1 {{main actor-isolated 'myname.ns' cannot be a 'sending' result. main actor-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring_globalactor_enum_uncheckedenumdata : $@convention(method) (@guaranteed MainActorIsolatedEnum) -> @sil_sending @owned NonSendableKlass {
|
|
bb0(%0 : @guaranteed $MainActorIsolatedEnum):
|
|
debug_value %0 : $MainActorIsolatedEnum, var, name "myname"
|
|
%2 = unchecked_enum_data %0 : $MainActorIsolatedEnum, #MainActorIsolatedEnum.second!enumelt
|
|
%3 = copy_value %2 : $NonSendableKlass
|
|
return %3 : $NonSendableKlass // expected-warning {{sending 'myname.second' risks causing data races}}
|
|
// expected-note @-1 {{main actor-isolated 'myname.second' cannot be a 'sending' result. main actor-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring_globalactor_enum_uncheckedtakeenumdataaddr : $@convention(method) (@in MainActorIsolatedEnum) -> @sil_sending @owned NonSendableKlass {
|
|
bb0(%0 : $*MainActorIsolatedEnum):
|
|
debug_value %0 : $*MainActorIsolatedEnum, var, name "myname"
|
|
%2 = unchecked_take_enum_data_addr %0 : $*MainActorIsolatedEnum, #MainActorIsolatedEnum.second!enumelt
|
|
%3 = load [take] %2 : $*NonSendableKlass
|
|
return %3 : $NonSendableKlass // expected-warning {{sending 'myname.second' risks causing data races}}
|
|
// expected-note @-1 {{main actor-isolated 'myname.second' cannot be a 'sending' result. main actor-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @synchronous_returns_transferring_globalactor_enum_switchenum : $@convention(method) (@guaranteed MainActorIsolatedEnum) -> @sil_sending @owned FakeOptional<NonSendableKlass> {
|
|
bb0(%0 : @guaranteed $MainActorIsolatedEnum):
|
|
debug_value %0 : $MainActorIsolatedEnum, var, name "myname"
|
|
switch_enum %0 : $MainActorIsolatedEnum, case #MainActorIsolatedEnum.first!enumelt: bb1, case #MainActorIsolatedEnum.second!enumelt: bb2
|
|
|
|
bb1:
|
|
%nil = enum $FakeOptional<NonSendableKlass>, #FakeOptional.none!enumelt
|
|
br bb3(%nil : $FakeOptional<NonSendableKlass>)
|
|
|
|
bb2(%1 : @guaranteed $NonSendableKlass):
|
|
%2 = copy_value %1 : $NonSendableKlass
|
|
%3 = enum $FakeOptional<NonSendableKlass>, #FakeOptional.some!enumelt, %2 : $NonSendableKlass
|
|
br bb3(%3 : $FakeOptional<NonSendableKlass>)
|
|
|
|
bb3(%4 : @owned $FakeOptional<NonSendableKlass>):
|
|
return %4 : $FakeOptional<NonSendableKlass> // expected-warning {{sending 'myname.some' risks causing data races}}
|
|
// expected-note @-1 {{main actor-isolated 'myname.some' cannot be a 'sending' result. main actor-isolated uses may race with caller uses}}
|
|
}
|
|
|
|
sil [ossa] @warningIfCallingGetter : $@convention(method) @async (@sil_isolated @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
debug_value %0 : $MyActor, let, name "self", argno 1
|
|
hop_to_executor %0 : $MyActor
|
|
%3 = class_method %0 : $MyActor, #MyActor.klass!getter : (isolated MyActor) -> () -> NonSendableKlass, $@convention(method) (@sil_isolated @guaranteed MyActor) -> @owned NonSendableKlass
|
|
%4 = apply %3(%0) : $@convention(method) (@sil_isolated @guaranteed MyActor) -> @owned NonSendableKlass
|
|
%5 = class_method %4 : $NonSendableKlass, #NonSendableKlass.asyncCall : (NonSendableKlass) -> () async -> (), $@convention(method) @async (@guaranteed NonSendableKlass) -> ()
|
|
%6 = apply [caller_isolation=nonisolated] [callee_isolation=actor_instance] %5(%4) : $@convention(method) @async (@guaranteed NonSendableKlass) -> () // expected-warning {{}}
|
|
// expected-note @-1 {{}}
|
|
destroy_value %4 : $NonSendableKlass
|
|
hop_to_executor %0 : $MyActor
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
sil [ossa] @assignIntoSetter : $@convention(method) @async (@sil_isolated @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
debug_value %0 : $MyActor, let, name "self", argno 1
|
|
hop_to_executor %0 : $MyActor
|
|
%4 = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
|
|
%5 = apply %4() : $@convention(thin) () -> @owned NonSendableKlass
|
|
%6 = move_value [lexical] [var_decl] %5 : $NonSendableKlass
|
|
debug_value %6 : $NonSendableKlass, let, name "x"
|
|
%8 = copy_value %6 : $NonSendableKlass
|
|
%9 = class_method %0 : $MyActor, #MyActor.klass!setter : (isolated MyActor) -> (NonSendableKlass) -> (), $@convention(method) (@owned NonSendableKlass, @sil_isolated @guaranteed MyActor) -> ()
|
|
%10 = apply %9(%8, %0) : $@convention(method) (@owned NonSendableKlass, @sil_isolated @guaranteed MyActor) -> ()
|
|
%11 = alloc_stack $NonSendableKlass
|
|
%12 = store_borrow %6 to %11 : $*NonSendableKlass
|
|
%13 = function_ref @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
%14 = apply [caller_isolation=actor_instance] [callee_isolation=global_actor] %13<NonSendableKlass>(%12) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> () // expected-warning {{}}
|
|
// expected-note @-1 {{}}
|
|
end_borrow %12 : $*NonSendableKlass
|
|
dealloc_stack %11 : $*NonSendableKlass
|
|
hop_to_executor %0 : $MyActor
|
|
destroy_value %6 : $NonSendableKlass
|
|
%19 = tuple ()
|
|
return %19 : $()
|
|
}
|
|
|
|
sil @sendableAsyncLetClosure : $@convention(thin) @Sendable @async @substituted <τ_0_0> (@guaranteed NonSendableKlass) -> (@out τ_0_0, @error any Error) for <Int>
|
|
|
|
sil [ossa] @sendableAsyncLetClosureTest : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%3 = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass
|
|
%4 = apply %3() : $@convention(thin) () -> @owned NonSendableKlass
|
|
%5 = move_value [lexical] [var_decl] %4 : $NonSendableKlass
|
|
debug_value %5 : $NonSendableKlass, let, name "x"
|
|
%7 = alloc_stack $Int
|
|
%8 = address_to_pointer %7 : $*Int to $Builtin.RawPointer
|
|
%9 = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
|
|
%10 = function_ref @sendableAsyncLetClosure : $@convention(thin) @Sendable @async @substituted <τ_0_0> (@guaranteed NonSendableKlass) -> (@out τ_0_0, @error any Error) for <Int>
|
|
%11 = copy_value %5 : $NonSendableKlass
|
|
%12 = partial_apply [callee_guaranteed] %10(%11) : $@convention(thin) @Sendable @async @substituted <τ_0_0> (@guaranteed NonSendableKlass) -> (@out τ_0_0, @error any Error) for <Int>
|
|
%13 = convert_function %12 : $@Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int> to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int>
|
|
%14 = convert_escape_to_noescape [not_guaranteed] %13 : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int> to $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int>
|
|
%15 = builtin "startAsyncLetWithLocalBuffer"<Int>(%9 : $Optional<Builtin.RawPointer>, %14 : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int>, %8 : $Builtin.RawPointer) : $Builtin.RawPointer
|
|
|
|
%useValue = function_ref @useNonSendableKlass : $@convention(thin) (@guaranteed NonSendableKlass) -> ()
|
|
apply %useValue(%5) : $@convention(thin) (@guaranteed NonSendableKlass) -> ()
|
|
|
|
%26 = function_ref @swift_asyncLet_get : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
|
|
%27 = apply %26(%15, %8) : $@convention(thin) @async (Builtin.RawPointer, Builtin.RawPointer) -> ()
|
|
%29 = load [trivial] %7 : $*Int
|
|
%31 = builtin "finishAsyncLet"(%15, %8) : $()
|
|
%33 = builtin "endAsyncLetLifetime"(%15 : $Builtin.RawPointer) : $()
|
|
destroy_value %14 : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int>
|
|
destroy_value %13 : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Int>
|
|
dealloc_stack %7 : $*Int
|
|
destroy_value %5 : $NonSendableKlass
|
|
%38 = tuple ()
|
|
return %38 : $()
|
|
}
|
|
|
|
// Make sure that when we process the following sil we do not crash.
|
|
//
|
|
// We previously crashed since we used the base of the storage instead of the
|
|
// operand of the root (the ref_element_addr)
|
|
sil [ossa] @test_ref_element_addr_with_different_storage_no_crash : $@convention(method) <Self where Self : NonSendableKlass> (@guaranteed Self) -> () {
|
|
bb0(%0 : @guaranteed $Self):
|
|
%1 = copy_value %0 : $Self
|
|
%2 = upcast %1 : $Self to $NonSendableKlass
|
|
%3 = begin_borrow %2 : $NonSendableKlass
|
|
%4 = ref_element_addr [immutable] %3 : $NonSendableKlass, #NonSendableKlass.klass
|
|
%5 = load [copy] %4 : $*Klass
|
|
destroy_value %5 : $Klass
|
|
end_borrow %3 : $NonSendableKlass
|
|
destroy_value %2 : $NonSendableKlass
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @sending_direct_result_from_callee : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = function_ref @constructNonSendableKlassAsyncSending : $@convention(thin) @async () -> @sil_sending @owned NonSendableKlass
|
|
%1 = apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %0() : $@convention(thin) @async () -> @sil_sending @owned NonSendableKlass
|
|
|
|
%useValue = function_ref @useNonSendableKlassAsync : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
apply [caller_isolation=nonisolated] [callee_isolation=actor_instance] %useValue(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
destroy_value %1
|
|
|
|
// Double check we actually error without @sil_sending
|
|
%2 = function_ref @constructNonSendableKlassAsync : $@convention(thin) @async () -> @owned NonSendableKlass
|
|
%3 = apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %2() : $@convention(thin) @async () -> @owned NonSendableKlass
|
|
// expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from global actor '<null>'-isolated function to nonisolated context}}
|
|
|
|
apply [caller_isolation=nonisolated] [callee_isolation=actor_instance] %useValue(%3) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
// expected-warning @-1 {{sending value of non-Sendable type 'NonSendableKlass' risks causing data races}}
|
|
// expected-note @-2 {{}}
|
|
|
|
destroy_value %3
|
|
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @sending_direct_result_from_callee_2 : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = function_ref @constructNonSendableKlassAsyncSending : $@convention(thin) @async () -> @sil_sending @owned NonSendableKlass
|
|
%1 = apply [caller_isolation=global_actor] [callee_isolation=global_actor] %0() : $@convention(thin) @async () -> @sil_sending @owned NonSendableKlass
|
|
|
|
%useValue = function_ref @useNonSendableKlassAsync : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
apply [caller_isolation=global_actor] [callee_isolation=actor_instance] %useValue(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
destroy_value %1
|
|
|
|
// Double check we actually error without @sil_sending
|
|
%2 = function_ref @constructNonSendableKlassAsync : $@convention(thin) @async () -> @owned NonSendableKlass
|
|
%3 = apply [caller_isolation=global_actor] [callee_isolation=global_actor] %2() : $@convention(thin) @async () -> @owned NonSendableKlass
|
|
// expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from global actor '<null>'-isolated function to global actor '<null>'-isolated context}}
|
|
|
|
apply [caller_isolation=global_actor] [callee_isolation=actor_instance] %useValue(%3) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> ()
|
|
// expected-warning @-1 {{sending value of non-Sendable type 'NonSendableKlass' risks causing data races}}
|
|
// expected-note @-2 {{}}
|
|
|
|
destroy_value %3
|
|
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
|
|
sil @closureForCheckedContinuation : $@convention(thin) <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()
|
|
sil @withCheckedContinuation : $@convention(thin) @async <τ_0_0> (@sil_isolated @guaranteed Optional<any Actor>, @guaranteed @noescape @callee_guaranteed <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()) -> @sil_sending @out τ_0_0
|
|
|
|
// We shouldn't emit any error here due to sil_sending.
|
|
sil [ossa] @sending_indirect_result_from_callee : $@convention(thin) @async () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $NonSendableKlass
|
|
%1 = function_ref @closureForCheckedContinuation : $@convention(thin) <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()
|
|
%1a = thin_to_thick_function %1 : $@convention(thin) <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> () to $@noescape @callee_guaranteed <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()
|
|
%2 = enum $Optional<any Actor>, #Optional.none!enumelt
|
|
%3 = function_ref @withCheckedContinuation : $@convention(thin) @async <τ_0_0> (@sil_isolated @guaranteed Optional<any Actor>, @guaranteed @noescape @callee_guaranteed <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()) -> @sil_sending @out τ_0_0
|
|
apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %3<NonSendableKlass>(%0, %2, %1a) : $@convention(thin) @async <τ_0_0> (@sil_isolated @guaranteed Optional<any Actor>, @guaranteed @noescape @callee_guaranteed <τ_0_0> (@in_guaranteed CheckedContinuation<τ_0_0, Never>) -> ()) -> @sil_sending @out τ_0_0
|
|
|
|
%f = function_ref @transferIndirect : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
apply [caller_isolation=nonisolated] [callee_isolation=actor_instance] %f<NonSendableKlass>(%0) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
|
|
|
|
destroy_addr %0 : $*NonSendableKlass
|
|
dealloc_stack %0 : $*NonSendableKlass
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Make sure that we do not crash on this.
|
|
//
|
|
// We used to crash on this since we would want to assign the region of an
|
|
// operand to the results... but we do not have one and have multiple
|
|
// results. This doesn't normally happen with most applies since applies do not
|
|
// have multiple results, so in such a case, we would just assign fresh and not
|
|
// try to do the assignment for the rest of the values.
|
|
sil [ossa] @handleNoOperandToAssignToResults : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @beginApplyMultipleResultCallee : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
|
|
(%1, %2, %3) = begin_apply %0() : $@yield_once @convention(thin) () -> (@yields @guaranteed NonSendableKlass, @yields @guaranteed NonSendableKlass)
|
|
end_apply %3 as $()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|