Skip to content

Commit ad359fa

Browse files
committed
Give @_objcImpl classes implicit deinits
1 parent a36b521 commit ad359fa

File tree

13 files changed

+256
-41
lines changed

13 files changed

+256
-41
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/IRGen/GenClass.cpp

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1760,7 +1760,7 @@ namespace {
17601760
/// Destructors need to be collected into the instance methods
17611761
/// list
17621762
void visitDestructorDecl(DestructorDecl *destructor) {
1763-
auto classDecl = cast<ClassDecl>(destructor->getDeclContext());
1763+
auto classDecl = cast<ClassDecl>(destructor->getDeclContext()->getImplementedObjCContext());
17641764
if (Lowering::usesObjCAllocator(classDecl) &&
17651765
hasObjCDeallocDefinition(destructor)) {
17661766
InstanceMethods.push_back(destructor);
@@ -2371,6 +2371,131 @@ namespace {
23712371
if (auto setter = subscript->getOpaqueAccessor(AccessorKind::Set))
23722372
methods.push_back(setter);
23732373
}
2374+
2375+
SWIFT_DEBUG_DUMP {
2376+
dump(llvm::errs());
2377+
llvm::errs() << "\n";
2378+
}
2379+
2380+
void dump(llvm::raw_ostream &os) const {
2381+
os << "(class_data_builder";
2382+
2383+
if (isBuildingClass())
2384+
os << " for_class";
2385+
if (isBuildingCategory())
2386+
os << " for_category";
2387+
if (isBuildingProtocol())
2388+
os << " for_protocol";
2389+
2390+
if (auto cd = getClass()) {
2391+
os << " class=";
2392+
cd->dumpRef(os);
2393+
}
2394+
if (auto pd = getProtocol()) {
2395+
os << " protocol=";
2396+
pd->dumpRef(os);
2397+
}
2398+
if (auto ty = getSpecializedGenericType()) {
2399+
os << " specialized=";
2400+
ty->print(os);
2401+
}
2402+
if (TheExtension) {
2403+
os << " extension=";
2404+
TheExtension->getExtendedTypeRepr()->print(os);
2405+
os << "@";
2406+
TheExtension->getLoc().print(os, IGM.Context.SourceMgr);
2407+
}
2408+
if (auto name = getObjCImplCategoryName()) {
2409+
os << " objc_impl_category_name=" << *name;
2410+
}
2411+
2412+
if (HasNonTrivialConstructor)
2413+
os << " has_non_trivial_constructor";
2414+
if (HasNonTrivialDestructor)
2415+
os << " has_non_trivial_destructor";
2416+
2417+
if (!CategoryName.empty())
2418+
os << " category_name=" << CategoryName;
2419+
2420+
os << "\n (ivars";
2421+
for (auto field : Ivars) {
2422+
os << "\n (";
2423+
switch (field.getKind()) {
2424+
case Field::Kind::Var:
2425+
os << "var ";
2426+
field.getVarDecl()->dumpRef(os);
2427+
break;
2428+
case Field::Kind::MissingMember:
2429+
os << "missing_member";
2430+
break;
2431+
case Field::Kind::DefaultActorStorage:
2432+
os << "default_actor_storage";
2433+
break;
2434+
}
2435+
os << ")";
2436+
}
2437+
os << ")";
2438+
2439+
auto printMethodList =
2440+
[&](StringRef label,
2441+
const SmallVectorImpl<MethodDescriptor> &methods) {
2442+
if (methods.empty()) return;
2443+
2444+
os << "\n (" << label;
2445+
for (auto method : methods) {
2446+
os << "\n (";
2447+
switch (method.getKind()) {
2448+
case MethodDescriptor::Kind::Method:
2449+
os << "method ";
2450+
method.getMethod()->dumpRef(os);
2451+
break;
2452+
2453+
case MethodDescriptor::Kind::IVarInitializer:
2454+
os << "ivar_initializer";
2455+
method.getImpl()->printAsOperand(os);
2456+
break;
2457+
2458+
case MethodDescriptor::Kind::IVarDestroyer:
2459+
os << "ivar_destroyer";
2460+
method.getImpl()->printAsOperand(os);
2461+
break;
2462+
}
2463+
os << ")";
2464+
}
2465+
os << ")";
2466+
};
2467+
2468+
printMethodList("instance_methods", InstanceMethods);
2469+
printMethodList("class_methods", ClassMethods);
2470+
printMethodList("opt_instance_methods", OptInstanceMethods);
2471+
printMethodList("opt_class_methods", OptClassMethods);
2472+
2473+
os << "\n (protocols";
2474+
for (auto pd : Protocols) {
2475+
os << "\n (protocol ";
2476+
pd->dumpRef(os);
2477+
os << ")";
2478+
}
2479+
os << ")";
2480+
2481+
auto printPropertyList = [&](StringRef label,
2482+
const SmallVectorImpl<VarDecl *> &props) {
2483+
if (props.empty()) return;
2484+
2485+
os << "\n (" << label;
2486+
for (auto prop : props) {
2487+
os << "\n (property ";
2488+
prop->dumpRef(os);
2489+
os << ")";
2490+
}
2491+
os << ")";
2492+
};
2493+
2494+
printPropertyList("instance_properties", InstanceProperties);
2495+
printPropertyList("class_properties", ClassProperties);
2496+
2497+
os << ")";
2498+
}
23742499
};
23752500
} // end anonymous namespace
23762501

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,13 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) {
420420
if (fn->hasForcedStaticDispatch())
421421
return Limit::OnDemand;
422422
}
423+
424+
if (auto dd = dyn_cast<DestructorDecl>(d)) {
425+
// The destructor of a class implemented with @_objcImplementation is only
426+
// ever called by its ObjC thunk, so it should not be public.
427+
if (d->getDeclContext()->getSelfNominalTypeDecl()->hasClangNode())
428+
return Limit::OnDemand;
429+
}
423430

