Skip to content

Commit 6c28360

Browse files
committed
Give @_objcImpl classes implicit deinits
1 parent 1892501 commit 6c28360

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

lib/SIL/IR/SILDeclRef.cpp

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

423430
switch (constant.kind) {
424431
case Kind::Func:
@@ -564,7 +571,8 @@ SILLinkage SILDeclRef::getDefinitionLinkage() const {
564571
// Stored property initializers have linkage based on the access level of
565572
// their nominal.
566573
if (isStoredPropertyInitializer())
567-
decl = cast<NominalTypeDecl>(decl->getDeclContext());
574+
decl = cast<NominalTypeDecl>(
575+
decl->getDeclContext()->getImplementedObjCContext());
568576

569577
// Compute the effective access level, taking e.g testable into consideration.
570578
auto effectiveAccess = decl->getEffectiveAccess();
@@ -790,7 +798,7 @@ IsSerialized_t SILDeclRef::isSerialized() const {
790798
// marked as @frozen.
791799
if (isStoredPropertyInitializer() || (isPropertyWrapperBackingInitializer() &&
792800
d->getDeclContext()->isTypeContext())) {
793-
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
801+
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext()->getImplementedObjCContext());
794802
auto scope =
795803
nominal->getFormalAccessScope(/*useDC=*/nullptr,
796804
/*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
@@ -1497,7 +1497,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
14971497
if (!cd->requiresStoredPropertyInits())
14981498
return false;
14991499

1500-
for (Decl *member : cd->getMembers()) {
1500+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
15011501
auto pbd = dyn_cast<PatternBindingDecl>(member);
15021502
if (!pbd) continue;
15031503

@@ -1510,7 +1510,7 @@ static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
15101510
}
15111511

15121512
bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) {
1513-
for (Decl *member : cd->getMembers()) {
1513+
for (Decl *member : cd->getImplementationContext()->getMembers()) {
15141514
auto *vd = dyn_cast<VarDecl>(member);
15151515
if (!vd || !vd->hasStorage()) continue;
15161516

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)