diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index f0f7ba95519a1..3f053210c0528 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1331,8 +1331,8 @@ static SILFunctionType * emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, SmallVectorImpl &args, SILValue &foreignErrorSlot, SILValue &foreignAsyncSlot, - std::optional &foreignError, - std::optional &foreignAsync, + std::optional foreignError, + std::optional foreignAsync, CanType &nativeFormalResultTy, CanType &bridgedFormalResultTy) { SILDeclRef native = thunk.asForeign(false); @@ -1355,18 +1355,6 @@ emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, SmallVector bridgedArgs; bridgedArgs.reserve(objcFnTy->getParameters().size()); - // Find the foreign error and async conventions if we have one. - if (thunk.hasDecl()) { - if (auto func = dyn_cast(thunk.getDecl())) { - foreignError = func->getForeignErrorConvention(); - foreignAsync = func->getForeignAsyncConvention(); - } - } - - // We don't know what to do with indirect results from the Objective-C side. - assert(objcFnTy->getNumIndirectFormalResults() == 0 - && "Objective-C methods cannot have indirect results"); - auto bridgedFormalTypes = getParameterTypes(objcFormalFnTy.getParams()); bridgedFormalResultTy = objcFormalFnTy.getResult(); @@ -1616,16 +1604,40 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { } } + std::optional foreignError; + std::optional foreignAsync; + + // Find the foreign error and async conventions if we have one. + if (thunk.hasDecl()) { + if (auto func = dyn_cast(thunk.getDecl())) { + foreignError = func->getForeignErrorConvention(); + foreignAsync = func->getForeignAsyncConvention(); + } + } + // If we are bridging a Swift method with Any return value(s), create a // stack allocation to hold the result(s), since Any is address-only. SmallVector args; + SILFunctionConventions funcConv = F.getConventions(); + bool needsBridging = true; if (substConv.hasIndirectSILResults()) { for (auto result : substConv.getResults()) { if (!substConv.isSILIndirect(result)) { continue; } + + if (!foreignAsync && funcConv.hasIndirectSILResults()) { + auto resultTy = + funcConv.getSingleSILResultType(getTypeExpansionContext()); + assert(substConv.getSingleSILResultType(getTypeExpansionContext()) == + resultTy); + args.push_back(F.begin()->createFunctionArgument(resultTy)); + needsBridging = false; + break; + } + args.push_back(emitTemporaryAllocation( - loc, substConv.getSILType(result, getTypeExpansionContext()))); + loc, substConv.getSILType(result, getTypeExpansionContext()))); } } @@ -1635,8 +1647,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { Scope argScope(Cleanups, CleanupLocation(loc)); // Bridge the arguments. - std::optional foreignError; - std::optional foreignAsync; SILValue foreignErrorSlot; SILValue foreignAsyncSlot; CanType nativeFormalResultType, bridgedFormalResultType; @@ -1863,12 +1873,14 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { if (foreignAsync) { result = passResultToCompletionHandler(result); } else { - if (substConv.hasIndirectSILResults()) { - assert(substTy->getNumResults() == 1); - result = args[0]; + if (needsBridging) { + if (substConv.hasIndirectSILResults()) { + assert(substTy->getNumResults() == 1); + result = args[0]; + } + result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType, + bridgedFormalResultType, objcResultTy); } - result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType, - bridgedFormalResultType, objcResultTy); } } else { SILBasicBlock *contBB = createBasicBlock(); diff --git a/test/Interop/Cxx/class/Inputs/closure.h b/test/Interop/Cxx/class/Inputs/closure.h index 2b4cf1b098ada..4228b29a26ea3 100644 --- a/test/Interop/Cxx/class/Inputs/closure.h +++ b/test/Interop/Cxx/class/Inputs/closure.h @@ -21,5 +21,6 @@ void cfuncARCStrong(void (*_Nonnull)(ARCStrong)); #endif void cfuncReturnNonTrivial(NonTrivial (^_Nonnull)()) noexcept; +void cfuncReturnNonTrivial2(NonTrivial (*_Nonnull)()) noexcept; #endif // __CLOSURE__ diff --git a/test/Interop/Cxx/class/closure-thunk-irgen.swift b/test/Interop/Cxx/class/closure-thunk-irgen.swift new file mode 100644 index 0000000000000..520c1131d845d --- /dev/null +++ b/test/Interop/Cxx/class/closure-thunk-irgen.swift @@ -0,0 +1,13 @@ +// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-irgen %s | %FileCheck %s + +// REQUIRES: OS=macosx || OS=linux-android + +import Closure + +// CHECK: define internal void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To"(ptr noalias sret(%{{.*}}) %[[V0:.*]]) +// CHECK: call swiftcc void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_"(ptr noalias sret(%{{.*}}) %[[V0]]) +// CHECK: ret void + +public func testClosureToFuncPtrReturnNonTrivial() { + cfuncReturnNonTrivial2({() -> NonTrivial in return NonTrivial()}); +} diff --git a/test/Interop/Cxx/class/closure-thunk.swift b/test/Interop/Cxx/class/closure-thunk.swift index f1fd614d58f49..6a91813d2f325 100644 --- a/test/Interop/Cxx/class/closure-thunk.swift +++ b/test/Interop/Cxx/class/closure-thunk.swift @@ -19,3 +19,13 @@ import Closure public func testClosureToFuncPtr() { cfunc2({N in}) } + +// CHECK: sil private [thunk] [ossa] @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To : $@convention(c) () -> @out NonTrivial { +// CHECK: bb0(%[[V0:.*]] : $*NonTrivial): +// CHECK: %[[V1:.*]] = function_ref @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_ : $@convention(thin) () -> @out NonTrivial +// CHECK: %[[V2:.*]] = apply %[[V1]](%[[V0]]) : $@convention(thin) () -> @out NonTrivial +// CHECK: return %[[V2]] : $() + +public func testClosureToFuncPtrReturnNonTrivial() { + cfuncReturnNonTrivial2({() -> NonTrivial in return NonTrivial()}); +}