From 0c2b62f836348da89e74f24d3968f962c16916c4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 30 May 2019 23:59:58 -0400 Subject: [PATCH] SILGen: Correctly emit vtables when an override is more visible than the base If an override B.f() is more visible than a base method A.f(), it is possible that an override C.f() of B.f() cannot see the original method A.f(). In this case, we would encounter linker errors if we referenced the method descriptor or method dispatch thunk for A.f(). Make this work by treating B.f() as the least derived method in this case, and ensuring that the vtable thunk for B.f() dispatches through the vtable again. Fixes , . --- include/swift/AST/Decl.h | 5 + include/swift/SIL/SILVTableVisitor.h | 30 ++- lib/AST/Decl.cpp | 6 + lib/SIL/SILDeclRef.cpp | 2 + lib/SILGen/SILGenFunction.h | 7 +- lib/SILGen/SILGenPoly.cpp | 20 +- lib/SILGen/SILGenType.cpp | 23 +- .../Inputs/vtables_multifile_2.swift | 22 ++ test/Interpreter/vtables_multifile.swift | 38 ++++ test/SILGen/Inputs/vtables_multifile_2.swift | 117 ++++++++++ test/SILGen/Inputs/vtables_multifile_3.swift | 27 +++ test/SILGen/vtables_multifile.swift | 214 ++++++++++++++++++ 12 files changed, 495 insertions(+), 16 deletions(-) create mode 100644 test/Interpreter/Inputs/vtables_multifile_2.swift create mode 100644 test/Interpreter/vtables_multifile.swift create mode 100644 test/SILGen/Inputs/vtables_multifile_2.swift create mode 100644 test/SILGen/Inputs/vtables_multifile_3.swift create mode 100644 test/SILGen/vtables_multifile.swift diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 1cebc888d04c7..59104e581fed6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5728,6 +5728,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return Bits.AbstractFunctionDecl.NeedsNewVTableEntry; } + bool isEffectiveLinkageMoreVisibleThan(ValueDecl *other) const { + return (std::min(getEffectiveAccess(), AccessLevel::Public) > + std::min(other->getEffectiveAccess(), AccessLevel::Public)); + } + bool isSynthesized() const { return Bits.AbstractFunctionDecl.Synthesized; } diff --git a/include/swift/SIL/SILVTableVisitor.h b/include/swift/SIL/SILVTableVisitor.h index 7072d9af9baa4..2f75267e32ae8 100644 --- a/include/swift/SIL/SILVTableVisitor.h +++ b/include/swift/SIL/SILVTableVisitor.h @@ -86,8 +86,7 @@ template class SILVTableVisitor { void maybeAddMethod(FuncDecl *fd) { assert(!fd->hasClangNode()); - SILDeclRef constant(fd, SILDeclRef::Kind::Func); - maybeAddEntry(constant, constant.requiresNewVTableEntry()); + maybeAddEntry(SILDeclRef(fd, SILDeclRef::Kind::Func)); } void maybeAddConstructor(ConstructorDecl *cd) { @@ -97,19 +96,38 @@ template class SILVTableVisitor { // The initializing entry point for designated initializers is only // necessary for super.init chaining, which is sufficiently constrained // to never need dynamic dispatch. - SILDeclRef constant(cd, SILDeclRef::Kind::Allocator); - maybeAddEntry(constant, constant.requiresNewVTableEntry()); + maybeAddEntry(SILDeclRef(cd, SILDeclRef::Kind::Allocator)); } - void maybeAddEntry(SILDeclRef declRef, bool needsNewEntry) { + void maybeAddEntry(SILDeclRef declRef) { // Introduce a new entry if required. - if (needsNewEntry) + if (declRef.requiresNewVTableEntry()) asDerived().addMethod(declRef); // Update any existing entries that it overrides. auto nextRef = declRef; while ((nextRef = nextRef.getNextOverriddenVTableEntry())) { auto baseRef = nextRef.getOverriddenVTableEntry(); + + // If A.f() is overridden by B.f() which is overridden by + // C.f(), it's possible that C.f() is not visible from C. + // In this case, we pretend that B.f() is the least derived + // method with a vtable entry in the override chain. + // + // This works because we detect the possibility of this + // happening when we emit B.f() and do two things: + // - B.f() always gets a new vtable entry, even if it is + // ABI compatible with A.f() + // - The vtable thunk for the override of A.f() in B does a + // vtable dispatch to the implementation of B.f() for the + // concrete subclass, so a subclass of B only needs to + // replace the vtable entry for B.f(); a call to A.f() + // will correctly dispatch to the implementation of B.f() + // in the subclass. + if (!baseRef.getDecl()->isAccessibleFrom( + declRef.getDecl()->getDeclContext())) + break; + asDerived().addMethodOverride(baseRef, declRef); nextRef = baseRef; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bafb31ccb62ca..65a407d374659 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6184,6 +6184,12 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { } } + // If the base is less visible than the override, we might need a vtable + // entry since callers of the override might not be able to see the base + // at all. + if (decl->isEffectiveLinkageMoreVisibleThan(base)) + return true; + // If the method overrides something, we only need a new entry if the // override has a more general AST type. However an abstraction // change is OK; we don't want to add a whole new vtable entry just diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp index c08e3ccef55ee..f831a4e3ebebd 100644 --- a/lib/SIL/SILDeclRef.cpp +++ b/lib/SIL/SILDeclRef.cpp @@ -852,6 +852,8 @@ SILDeclRef SILDeclRef::getNextOverriddenVTableEntry() const { if (overridden.kind == SILDeclRef::Kind::Initializer) { return SILDeclRef(); } + + // Overrides of @objc dynamic declarations are not in the vtable. if (overridden.getDecl()->isObjCDynamic()) { return SILDeclRef(); } diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index ce346e44a25ef..ae92c63877fd1 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -682,12 +682,17 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// \param inputOrigType Abstraction pattern of base class method /// \param inputSubstType Formal AST type of base class method /// \param outputSubstType Formal AST type of derived class method + /// \param baseLessVisibleThanDerived If true, the thunk does a + /// double dispatch to the derived method's vtable entry, so that if + /// the derived method has an override that cannot access the base, + /// calls to the base dispatch to the correct method. void emitVTableThunk(SILDeclRef base, SILDeclRef derived, SILFunction *implFn, AbstractionPattern inputOrigType, CanAnyFunctionType inputSubstType, - CanAnyFunctionType outputSubstType); + CanAnyFunctionType outputSubstType, + bool baseLessVisibleThanDerived); //===--------------------------------------------------------------------===// // Control flow diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 63af07834c4dd..38bc76169ab9f 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3546,7 +3546,8 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, SILFunction *implFn, AbstractionPattern inputOrigType, CanAnyFunctionType inputSubstType, - CanAnyFunctionType outputSubstType) { + CanAnyFunctionType outputSubstType, + bool baseLessVisibleThanDerived) { auto fd = cast(derived.getDecl()); SILLocation loc(fd); @@ -3558,7 +3559,12 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, SmallVector thunkArgs; collectThunkParams(loc, thunkArgs); - auto derivedFTy = SGM.Types.getConstantInfo(derived).SILFnType; + CanSILFunctionType derivedFTy; + if (baseLessVisibleThanDerived) { + derivedFTy = SGM.Types.getConstantOverrideType(derived); + } else { + derivedFTy = SGM.Types.getConstantInfo(derived).SILFnType; + } SubstitutionMap subs; if (auto *genericEnv = fd->getGenericEnvironment()) { @@ -3610,7 +3616,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, forwardFunctionArguments(*this, loc, derivedFTy, substArgs, args); // Create the call. - auto derivedRef = B.createFunctionRefFor(loc, implFn); + SILValue derivedRef; + if (baseLessVisibleThanDerived) { + // See the comment in SILVTableVisitor.h under maybeAddMethod(). + auto selfValue = thunkArgs.back().getValue(); + auto derivedTy = SGM.Types.getConstantOverrideType(derived); + derivedRef = emitClassMethodRef(loc, selfValue, derived, derivedTy); + } else { + derivedRef = B.createFunctionRefFor(loc, implFn); + } SILValue result; diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 3b47292f58251..8ead804789a62 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -42,8 +42,8 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, SILDeclRef derived, SILDeclRef base) { assert(base.kind == derived.kind); - auto *baseDecl = base.getDecl(); - auto *derivedDecl = derived.getDecl(); + auto *baseDecl = cast(base.getDecl()); + auto *derivedDecl = cast(derived.getDecl()); // Note: We intentionally don't support extension members here. // @@ -80,8 +80,11 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, // If the member is dynamic, reference its dynamic dispatch thunk so that // it will be redispatched, funneling the method call through the runtime // hook point. - if (derivedDecl->isObjCDynamic() - && derived.kind != SILDeclRef::Kind::Allocator) { + bool usesObjCDynamicDispatch = + (derivedDecl->isObjCDynamic() && + derived.kind != SILDeclRef::Kind::Allocator); + + if (usesObjCDynamicDispatch) { implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType); implLinkage = SILLinkage::Public; } else { @@ -93,6 +96,12 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, if (derived == base) return SILVTable::Entry(base, implFn, implKind, implLinkage); + // If the base method is less visible than the derived method, we need + // a thunk. + bool baseLessVisibleThanDerived = + (derivedDecl->isEffectiveLinkageMoreVisibleThan(baseDecl) && + !usesObjCDynamicDispatch); + // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); @@ -104,7 +113,8 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, // The override member type is semantically a subtype of the base // member type. If the override is ABI compatible, we do not need // a thunk. - if (M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType, + if (!baseLessVisibleThanDerived && + M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType, overrideInfo.SILFnType) == TypeConverter::ABIDifference::Trivial) return SILVTable::Entry(base, implFn, implKind, implLinkage); @@ -143,7 +153,8 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, SILGenFunction(*this, *thunk, theClass) .emitVTableThunk(base, derived, implFn, basePattern, overrideInfo.LoweredType, - derivedInfo.LoweredType); + derivedInfo.LoweredType, + baseLessVisibleThanDerived); return SILVTable::Entry(base, thunk, implKind, implLinkage); } diff --git a/test/Interpreter/Inputs/vtables_multifile_2.swift b/test/Interpreter/Inputs/vtables_multifile_2.swift new file mode 100644 index 0000000000000..8fb3720a60b44 --- /dev/null +++ b/test/Interpreter/Inputs/vtables_multifile_2.swift @@ -0,0 +1,22 @@ + +open class Base { + public init() {} + + fileprivate func privateMethod() -> Int { + return 1 + } +} + +open class Derived : Base { + open override func privateMethod() -> Int { + return super.privateMethod() + 1 + } +} + +public func callBaseMethod(_ b: Base) -> Int { + return b.privateMethod() +} + +public func callDerivedMethod(_ d: Derived) -> Int { + return d.privateMethod() +} diff --git a/test/Interpreter/vtables_multifile.swift b/test/Interpreter/vtables_multifile.swift new file mode 100644 index 0000000000000..db1b9dc6008f5 --- /dev/null +++ b/test/Interpreter/vtables_multifile.swift @@ -0,0 +1,38 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_2)) -enable-library-evolution %S/Inputs/vtables_multifile_2.swift -emit-module -emit-module-path %t/vtables_multifile_2.swiftmodule +// RUN: %target-codesign %t/%target-library-name(vtables_multifile_2) + +// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_2 -o %t/main %target-rpath(%t) +// RUN: %target-codesign %t/main + +// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_2) + +// REQUIRES: executable_test + +import StdlibUnittest +import vtables_multifile_2 + +var VTableTestSuite = TestSuite("VTable") + +open class OtherDerived : Derived { + open override func privateMethod() -> Int { + return super.privateMethod() + 1 + } +} + +VTableTestSuite.test("Base") { + expectEqual(1, callBaseMethod(Base())) +} + +VTableTestSuite.test("Derived") { + expectEqual(2, callBaseMethod(Derived())) + expectEqual(2, callDerivedMethod(Derived())) +} + +VTableTestSuite.test("OtherDerived") { + expectEqual(3, callBaseMethod(OtherDerived())) + expectEqual(3, callDerivedMethod(OtherDerived())) +} + +runAllTests() diff --git a/test/SILGen/Inputs/vtables_multifile_2.swift b/test/SILGen/Inputs/vtables_multifile_2.swift new file mode 100644 index 0000000000000..c3cb24c52852f --- /dev/null +++ b/test/SILGen/Inputs/vtables_multifile_2.swift @@ -0,0 +1,117 @@ +open class OtherDerived : Derived { + internal override func privateMethod1() { + super.privateMethod1() + } + internal override func privateMethod2(_ arg: AnyObject?) { + super.privateMethod2(arg) + } + internal override func privateMethod3(_ arg: Int?) { + super.privateMethod3(arg) + } + internal override func privateMethod4(_ arg: Int) { + super.privateMethod4(arg) + } +} + +// -- +// Super method calls directly reference the superclass method +// -- + +// CHECK-LABEL: sil hidden [ossa] @$s17vtables_multifile12OtherDerivedC14privateMethod1yyF : $@convention(method) (@guaranteed OtherDerived) -> () { +// CHECK: bb0(%0 : @guaranteed $OtherDerived): +// CHECK: [[SELF:%.*]] = copy_value %0 : $OtherDerived +// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF]] : $OtherDerived to $Derived +// CHECK: [[METHOD:%.*]] = function_ref @$s17vtables_multifile7DerivedC14privateMethod1yyF : $@convention(method) (@guaranteed Derived) -> () // user: %5 +// CHECK-NEXT: apply [[METHOD:%.*]]([[SUPER]]) : $@convention(method) (@guaranteed Derived) -> () +// CHECK-NEXT: destroy_value [[SUPER]] : $Derived +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT:} + +// CHECK-LABEL: sil hidden_external @$s17vtables_multifile7DerivedC14privateMethod1yyF : $@convention(method) (@guaranteed Derived) -> () + +// CHECK-LABEL: sil hidden [ossa] @$s17vtables_multifile12OtherDerivedC14privateMethod2yyyXlSgF : $@convention(method) (@guaranteed Optional, @guaranteed OtherDerived) -> () { +// CHECK: bb0(%0 : @guaranteed $Optional, %1 : @guaranteed $OtherDerived): +// CHECK: [[SELF:%.*]] = copy_value %1 : $OtherDerived +// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF]] : $OtherDerived to $Derived +// CHECK: [[METHOD:%.*]] = function_ref @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgF : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, [[SUPER]]) : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: destroy_value [[SUPER]] : $Derived +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil hidden_external @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgF : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK: bb0(%0 : $Optional, %1 : @guaranteed $OtherDerived): +// CHECK: [[SELF:%.*]] = copy_value %1 : $OtherDerived +// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF]] : $OtherDerived to $Derived +// CHECK: [[METHOD:%.*]] = function_ref @$s17vtables_multifile7DerivedC14privateMethod3yySiSgF : $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, [[SUPER]]) : $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: destroy_value [[SUPER]] : $Derived +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil hidden_external @$s17vtables_multifile7DerivedC14privateMethod3yySiSgF : $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK: bb0(%0 : $Int, %1 : @guaranteed $OtherDerived): +// CHECK: [[SELF:%.*]] = copy_value %1 : $OtherDerived +// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF]] : $OtherDerived to $Derived +// CHECK: [[METHOD:%.*]] = function_ref @$s17vtables_multifile7DerivedC14privateMethod4yySiF : $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, [[SUPER]]) : $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: destroy_value [[SUPER]] : $Derived +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil hidden_external @$s17vtables_multifile7DerivedC14privateMethod4yySiF : $@convention(method) (Int, @guaranteed Derived) -> () + +// -- +// VTable thunks for methods of Base redispatch to methods of Derived +// -- + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV : $@convention(method) (@guaranteed Derived) -> () { +// CHECK: bb0(%0 : @guaranteed $Derived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %0 : $Derived, #Derived.privateMethod1!1 : (Derived) -> () -> (), $@convention(method) (@guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0) : $@convention(method) (@guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : @guaranteed $Optional, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod2!1 : (Derived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : $Int, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[ARG:%.*]] = enum $Optional, #Optional.some!enumelt.1, %0 : $Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod3!1 : (Derived) -> (Int?) -> (), $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[ARG:%.*]] = load [trivial] %0 : $*Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod4!1 : (Derived) -> (Int) -> (), $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil_vtable [serialized] OtherDerived { +// CHECK-NEXT: #Base.privateMethod1!1: (Base) -> () -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [inherited] // vtable thunk for Base.privateMethod1() dispatching to Derived.privateMethod1() +// CHECK-NEXT: #Base.privateMethod2!1: (Base) -> (AnyObject) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [inherited] // vtable thunk for Base.privateMethod2(_:) dispatching to Derived.privateMethod2(_:) +// CHECK-NEXT: #Base.privateMethod3!1: (Base) -> (Int) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [inherited] // vtable thunk for Base.privateMethod3(_:) dispatching to Derived.privateMethod3(_:) +// CHECK-NEXT: #Base.privateMethod4!1: (Base) -> (T) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [inherited] // vtable thunk for Base.privateMethod4(_:) dispatching to Derived.privateMethod4(_:) +// CHECK-NEXT: #Base.init!allocator.1: (Base.Type) -> () -> Base : @$s17vtables_multifile12OtherDerivedCACycfC [override] // OtherDerived.__allocating_init() +// CHECK-NEXT: #Derived.privateMethod1!1: (Derived) -> () -> () : @$s17vtables_multifile12OtherDerivedC14privateMethod1yyF [override] // OtherDerived.privateMethod1() +// CHECK-NEXT: #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : @$s17vtables_multifile12OtherDerivedC14privateMethod2yyyXlSgF [override] // OtherDerived.privateMethod2(_:) +// CHECK-NEXT: #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : @$s17vtables_multifile12OtherDerivedC14privateMethod3yySiSgF [override] // OtherDerived.privateMethod3(_:) +// CHECK-NEXT: #Derived.privateMethod4!1: (Derived) -> (Int) -> () : @$s17vtables_multifile12OtherDerivedC14privateMethod4yySiF [override] // OtherDerived.privateMethod4(_:) +// CHECK-NEXT: #OtherDerived.deinit!deallocator.1: @$s17vtables_multifile12OtherDerivedCfD // OtherDerived.__deallocating_deinit +// CHECK-NEXT:} \ No newline at end of file diff --git a/test/SILGen/Inputs/vtables_multifile_3.swift b/test/SILGen/Inputs/vtables_multifile_3.swift new file mode 100644 index 0000000000000..a1aca62b7cc36 --- /dev/null +++ b/test/SILGen/Inputs/vtables_multifile_3.swift @@ -0,0 +1,27 @@ +import vtables_multifile + +open class OtherDerived : MostDerived { + open override func privateMethod1() { + super.privateMethod1() + } + open override func privateMethod2(_ arg: AnyObject?) { + super.privateMethod2(arg) + } + open override func privateMethod3(_ arg: Int?) { + super.privateMethod3(arg) + } + open override func privateMethod4(_ arg: Int) { + super.privateMethod4(arg) + } +} + +// Note that the vtable does not mention the private methods of Base +// or Derived, which we cannot see from here. + +// CHECK-LABEL: sil_vtable [serialized] OtherDerived { +// CHECK-NEXT: #MoreDerived.privateMethod1!1: (MoreDerived) -> () -> () : @$s19vtables_multifile_312OtherDerivedC14privateMethod1yyF [override] // OtherDerived.privateMethod1() +// CHECK-NEXT: #MoreDerived.privateMethod2!1: (MoreDerived) -> (AnyObject?) -> () : @$s19vtables_multifile_312OtherDerivedC14privateMethod2yyyXlSgF [override] // OtherDerived.privateMethod2(_:) +// CHECK-NEXT: #MoreDerived.privateMethod3!1: (MoreDerived) -> (Int?) -> () : @$s19vtables_multifile_312OtherDerivedC14privateMethod3yySiSgF [override] // OtherDerived.privateMethod3(_:) +// CHECK-NEXT: #MoreDerived.privateMethod4!1: (MoreDerived) -> (Int) -> () : @$s19vtables_multifile_312OtherDerivedC14privateMethod4yySiF [override] // OtherDerived.privateMethod4(_:) +// CHECK-NEXT: #OtherDerived.deinit!deallocator.1: @$s19vtables_multifile_312OtherDerivedCfD // OtherDerived.__deallocating_deinit +// CHECK-NEXT: } diff --git a/test/SILGen/vtables_multifile.swift b/test/SILGen/vtables_multifile.swift new file mode 100644 index 0000000000000..15aebbfe0aac0 --- /dev/null +++ b/test/SILGen/vtables_multifile.swift @@ -0,0 +1,214 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s -primary-file %S/Inputs/vtables_multifile_2.swift | %FileCheck %S/Inputs/vtables_multifile_2.swift + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %s -enable-library-evolution -emit-module-path %t/vtables_multifile.swiftmodule +// RUN: %target-swift-emit-silgen %S/Inputs/vtables_multifile_3.swift -I %t | %FileCheck %S/Inputs/vtables_multifile_3.swift + + +open class Base { + fileprivate func privateMethod1() {} + fileprivate func privateMethod2(_: AnyObject) {} + fileprivate func privateMethod3(_: Int) {} + fileprivate func privateMethod4(_: T) {} +} + +open class Derived : Base { + internal override func privateMethod1() {} // ABI compatible override with same type + internal override func privateMethod2(_: AnyObject?) {} // ABI compatible override with different type + internal override func privateMethod3(_: Int?) {} // Requires thunking, different type + internal override func privateMethod4(_: Int) {} // Requires thunking, same type +} + +open class MoreDerived : Derived { + public override func privateMethod1() {} + public override func privateMethod2(_: AnyObject?) {} + public override func privateMethod3(_: Int?) {} + public override func privateMethod4(_: Int) {} +} + +open class MostDerived : MoreDerived { + open override func privateMethod1() {} + open override func privateMethod2(_: AnyObject?) {} + open override func privateMethod3(_: Int?) {} + open override func privateMethod4(_: Int) {} +} + +// See Inputs/vtables_multifile_2.swift for overrides in a different file. +// See Inputs/vtables_multifile_3.swift for overrides in a different module. + +// -- +// VTable thunks for the more visible overrides of less visible methods dispatch to the +// vtable slot for the more visible method. +// -- + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV : $@convention(method) (@guaranteed Derived) -> () { +// CHECK: bb0(%0 : @guaranteed $Derived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %0 : $Derived, #Derived.privateMethod1!1 : (Derived) -> () -> (), $@convention(method) (@guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0) : $@convention(method) (@guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : @guaranteed $Optional, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod2!1 : (Derived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : $Int, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[ARG:%.*]] = enum $Optional, #Optional.some!enumelt.1, %0 : $Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod3!1 : (Derived) -> (Int?) -> (), $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Optional, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed Derived) -> () { +// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $Derived): +// CHECK-NEXT: [[ARG:%.*]] = load [trivial] %0 : $*Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $Derived, #Derived.privateMethod4!1 : (Derived) -> (Int) -> (), $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Int, @guaranteed Derived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// -- +// The subclass can see both the methods of Base and the methods of Derived, +// so it overrides both with thunks that dispatch to methods of MoreDerived. +// -- + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV : $@convention(method) (@guaranteed MoreDerived) -> () +// CHECK: bb0(%0 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %0 : $MoreDerived, #MoreDerived.privateMethod1!1 : (MoreDerived) -> () -> (), $@convention(method) (@guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0) : $@convention(method) (@guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV : $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : @guaranteed $Optional, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod2!1 : (MoreDerived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV : $@convention(method) (Int, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : $Int, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[ARG:%.*]] = enum $Optional, #Optional.some!enumelt.1, %0 : $Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod3!1 : (MoreDerived) -> (Int?) -> (), $@convention(method) (Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : $*Int, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[ARG:%.*]] = load [trivial] %0 : $*Int +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod4!1 : (MoreDerived) -> (Int) -> (), $@convention(method) (Int, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply %3(%2, %1) : $@convention(method) (Int, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// -- +// Thunks override methods of Derived as well. +// -- + +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA0D0CADyyFTV : $@convention(method) (@guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %0 : $MoreDerived, #MoreDerived.privateMethod1!1 : (MoreDerived) -> () -> (), $@convention(method) (@guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0) : $@convention(method) (@guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// vtable thunk for Derived.privateMethod2(_:) dispatching to MoreDerived.privateMethod2(_:) +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV : $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : @guaranteed $Optional, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod2!1 : (MoreDerived) -> (AnyObject?) -> (), $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (@guaranteed Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// vtable thunk for Derived.privateMethod3(_:) dispatching to MoreDerived.privateMethod3(_:) +// CHECK-LABEL: il private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV : $@convention(method) (Optional, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : $Optional, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod3!1 : (MoreDerived) -> (Int?) -> (), $@convention(method) (Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (Optional, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// vtable thunk for Derived.privateMethod4(_:) dispatching to MoreDerived.privateMethod4(_:) +// CHECK-LABEL: sil private [ossa] @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA0D0CADyySiFTV : $@convention(method) (Int, @guaranteed MoreDerived) -> () { +// CHECK: bb0(%0 : $Int, %1 : @guaranteed $MoreDerived): +// CHECK-NEXT: [[METHOD:%.*]] = class_method %1 : $MoreDerived, #MoreDerived.privateMethod4!1 : (MoreDerived) -> (Int) -> (), $@convention(method) (Int, @guaranteed MoreDerived) -> () +// CHECK-NEXT: apply [[METHOD]](%0, %1) : $@convention(method) (Int, @guaranteed MoreDerived) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() +// CHECK-NEXT: } + +// -- +// VTable for Derived. +// -- + +// CHECK-LABEL: sil_vtable [serialized] Derived { +// CHECK-NEXT: #Base.privateMethod1!1: (Base) -> () -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override] // vtable thunk for Base.privateMethod1() dispatching to Derived.privateMethod1() +// CHECK-NEXT: #Base.privateMethod2!1: (Base) -> (AnyObject) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override] // vtable thunk for Base.privateMethod2(_:) dispatching to Derived.privateMethod2(_:) +// CHECK-NEXT: #Base.privateMethod3!1: (Base) -> (Int) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override] // vtable thunk for Base.privateMethod3(_:) dispatching to Derived.privateMethod3(_:) +// CHECK-NEXT: #Base.privateMethod4!1: (Base) -> (T) -> () : hidden @$s17vtables_multifile7DerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to Derived.privateMethod4(_:) +// CHECK-NEXT: #Base.init!allocator.1: (Base.Type) -> () -> Base : @$s17vtables_multifile7DerivedCACycfC [override] // Derived.__allocating_init() +// CHECK-NEXT: #Derived.privateMethod1!1: (Derived) -> () -> () : @$s17vtables_multifile7DerivedC14privateMethod1yyF // Derived.privateMethod1() +// CHECK-NEXT: #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : @$s17vtables_multifile7DerivedC14privateMethod2yyyXlSgF // Derived.privateMethod2(_:) +// CHECK-NEXT: #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : @$s17vtables_multifile7DerivedC14privateMethod3yySiSgF // Derived.privateMethod3(_:) +// CHECK-NEXT: #Derived.privateMethod4!1: (Derived) -> (Int) -> () : @$s17vtables_multifile7DerivedC14privateMethod4yySiF // Derived.privateMethod4(_:) +// CHECK-NEXT: #Derived.deinit!deallocator.1: @$s17vtables_multifile7DerivedCfD // Derived.__deallocating_deinit +// CHECK-NEXT: } + +// -- +// VTable for MoreDerived. +// -- + +// CHECK-LABEL: sil_vtable [serialized] MoreDerived { +// CHECK-NEXT: #Base.privateMethod1!1: (Base) -> () -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override] // vtable thunk for Base.privateMethod1() dispatching to MoreDerived.privateMethod1() +// CHECK-NEXT: #Base.privateMethod2!1: (Base) -> (AnyObject) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override] // vtable thunk for Base.privateMethod2(_:) dispatching to MoreDerived.privateMethod2(_:) +// CHECK-NEXT: #Base.privateMethod3!1: (Base) -> (Int) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override] // vtable thunk for Base.privateMethod3(_:) dispatching to MoreDerived.privateMethod3(_:) +// CHECK-NEXT: #Base.privateMethod4!1: (Base) -> (T) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to MoreDerived.privateMethod4(_:) +// CHECK-NEXT: #Base.init!allocator.1: (Base.Type) -> () -> Base : @$s17vtables_multifile11MoreDerivedCACycfC [override] // MoreDerived.__allocating_init() +// CHECK-NEXT: #Derived.privateMethod1!1: (Derived) -> () -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod1yyFAA0D0CADyyFTV [override] // vtable thunk for Derived.privateMethod1() dispatching to MoreDerived.privateMethod1() +// CHECK-NEXT: #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod2(_:) dispatching to MoreDerived.privateMethod2(_:) +// CHECK-NEXT: #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod3(_:) dispatching to MoreDerived.privateMethod3(_:) +// CHECK-NEXT: #Derived.privateMethod4!1: (Derived) -> (Int) -> () : public @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiFAA0D0CADyySiFTV [override] // vtable thunk for Derived.privateMethod4(_:) dispatching to MoreDerived.privateMethod4(_:) +// CHECK-NEXT: #MoreDerived.privateMethod1!1: (MoreDerived) -> () -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod1yyF // MoreDerived.privateMethod1() +// CHECK-NEXT: #MoreDerived.privateMethod2!1: (MoreDerived) -> (AnyObject?) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod2yyyXlSgF // MoreDerived.privateMethod2(_:) +// CHECK-NEXT: #MoreDerived.privateMethod3!1: (MoreDerived) -> (Int?) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod3yySiSgF // MoreDerived.privateMethod3(_:) +// CHECK-NEXT: #MoreDerived.privateMethod4!1: (MoreDerived) -> (Int) -> () : @$s17vtables_multifile11MoreDerivedC14privateMethod4yySiF // MoreDerived.privateMethod4(_:) +// CHECK-NEXT: #MoreDerived.deinit!deallocator.1: @$s17vtables_multifile11MoreDerivedCfD // MoreDerived.__deallocating_deinit +// CHECK-NEXT: } + +// -- +// MostDerived just makes public methods open, which does not require thunking. +// -- + +// CHECK-LABEL: sil_vtable [serialized] MostDerived { +// CHECK-NEXT: #Base.privateMethod1!1: (Base) -> () -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyFTV [override] // vtable thunk for Base.privateMethod1() dispatching to MostDerived.privateMethod1() +// CHECK-NEXT: #Base.privateMethod2!1: (Base) -> (AnyObject) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyyXlFTV [override] // vtable thunk for Base.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:) +// CHECK-NEXT: #Base.privateMethod3!1: (Base) -> (Int) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyySiFTV [override] // vtable thunk for Base.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:) +// CHECK-NEXT: #Base.privateMethod4!1: (Base) -> (T) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA4BaseCAD33_63E5F2521A3C787F5F9EFD57FB9237EALLyyxFTV [override] // vtable thunk for Base.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:) +// CHECK-NEXT: #Base.init!allocator.1: (Base.Type) -> () -> Base : @$s17vtables_multifile11MostDerivedCACycfC [override] // MostDerived.__allocating_init() +// CHECK-NEXT: #Derived.privateMethod1!1: (Derived) -> () -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod1yyFAA0D0CADyyFTV [override] // vtable thunk for Derived.privateMethod1() dispatching to MostDerived.privateMethod1() +// CHECK-NEXT: #Derived.privateMethod2!1: (Derived) -> (AnyObject?) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod2(_:) dispatching to MostDerived.privateMethod2(_:) +// CHECK-NEXT: #Derived.privateMethod3!1: (Derived) -> (Int?) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgFAA0D0CADyyAEFTV [override] // vtable thunk for Derived.privateMethod3(_:) dispatching to MostDerived.privateMethod3(_:) +// CHECK-NEXT: #Derived.privateMethod4!1: (Derived) -> (Int) -> () : public @$s17vtables_multifile11MostDerivedC14privateMethod4yySiFAA0D0CADyySiFTV [override] // vtable thunk for Derived.privateMethod4(_:) dispatching to MostDerived.privateMethod4(_:) +// CHECK-NEXT: #MoreDerived.privateMethod1!1: (MoreDerived) -> () -> () : @$s17vtables_multifile11MostDerivedC14privateMethod1yyF [override] // MostDerived.privateMethod1() +// CHECK-NEXT: #MoreDerived.privateMethod2!1: (MoreDerived) -> (AnyObject?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod2yyyXlSgF [override] // MostDerived.privateMethod2(_:) +// CHECK-NEXT: #MoreDerived.privateMethod3!1: (MoreDerived) -> (Int?) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod3yySiSgF [override] // MostDerived.privateMethod3(_:) +// CHECK-NEXT: #MoreDerived.privateMethod4!1: (MoreDerived) -> (Int) -> () : @$s17vtables_multifile11MostDerivedC14privateMethod4yySiF [override] // MostDerived.privateMethod4(_:) +// CHECK-NEXT: #MostDerived.deinit!deallocator.1: @$s17vtables_multifile11MostDerivedCfD // MostDerived.__deallocating_deinit +// CHECK-NEXT: }