Skip to content

Commit 2ad15fe

Browse files
committed
PrintAsObjC: Add support for classes with resilient ancestry
Without -enable-resilient-objc-class-stubs, don't print classes with resilient ancestry at all, since they're not actually visible to Clang and referencing one will not actually work. When the flag is specified, such classes do appear in the generated header with the new objc_class_stub Clang attribute.
1 parent 8ecb83e commit 2ad15fe

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,22 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
322322
void visitClassDecl(ClassDecl *CD) {
323323
printDocumentationComment(CD);
324324

325+
bool hasResilientAncestry =
326+
CD->checkAncestry().contains(AncestryFlags::ResilientOther);
327+
if (hasResilientAncestry) {
328+
os << "SWIFT_RESILIENT_CLASS";
329+
} else {
330+
os << "SWIFT_CLASS";
331+
}
332+
325333
StringRef customName = getNameForObjC(CD, CustomNamesOnly);
326334
if (customName.empty()) {
327335
llvm::SmallString<32> scratch;
328-
os << "SWIFT_CLASS(\"" << CD->getObjCRuntimeName(scratch) << "\")";
336+
os << "(\"" << CD->getObjCRuntimeName(scratch) << "\")";
329337
printAvailability(CD);
330338
os << "\n@interface " << CD->getName();
331339
} else {
332-
os << "SWIFT_CLASS_NAMED(\"" << CD->getName() << "\")";
340+
os << "_NAMED(\"" << CD->getName() << "\")";
333341
printAvailability(CD);
334342
os << "\n@interface " << customName;
335343
}
@@ -2640,6 +2648,20 @@ class ModuleWriter {
26402648
"SWIFT_CLASS_EXTRA\n"
26412649
"# endif\n"
26422650
"#endif\n"
2651+
"#if !defined(SWIFT_RESILIENT_CLASS)\n"
2652+
"# if __has_attribute(objc_class_stub)\n"
2653+
"# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) "
2654+
"__attribute__((objc_class_stub))\n"
2655+
"# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) "
2656+
"__attribute__((objc_class_stub)) "
2657+
"SWIFT_CLASS_NAMED(SWIFT_NAME)\n"
2658+
"# else\n"
2659+
"# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) "
2660+
"SWIFT_CLASS(SWIFT_NAME)\n"
2661+
"# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) "
2662+
"SWIFT_CLASS_NAMED(SWIFT_NAME)\n"
2663+
"# endif\n"
2664+
"#endif\n"
26432665
"\n"
26442666
"#if !defined(SWIFT_PROTOCOL)\n"
26452667
"# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) "

test/PrintAsObjC/Inputs/custom-modules/module.map

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ module VersionedFMWK {
4242
header "VersionedFMWK.h"
4343
export *
4444
}
45+
46+
module resilient_objc_class {
47+
header "resilient_objc_class.h"
48+
export *
49+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Please keep this file in alphabetical order!
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %target-swift-frontend -emit-module-path %t/resilient_struct.swiftmodule %S/../Inputs/resilient_struct.swift -enable-library-evolution
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module-path %t/resilient_objc_class.swiftmodule %S/../Inputs/resilient_objc_class.swift -I %t -enable-library-evolution -emit-objc-header-path %t/resilient_objc_class.h
6+
7+
// RUN: cp %S/Inputs/custom-modules/module.map %t/module.map
8+
9+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -module-name resilient -emit-objc-header-path %t/resilient.h -I %t -enable-library-evolution
10+
// RUN: %FileCheck %s --check-prefix=NO-STUBS < %t/resilient.h
11+
// RUN: %check-in-clang %t/resilient.h -I %t
12+
13+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -module-name resilient -emit-objc-header-path %t/resilient.h -I %t -enable-library-evolution -enable-resilient-objc-class-stubs
14+
// RUN: %FileCheck %s < %t/resilient.h
15+
// RUN: %check-in-clang %t/resilient.h -I %t
16+
17+
// REQUIRES: objc_interop
18+
19+
import Foundation
20+
import resilient_objc_class
21+
22+
// Note: @_fixed_layout on a class only applies to the storage layout and
23+
// not metadata, which remains resilient.
24+
25+
// NO-STUBS-NOT: FixedLayoutNSObjectSubclass
26+
27+
// CHECK-LABEL: SWIFT_RESILIENT_CLASS("_TtC9resilient27FixedLayoutNSObjectSubclass")
28+
// CHECK-NEXT: @interface FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent
29+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
30+
// CHECK-NEXT: @end
31+
32+
@_fixed_layout
33+
public class FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
34+
35+
// NO-STUBS-NOT: ResilientNSObjectSubclass
36+
37+
// CHECK-LABEL: SWIFT_RESILIENT_CLASS("_TtC9resilient25ResilientNSObjectSubclass")
38+
// CHECK-NEXT: @interface ResilientNSObjectSubclass : ResilientNSObjectOutsideParent
39+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
40+
// CHECK-NEXT: @end
41+
42+
public class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
43+
44+
// NO-STUBS-NOT: RenamedNSObjectSubclass
45+
46+
// CHECK-LABEL: SWIFT_RESILIENT_CLASS_NAMED("UnrenamedNSObjectSubclass")
47+
// CHECK-NEXT: @interface RenamedNSObjectSubclass : ResilientNSObjectOutsideParent
48+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
49+
// CHECK-NEXT: @end
50+
51+
@objc(RenamedNSObjectSubclass)
52+
public class UnrenamedNSObjectSubclass : ResilientNSObjectOutsideParent {}

0 commit comments

Comments
 (0)