Skip to content

Commit 384b2a6

Browse files
committed
Actually honor MissingMemberDecls in ClassMetadataScanner.
...which is sufficient to correctly invoke methods in a vtable even when members have been deleted. 🎉
1 parent 4cdb597 commit 384b2a6

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

include/swift/SIL/SILVTableVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ template <class T> class SILVTableVisitor {
9494
maybeAddMethod(fd);
9595
else if (auto *cd = dyn_cast<ConstructorDecl>(member))
9696
maybeAddConstructor(cd);
97+
else if (auto *placeholder = dyn_cast<MissingMemberDecl>(member))
98+
asDerived().addPlaceholder(placeholder);
9799
}
98100
}
99101
};

lib/IRGen/ClassMetadataLayout.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ class ClassMetadataScanner : public ClassMetadataLayout<Impl> {
181181
ClassDecl *forClass) {
182182
addPointer();
183183
}
184+
void addPlaceholder(MissingMemberDecl *MMD) {
185+
for (auto i : range(MMD->getNumberOfVTableEntries())) {
186+
(void)i;
187+
addPointer();
188+
}
189+
}
184190

185191
private:
186192
// Our layout here assumes that there will never be unclaimed space

lib/IRGen/GenMeta.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,10 @@ namespace {
35023502
}
35033503
}
35043504

3505+
void addPlaceholder(MissingMemberDecl *) {
3506+
llvm_unreachable("cannot generate metadata with placeholders in it");
3507+
}
3508+
35053509
void addMethodOverride(SILDeclRef baseRef, SILDeclRef declRef) {}
35063510

35073511
void addGenericArgument(CanType argTy, ClassDecl *forClass) {

test/Serialization/Recovery/typedefs.swift

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: rm -rf %t && mkdir -p %t
2-
// RUN: %target-swift-frontend -emit-module -o %t -module-name Lib -I %S/Inputs/custom-modules %s
2+
// RUN: %target-swift-frontend -emit-sil -o - -emit-module-path %t/Lib.swiftmodule -module-name Lib -I %S/Inputs/custom-modules %s | %FileCheck -check-prefix CHECK-VTABLE %s
33

44
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules | %FileCheck %s
55

@@ -9,6 +9,7 @@
99

1010
// RUN: %target-swift-frontend -typecheck -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -DTEST -enable-experimental-deserialization-recovery -DVERIFY %s -verify
1111
// RUN: %target-swift-frontend -emit-silgen -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -DTEST -enable-experimental-deserialization-recovery %s | %FileCheck -check-prefix CHECK-SIL %s
12+
// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -DTEST -enable-experimental-deserialization-recovery %s | %FileCheck -check-prefix CHECK-IR %s
1213

1314
#if TEST
1415

@@ -24,6 +25,16 @@ func testSymbols() {
2425
_ = Lib.usesAssoc
2526
} // CHECK-SIL: end sil function '_T08typedefs11testSymbolsyyF'
2627

28+
// CHECK-IR-LABEL: define{{.*}} void @_T08typedefs18testVTableBuildingy3Lib4UserC4user_tF
29+
public func testVTableBuilding(user: User) {
30+
// The important thing in this CHECK line is the "i64 23", which is the offset
31+
// for the vtable slot for 'lastMethod()'. If the layout here
32+
// changes, please check that offset 23 is still correct.
33+
// CHECK-IR-NOT: ret
34+
// CHECK-IR: getelementptr inbounds void (%T3Lib4UserC*)*, void (%T3Lib4UserC*)** %{{[0-9]+}}, i64 23
35+
_ = user.lastMethod()
36+
} // CHECK-IR: ret void
37+
2738
#if VERIFY
2839
let _: String = useAssoc(ImportedType.self) // expected-error {{cannot convert call result type '_.Assoc?' to expected type 'String'}}
2940
let _: Bool? = useAssoc(ImportedType.self) // expected-error {{cannot convert value of type 'Int32?' to specified type 'Bool?'}}
@@ -93,12 +104,34 @@ open class User {
93104

94105
// CHECK: required init(wrappedRequired: WrappedInt)
95106
// CHECK-RECOVERY: /* placeholder for init(wrappedRequired:) */
96-
// CHECK-RECOVERY: /* placeholder for init(wrappedRequired:) */
97107
public required init(wrappedRequired: WrappedInt) {}
108+
109+
public func lastMethod() {}
98110
}
99111
// CHECK: {{^}$}}
100112
// CHECK-RECOVERY: {{^}$}}
101113

114+
// This is mostly to check when changes are necessary for the CHECK-IR lines
115+
// above.
116+
// CHECK-VTABLE-LABEL: sil_vtable User {
117+
// (8 words of normal class metadata)
118+
// 9 CHECK-VTABLE-NEXT: #User.unwrappedProp!getter.1:
119+
// 10 CHECK-VTABLE-NEXT: #User.unwrappedProp!setter.1:
120+
// 11 CHECK-VTABLE-NEXT: #User.unwrappedProp!materializeForSet.1:
121+
// 12 CHECK-VTABLE-NEXT: #User.wrappedProp!getter.1:
122+
// 13 CHECK-VTABLE-NEXT: #User.wrappedProp!setter.1:
123+
// 14 CHECK-VTABLE-NEXT: #User.wrappedProp!materializeForSet.1:
124+
// 15 CHECK-VTABLE-NEXT: #User.returnsUnwrappedMethod!1:
125+
// 16 CHECK-VTABLE-NEXT: #User.returnsWrappedMethod!1:
126+
// 17 CHECK-VTABLE-NEXT: #User.subscript!getter.1:
127+
// 18 CHECK-VTABLE-NEXT: #User.init!initializer.1:
128+
// 19 CHECK-VTABLE-NEXT: #User.init!initializer.1:
129+
// 20 CHECK-VTABLE-NEXT: #User.init!initializer.1:
130+
// 21 CHECK-VTABLE-NEXT: #User.init!allocator.1:
131+
// 22 CHECK-VTABLE-NEXT: #User.init!initializer.1:
132+
// 23 CHECK-VTABLE-NEXT: #User.lastMethod!1:
133+
// CHECK-VTABLE: }
134+
102135

103136
// CHECK-LABEL: class UserConvenience
104137
// CHECK-RECOVERY-LABEL: class UserConvenience

0 commit comments

Comments
 (0)