Skip to content

Commit c17d649

Browse files
authored
Merge pull request #8387 from slavapestov/protocol-witness-thunk-linkage
Protocol witness thunks don't need public linkage
2 parents 3af929e + 6a83e73 commit c17d649

39 files changed

+366
-279
lines changed

lib/SIL/SILVerifier.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,8 +1131,25 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
11311131
"result of function_ref");
11321132
require(!fnType->getExtInfo().hasContext(),
11331133
"function_ref should have a context-free function result");
1134+
1135+
// Note: in SingleFunction mode, we relax some of these checks because
1136+
// we may not have linked everything yet.
1137+
1138+
SILFunction *RefF = FRI->getReferencedFunction();
1139+
1140+
// A direct reference to a shared_external declaration is an error; we
1141+
// should have deserialized a body.
1142+
if (RefF->isExternalDeclaration()) {
1143+
require(SingleFunction ||
1144+
!hasSharedVisibility(RefF->getLinkage()) ||
1145+
RefF->hasForeignBody(),
1146+
"external declarations of SILFunctions with shared visibility is "
1147+
"not allowed");
1148+
}
1149+
1150+
// A direct reference to a non-public or shared but not fragile function
1151+
// from a fragile function is an error.
11341152
if (F.isSerialized()) {
1135-
SILFunction *RefF = FRI->getReferencedFunction();
11361153
require((SingleFunction && RefF->isExternalDeclaration()) ||
11371154
RefF->hasValidLinkageForFragileRef(),
11381155
"function_ref inside fragile function cannot "
@@ -3912,9 +3929,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
39123929

39133930
assert(F->isAvailableExternally() &&
39143931
"external declaration of internal SILFunction not allowed");
3915-
assert(!hasSharedVisibility(F->getLinkage()) &&
3916-
"external declarations of SILFunctions with shared visibility is not "
3917-
"allowed");
39183932
// If F is an external declaration, there is nothing further to do,
39193933
// return.
39203934
return;
@@ -4037,15 +4051,20 @@ void SILWitnessTable::verify(const SILModule &M) const {
40374051

40384052
auto *protocol = getConformance()->getProtocol();
40394053

4040-
// Currently all witness tables have public conformances, thus witness tables
4041-
// should not reference SILFunctions without public/public_external linkage.
4042-
// FIXME: Once we support private conformances, update this.
40434054
for (const Entry &E : getEntries())
40444055
if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
40454056
SILFunction *F = E.getMethodWitness().Witness;
40464057
if (F) {
4047-
assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
4048-
"Witness tables should not reference less visible functions.");
4058+
// If a SILWitnessTable is going to be serialized, it must only
4059+
// reference public or serializable functions.
4060+
if (isSerialized()) {
4061+
assert((!isLessVisibleThan(F->getLinkage(), getLinkage()) ||
4062+
(F->isSerialized() &&
4063+
hasSharedVisibility(F->getLinkage()))) &&
4064+
"Fragile witness tables should not reference "
4065+
"less visible functions.");
4066+
}
4067+
40494068
assert(F->getLoweredFunctionType()->getRepresentation() ==
40504069
SILFunctionTypeRepresentation::WitnessMethod &&
40514070
"Witnesses must have witness_method representation.");
@@ -4069,9 +4088,12 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const {
40694088
continue;
40704089

40714090
SILFunction *F = E.getWitness();
4091+
// FIXME
4092+
#if 0
40724093
assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
40734094
"Default witness tables should not reference "
40744095
"less visible functions.");
4096+
#endif
40754097
assert(F->getLoweredFunctionType()->getRepresentation() ==
40764098
SILFunctionTypeRepresentation::WitnessMethod &&
40774099
"Default witnesses must have witness_method representation.");

lib/SILGen/SILGen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
317317
/// Emit a protocol witness entry point.
318318
SILFunction *emitProtocolWitness(ProtocolConformance *conformance,
319319
SILLinkage linkage,
320+
IsSerialized_t isSerialized,
320321
SILDeclRef requirement,
321322
SILDeclRef witnessRef,
322323
IsFreeFunctionWitness_t isFree,

lib/SILGen/SILGenType.cpp

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -312,16 +312,34 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
312312
NormalProtocolConformance *Conformance;
313313
std::vector<SILWitnessTable::Entry> Entries;
314314
SILLinkage Linkage;
315+
IsSerialized_t Serialized;
315316

316317
SILGenConformance(SILGenModule &SGM, NormalProtocolConformance *C)
317318
// We only need to emit witness tables for base NormalProtocolConformances.
318319
: SGM(SGM), Conformance(C->getRootNormalConformance()),
319320
Linkage(getLinkageForProtocolConformance(Conformance,
320321
ForDefinition))
321322
{
322-
// Not all protocols use witness tables.
323-
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(
324-
Conformance->getProtocol()))
323+
auto *proto = Conformance->getProtocol();
324+
325+
Serialized = IsNotSerialized;
326+
327+
// Serialize the witness table if we're serializing everything with
328+
// -sil-serialize-all.
329+
if (SGM.makeModuleFragile)
330+
Serialized = IsSerialized;
331+
332+
// Serialize the witness table if type has a fixed layout in all
333+
// resilience domains, and the conformance is externally visible.
334+
auto nominal = Conformance->getInterfaceType()->getAnyNominal();
335+
if (nominal->hasFixedLayout() &&
336+
proto->getEffectiveAccess() >= Accessibility::Public &&
337+
nominal->getEffectiveAccess() >= Accessibility::Public)
338+
Serialized = IsSerialized;
339+
340+
// Not all protocols use witness tables; in this case we just skip
341+
// all of emit() below completely.
342+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
325343
Conformance = nullptr;
326344
}
327345

@@ -333,19 +351,6 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
333351
auto *proto = Conformance->getProtocol();
334352
visitProtocolDecl(proto);
335353

336-
// Serialize the witness table in two cases:
337-
// 1) We're serializing everything
338-
// 2) The type has a fixed layout in all resilience domains, and the
339-
// conformance is externally visible
340-
IsSerialized_t isSerialized = IsNotSerialized;
341-
if (SGM.makeModuleFragile)
342-
isSerialized = IsSerialized;
343-
if (auto nominal = Conformance->getInterfaceType()->getAnyNominal())
344-
if (nominal->hasFixedLayout() &&
345-
proto->getEffectiveAccess() >= Accessibility::Public &&
346-
nominal->getEffectiveAccess() >= Accessibility::Public)
347-
isSerialized = IsSerialized;
348-
349354
// Check if we already have a declaration or definition for this witness
350355
// table.
351356
if (auto *wt = SGM.M.lookUpWitnessTable(Conformance, false)) {
@@ -358,7 +363,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
358363

359364
// If we have a declaration, convert the witness table to a definition.
360365
if (wt->isDeclaration()) {
361-
wt->convertToDefinition(Entries, isSerialized);
366+
wt->convertToDefinition(Entries, Serialized);
362367

363368
// Since we had a declaration before, its linkage should be external,
364369
// ensure that we have a compatible linkage for sanity. *NOTE* we are ok
@@ -375,7 +380,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
375380
}
376381

377382
// Otherwise if we have no witness table yet, create it.
378-
return SILWitnessTable::create(SGM.M, Linkage, isSerialized,
383+
return SILWitnessTable::create(SGM.M, Linkage, Serialized,
379384
Conformance, Entries);
380385
}
381386

@@ -427,9 +432,33 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
427432
return;
428433
}
429434

435+
auto witnessLinkage = witnessRef.getLinkage(ForDefinition);
436+
auto witnessSerialized = Serialized;
437+
if (witnessSerialized &&
438+
!hasPublicVisibility(witnessLinkage) &&
439+
!hasSharedVisibility(witnessLinkage)) {
440+
// FIXME: This should not happen, but it looks like visibility rules
441+
// for extension members are slightly bogus.
442+
//
443+
// We allow a 'public' member of an extension to witness a public
444+
// protocol requirement, even if the extended type is not public;
445+
// then SILGen gives the member private linkage, ignoring the more
446+
// visible accessibility it was given in the AST.
447+
witnessLinkage = SILLinkage::Public;
448+
witnessSerialized = (SGM.makeModuleFragile
449+
? IsSerialized
450+
: IsNotSerialized);
451+
} else {
452+
// This is the "real" rule; the above case should go away once we
453+
// figure out what's going on.
454+
witnessLinkage = (witnessSerialized
455+
? SILLinkage::Shared
456+
: SILLinkage::Private);
457+
}
458+
430459
SILFunction *witnessFn =
431-
SGM.emitProtocolWitness(Conformance, Linkage, requirementRef, witnessRef,
432-
isFree, witness);
460+
SGM.emitProtocolWitness(Conformance, witnessLinkage, witnessSerialized,
461+
requirementRef, witnessRef, isFree, witness);
433462
Entries.push_back(
434463
SILWitnessTable::MethodWitness{requirementRef, witnessFn});
435464
}
@@ -540,6 +569,7 @@ static bool maybeOpenCodeProtocolWitness(SILGenFunction &gen,
540569
SILFunction *
541570
SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
542571
SILLinkage linkage,
572+
IsSerialized_t isSerialized,
543573
SILDeclRef requirement,
544574
SILDeclRef witnessRef,
545575
IsFreeFunctionWitness_t isFree,
@@ -637,14 +667,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
637667
if (witnessRef.isAlwaysInline())
638668
InlineStrategy = AlwaysInline;
639669

640-
IsSerialized_t isSerialized = IsNotSerialized;
641-
if (makeModuleFragile)
642-
isSerialized = IsSerialized;
643-
if (witnessRef.isSerialized() &&
644-
(hasSharedVisibility(linkage) ||
645-
hasPublicVisibility(linkage)))
646-
isSerialized = IsSerialized;
647-
648670
auto *f = M.createFunction(
649671
linkage, nameBuffer, witnessSILFnType,
650672
genericEnv, SILLocation(witnessRef.getDecl()),
@@ -742,7 +764,9 @@ class SILGenDefaultWitnessTable
742764
SILDeclRef witnessRef,
743765
IsFreeFunctionWitness_t isFree,
744766
Witness witness) {
745-
SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr, Linkage,
767+
SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr,
768+
SILLinkage::Private,
769+
IsNotSerialized,
746770
requirementRef, witnessRef,
747771
isFree, witness);
748772
auto entry = SILDefaultWitnessTable::Entry(requirementRef, witnessFn);

test/IRGen/dependent_reabstraction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ protocol A {
88
}
99

1010
struct X<Y> : A {
11-
// CHECK-LABEL: define hidden swiftcc void @_T023dependent_reabstraction1XVyxGAA1AAAlAaEP1by1BQzFTW(%swift.type** noalias nocapture dereferenceable({{.*}}), %T23dependent_reabstraction1XV* noalias nocapture swiftself, %swift.type* %Self, i8** %SelfWitnessTable)
11+
// CHECK-LABEL: define internal swiftcc void @_T023dependent_reabstraction1XVyxGAA1AAAlAaEP1by1BQzFTW(%swift.type** noalias nocapture dereferenceable({{.*}}), %T23dependent_reabstraction1XV* noalias nocapture swiftself, %swift.type* %Self, i8** %SelfWitnessTable)
1212
func b(_ b: X.Type) {
1313
let x: Any = b
1414
markUsed(b as X.Type)

test/IRGen/metadata_dominance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,6 @@ func testMakeFoo(_ p: P) -> Foo.Type {
7979
// The protocol witness for metadata_dominance.P.makeFoo () -> metadata_dominance.Foo in
8080
// conformance metadata_dominance.Foo : metadata_dominance.P should not use the Self type
8181
// as the type of the object to be created. It should dynamically obtain the type.
82-
// CHECK-OPT-LABEL: define hidden swiftcc %T18metadata_dominance3FooC* @_T018metadata_dominance3FooCAA1PA2aDP04makeC0ACyFTW
82+
// CHECK-OPT-LABEL: define internal swiftcc %T18metadata_dominance3FooC* @_T018metadata_dominance3FooCAA1PA2aDP04makeC0ACyFTW
8383
// CHECK-OPT-NOT: tail call noalias %swift.refcounted* @swift_rt_swift_allocObject(%swift.type* %Self
8484

test/IRGen/objc_generic_protocol_conformance.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ protocol P {
99

1010
extension Foo: P {}
1111

12-
// SIL-LABEL: sil hidden [transparent] [thunk] @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW {{.*}} @pseudogeneric
13-
// IR-LABEL: define hidden swiftcc void @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW(%TSo3FooC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type*{{( %Self)?}}, i8**{{( %SelfWitnessTable)?}})
12+
// SIL-LABEL: sil private [transparent] [thunk] @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW {{.*}} @pseudogeneric
13+
// IR-LABEL: define internal swiftcc void @_T0So3FooCyxG33objc_generic_protocol_conformance1PADs9AnyObjectRzlAdEP3fooyyFTW(%TSo3FooC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type*{{( %Self)?}}, i8**{{( %SelfWitnessTable)?}})

test/SILGen/cf.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ protocol Impedance {
6565

6666
extension CCImpedance: Impedance {}
6767

68-
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
68+
// CHECK-LABEL: sil private [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
6969
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4realSdfg
70-
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
70+
// CHECK-LABEL: sil private [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
7171
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4imagSdfg
7272

7373
class MyMagnetism : CCMagnetismModel {

test/SILGen/dependent_member_lowering.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ struct Foo<T>: P {
99
typealias A = T.Type
1010

1111
func f(_ t: T.Type) {}
12-
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T025dependent_member_lowering3FooVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @thick τ_0_0.Type, @in_guaranteed Foo<τ_0_0>) -> ()
12+
// CHECK-LABEL: sil private [transparent] [thunk] @_T025dependent_member_lowering3FooVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @thick τ_0_0.Type, @in_guaranteed Foo<τ_0_0>) -> ()
1313
// CHECK: bb0(%0 : $*@thick τ_0_0.Type, %1 : $*Foo<τ_0_0>):
1414
}
1515
struct Bar<T>: P {
1616
typealias A = (Int) -> T
1717

1818
func f(_ t: @escaping (Int) -> T) {}
19-
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T025dependent_member_lowering3BarVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @callee_owned (@in Int) -> @out τ_0_0, @in_guaranteed Bar<τ_0_0>) -> ()
19+
// CHECK-LABEL: sil private [transparent] [thunk] @_T025dependent_member_lowering3BarVyxGAA1PAAlAaEP1fy1AQzFTW : $@convention(witness_method) <τ_0_0> (@in @callee_owned (@in Int) -> @out τ_0_0, @in_guaranteed Bar<τ_0_0>) -> ()
2020
// CHECK: bb0(%0 : $*@callee_owned (@in Int) -> @out τ_0_0, %1 : $*Bar<τ_0_0>):
2121
}

0 commit comments

Comments
 (0)