Skip to content

Commit fbe65e2

Browse files
authored
[ClangImporter] Import objc_subclassing_restricted classes as 'public' (#14766)
(rather than 'open') This attribute was originally introduced for Swift classes exposed to Objective-C, but if it /is/ used on a pure Objective-C class Swift should respect it. There might be an actual reason, such as a hot code path in ContrivedExampleKit checking against the class object's address instead of using -isKindOfClass:. For source compatibility, only enforce this in Swift 5 mode. rdar://problem/33971529
1 parent cad6045 commit fbe65e2

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,15 +4511,15 @@ namespace {
45114511
}
45124512

45134513
Decl *VisitObjCInterfaceDecl(const clang::ObjCInterfaceDecl *decl) {
4514-
auto createRootClass = [=](Identifier name,
4515-
DeclContext *dc = nullptr) -> ClassDecl * {
4514+
auto createFakeRootClass = [=](Identifier name,
4515+
DeclContext *dc = nullptr) -> ClassDecl * {
45164516
if (!dc) {
45174517
dc = Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
45184518
/*allowForwardDeclaration=*/true);
45194519
}
45204520

45214521
auto result = Impl.createDeclWithClangNode<ClassDecl>(decl,
4522-
AccessLevel::Open,
4522+
AccessLevel::Public,
45234523
SourceLoc(), name,
45244524
SourceLoc(), None,
45254525
nullptr, dc);
@@ -4547,7 +4547,7 @@ namespace {
45474547
const ClassDecl *nsObjectDecl =
45484548
nsObjectTy->getClassOrBoundGenericClass();
45494549

4550-
auto result = createRootClass(Impl.SwiftContext.Id_Protocol,
4550+
auto result = createFakeRootClass(Impl.SwiftContext.Id_Protocol,
45514551
nsObjectDecl->getDeclContext());
45524552
result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly);
45534553
return result;
@@ -4579,7 +4579,7 @@ namespace {
45794579

45804580
if (Impl.ImportForwardDeclarations) {
45814581
// Fake it by making an unavailable opaque @objc root class.
4582-
auto result = createRootClass(name);
4582+
auto result = createFakeRootClass(name);
45834583
result->setImplicit();
45844584
auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext,
45854585
"This Objective-C class has only been forward-declared; "
@@ -4602,13 +4602,16 @@ namespace {
46024602
if (declaredNative && nativeDecl)
46034603
return nativeDecl;
46044604

4605+
auto access = AccessLevel::Open;
4606+
if (decl->hasAttr<clang::ObjCSubclassingRestrictedAttr>() &&
4607+
Impl.SwiftContext.isSwiftVersionAtLeast(5)) {
4608+
access = AccessLevel::Public;
4609+
}
4610+
46054611
// Create the class declaration and record it.
4606-
auto result = Impl.createDeclWithClangNode<ClassDecl>(decl,
4607-
AccessLevel::Open,
4608-
Impl.importSourceLoc(decl->getLocStart()),
4609-
name,
4610-
Impl.importSourceLoc(decl->getLocation()),
4611-
None, nullptr, dc);
4612+
auto result = Impl.createDeclWithClangNode<ClassDecl>(
4613+
decl, access, Impl.importSourceLoc(decl->getLocStart()), name,
4614+
Impl.importSourceLoc(decl->getLocation()), None, nullptr, dc);
46124615

46134616
// Import generic arguments, if any.
46144617
if (auto gpImportResult = importObjCGenericParams(decl, dc)) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// This file is meant to be used with the mock SDK.
2+
#import <Foundation.h>
3+
4+
__attribute__((objc_subclassing_restricted))
5+
@interface Restricted: NSObject
6+
@end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/attr-objc_subclassing_restricted.h %s -swift-version 5 -verify
2+
3+
// No errors in Swift 3 and 4 modes.
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/attr-objc_subclassing_restricted.h %s -swift-version 4
5+
6+
// REQUIRES: objc_interop
7+
8+
class Sub: Restricted { // expected-error {{cannot inherit from non-open class 'Restricted' outside of its defining module}}
9+
}

0 commit comments

Comments
 (0)