Skip to content

Commit 296f231

Browse files
committed
[TBDGen] Protocol witnesses thunks for members of public superprotocols are public.
Specifically, public superprotocols of non-public protocols have some weird handling in SILGen, so we reproduce this. Fixes rdar://problem/32254485 .
1 parent 8d455a4 commit 296f231

File tree

4 files changed

+100
-33
lines changed

4 files changed

+100
-33
lines changed

include/swift/AST/ProtocolConformance.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,14 @@ class NormalProtocolConformance : public ProtocolConformance,
397397
AbstractStorageDecl *getBehaviorDecl() const {
398398
return ContextAndInvalid.getPointer().dyn_cast<AbstractStorageDecl *>();
399399
}
400-
400+
401+
bool isSerialized() const {
402+
auto *nominal = getType()->getAnyNominal();
403+
return nominal->hasFixedLayout() &&
404+
getProtocol()->getEffectiveAccess() >= Accessibility::Public &&
405+
nominal->getEffectiveAccess() >= Accessibility::Public;
406+
}
407+
401408
/// Retrieve the type witness and type decl (if one exists)
402409
/// for the given associated type.
403410
std::pair<Type, TypeDecl *>

include/swift/SIL/SILLinkage.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,20 @@ inline SILLinkage effectiveLinkageForClassMember(SILLinkage linkage,
252252
return linkage;
253253
}
254254

255+
// FIXME: This should not be necessary, but it looks like visibility rules for
256+
// extension members are slightly bogus, and so some protocol witness thunks
257+
// need to be public.
258+
//
259+
// We allow a 'public' member of an extension to witness a public
260+
// protocol requirement, even if the extended type is not public;
261+
// then SILGen gives the member private linkage, ignoring the more
262+
// visible accessibility it was given in the AST.
263+
inline bool
264+
fixmeWitnessHasLinkageThatNeedsToBePublic(SILLinkage witnessLinkage) {
265+
return !hasPublicVisibility(witnessLinkage) &&
266+
!hasSharedVisibility(witnessLinkage);
267+
}
268+
255269
} // end swift namespace
256270

257271
#endif

lib/SILGen/SILGenType.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
315315

316316
// Serialize the witness table if we're serializing everything with
317317
// -sil-serialize-all, or if the conformance itself thinks it should be.
318-
if (SGM.isMakeModuleFragile())
319-
Serialized = IsSerialized;
320-
321-
auto *nominal = Conformance->getType()->getAnyNominal();
322-
if (nominal->hasFixedLayout() &&
323-
proto->getEffectiveAccess() >= Accessibility::Public &&
324-
nominal->getEffectiveAccess() >= Accessibility::Public)
318+
if (SGM.isMakeModuleFragile() || Conformance->isSerialized())
325319
Serialized = IsSerialized;
326320

