Skip to content

Commit bc42289

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 b6b943e commit bc42289

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
@@ -2288,9 +2288,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
22882288
continue;
22892289

22902290
// We can always capture the storage in these cases.
2291-
Type captureType = capturedVar->getType();
2292-
if (auto *metatypeType = captureType->getAs<MetatypeType>())
2293-
captureType = metatypeType->getInstanceType();
2291+
Type captureType = capturedVar->getType()->getMetatypeInstanceType();
22942292

22952293
if (auto *selfType = captureType->getAs<DynamicSelfType>()) {
22962294
captureType = selfType->getSelfType();
@@ -2302,11 +2300,22 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
23022300
// mutable, we're going to be capturing a box or an address.
23032301
if (captureType->getClassOrBoundGenericClass() &&
23042302
capturedVar->isLet()) {
2305-
if (selfCapture)
2303+
// If we've already captured the same value already, just merge
2304+
// flags.
2305+
if (selfCapture && selfCapture->getDecl() == capture.getDecl()) {
23062306
selfCapture = selfCapture->mergeFlags(capture);
2307-
else
2307+
continue;
2308+
2309+
// Otherwise, record the canonical self capture. It will appear
2310+
// at the end of the capture list.
2311+
} else if (!selfCapture) {
23082312
selfCapture = capture;
2309-
continue;
2313+
continue;
2314+
}
2315+
2316+
// If we end up here, we have multiple different captured values
2317+
// with a dynamic 'Self' type. Handle this and any subsequent
2318+
// captures via the normal code path below.
23102319
}
23112320
}
23122321

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)