Skip to content

Commit 2b4f85e

Browse files
Merge pull request swiftlang#74577 from swiftlang/closure-to-fp-indirect-return
[SILGen] Fix a crash when a closure is converted to a pointer to a function returning a non-trivial C++ type
2 parents 09d8d49 + 3ed000a commit 2b4f85e

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)