Skip to content

Commit 406e72d

Browse files
authored
Merge pull request #9983 from huonw/symbol-list-9
More TBD work
2 parents d43099f + 296f231 commit 406e72d

File tree

7 files changed

+138
-43
lines changed

7 files changed

+138
-43
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4099,6 +4099,10 @@ class AbstractStorageDecl : public ValueDecl {
40994099

41004100
FuncDecl *getAccessorFunction(AccessorKind accessor) const;
41014101

4102+
/// \brief Push all of the accessor functions associated with this VarDecl
4103+
/// onto `decls`.
4104+
void getAllAccessorFunctions(SmallVectorImpl<Decl *> &decls) const;
4105+
41024106
/// \brief Turn this into a computed variable, providing a getter and setter.
41034107
void makeComputed(SourceLoc LBraceLoc, FuncDecl *Get, FuncDecl *Set,
41044108
FuncDecl *MaterializeForSet, SourceLoc RBraceLoc);

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/AST/Decl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3432,6 +3432,28 @@ FuncDecl *AbstractStorageDecl::getAccessorFunction(AccessorKind kind) const {
34323432
llvm_unreachable("bad accessor kind!");
34333433
}
34343434

3435+
void AbstractStorageDecl::getAllAccessorFunctions(
3436+
SmallVectorImpl<Decl *> &decls) const {
3437+
auto tryPush = [&](Decl *decl) {
3438+
if (decl)
3439+
decls.push_back(decl);
3440+
};
3441+
3442+
tryPush(getGetter());
3443+
tryPush(getSetter());
3444+
tryPush(getMaterializeForSetFunc());
3445+
3446+
if (hasObservers()) {
3447+
tryPush(getDidSetFunc());
3448+
tryPush(getWillSetFunc());
3449+
}
3450+
3451+
if (hasAddressors()) {
3452+
tryPush(getAddressor());
3453+
tryPush(getMutableAddressor());
3454+
}
3455+
}
3456+
34353457
void AbstractStorageDecl::configureGetSetRecord(GetSetRecord *getSetInfo,
34363458
FuncDecl *getter,
34373459
FuncDecl *setter,

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: 87 additions & 25 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,
@@ -96,6 +81,8 @@ class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
9681
addMembers(ED->getMembers());
9782
else if (auto NTD = dyn_cast<NominalTypeDecl>(D))
9883
addMembers(NTD->getMembers());
84+
else if (auto VD = dyn_cast<VarDecl>(D))
85+
VD->getAllAccessorFunctions(members);
9986

10087
for (auto member : members) {
10188
ASTVisitor::visit(member);
@@ -160,10 +147,6 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) {
160147
// currently need to refer to them by symbol for their own vtable.
161148
switch (declRef.getSubclassScope()) {
162149
case SubclassScope::External:
163-
// Allocating constructors retain their normal linkage behavior.
164-
if (declRef.kind == SILDeclRef::Kind::Allocator)
165-
break;
166-
167150
// Unlike the "truly" public things, private things have public symbols
168151
// unconditionally, even if they're theoretically SIL only.
169152
if (isPrivate) {
@@ -186,6 +169,81 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) {
186169
addSymbol(declRef.mangle());
187170
}
188171

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+
189247
void TBDGenVisitor::visitValueDecl(ValueDecl *VD) {
190248
addSymbol(SILDeclRef(VD));
191249
visitMembers(VD);
@@ -225,9 +283,11 @@ void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
225283
// like globals.
226284
if (!FileHasEntryPoint)
227285
addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
228-
}
229286

230-
visitMembers(VD);
287+
// In this case, the members of the VarDecl don't also appear as top-level
288+
// decls, so we need to explicitly walk them.
289+
visitMembers(VD);
290+
}
231291
}
232292

233293
void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
@@ -281,9 +341,11 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
281341
auto hasFieldOffset =
282342
!isGeneric && var && var->hasStorage() && !var->isStatic();
283343
if (hasFieldOffset) {
284-
// Field are only direct if the class's internals are completely known.
285-
auto isIndirect = !CD->hasFixedLayout();
286-
addSymbol(LinkEntity::forFieldOffset(var, isIndirect));
344+
// FIXME: a field only has one sort of offset, but it is moderately
345+
// non-trivial to compute which one. Including both is less painful than
346+
// missing the correct one (for now), so we do that.
347+
addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/false));
348+
addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/true));
287349
}
288350

289351
// The non-allocating forms of the constructors and destructors.

test/TBD/class.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=all %s
1+
// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=missing %s
22

33
open class OpenNothing {}
44

0 commit comments

Comments
 (0)