Skip to content

Commit 9e5e240

Browse files
committed
SILGen: Fix inconsistency between vtable layout and vtable entry emission.
As part of the criteria to determine whether a method override requires a new vtable entry in addition to overriding the base class's vtable entry for the method, we compare the visibility of the base class to that of the derived class, since if further subclasses of the derived class cannot see the original base class's method descriptor, they would not be able to directly override its vtable entry. However, there was a subtle inconsistency in our checks in two different places: `NeedsNewVTableEntryRequest::evaluate` compared the visibility of the derived method to its immediate override method, whereas `SILGenModule::emitVTableMethod` compared visibility with the ultimate base method that originated the vtable entry in question. Internal imports create a situation where this leads to inconsistent answers, causing us to emit a vtable thunk but without a corresponding new vtable entry, causing the thunk to become self-recursive (rdar://147360093). If the base class is in a separate module: ``` // Module1 open class Base { public required init() {} } ``` and an intermediate class inherits that base class, it must `public import` the module in the file defining the class to do so: ``` // Module2 public import Module1 open class MidDerived: Base { } ``` However, another file in the same module can further inherit that class, but with only an `internal import` of the base module: ``` // Also Module2 import Module1 open class MostDerived: MidDerived { } ``` The implicit `init()` is `public` in each class, but from the perspective of `MostDerived.init`, `Base.init` is `internal` because of the import. However, the fact that its immediate parent is `public` should be sufficient evidence that its original definition had visibility to `Base`, so no thunk should be necessary.
1 parent 432cc45 commit 9e5e240

File tree

5 files changed

+38
-9
lines changed

5 files changed

+38
-9
lines changed

lib/SILGen/SILGenType.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,18 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, SILDeclRef derived,
112112

113113
// If the base method is less visible than the derived method, we need
114114
// a thunk.
115+
//
116+
// Note that we check the visibility of the derived method's immediate base
117+
// here, rather than the ultimate base of the vtable entry, because it is
118+
// possible through import visibility for an intermediate base class in one
119+
// file to have public visibility to the ultimate base via a public import,
120+
// but then in turn be overridden by a derived class in another file in
121+
// the same module that either doesn't import the ultimate base class's
122+
// module or else imports it non-publicly in its file.
115123
bool baseLessVisibleThanDerived =
116124
(!usesObjCDynamicDispatch &&
117125
!derivedDecl->isFinal() &&
118-
derivedDecl->isMoreVisibleThan(baseDecl));
126+
derivedDecl->isMoreVisibleThan(derivedDecl->getOverriddenDecl()));
119127

120128
// Determine the derived thunk type by lowering the derived type against the
121129
// abstraction pattern of the base.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
open class Base {
2+
public required init() {}
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public import Repro1
2+
3+
open class MidDerived: Base {
4+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -enable-library-evolution -emit-module-path %t/Repro1.swiftmodule -module-name Repro1 %S/Inputs/vtable_internal_imported_ancestor/Repro1.swift
3+
// RUN: %target-swift-frontend -enable-upcoming-feature InternalImportsByDefault -I %t -emit-silgen %S/Inputs/vtable_internal_imported_ancestor/Repro2.swift -primary-file %s | %FileCheck %s
4+
5+
// REQUIRES: swift_feature_InternalImportsByDefault
6+
7+
import Repro1
8+
9+
public class MostDerived: MidDerived {
10+
}
11+
12+
// CHECK-NOT: vtable thunk
13+
// CHECK-LABEL: sil_vtable{{.*}} MostDerived {
14+
// CHECK: #Base.init!allocator: {{.*}} @$s6Repro211MostDerivedCACycfC [override]

test/SILGen/vtables_multifile.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,15 @@ public final class FinalDerived : Base<Int> {
225225
// --
226226

227227
// CHECK-LABEL: sil_vtable [serialized] MostDerived {
228-
// CHECK-NEXT: #Base.privateMethod1: <T> (Base<T>) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override] // vtable thunk for Base.privateMethod1() dispatching to MostDerived.privateMethod1()
229-
// CHECK-NEXT: #Base.privateMethod2: <T> (Base<T>) -> (AnyObject) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override] // vtable thunk for Base.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:)
230-
// CHECK-NEXT: #Base.privateMethod3: <T> (Base<T>) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override] // vtable thunk for Base.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:)
231-
// CHECK-NEXT: #Base.privateMethod4: <T> (Base<T>) -> (T) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:)
228+
// CHECK-NEXT: #Base.privateMethod1: <T> (Base<T>) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyF
229+
// CHECK-NEXT: #Base.privateMethod2: <T> (Base<T>) -> (AnyObject) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgF
230+
// CHECK-NEXT: #Base.privateMethod3: <T> (Base<T>) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgF
231+
// CHECK-NEXT: #Base.privateMethod4: <T> (Base<T>) -> (T) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiF
232232
// CHECK-NEXT: #Base.init!allocator: <T> (Base<T>.Type) -> () -> Base<T> : @$s17vtables_multifile11MostDerivedCACycfC [override] // MostDerived.__allocating_init()
233-
// CHECK-NEXT: #Derived.privateMethod1: (Derived) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA0D0CADyyFTV [override] // vtable thunk for Derived.privateMethod1() dispatching to MostDerived.privateMethod1()
234-
// CHECK-NEXT: #Derived.privateMethod2: (Derived) -> (AnyObject?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:)
235-
// CHECK-NEXT: #Derived.privateMethod3: (Derived) -> (Int?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:)
236-
// CHECK-NEXT: #Derived.privateMethod4: (Derived) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA0D0CADyySiFTV [override] // vtable thunk for Derived.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:)
233+
// CHECK-NEXT: #Derived.privateMethod1: (Derived) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyF
234+
// CHECK-NEXT: #Derived.privateMethod2: (Derived) -> (AnyObject?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgF
235+
// CHECK-NEXT: #Derived.privateMethod3: (Derived) -> (Int?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgF
236+
// CHECK-NEXT: #Derived.privateMethod4: (Derived) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiF
237237
// CHECK-NEXT: #MoreDerived.privateMethod1: (MoreDerived) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyF [override] // MostDerived.privateMethod1()
238238
// CHECK-NEXT: #MoreDerived.privateMethod2: (MoreDerived) -> (AnyObject?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgF [override] // MostDerived.privateMethod2(_:)
239239
// CHECK-NEXT: #MoreDerived.privateMethod3: (MoreDerived) -> (Int?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgF [override] // MostDerived.privateMethod3(_:)

0 commit comments

Comments
 (0)