327321
// Not all protocols use witness tables; in this case we just skip
@@ -421,15 +415,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
421415
auto witnessLinkage = witnessRef.getLinkage(ForDefinition);
422416
auto witnessSerialized = Serialized;
423417
if (witnessSerialized &&
424-
!hasPublicVisibility(witnessLinkage) &&
425-
!hasSharedVisibility(witnessLinkage)) {
426-
// FIXME: This should not happen, but it looks like visibility rules
427-
// for extension members are slightly bogus.
428-
//
429-
// We allow a 'public' member of an extension to witness a public
430-
// protocol requirement, even if the extended type is not public;
431-
// then SILGen gives the member private linkage, ignoring the more
432-
// visible accessibility it was given in the AST.
418+
fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) {
433419
witnessLinkage = SILLinkage::Public;
434420
witnessSerialized = (SGM.isMakeModuleFragile()
435421
? IsSerialized

lib/TBDGen/TBDGen.cpp

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,7 @@ class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
6262
addSymbol(linkage.getName());
6363
}
6464

65-
void addConformances(DeclContext *DC) {
66-
for (auto conformance : DC->getLocalConformances()) {
67-
auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(
68-
conformance->getProtocol());
69-
if (!needsWTable)
70-
continue;
71-
72-
// Only normal conformances get symbols; the others get any public symbols
73-
// from their parent normal conformance.
74-
if (conformance->getKind() != ProtocolConformanceKind::Normal)
75-
continue;
76-
77-
addSymbol(LinkEntity::forDirectProtocolWitnessTable(conformance));
78-
addSymbol(LinkEntity::forProtocolWitnessTableAccessFunction(conformance));
79-
}
80-
}
65+
void addConformances(DeclContext *DC);
8166

8267
public:
8368
TBDGenVisitor(StringSet &symbols,
@@ -184,6 +169,81 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) {
184169
addSymbol(declRef.mangle());
185170
}
186171

172+
void TBDGenVisitor::addConformances(DeclContext *DC) {
173+
for (auto conformance : DC->getLocalConformances()) {
174+
auto protocol = conformance->getProtocol();
175+
auto needsWTable =
176+
Lowering::TypeConverter::protocolRequiresWitnessTable(protocol);
177+
if (!needsWTable)
178+
continue;
179+
180+
// Only normal conformances get symbols; the others get any public symbols
181+
// from their parent normal conformance.
182+
auto normalConformance = dyn_cast<NormalProtocolConformance>(conformance);
183+
if (!normalConformance)
184+
continue;
185+
186+
addSymbol(LinkEntity::forDirectProtocolWitnessTable(normalConformance));
187+
addSymbol(
188+
LinkEntity::forProtocolWitnessTableAccessFunction(normalConformance));
189+
190+
// FIXME: the logic around visibility in extensions is confusing, and
191+
// sometimes witness thunks need to be manually made public.
192+
193+
auto conformanceIsSerialized = normalConformance->isSerialized();
194+
auto addSymbolIfNecessary = [&](ValueDecl *valueReq,
195+
SILLinkage witnessLinkage) {
196+
if (conformanceIsSerialized &&
197+
fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) {
198+
Mangle::ASTMangler Mangler;
199+
addSymbol(Mangler.mangleWitnessThunk(normalConformance, valueReq));
200+
}
201+
};
202+
normalConformance->forEachValueWitness(nullptr, [&](ValueDecl *valueReq,
203+
Witness witness) {
204+
if (isa<AbstractFunctionDecl>(valueReq)) {
205+
auto witnessLinkage =
206+
SILDeclRef(witness.getDecl()).getLinkage(ForDefinition);
207+
addSymbolIfNecessary(valueReq, witnessLinkage);
208+
} else if (auto VD = dyn_cast<AbstractStorageDecl>(valueReq)) {
209+
// A var or subscript decl needs special handling in the special
210+
// handling: the things that end up in the witness table are the
211+
// accessors, but the compiler only talks about the actual storage decl
212+
// in the conformance, so we have to manually walk over the members,
213+
// having pulled out something that will have the right linkage.
214+
auto witnessVD = cast<AbstractStorageDecl>(witness.getDecl());
215+
216+
SmallVector<Decl *, 4> members;
217+
VD->getAllAccessorFunctions(members);
218+
219+
// Grab one of the accessors, and then use that to pull out which of the
220+
// getter or setter will have the appropriate linkage.
221+
FuncDecl *witnessWithRelevantLinkage;
222+
switch (cast<FuncDecl>(members[0])->getAccessorKind()) {
223+
case AccessorKind::NotAccessor:
224+
llvm_unreachable("must be an accessor");
225+
case AccessorKind::IsGetter:
226+
case AccessorKind::IsAddressor:
227+
witnessWithRelevantLinkage = witnessVD->getGetter();
228+
break;
229+
case AccessorKind::IsSetter:
230+
case AccessorKind::IsWillSet:
231+
case AccessorKind::IsDidSet:
232+
case AccessorKind::IsMaterializeForSet:
233+
case AccessorKind::IsMutableAddressor:
234+
witnessWithRelevantLinkage = witnessVD->getSetter();
235+
break;
236+
}
237+
auto witnessLinkage =
238+
SILDeclRef(witnessWithRelevantLinkage).getLinkage(ForDefinition);
239+
for (auto member : members) {
240+
addSymbolIfNecessary(cast<ValueDecl>(member), witnessLinkage);
241+
}
242+
}
243+
});
244+
}
245+
}
246+
187247
void TBDGenVisitor::visitValueDecl(ValueDecl *VD) {
188248
addSymbol(SILDeclRef(VD));
189249
visitMembers(VD);

0 commit comments

Comments
 (0)