Skip to content

Commit 0e801c6

Browse files
committed
SILGen: Fix crash when a closure captures two values with dynamic 'Self' type
We give special treatment to a capture of a value with dynamic 'Self' type, by adding it at the end of the capture list. This ensures that IRGen can recover the 'Self' metadata from this parameter if needed. However, the code would crash with an assertion if there were multiple captured values having the dynamic 'Self' type. This was slightly more difficult to spell before SE-0068, but it was still possible if you tried; now its completely trivial. Fixes <https://bugs.swift.org/browse/SR-11928>, <rdar://problem/57823886>.
1 parent 22bfebe commit 0e801c6

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

lib/SIL/TypeLowering.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,9 +2301,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
23012301
continue;
23022302

23032303
// We can always capture the storage in these cases.
2304-
Type captureType = capturedVar->getType();
2305-
if (auto *metatypeType = captureType->getAs<MetatypeType>())
2306-
captureType = metatypeType->getInstanceType();
2304+
Type captureType = capturedVar->getType()->getMetatypeInstanceType();
23072305

23082306
if (auto *selfType = captureType->getAs<DynamicSelfType>()) {
23092307
captureType = selfType->getSelfType();
@@ -2315,11 +2313,22 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
23152313
// mutable, we're going to be capturing a box or an address.
23162314
if (captureType->getClassOrBoundGenericClass() &&
23172315
capturedVar->isLet()) {
2318-
if (selfCapture)
2316+
// If we've already captured the same value already, just merge
2317+
// flags.
2318+
if (selfCapture && selfCapture->getDecl() == capture.getDecl()) {
23192319
selfCapture = selfCapture->mergeFlags(capture);
2320-
else
2320+
continue;
2321+
2322+
// Otherwise, record the canonical self capture. It will appear
2323+
// at the end of the capture list.
2324+
} else if (!selfCapture) {
23212325
selfCapture = capture;
2322-
continue;
2326+
continue;
2327+
}
2328+
2329+
// If we end up here, we have multiple different captured values
2330+
// with a dynamic 'Self' type. Handle this and any subsequent
2331+
// captures via the normal code path below.
23232332
}
23242333
}
23252334

test/SILGen/dynamic_self.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,25 @@ public class FunctionConversionTest : EmptyProtocol {
442442
}
443443
}
444444

445+
public class CaptureTwoValuesTest {
446+
public required init() {}
447+
448+
// CHECK-LABEL: sil [ossa] @$s12dynamic_self20CaptureTwoValuesTestC08capturesdE0yyFZ : $@convention(method) (@thick CaptureTwoValuesTest.Type) -> () {
449+
public static func capturesTwoValues() {
450+
let a = Self()
451+
let b = Self()
452+
453+
// CHECK: function_ref @$s12dynamic_self20CaptureTwoValuesTestC08capturesdE0yyFZyycfU_ : $@convention(thin) (@guaranteed CaptureTwoValuesTest, @guaranteed CaptureTwoValuesTest) -> ()
454+
_ = {
455+
_ = a
456+
_ = b
457+
_ = Self.self
458+
}
459+
460+
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self20CaptureTwoValuesTestC08capturesdE0yyFZyycfU_ : $@convention(thin) (@guaranteed CaptureTwoValuesTest, @guaranteed CaptureTwoValuesTest) -> () {
461+
}
462+
}
463+
445464
// CHECK-LABEL: sil_witness_table hidden X: P module dynamic_self {
446465
// CHECK: method #P.f!1: {{.*}} : @$s12dynamic_self1XCAA1PA2aDP1f{{[_0-9a-zA-Z]*}}FTW
447466

0 commit comments

Comments
 (0)