Skip to content

Commit 31dc5d7

Browse files
committed
[IRGen] Fix crasher in emitPartialApplicationForwarder when the return type is a tuple that contains a closure.
In `emitPartialApplicationForwarder`, when we handle result types that have a type parameter, the lowered result type could be a struct. This happens when we have a function result, for instance: ```swift %0 = function_ref @returns_closure : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> (@owned Empty<τ_0_0>, @owned @callee_guaranteed (Empty<τ_0_0>) -> @owned Empty<τ_0_0>) %1 = partial_apply [callee_guaranteed] %0<S>() : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> (@owned Empty<τ_0_0>, @owned @callee_guaranteed (Empty<τ_0_0>) -> @owned Empty<τ_0_0>) ``` In this case, we emit code that casts the struct memberwise. Resolves [SR-9709](https://bugs.swift.org/browse/SR-9709).
1 parent 1728fc6 commit 31dc5d7

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

lib/IRGen/GenFunc.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,20 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
12441244
// cast to the result type - it could be substituted.
12451245
if (origConv.getSILResultType().hasTypeParameter()) {
12461246
auto ResType = fwd->getReturnType();
1247-
callResult = subIGF.Builder.CreateBitCast(callResult, ResType);
1247+
if (auto *structType = dyn_cast<llvm::StructType>(ResType)) {
1248+
// Cast all struct elements to the desired type.
1249+
llvm::Value *castResult = llvm::UndefValue::get(structType);
1250+
for (auto i : range(structType->getStructNumElements())) {
1251+
auto desiredEltTy = structType->getElementType(i);
1252+
auto elt = subIGF.Builder.CreateExtractValue(callResult, {i});
1253+
auto castElt = subIGF.Builder.CreateBitCast(elt, desiredEltTy);
1254+
castResult =
1255+
subIGF.Builder.CreateInsertValue(castResult, castElt, {i});
1256+
}
1257+
callResult = castResult;
1258+
}
1259+
else
1260+
callResult = subIGF.Builder.CreateBitCast(callResult, ResType);
12481261
}
12491262
subIGF.Builder.CreateRet(callResult);
12501263
}

test/IRGen/partial_apply_forwarder.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,35 @@ bb0(%0 : $*τ_0_1, %1: $S):
222222
return %9 : $@callee_owned () -> ()
223223
}
224224

225+
public class Empty<T> {}
226+
227+
sil private @inner_closure : $@convention(thin) <T> (Empty<T>) -> @owned Empty<T> {
228+
bb0(%0 : $Empty<T>):
229+
return %0 : $Empty<T>
230+
}
231+
232+
sil hidden @returns_closure : $@convention(thin) <T> (Empty<T>) -> (@owned Empty<T>, @callee_guaranteed @owned (Empty<T>) -> @owned Empty<T>) {
233+
bb0(%0 : $Empty<T>):
234+
%1 = function_ref @inner_closure : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> @owned Empty<τ_0_0>
235+
%2 = partial_apply [callee_guaranteed] %1<T>() : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> @owned Empty<τ_0_0>
236+
%5 = tuple (%0 : $Empty<T>, %2 : $@callee_guaranteed (Empty<T>) -> @owned Empty<T>)
237+
return %5 : $(Empty<T>, @callee_guaranteed (Empty<T>) -> @owned Empty<T>)
238+
}
239+
240+
sil hidden @specializes_closure_returning_closure : $@convention(thin) () -> @callee_guaranteed (Empty<S>) -> (@owned Empty<S>, @owned @callee_guaranteed (Empty<S>) -> @owned Empty<S>) {
241+
bb0:
242+
%0 = function_ref @returns_closure : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> (@owned Empty<τ_0_0>, @owned @callee_guaranteed (Empty<τ_0_0>) -> @owned Empty<τ_0_0>)
243+
%1 = partial_apply [callee_guaranteed] %0<S>() : $@convention(thin) <τ_0_0> (Empty<τ_0_0>) -> (@owned Empty<τ_0_0>, @owned @callee_guaranteed (Empty<τ_0_0>) -> @owned Empty<τ_0_0>)
244+
return %1 : $@callee_guaranteed (Empty<S>) -> (@owned Empty<S>, @owned @callee_guaranteed (Empty<S>) -> @owned Empty<S>)
245+
}
246+
247+
// CHECK-LABEL: define hidden swiftcc { i8*, %swift.refcounted* } @specializes_closure_returning_closure() #0 {
248+
// CHECK: entry:
249+
// CHECK: ret { i8*, %swift.refcounted* } { i8* bitcast ({ %{{.*}}Empty{{.*}}*, i8*, %swift.refcounted* } (%{{.*}}Empty{{.*}}*, %swift.refcounted*)* @"{{.*}}returns_closure{{.*}}" to i8*), %swift.refcounted* null }
250+
225251
sil_vtable WeakBox {}
226252
sil_vtable C {}
227253
sil_vtable D {}
228254
sil_vtable E {}
255+
sil_vtable Empty {}
229256
sil_witness_table C: P module main {}

0 commit comments

Comments
 (0)