Skip to content

Commit d0d2c4b

Browse files
authored
[SILGen] Fix a crash when a closure is converted to a block returning a value indirectly (#73967)
Fix the type of the function argument added to the entry basic block. Also, fix the predicate passed to emitEntryPointIndirectReturn so that it returns true only when the result is returned indirectly at the IR level but directly at the SIL level. rdar://127745392
1 parent 370cec6 commit d0d2c4b

File tree

5 files changed

+46
-2
lines changed

5 files changed

+46
-2
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2330,7 +2330,9 @@ static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF,
23302330
// First, claim all the indirect results.
23312331
ArrayRef<SILArgument *> args = emitEntryPointIndirectReturn(
23322332
*emission, IGF, entry, funcTy, [&](SILType directResultType) -> bool {
2333-
return FI.getReturnInfo().isIndirect();
2333+
// Indirect at the IR level but direct at the SIL level.
2334+
return FI.getReturnInfo().isIndirect() &&
2335+
!funcTy->hasIndirectFormalResults();
23342336
});
23352337

23362338
unsigned nextArgTyIdx = 0;

lib/SILGen/SILGenBridging.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &SGF,
392392
if (blockTy->getNumResults() != 0) {
393393
auto result = blockTy->getSingleResult();
394394
if (result.getConvention() == ResultConvention::Indirect) {
395-
indirectResult = entry->createFunctionArgument(blockResultTy);
395+
indirectResult =
396+
entry->createFunctionArgument(blockResultTy.getAddressType());
396397
}
397398
}
398399

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ struct ARCStrong {
2020
void cfuncARCStrong(void (*_Nonnull)(ARCStrong));
2121
#endif
2222

23+
void cfuncReturnNonTrivial(NonTrivial (^_Nonnull)()) noexcept;
24+
2325
#endif // __CLOSURE__
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swiftxx-frontend -I %S/Inputs -emit-irgen %s | %FileCheck %s
2+
3+
// REQUIRES: OS=macosx
4+
5+
import Closure
6+
7+
// CHECK: define internal swiftcc void @"$s4main34testClosureToBlockReturnNonTrivialyyFSo0gH0VycfU_"(ptr noalias sret(%{{.*}}) %[[V0:.*]])
8+
// CHECK: call {{void|ptr}} @__swift_cxx_ctor_ZN10NonTrivialC1Ev(ptr %[[V0]])
9+
// CHECK: ret void
10+
11+
// CHECK: define linkonce_odr hidden void @"$sSo10NonTrivialVIegr_ABIeyBr_TR"(ptr noalias sret(%{{.*}}) %[[V0:.*]], ptr %[[V1:.*]])
12+
// CHECK: %[[V2:.*]] = getelementptr inbounds { %{{.*}}, %{{.*}} }, ptr %[[V1]], i32 0, i32 1
13+
// CHECK: %[[_FN:.*]] = getelementptr inbounds %{{.*}}, ptr %[[V2]], i32 0, i32 0
14+
// CHECK: %[[V3:.*]] = load ptr, ptr %[[_FN]], align 8
15+
// CHECK: %[[_DATA:.*]] = getelementptr inbounds %{{.*}}, ptr %[[V2]], i32 0, i32 1
16+
// CHECK: %[[V4:.*]] = load ptr, ptr %[[_DATA]], align 8
17+
// CHECK: call ptr @swift_retain(ptr returned %[[V4]])
18+
// CHECK: call swiftcc void %[[V3]](ptr noalias sret(%{{.*}}) %[[V0]], ptr swiftself %[[V4]])
19+
// CHECK: call void @swift_release(ptr %[[V4]])
20+
// CHECK: ret void
21+
22+
public func testClosureToBlockReturnNonTrivial() {
23+
cfuncReturnNonTrivial({() -> NonTrivial in return NonTrivial() })
24+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,18 @@ import Closure
2020
public func testClosureToFuncPtr() {
2121
cfuncARCStrong({N in})
2222
}
23+
24+
// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSo10NonTrivialVIegr_ABIeyBr_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> @out NonTrivial) -> @out NonTrivial {
25+
// CHECK: bb0(%[[V0:.*]] : $*NonTrivial, %[[V1:.*]] : $*@block_storage @callee_guaranteed () -> @out NonTrivial):
26+
// CHECK: %[[V2:.*]] = project_block_storage %[[V1]] : $*@block_storage @callee_guaranteed () -> @out NonTrivial
27+
// CHECK: %[[V3:.*]] = load [copy] %[[V2]] : $*@callee_guaranteed () -> @out NonTrivial
28+
// CHECK: %[[V4:.*]] = begin_borrow %[[V3]] : $@callee_guaranteed () -> @out NonTrivial
29+
// CHECK: apply %[[V4]](%[[V0]]) : $@callee_guaranteed () -> @out NonTrivial
30+
// CHECK: end_borrow %[[V4]] : $@callee_guaranteed () -> @out NonTrivial
31+
// CHECK: %[[V8:.*]] = tuple ()
32+
// CHECK: destroy_value %[[V3]] : $@callee_guaranteed () -> @out NonTrivial
33+
// CHECK: return %[[V8]] : $()
34+
35+
public func testClosureToBlockReturnNonTrivial() {
36+
cfuncReturnNonTrivial({() -> NonTrivial in return NonTrivial() })
37+
}

0 commit comments

Comments
 (0)