diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 36b46e295dfbf..1a61bd092e4a8 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -460,8 +460,47 @@ class ExternalFunctionDefinitionsElimination : FunctionLivenessComputation { /// ExternalFunctionDefinitionsElimination pass does not take functions /// reachable via vtables and witness_tables into account when computing - /// a function liveness information. + /// a function liveness information. The only exceptions are external + /// transparent functions, because bodies of external transparent functions + /// should never be removed. void findAnchorsInTables() override { + // Check vtable methods. + for (SILVTable &vTable : Module->getVTableList()) { + for (auto &entry : vTable.getEntries()) { + SILFunction *F = entry.second; + if (F->isTransparent() && isAvailableExternally(F->getLinkage())) + ensureAlive(F); + } + } + + // Check witness methods. + for (SILWitnessTable &WT : Module->getWitnessTableList()) { + bool tableIsAlive = isVisibleExternally(WT.getConformance()->getProtocol()); + for (const SILWitnessTable::Entry &entry : WT.getEntries()) { + if (entry.getKind() != SILWitnessTable::Method) + continue; + + auto methodWitness = entry.getMethodWitness(); + SILFunction *F = methodWitness.Witness; + if (!F) + continue; + if (F->isTransparent() && isAvailableExternally(F->getLinkage())) + ensureAlive(F); + } + } + + // Check default witness methods. + for (SILDefaultWitnessTable &WT : Module->getDefaultWitnessTableList()) { + for (const SILDefaultWitnessTable::Entry &entry : WT.getEntries()) { + if (!entry.isValid()) + continue; + + SILFunction *F = entry.getWitness(); + if (F->isTransparent() && isAvailableExternally(F->getLinkage())) + ensureAlive(F); + } + } + } bool findAliveFunctions() { diff --git a/test/SILOptimizer/external_func_definition_elim_transparent_methods.sil b/test/SILOptimizer/external_func_definition_elim_transparent_methods.sil new file mode 100644 index 0000000000000..d963335b75375 --- /dev/null +++ b/test/SILOptimizer/external_func_definition_elim_transparent_methods.sil @@ -0,0 +1,54 @@ +// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -external-func-definition-elim %s | %FileCheck %s + +// Check that public_external transparent methods referenced from vtables +// and witness tables are not removed by ExternalFunctionDefinitionsElimination. + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +private class Base { + init() + func foo() +} + +private class Derived : Base { +} + +sil private @BaseInit : $@convention(method) (@owned Base) -> @owned Base { +bb0(%4 : $Base): + return %4 : $Base +} + +sil private @DerivedInit : $@convention(method) (@owned Derived) -> @owned Derived { +bb0(%4 : $Derived): + return %4 : $Derived +} + +sil public_external [transparent] @foo : $@convention(method) (@guaranteed Base) -> () { +bb0(%0 : $Base): + %2 = tuple () + return %2 : $() +} // end sil function 'foo' + + +sil_vtable Base { + #Base.init!initializer.1: BaseInit + #Base.foo!1: foo +} + +sil_vtable Derived { + #Base.init!initializer.1: DerivedInit + #Base.foo!1: foo +} + +// CHECK-LABEL: sil public_external [transparent] @foo +// CHECK: end sil function 'foo' + +// CHECK-LABEL: sil_vtable Base +// CHECK-: BaseInit + +// CHECK-LABEL: sil_vtable Derived +// CHECK: DerivedInit