[SILGen] Account for an implicit isolation parameter while emitting native->foreign thunk arguments

This is an "off-by-one" error because the code to emit bridged
arguments didn't account for the fact that "native" function
type can have a leading implicit isolation parameter if declaration
is `nonisolated(nonsending)`.

Resolves: rdar://164561176
This commit is contained in:
Pavel Yaskevich
2025-11-24 10:55:49 -08:00
parent d1227fb693
commit cfb11a3f4d
2 changed files with 49 additions and 1 deletions

View File

@@ -1438,11 +1438,12 @@ emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk,
// Bridge the input types.
assert(bridgedArgs.size() == nativeInputs.size() - bool(nativeInputsHasImplicitIsolatedParam));
for (unsigned i = 0, size = bridgedArgs.size(); i < size; ++i) {
unsigned nativeParamIndex = i + nativeInputsHasImplicitIsolatedParam;
// Consider the bridged values to be "call results" since they're coming
// from potentially nil-unsound ObjC callers.
ManagedValue native = SGF.emitBridgedToNativeValue(
loc, bridgedArgs[i], bridgedFormalTypes[i], nativeFormalTypes[i],
swiftFnTy->getParameters()[i].getSILStorageType(
swiftFnTy->getParameters()[nativeParamIndex].getSILStorageType(
SGF.SGM.M, swiftFnTy, SGF.getTypeExpansionContext()),
SGFContext(),
/*isCallResult*/ true);

View File

@@ -0,0 +1,47 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault -verify %s | %FileCheck %s
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault
// REQUIRES: concurrency
// REQUIRES: objc_interop
import Foundation
class Test: NSObject {
// CHECK: // Test.testExplicit(_:)
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
// CHECK-LABEL: sil hidden [ossa] @$s27nonisolated_nonsending_objc4TestC12testExplicityyySSYbcYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK: // @objc Test.testExplicit(_:)
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
// CHECK-LABEL: sil private [thunk] [ossa] @$s27nonisolated_nonsending_objc4TestC12testExplicityyySSYbcYaFTo : $@convention(objc_method) (@convention(block) @Sendable (NSString) -> (), @convention(block) () -> (), Test) -> ()
// @objc closure #1 in Test.testExplicit(_:)
// CHECK-LABEL: sil shared [thunk] [ossa] @$s27nonisolated_nonsending_objc4TestC12testExplicityyySSYbcYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable (NSString) -> (), @convention(block) () -> (), Test) -> () {
// CHECK: [[ACTOR:%.*]] = enum $Optional<any Actor>, #Optional.none!enumelt
// CHECK: [[BUILTIN_ACTOR:%.*]] = unchecked_value_cast [[ACTOR]] to $Builtin.ImplicitActor
// CHECK: [[TEST_EXPLICIT_REF:%.*]] = function_ref @$s27nonisolated_nonsending_objc4TestC12testExplicityyySSYbcYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK-NEXT: apply [[TEST_EXPLICIT_REF]]([[BUILTIN_ACTOR]], {{.*}}) : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK: } // end sil function '$s27nonisolated_nonsending_objc4TestC12testExplicityyySSYbcYaFyyYacfU_To'
@objc nonisolated(nonsending) func testExplicit(_: @Sendable @escaping (String) -> Void) async {
}
// CHECK: // Test.testImplicit(_:)
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
// CHECK-LABEL: sil hidden [ossa] @$s27nonisolated_nonsending_objc4TestC12testImplicityyySSYbcYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK: // @objc Test.testImplicit(_:)
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
// CHECK-LABEL: sil private [thunk] [ossa] @$s27nonisolated_nonsending_objc4TestC12testImplicityyySSYbcYaFTo : $@convention(objc_method) (@convention(block) @Sendable (NSString) -> (), @convention(block) () -> (), Test) -> ()
// @objc closure #1 in Test.testImplicit(_:)
// CHECK-LABEL: sil shared [thunk] [ossa] @$s27nonisolated_nonsending_objc4TestC12testImplicityyySSYbcYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable (NSString) -> (), @convention(block) () -> (), Test) -> () {
// CHECK: [[ACTOR:%.*]] = enum $Optional<any Actor>, #Optional.none!enumelt
// CHECK: [[BUILTIN_ACTOR:%.*]] = unchecked_value_cast [[ACTOR]] to $Builtin.ImplicitActor
// CHECK: [[TEST_IMPLICIT_REF:%.*]] = function_ref @$s27nonisolated_nonsending_objc4TestC12testImplicityyySSYbcYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK-NEXT: apply [[TEST_IMPLICIT_REF]]([[BUILTIN_ACTOR]], {{.*}}) : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed @Sendable @callee_guaranteed (@guaranteed String) -> (), @guaranteed Test) -> ()
// CHECK: } // end sil function '$s27nonisolated_nonsending_objc4TestC12testImplicityyySSYbcYaFyyYacfU_To'
@objc func testImplicit(_: @Sendable @escaping (String) -> Void) async {
}
}