Skip to content

Commit 2dac584

Browse files
committed
IRGen: Keep vtables entries inherited from fragile base classes.
If a subclass is resilient, but has a fragile base class, we need to preserve the ABI-exposed vtable entries inherited from the base class.
1 parent 3a9440a commit 2dac584

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5138,7 +5138,8 @@ void IRGenModule::emitOpaqueTypeDecl(OpaqueTypeDecl *D) {
51385138
bool irgen::methodRequiresReifiedVTableEntry(IRGenModule &IGM,
51395139
const SILVTable *vtable,
51405140
SILDeclRef method) {
5141-
auto entry = vtable->getEntry(IGM.getSILModule(), method);
5141+
Optional<SILVTable::Entry> entry
5142+
= vtable->getEntry(IGM.getSILModule(), method);
51425143
LLVM_DEBUG(llvm::dbgs() << "looking at vtable:\n";
51435144
vtable->print(llvm::dbgs()));
51445145
if (!entry) {
@@ -5150,7 +5151,8 @@ bool irgen::methodRequiresReifiedVTableEntry(IRGenModule &IGM,
51505151
return true;
51515152
}
51525153
LLVM_DEBUG(llvm::dbgs() << "entry: ";
5153-
entry->print(llvm::dbgs()));
5154+
entry->print(llvm::dbgs());
5155+
llvm::dbgs() << "\n");
51545156

51555157
// We may be able to elide the vtable entry, ABI permitting, if it's not
51565158
// overridden.
@@ -5163,21 +5165,25 @@ bool irgen::methodRequiresReifiedVTableEntry(IRGenModule &IGM,
51635165
return true;
51645166
}
51655167

5166-
// Does the ABI require a vtable entry to exist? If the class is public,
5168+
// Does the ABI require a vtable entry to exist? If the class the vtable
5169+
// entry originates from is public,
51675170
// and it's either marked fragile or part of a non-resilient module, then
51685171
// other modules will directly address vtable offsets and we can't remove
51695172
// vtable entries.
5170-
if (vtable->getClass()->getEffectiveAccess() >= AccessLevel::Public) {
5173+
auto originatingClass =
5174+
cast<ClassDecl>(method.getOverriddenVTableEntry().getDecl()->getDeclContext());
5175+
5176+
if (originatingClass->getEffectiveAccess() >= AccessLevel::Public) {
51715177
// If the class is public,
51725178
// and it's either marked fragile or part of a non-resilient module, then
51735179
// other modules will directly address vtable offsets and we can't remove
51745180
// vtable entries.
5175-
if (!vtable->getClass()->isResilient()) {
5181+
if (!originatingClass->isResilient()) {
51765182
LLVM_DEBUG(llvm::dbgs() << "vtable entry in "
51775183
<< vtable->getClass()->getName()
51785184
<< " for ";
51795185
method.print(llvm::dbgs());
5180-
llvm::dbgs() << " is in a public fragile class\n");
5186+
llvm::dbgs() << " originates from a public fragile class\n");
51815187
return true;
51825188
}
51835189
}

test/IRGen/vtable_non_overridden.sil

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,35 @@ sil_vtable PublicFragileB {
138138
// CHECK-SAME: @PublicFragileB_bar
139139
// CHECK-SAME: @PublicFragileA_bas
140140

141+
sil @PublicResilientSubclassOfFragile_bar : $@convention(method) (@guaranteed PublicResilientSubclassOfFragile) -> ()
142+
sil @PublicResilientSubclassOfFragile_init : $@convention(method) (@thick PublicResilientSubclassOfFragile.Type) -> @owned PublicResilientSubclassOfFragile
143+
sil @PublicResilientSubclassOfFragile_dealloc : $@convention(method) (@owned PublicResilientSubclassOfFragile) -> ()
144+
145+
public class PublicResilientSubclassOfFragile: PublicFragileA {
146+
override func bar()
147+
}
148+
149+
sil_vtable PublicResilientSubclassOfFragile {
150+
#PublicResilientSubclassOfFragile.deinit!deallocator : @PublicResilientSubclassOfFragile_dealloc
151+
#PublicFragileA.init!allocator : @PublicResilientSubclassOfFragile_init [override]
152+
#PublicFragileA.foo : @PublicFragileA_foo [inherited] [nonoverridden]
153+
#PublicFragileA.bar : @PublicResilientSubclassOfFragile_bar [override]
154+
#PublicFragileA.bas : @PublicFragileA_bas [inherited] [nonoverridden]
155+
}
156+
157+
// -- all entries from fragile base class should be preserved in public method descriptor table
158+
// CHECK-LABEL: @"$s21vtable_non_overridden32PublicResilientSubclassOfFragileCMn" =
159+
// CHECK-SAME: i32 2, %swift.method_override_descriptor
160+
// CHECK-SAME: @PublicResilientSubclassOfFragile_bar
161+
// CHECK-SAME: @PublicResilientSubclassOfFragile_init
162+
163+
// -- all entries from fragile base class should be preserved in public vtable
164+
// CHECK-LABEL: @"$s21vtable_non_overridden32PublicResilientSubclassOfFragileCMf" =
165+
// CHECK-SAME: @PublicResilientSubclassOfFragile_init
166+
// CHECK-SAME: @PublicFragileA_foo
167+
// CHECK-SAME: @PublicResilientSubclassOfFragile_bar
168+
// CHECK-SAME: @PublicFragileA_bas
169+
141170
public class PublicA {
142171
init()
143172
public func foo()

0 commit comments

Comments
 (0)