Skip to content

Commit 1b0df4e

Browse files
authored
[SILGen] Fix a crash when a closure is converted to a pointer to a function returning a non-trivial C++ type (#73561)
When emitting a native-to-foreign thunk, pass the thunk's result address parameter to the native function if both the thunk and the native function return their results indirectly and the thunk is not for an async function. Also, remove an outdated assertion. rdar://124501345
1 parent cb1605f commit 1b0df4e

File tree

4 files changed

+58
-22
lines changed

4 files changed

+58
-22
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,8 +1331,8 @@ static SILFunctionType *
13311331
emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk,
13321332
SmallVectorImpl<SILValue> &args,
13331333
SILValue &foreignErrorSlot, SILValue &foreignAsyncSlot,
1334-
std::optional<ForeignErrorConvention> &foreignError,
1335-
std::optional<ForeignAsyncConvention> &foreignAsync,
1334+
std::optional<ForeignErrorConvention> foreignError,
1335+
std::optional<ForeignAsyncConvention> foreignAsync,
13361336
CanType &nativeFormalResultTy,
13371337
CanType &bridgedFormalResultTy) {
13381338
SILDeclRef native = thunk.asForeign(false);
@@ -1355,18 +1355,6 @@ emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk,
13551355
SmallVector<ManagedValue, 8> bridgedArgs;
13561356
bridgedArgs.reserve(objcFnTy->getParameters().size());
13571357

1358-
// Find the foreign error and async conventions if we have one.
1359-
if (thunk.hasDecl()) {
1360-
if (auto func = dyn_cast<AbstractFunctionDecl>(thunk.getDecl())) {
1361-
foreignError = func->getForeignErrorConvention();
1362-
foreignAsync = func->getForeignAsyncConvention();
1363-
}
1364-
}
1365-
1366-
// We don't know what to do with indirect results from the Objective-C side.
1367-
assert(objcFnTy->getNumIndirectFormalResults() == 0
1368-
&& "Objective-C methods cannot have indirect results");
1369-
13701358
auto bridgedFormalTypes = getParameterTypes(objcFormalFnTy.getParams());
13711359
bridgedFormalResultTy = objcFormalFnTy.getResult();
13721360

@@ -1618,16 +1606,40 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
16181606
}
16191607
}
16201608

1609+
std::optional<ForeignErrorConvention> foreignError;
1610+
std::optional<ForeignAsyncConvention> foreignAsync;
1611+
1612+
// Find the foreign error and async conventions if we have one.
1613+
if (thunk.hasDecl()) {
1614+
if (auto func = dyn_cast<AbstractFunctionDecl>(thunk.getDecl())) {
1615+
foreignError = func->getForeignErrorConvention();
1616+
foreignAsync = func->getForeignAsyncConvention();
1617+
}
1618+
}
1619+
16211620
// If we are bridging a Swift method with Any return value(s), create a
16221621
// stack allocation to hold the result(s), since Any is address-only.
16231622
SmallVector<SILValue, 4> args;
1623+
SILFunctionConventions funcConv = F.getConventions();
1624+
bool needsBridging = true;
16241625
if (substConv.hasIndirectSILResults()) {
16251626
for (auto result : substConv.getResults()) {
16261627
if (!substConv.isSILIndirect(result)) {
16271628
continue;
16281629
}
1630+
1631+
if (!foreignAsync && funcConv.hasIndirectSILResults()) {
1632+
auto resultTy =
1633+
funcConv.getSingleSILResultType(getTypeExpansionContext());
1634+
assert(substConv.getSingleSILResultType(getTypeExpansionContext()) ==
1635+
resultTy);
1636+
args.push_back(F.begin()->createFunctionArgument(resultTy));
1637+
needsBridging = false;
1638+
break;
1639+
}
1640+
16291641
args.push_back(emitTemporaryAllocation(
1630-
loc, substConv.getSILType(result, getTypeExpansionContext())));
1642+
loc, substConv.getSILType(result, getTypeExpansionContext())));
16311643
}
16321644
}
16331645

@@ -1637,8 +1649,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
16371649
Scope argScope(Cleanups, CleanupLocation(loc));
16381650

16391651
// Bridge the arguments.
1640-
std::optional<ForeignErrorConvention> foreignError;
1641-
std::optional<ForeignAsyncConvention> foreignAsync;
16421652
SILValue foreignErrorSlot;
16431653
SILValue foreignAsyncSlot;
16441654
CanType nativeFormalResultType, bridgedFormalResultType;
@@ -1872,12 +1882,14 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
18721882
if (foreignAsync) {
18731883
result = passResultToCompletionHandler(result);
18741884
} else {
1875-
if (substConv.hasIndirectSILResults()) {
1876-
assert(substTy->getNumResults() == 1);
1877-
result = args[0];
1885+
if (needsBridging) {
1886+
if (substConv.hasIndirectSILResults()) {
1887+
assert(substTy->getNumResults() == 1);
1888+
result = args[0];
1889+
}
1890+
result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType,
1891+
bridgedFormalResultType, objcResultTy);
18781892
}
1879-
result = emitBridgeReturnValue(*this, loc, result, nativeFormalResultType,
1880-
bridgedFormalResultType, objcResultTy);
18811893
}
18821894
} else {
18831895
SILBasicBlock *contBB = createBasicBlock();

test/Interop/Cxx/class/Inputs/closure.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ void cfuncARCStrong(void (*_Nonnull)(ARCStrong));
2121
#endif
2222

2323
void cfuncReturnNonTrivial(NonTrivial (^_Nonnull)()) noexcept;
24+
void cfuncReturnNonTrivial2(NonTrivial (*_Nonnull)()) noexcept;
2425

2526
#endif // __CLOSURE__
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-irgen %s | %FileCheck %s
2+
3+
// REQUIRES: OS=macosx || OS=linux-android
4+
5+
import Closure
6+
7+
// CHECK: define internal void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To"(ptr noalias sret(%{{.*}}) %[[V0:.*]])
8+
// CHECK: call swiftcc void @"$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_"(ptr noalias sret(%{{.*}}) %[[V0]])
9+
// CHECK: ret void
10+
11+
public func testClosureToFuncPtrReturnNonTrivial() {
12+
cfuncReturnNonTrivial2({() -> NonTrivial in return NonTrivial()});
13+
}

test/Interop/Cxx/class/closure-thunk.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ import Closure
1919
public func testClosureToFuncPtr() {
2020
cfunc2({N in})
2121
}
22+
23+
// CHECK: sil private [thunk] [ossa] @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_To : $@convention(c) () -> @out NonTrivial {
24+
// CHECK: bb0(%[[V0:.*]] : $*NonTrivial):
25+
// CHECK: %[[V1:.*]] = function_ref @$s4main36testClosureToFuncPtrReturnNonTrivialyyFSo0hI0VycfU_ : $@convention(thin) () -> @out NonTrivial
26+
// CHECK: %[[V2:.*]] = apply %[[V1]](%[[V0]]) : $@convention(thin) () -> @out NonTrivial
27+
// CHECK: return %[[V2]] : $()
28+
29+
public func testClosureToFuncPtrReturnNonTrivial() {
30+
cfuncReturnNonTrivial2({() -> NonTrivial in return NonTrivial()});
31+
}

0 commit comments

Comments
 (0)