Skip to content

Commit 76beb1c

Browse files
committed
Give @_objcImpl classes implicit deinits
1 parent cb95dad commit 76beb1c

15 files changed

+258
-44
lines changed

include/swift/AST/TypeMemberVisitor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ class TypeMemberVisitor : public DeclVisitor<ImplClass, RetTy> {
6868
for (Decl *member : D->getImplementationContext()->getMembers()) {
6969
asImpl().visit(member);
7070
}
71+
72+
// If this is a main-interface @_objcImplementation extension and the class
73+
// has a synthesized destructor, visit it now.
74+
if (auto cd = dyn_cast_or_null<ClassDecl>(D)) {
75+
auto dd = cd->getDestructor();
76+
if (dd->getDeclContext() == cd && cd->getImplementationContext() != cd)
77+
asImpl().visit(dd);
78+
}
7179
}
7280
};
7381

lib/AST/AccessRequests.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,14 @@ AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
8484
if (D->hasInterfaceType() && D->isInvalid()) {
8585
return AccessLevel::Private;
8686
} else {
87-
auto container = cast<NominalTypeDecl>(D->getDeclContext());
87+
auto container = dyn_cast<NominalTypeDecl>(DC);
88+
if (D->getKind() == DeclKind::Destructor && !container) {
89+
// A destructor in an extension means @_objcImplementation. An
90+
// @_objcImplementation class's deinit is only called by the ObjC thunk,
91+
// if at all, so it is nonpublic.
92+
return AccessLevel::Internal;
93+
}
94+
8895
return std::max(container->getFormalAccess(), AccessLevel::Internal);
8996
}
9097
}