424431
switch (constant.kind) {
425432
case Kind::Func:
@@ -565,7 +572,8 @@ SILLinkage SILDeclRef::getDefinitionLinkage() const {
565572
// Stored property initializers have linkage based on the access level of
566573
// their nominal.
567574
if (isStoredPropertyInitializer())
568-
decl = cast<NominalTypeDecl>(decl->getDeclContext());
575+
decl = cast<NominalTypeDecl>(
576+
decl->getDeclContext()->getImplementedObjCContext());
569577

570578
// Compute the effective access level, taking e.g testable into consideration.
571579
auto effectiveAccess = decl->getEffectiveAccess();
@@ -791,7 +799,7 @@ IsSerialized_t SILDeclRef::isSerialized() const {
791799
// marked as @frozen.
792800
if (isStoredPropertyInitializer() || (isPropertyWrapperBackingInitializer() &&
793801
d->getDeclContext()->isTypeContext())) {
794-
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
802+
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext()->getImplementedObjCContext());
795803
auto scope =
796804
nominal->getFormalAccessScope(/*useDC=*/nullptr,
797805
/*treatUsableFromInlineAsPublic=*/true);

lib/SIL/IR/SILFunctionBuilder.cpp

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

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

315316
if (auto availability = constant.getAvailabilityForLinkage())

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
14871487
if (!cd->requiresStoredPropertyInits())
14881488
return false;
14891489

1490-
for (Decl *member : cd->getMembers()) {
1490+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
14911491
auto pbd = dyn_cast<PatternBindingDecl>(member);
14921492
if (!pbd) continue;
14931493

@@ -1500,7 +1500,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
15001500
}
15011501

15021502
bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) {
1503-
for (Decl *member : cd->getMembers()) {
1503+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
15041504
auto *vd = dyn_cast<VarDecl>(member);
15051505
if (!vd || !vd->hasStorage()) continue;
15061506

lib/SILGen/SILGenDestructor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ void SILGenFunction::emitMoveOnlyMemberDestruction(SILValue selfValue,
586586

587587
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) {
588588
auto dd = cast<DestructorDecl>(dtor.getDecl());
589-
auto cd = cast<ClassDecl>(dd->getDeclContext());
589+
auto cd = cast<ClassDecl>(dd->getDeclContext()->getImplementedObjCContext());
590590
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));
591591

592592
RegularLocation loc(dd);

lib/SILGen/SILGenType.cpp

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

12451245
for (Decl *member : e->getABIMembers())
12461246
visit(member);
1247+
1248+
// If this is a main-interface @_objcImplementation extension and the class
1249+
// has a synthesized destructor, emit it now.
1250+
if (auto cd = dyn_cast_or_null<ClassDecl>(e->getImplementedObjCDecl())) {
1251+
auto dd = cd->getDestructor();
1252+
if (dd->getDeclContext() == cd)
1253+
visit(dd);
1254+
}
12471255

12481256
if (!isa<ProtocolDecl>(e->getExtendedNominal())) {
12491257
// Emit witness tables for protocol conformances introduced by the
@@ -1302,14 +1310,18 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
13021310
SGM.emitObjCConstructorThunk(cd);
13031311
}
13041312
void visitDestructorDecl(DestructorDecl *dd) {
1313+
auto contextInterface = dd->getDeclContext()->getImplementedObjCContext();
1314+
if (auto cd = dyn_cast<ClassDecl>(contextInterface)) {
1315+
SGM.emitDestructor(cd, dd);
1316+
return;
1317+
}
13051318
llvm_unreachable("destructor in extension?!");
13061319
}
13071320

13081321
void visitPatternBindingDecl(PatternBindingDecl *pd) {
13091322
// Emit initializers for static variables.
13101323
for (auto i : range(pd->getNumPatternEntries())) {
1311-
if (pd->getExecutableInit(i)) {
1312-
assert(pd->isStatic() && "stored property in extension?!");
1324+
if (pd->getExecutableInit(i) && pd->isStatic()) {
13131325
SGM.emitGlobalInitialization(pd, i);
13141326
}
13151327
}

lib/Sema/TypeCheckDeclPrimary.cpp

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

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

32103210
TypeChecker::checkDeclAttributes(ED);
32113211

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

lib/TBDGen/TBDGen.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,11 +892,11 @@ void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
892892
visit(member);
893893
}
894894

895-
void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
895+
bool TBDGenVisitor::addClassMetadata(ClassDecl *CD) {
896896
if (Opts.PublicSymbolsOnly &&
897897
getDeclLinkage(CD) != FormalLinkage::PublicUnique)
898-
return;
899-
898+
return false;
899+
900900
auto &ctxt = CD->getASTContext();
901901
auto isGeneric = CD->isGenericContext();
902902
auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric;
@@ -947,7 +947,14 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
947947
CD, TypeMetadataAddress::AddressPoint));
948948
}
949949
}
950+
951+
return true;
952+
}
950953

954+
void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
955+
if (!addClassMetadata(CD))
956+
return;
957+
951958
// Emit dispatch thunks for every new vtable entry.
952959
struct VTableVisitor : public SILVTableVisitor<VTableVisitor> {
953960
TBDGenVisitor &TBD;
@@ -1020,9 +1027,8 @@ void TBDGenVisitor::visitDestructorDecl(DestructorDecl *DD) {
10201027

10211028
void TBDGenVisitor::visitExtensionDecl(ExtensionDecl *ED) {
10221029
if (auto CD = dyn_cast_or_null<ClassDecl>(ED->getImplementedObjCDecl())) {
1023-
// Generate symbols for the class instead of the extension.
1024-
visitClassDecl(CD);
1025-
return;
1030+
// @_objcImplementation extensions generate the class metadata symbols.
1031+
(void)addClassMetadata(CD);
10261032
}
10271033

10281034
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)