Skip to content

Commit ae27e88

Browse files
committed
[cxx-interop] Do not crash when calling a subscript with unnamed parameter
This fixes a crash in SILGen when calling a C++ subscript that has an unnamed parameter from Swift. The parameters from a C++ `operator[]` get carried over to the synthesized Swift subscript. If the Swift parameter has no name, there is no way to refer to it in SIL. However, the synthesized subscript accessor needs to pass this parameter to C++. This change makes sure that we give a name to the Swift parameter if there isn't already a name on the C++ side. rdar://83163841
1 parent d7426e2 commit ae27e88

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,16 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter,
16921692
: rawElementTy;
16931693

16941694
auto &ctx = ImporterImpl.SwiftContext;
1695-
auto bodyParams = getterImpl->getParameters();
1695+
1696+
assert(getterImpl->getParameters()->size() == 1 &&
1697+
"subscript can only have 1 parameter");
1698+
auto bodyParam = ParamDecl::clone(ctx, getterImpl->getParameters()->get(0));
1699+
// If the subscript parameter is unnamed, give it a name to make sure SILGen
1700+
// creates a variable for it.
1701+
if (bodyParam->getName().empty())
1702+
bodyParam->setName(ctx.getIdentifier("__index"));
1703+
1704+
auto bodyParams = ParameterList::create(ctx, bodyParam);
16961705
DeclName name(ctx, DeclBaseName::createSubscript(), bodyParams);
16971706
auto dc = getterImpl->getDeclContext();
16981707

test/Interop/Cxx/operators/Inputs/member-inline.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,16 @@ struct DerivedFromReadWriteIntArray : ReadWriteIntArray {};
386386

387387
struct DerivedFromNonTrivialArrayByVal : NonTrivialArrayByVal {};
388388

389+
struct SubscriptUnnamedParameter {
390+
int operator[](int) const { return 123; }
391+
};
392+
393+
struct SubscriptUnnamedParameterReadWrite {
394+
int value = 0;
395+
const int &operator[](int) const { return value; }
396+
int &operator[](int) { return value; }
397+
};
398+
389399
struct Iterator {
390400
private:
391401
int value = 123;

test/Interop/Cxx/operators/member-inline-module-interface.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@
211211
// CHECK: mutating func __operatorSubscriptConst(_ x: Int32) -> NonTrivial
212212
// CHECK: }
213213

214+
// CHECK: struct SubscriptUnnamedParameter {
215+
// CHECK: subscript(__index: Int32) -> Int32 { get }
216+
// CHECK: }
217+
// CHECK: struct SubscriptUnnamedParameterReadWrite {
218+
// CHECK: subscript(__index: Int32) -> Int32
219+
// CHECK: }
220+
214221
// CHECK: struct Iterator {
215222
// CHECK: var pointee: Int32 { mutating get set }
216223
// CHECK: @available(*, unavailable, message: "use .pointee property")

test/Interop/Cxx/operators/member-inline-silgen.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@ public func index(_ arr: inout ConstPtrByVal, _ arg: Int32, _ val: Int32) -> Int
171171
// CHECK: end_access [[SELFACCESS]] : $*ConstPtrByVal
172172
// CHECK: } // end sil function '$sSo13ConstPtrByValVySPys5Int32VGSgADcig
173173

174+
public func subscriptUnnamed(_ unnamed: SubscriptUnnamedParameter, _ arg: Int32) -> Int32 { unnamed[arg] }
175+
// CHECK: sil shared [transparent] @$sSo25SubscriptUnnamedParameterVys5Int32VADcig : $@convention(method) (Int32, SubscriptUnnamedParameter) -> Int32 {
176+
// CHECK: bb0([[INDEX:%.*]] : $Int32, [[SELF:%.*]] : $SubscriptUnnamedParameter):
177+
// CHECK: [[SELFACCESS:%.*]] = alloc_stack $SubscriptUnnamedParameter
178+
// CHECK: [[OP:%.*]] = function_ref [[OPERATORNAME:@(_ZNK25SubscriptUnnamedParameterixEi|\?\?ASubscriptUnnamedParameter@@QEBAHH@Z)]] : $@convention(cxx_method) (Int32, @in_guaranteed SubscriptUnnamedParameter) -> Int32
179+
// CHECK: [[PTR:%.*]] = apply [[OP]]([[INDEX]], [[SELFACCESS]]) : $@convention(cxx_method) (Int32, @in_guaranteed SubscriptUnnamedParameter) -> Int32
180+
// CHECK: dealloc_stack [[SELFACCESS]]
181+
// CHECK: } // end sil function '$sSo25SubscriptUnnamedParameterVys5Int32VADcig'
182+
174183
// CHECK: sil [clang ReadOnlyIntArray.__operatorSubscriptConst] [[READCLASSNAME]] : $@convention(cxx_method) (Int32, @in_guaranteed ReadOnlyIntArray) -> UnsafePointer<Int32>
175184
// CHECK: sil [clang ReadWriteIntArray.__operatorSubscript] [[READWRITECLASSNAME]] : $@convention(cxx_method) (Int32, @inout ReadWriteIntArray) -> UnsafeMutablePointer<Int32>
176185
// CHECK: sil [clang NonTrivialIntArrayByVal.__operatorSubscriptConst] [[READWRITECLASSNAMEBYVAL]] : $@convention(cxx_method) (Int32, @in_guaranteed NonTrivialIntArrayByVal) -> Int32

test/Interop/Cxx/operators/member-inline.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,22 @@ OperatorsTestSuite.test("SubscriptSetterConst") {
394394
setterConst[0] = 10
395395
}
396396

397+
OperatorsTestSuite.test("SubscriptUnnamedParameter") {
398+
let unnamed = SubscriptUnnamedParameter()
399+
expectEqual(123, unnamed[0])
400+
expectEqual(123, unnamed[321])
401+
}
402+
403+
OperatorsTestSuite.test("SubscriptUnnamedParameterReadWrite") {
404+
var unnamed = SubscriptUnnamedParameterReadWrite()
405+
expectEqual(0, unnamed[0])
406+
expectEqual(0, unnamed[321])
407+
408+
unnamed[456] = 456
409+
expectEqual(456, unnamed[0])
410+
expectEqual(456, unnamed[321])
411+
}
412+
397413
OperatorsTestSuite.test("DerivedFromConstIteratorPrivatelyWithUsingDecl.pointee") {
398414
let stars = DerivedFromConstIteratorPrivatelyWithUsingDecl()
399415
let res = stars.pointee

0 commit comments

Comments
 (0)