lib/AST/Decl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4982,7 +4982,6 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const {
49824982
// Synthesize an empty body for the destructor as needed.
49834983
DD->setBodySynthesizer(synthesizeEmptyFunctionBody);
49844984

4985-
// Propagate access control and versioned-ness.
49864985
DD->copyFormalAccessFrom(CD, /*sourceIsParentContext*/true);
49874986

49884987
// Mark DD as ObjC, as all dtors are.
@@ -9547,4 +9546,4 @@ bool ActorIsolation::isDistributedActor() const {
95479546
BuiltinTupleDecl::BuiltinTupleDecl(Identifier Name,
95489547
DeclContext *Parent)
95499548
: NominalTypeDecl(DeclKind::BuiltinTuple, Parent, Name, SourceLoc(),
9550-
ArrayRef<InheritedEntry>(), nullptr) {}
9549+
ArrayRef<InheritedEntry>(), nullptr) {}

lib/IRGen/GenClass.cpp

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,7 @@ namespace {
16921692
/// Destructors need to be collected into the instance methods
16931693
/// list
16941694
void visitDestructorDecl(DestructorDecl *destructor) {
1695-
auto classDecl = cast<ClassDecl>(destructor->getDeclContext());
1695+
auto classDecl = cast<ClassDecl>(destructor->getDeclContext()->getImplementedObjCContext());
16961696
if (Lowering::usesObjCAllocator(classDecl) &&
16971697
hasObjCDeallocDefinition(destructor)) {
16981698
InstanceMethods.push_back(destructor);
@@ -2303,6 +2303,131 @@ namespace {
23032303
if (auto setter = subscript->getOpaqueAccessor(AccessorKind::Set))
23042304
methods.push_back(setter);
23052305
}
2306+
2307+
SWIFT_DEBUG_DUMP {
2308+
dump(llvm::errs());
2309+
llvm::errs() << "\n";
2310+
}
2311+
2312+
void dump(llvm::raw_ostream &os) const {
2313+
os << "(class_data_builder";
2314+
2315+
if (isBuildingClass())
2316+
os << " for_class";
2317+
if (isBuildingCategory())
2318+
os << " for_category";
2319+
if (isBuildingProtocol())
2320+
os << " for_protocol";
2321+
2322+
if (auto cd = getClass()) {
2323+
os << " class=";
2324+
cd->dumpRef(os);
2325+
}
2326+
if (auto pd = getProtocol()) {
2327+
os << " protocol=";
2328+
pd->dumpRef(os);
2329+
}
2330+
if (auto ty = getSpecializedGenericType()) {
2331+
os << " specialized=";
2332+
ty->print(os);
2333+
}
2334+
if (TheExtension) {
2335+
os << " extension=";
2336+
TheExtension->getExtendedTypeRepr()->print(os);
2337+
os << "@";
2338+
TheExtension->getLoc().print(os, IGM.Context.SourceMgr);
2339+
}
2340+
if (auto name = getObjCImplCategoryName()) {
2341+
os << " objc_impl_category_name=" << *name;
2342+
}
2343+
2344+
if (HasNonTrivialConstructor)
2345+
os << " has_non_trivial_constructor";
2346+
if (HasNonTrivialDestructor)
2347+
os << " has_non_trivial_destructor";
2348+
2349+
if (!CategoryName.empty())
2350+
os << " category_name=" << CategoryName;
2351+
2352+
os << "\n (ivars";
2353+
for (auto field : Ivars) {
2354+
os << "\n (";
2355+
switch (field.getKind()) {
2356+
case Field::Kind::Var:
2357+
os << "var ";
2358+
field.getVarDecl()->dumpRef(os);
2359+
break;
2360+
case Field::Kind::MissingMember:
2361+
os << "missing_member";
2362+
break;
2363+
case Field::Kind::DefaultActorStorage:
2364+
os << "default_actor_storage";
2365+
break;
2366+
}
2367+
os << ")";
2368+
}
2369+
os << ")";
2370+
2371+
auto printMethodList =
2372+
[&](StringRef label,
2373+
const SmallVectorImpl<MethodDescriptor> &methods) {
2374+
if (methods.empty()) return;
2375+
2376+
os << "\n (" << label;
2377+
for (auto method : methods) {
2378+
os << "\n (";
2379+
switch (method.getKind()) {
2380+
case MethodDescriptor::Kind::Method:
2381+
os << "method ";
2382+
method.getMethod()->dumpRef(os);
2383+
break;
2384+
2385+
case MethodDescriptor::Kind::IVarInitializer:
2386+
os << "ivar_initializer";
2387+
method.getImpl()->printAsOperand(os);
2388+
break;
2389+
2390+
case MethodDescriptor::Kind::IVarDestroyer:
2391+
os << "ivar_destroyer";
2392+
method.getImpl()->printAsOperand(os);
2393+
break;
2394+
}
2395+
os << ")";
2396+
}
2397+
os << ")";
2398+
};
2399+
2400+
printMethodList("instance_methods", InstanceMethods);
2401+
printMethodList("class_methods", ClassMethods);
2402+
printMethodList("opt_instance_methods", OptInstanceMethods);
2403+
printMethodList("opt_class_methods", OptClassMethods);
2404+
2405+
os << "\n (protocols";
2406+
for (auto pd : Protocols) {
2407+
os << "\n (protocol ";
2408+
pd->dumpRef(os);
2409+
os << ")";
2410+
}
2411+
os << ")";
2412+
2413+
auto printPropertyList = [&](StringRef label,
2414+
const SmallVectorImpl<VarDecl *> &props) {
2415+
if (props.empty()) return;
2416+
2417+
os << "\n (" << label;
2418+
for (auto prop : props) {
2419+
os << "\n (property ";
2420+
prop->dumpRef(os);
2421+
os << ")";
2422+
}
2423+
os << ")";
2424+
};
2425+
2426+
printPropertyList("instance_properties", InstanceProperties);
2427+
printPropertyList("class_properties", ClassProperties);
2428+
2429+
os << ")";
2430+
}
23062431
};
23072432
} // end anonymous namespace
23082433

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,13 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
416416
if (isEnumElement()) {
417417
limit = Limit::OnDemand;
418418
}
419+
420+
if (auto dd = dyn_cast<DestructorDecl>(d)) {
421+
// The destructor of a class implemented with @_objcImplementation is only
422+
// ever called by its ObjC thunk, so it should not be public.
423+
if (d->getDeclContext()->getSelfClassDecl()->hasClangNode())
424+
limit = Limit::OnDemand;
425+
}
419426

420427
auto effectiveAccess = d->getEffectiveAccess();
421428

@@ -625,7 +632,7 @@ IsSerialized_t SILDeclRef::isSerialized() const {
625632
// marked as @frozen.
626633
if (isStoredPropertyInitializer() || (isPropertyWrapperBackingInitializer() &&
627634
d->getDeclContext()->isTypeContext())) {
628-
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
635+
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext()->getImplementedObjCContext());
629636
auto scope =
630637
nominal->getFormalAccessScope(/*useDC=*/nullptr,
631638
/*treatUsableFromInlineAsPublic=*/true);

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
308308
if (constant.hasDecl()) {
309309
auto decl = constant.getDecl();
310310

311-
if (constant.isForeign && decl->hasClangNode())
311+
if (constant.isForeign && decl->hasClangNode() &&
312+
!decl->getObjCImplementationDecl())
312313
F->setClangNodeOwner(decl);
313314

314315
F->setAvailabilityForLinkage(decl->getAvailabilityForLinkage());

lib/SILGen/SILGen.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
10851085

10861086
case SILDeclRef::Kind::Deallocator: {
10871087
auto *dd = cast<DestructorDecl>(constant.getDecl());
1088-
auto *cd = cast<ClassDecl>(dd->getDeclContext());
1088+
auto *cd = cast<ClassDecl>(dd->getDeclContext()->getImplementedObjCContext());
10891089

10901090
if (usesObjCAllocator(cd)) {
10911091
preEmitFunction(constant, f, dd);
@@ -1508,7 +1508,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
15081508
if (!cd->requiresStoredPropertyInits())
15091509
return false;
15101510

1511-
for (Decl *member : cd->getMembers()) {
1511+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
15121512
auto pbd = dyn_cast<PatternBindingDecl>(member);
15131513
if (!pbd) continue;
15141514

@@ -1521,7 +1521,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
15211521
}
15221522

15231523
bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) {
1524-
for (Decl *member : cd->getMembers()) {
1524+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
15251525
auto *vd = dyn_cast<VarDecl>(member);
15261526
if (!vd || !vd->hasStorage()) continue;
15271527

lib/SILGen/SILGenDestructor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
442442

443443
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) {
444444
auto dd = cast<DestructorDecl>(dtor.getDecl());
445-
auto cd = cast<ClassDecl>(dd->getDeclContext());
445+
auto cd = cast<ClassDecl>(dd->getDeclContext()->getImplementedObjCContext());
446446
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));
447447

448448
RegularLocation loc(dd);

lib/SILGen/SILGenType.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,14 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
12361236

12371237
for (Decl *member : e->getABIMembers())
12381238
visit(member);
1239+
1240+
// If this is a main-interface @_objcImplementation extension and the class
1241+
// has a synthesized destructor, emit it now.
1242+
if (auto cd = dyn_cast_or_null<ClassDecl>(e->getImplementedObjCDecl())) {
1243+
auto dd = cd->getDestructor();
1244+
if (dd->getDeclContext() == cd)
1245+
visit(dd);
1246+
}
12391247

12401248
if (!isa<ProtocolDecl>(e->getExtendedNominal())) {
12411249
// Emit witness tables for protocol conformances introduced by the
@@ -1294,14 +1302,18 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
12941302
SGM.emitObjCConstructorThunk(cd);
12951303
}
12961304
void visitDestructorDecl(DestructorDecl *dd) {
1305+
auto contextInterface = dd->getDeclContext()->getImplementedObjCContext();
1306+
if (auto cd = dyn_cast<ClassDecl>(contextInterface)) {
1307+
SGM.emitDestructor(cd, dd);
1308+
return;
1309+
}
12971310
llvm_unreachable("destructor in extension?!");
12981311
}
12991312

13001313
void visitPatternBindingDecl(PatternBindingDecl *pd) {
13011314
// Emit initializers for static variables.
13021315
for (auto i : range(pd->getNumPatternEntries())) {
1303-
if (pd->getExecutableInit(i)) {
1304-
assert(pd->isStatic() && "stored property in extension?!");
1316+
if (pd->getExecutableInit(i) && pd->isStatic()) {
13051317
SGM.emitGlobalInitialization(pd, i);
13061318
}
13071319
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ static void checkObjCImplementationMemberAvoidsVTable(ValueDecl *VD) {
12291229
"@_objcImplementation on non-class or Swift class?");
12301230

12311231
if (VD->isSemanticallyFinal() || VD->isObjC()) {
1232-
assert(!VD->isObjC() || VD->isDynamic() &&
1232+
assert(isa<DestructorDecl>(VD) || !VD->isObjC() || VD->isDynamic() &&
12331233
"@objc decls in @_objcImplementations should be dynamic!");
12341234
return;
12351235
}
@@ -3205,6 +3205,18 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32053205

32063206
TypeChecker::checkDeclAttributes(ED);
32073207

3208+
// If this is an @_objcImplementation of a class, set up some aspects of the
3209+
// class.
3210+
if (auto CD = dyn_cast_or_null<ClassDecl>(ED->getImplementedObjCDecl())) {
3211+
// Force lowering of stored properties.
3212+
(void) CD->getStoredProperties();
3213+
3214+
// Force creation of an implicit destructor, if any.
3215+
(void) CD->getDestructor();
3216+
3217+
// FIXME: Should we duplicate any other logic from visitClassDecl()?
3218+
}
3219+
32083220
for (Decl *Member : ED->getMembers())
32093221
visit(Member);
32103222

lib/TBDGen/TBDGen.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -888,11 +888,11 @@ void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
888888
visit(member);
889889
}
890890

891-
void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
891+
bool TBDGenVisitor::addClassMetadata(ClassDecl *CD) {
892892
if (Opts.PublicSymbolsOnly &&
893893
getDeclLinkage(CD) != FormalLinkage::PublicUnique)
894-
return;
895-
894+
return false;
895+
896896
auto &ctxt = CD->getASTContext();
897897
auto isGeneric = CD->isGenericContext();
898898
auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric;
@@ -943,7 +943,14 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
943943
CD, TypeMetadataAddress::AddressPoint));
944944
}
945945
}
946+
947+
return true;
948+
}
946949

950+
void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
951+
if (!addClassMetadata(CD))
952+
return;
953+
947954
// Emit dispatch thunks for every new vtable entry.
948955
struct VTableVisitor : public SILVTableVisitor<VTableVisitor> {
949956
TBDGenVisitor &TBD;
@@ -1015,9 +1022,8 @@ void TBDGenVisitor::visitDestructorDecl(DestructorDecl *DD) {
10151022

10161023
void TBDGenVisitor::visitExtensionDecl(ExtensionDecl *ED) {
10171024
if (auto CD = dyn_cast_or_null<ClassDecl>(ED->getImplementedObjCDecl())) {
1018-
// Generate symbols for the class instead of the extension.
1019-
visitClassDecl(CD);
1020-
return;
1025+
// @_objcImplementation extensions generate the class metadata symbols.
1026+
(void)addClassMetadata(CD);
10211027
}
10221028

10231029
if (!isa<ProtocolDecl>(ED->getExtendedNominal())) {

lib/TBDGen/TBDGenVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
127127
void addAsyncFunctionPointerSymbol(SILDeclRef declRef);
128128

129129
void addSymbol(LinkEntity entity);
130+
131+
bool addClassMetadata(ClassDecl *CD);
130132

131133
void addConformances(const IterableDeclContext *IDC);
132134

0 commit comments

Comments
 (0)