@@ -312,16 +312,34 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
312
312
NormalProtocolConformance *Conformance;
313
313
std::vector<SILWitnessTable::Entry> Entries;
314
314
SILLinkage Linkage;
315
+ IsSerialized_t Serialized;
315
316
316
317
SILGenConformance (SILGenModule &SGM, NormalProtocolConformance *C)
317
318
// We only need to emit witness tables for base NormalProtocolConformances.
318
319
: SGM(SGM), Conformance(C->getRootNormalConformance ()),
319
320
Linkage(getLinkageForProtocolConformance(Conformance,
320
321
ForDefinition))
321
322
{
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))
325
343
Conformance = nullptr ;
326
344
}
327
345
@@ -333,19 +351,6 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
333
351
auto *proto = Conformance->getProtocol ();
334
352
visitProtocolDecl (proto);
335
353
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
-
349
354
// Check if we already have a declaration or definition for this witness
350
355
// table.
351
356
if (auto *wt = SGM.M .lookUpWitnessTable (Conformance, false )) {
@@ -358,7 +363,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
358
363
359
364
// If we have a declaration, convert the witness table to a definition.
360
365
if (wt->isDeclaration ()) {
361
- wt->convertToDefinition (Entries, isSerialized );
366
+ wt->convertToDefinition (Entries, Serialized );
362
367
363
368
// Since we had a declaration before, its linkage should be external,
364
369
// ensure that we have a compatible linkage for sanity. *NOTE* we are ok
@@ -375,7 +380,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
375
380
}
376
381
377
382
// 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 ,
379
384
Conformance, Entries);
380
385
}
381
386
@@ -427,9 +432,33 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
427
432
return ;
428
433
}
429
434
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
+
430
459
SILFunction *witnessFn =
431
- SGM.emitProtocolWitness (Conformance, Linkage, requirementRef, witnessRef ,
432
- isFree, witness);
460
+ SGM.emitProtocolWitness (Conformance, witnessLinkage, witnessSerialized ,
461
+ requirementRef, witnessRef, isFree, witness);
433
462
Entries.push_back (
434
463
SILWitnessTable::MethodWitness{requirementRef, witnessFn});
435
464
}
@@ -540,6 +569,7 @@ static bool maybeOpenCodeProtocolWitness(SILGenFunction &gen,
540
569
SILFunction *
541
570
SILGenModule::emitProtocolWitness (ProtocolConformance *conformance,
542
571
SILLinkage linkage,
572
+ IsSerialized_t isSerialized,
543
573
SILDeclRef requirement,
544
574
SILDeclRef witnessRef,
545
575
IsFreeFunctionWitness_t isFree,
@@ -637,14 +667,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
637
667
if (witnessRef.isAlwaysInline ())
638
668
InlineStrategy = AlwaysInline;
639
669
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
-
648
670
auto *f = M.createFunction (
649
671
linkage, nameBuffer, witnessSILFnType,
650
672
genericEnv, SILLocation (witnessRef.getDecl ()),
@@ -742,7 +764,9 @@ class SILGenDefaultWitnessTable
742
764
SILDeclRef witnessRef,
743
765
IsFreeFunctionWitness_t isFree,
744
766
Witness witness) {
745
- SILFunction *witnessFn = SGM.emitProtocolWitness (nullptr , Linkage,
767
+ SILFunction *witnessFn = SGM.emitProtocolWitness (nullptr ,
768
+ SILLinkage::Private,
769
+ IsNotSerialized,
746
770
requirementRef, witnessRef,
747
771
isFree, witness);
748
772
auto entry = SILDefaultWitnessTable::Entry (requirementRef, witnessFn);
0 commit comments