Skip to content

Commit 51c1fa9

Browse files
committed
SILGen: Fix assertion failure when emitting foreign-to-native thunk for a method with inout 'self'
We import a C function taking a non-const pointer 'self' parameter as a mutating method. The getParameterTypes() helper method in SILGenBridging.cpp would assert upon encountering the inout 'self' parameter, even though emitForeignToNativeThunk() would still emit correct code as long as the 'self' type was not bridged. Relax the assertion a bit to hopefully still catch bugs where other parameters are unexpectedly 'inout', but allow it on 'self', and add a test. Fixes <rdar://problem/70346482>.
1 parent d32a371 commit 51c1fa9

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,17 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILLocation loc,
336336

337337
/// Get the type of each parameter, filtering out empty tuples.
338338
static SmallVector<CanType, 8>
339-
getParameterTypes(AnyFunctionType::CanParamArrayRef params) {
339+
getParameterTypes(AnyFunctionType::CanParamArrayRef params,
340+
bool hasSelfParam=false) {
340341
SmallVector<CanType, 8> results;
341-
for (auto param : params) {
342-
assert(!param.isInOut() && !param.isVariadic());
342+
for (auto n : indices(params)) {
343+
bool isSelf = (hasSelfParam ? n == params.size() - 1 : false);
344+
345+
const auto &param = params[n];
346+
assert(isSelf || !param.isInOut() &&
347+
"Only the 'self' parameter can be inout in a bridging thunk");
348+
assert(!param.isVariadic());
349+
343350
if (param.getPlainType()->isVoid())
344351
continue;
345352
results.push_back(param.getPlainType());
@@ -1723,10 +1730,11 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
17231730
};
17241731

17251732
{
1733+
bool hasSelfParam = fd->hasImplicitSelfDecl();
17261734
auto foreignFormalParams =
1727-
getParameterTypes(foreignCI.LoweredType.getParams());
1735+
getParameterTypes(foreignCI.LoweredType.getParams(), hasSelfParam);
17281736
auto nativeFormalParams =
1729-
getParameterTypes(nativeCI.LoweredType.getParams());
1737+
getParameterTypes(nativeCI.LoweredType.getParams(), hasSelfParam);
17301738

17311739
for (unsigned nativeParamIndex : indices(params)) {
17321740
// Bring the parameter to +1.
@@ -1762,7 +1770,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
17621770

17631771
maybeAddForeignErrorArg();
17641772

1765-
bool isSelf = nativeParamIndex == params.size() - 1;
1773+
bool isSelf = (hasSelfParam && nativeParamIndex == params.size() - 1);
17661774

17671775
if (memberStatus.isInstance()) {
17681776
// Leave space for `self` to be filled in later.
@@ -1787,6 +1795,12 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
17871795
F.mapTypeIntoContext(foreignFormalParams[nativeParamIndex])
17881796
->getCanonicalType();
17891797

1798+
if (isSelf) {
1799+
assert(!nativeCI.LoweredType.getParams()[nativeParamIndex].isInOut() ||
1800+
nativeFormalType == foreignFormalType &&
1801+
"Cannot bridge 'self' parameter if passed inout");
1802+
}
1803+
17901804
auto foreignParam = foreignFnTy->getParameters()[foreignArgIndex++];
17911805
SILType foreignLoweredTy =
17921806
F.mapTypeIntoContext(foreignParam.getSILStorageType(
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
typedef struct {} MyIterator __attribute__((swift_name("MyIterator")));
2+
3+
void MyIteratorNext(MyIterator *self) __attribute__((swift_name("MyIterator.next(self:)")));
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -import-objc-header %S/Inputs/foreign_to_native_inout_self_helper.h | %FileCheck %s
2+
3+
protocol FakeIterator {
4+
mutating func next()
5+
}
6+
7+
extension MyIterator : FakeIterator {}
8+
9+
// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo10MyIteratora4nextyyFTO : $@convention(method) (@inout MyIterator) -> () {
10+
// CHECK: bb0(%0 : $*MyIterator):
11+
// CHECK: [[FN:%.*]] = function_ref @MyIteratorNext : $@convention(c) (@inout MyIterator) -> ()
12+
// CHECK: apply [[FN]](%0) : $@convention(c) (@inout MyIterator) -> ()
13+
// CHECK: [[RESULT:%.*]] = tuple ()
14+
// CHECK: return [[RESULT]] : $()
15+
// CHECK: }

0 commit comments

Comments
 (0)