Skip to content

Commit 5938f5a

Browse files
authored
Merge pull request #24585 from slavapestov/weak-link-class-stubs
Add tests for weak-linked class stubs
2 parents b630380 + 9f4b86b commit 5938f5a

File tree

7 files changed

+99
-8
lines changed

7 files changed

+99
-8
lines changed

lib/PrintAsObjC/PrintAsObjC.cpp

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

325+
// This is just for testing, so we check explicitly for the attribute instead
326+
// of asking if the class is weak imported. If the class has availablility,
327+
// we'll print a SWIFT_AVAIALBLE() which implies __attribute__((weak_imported))
328+
// already.
329+
if (CD->getAttrs().hasAttribute<WeakLinkedAttr>())
330+
os << "SWIFT_WEAK_IMPORT\n";
331+
325332
bool hasResilientAncestry =
326333
CD->checkAncestry().contains(AncestryFlags::ResilientOther);
327334
if (hasResilientAncestry) {
@@ -2717,6 +2724,9 @@ class ModuleWriter {
27172724
"#if !defined(SWIFT_AVAILABILITY)\n"
27182725
"# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))\n"
27192726
"#endif\n"
2727+
"#if !defined(SWIFT_WEAK_IMPORT)\n"
2728+
"# define SWIFT_WEAK_IMPORT __attribute__((weak_import))\n"
2729+
"#endif\n"
27202730
"#if !defined(SWIFT_DEPRECATED)\n"
27212731
"# define SWIFT_DEPRECATED __attribute__((deprecated))\n"
27222732
"#endif\n"

test/PrintAsObjC/classes.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,3 +805,9 @@ public class NonObjCClass { }
805805
@objc func referenceSingleGenericClass(_: SingleImportedObjCGeneric<AnyObject>?) {}
806806
}
807807
// CHECK: @end
808+
809+
// CHECK: SWIFT_WEAK_IMPORT
810+
// CHECK-NEXT: SWIFT_CLASS("_TtC7classes17WeakImportedClass")
811+
// CHECK-NEXT: @interface WeakImportedClass
812+
// CHECK-NEXT: @end
813+
@_weakLinked @objc class WeakImportedClass {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
3+
open class BaseClass : NSObject {
4+
@objc dynamic open func instanceMethod() -> Int {
5+
return 42
6+
}
7+
8+
@objc dynamic open class func classMethod() -> Int {
9+
return 31337
10+
}
11+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module first {
2+
header "first.h"
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import first
2+
3+
#if BEFORE
4+
@_weakLinked public class DerivedClass : BaseClass {}
5+
#endif

validation-test/Runtime/class_stubs.m

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
// RUN: %target-build-swift -emit-library -emit-module -o %t/libfirst.dylib -emit-objc-header-path %t/first.h %S/Inputs/class-stubs-from-objc/first.swift -Xlinker -install_name -Xlinker @executable_path/libfirst.dylib -enable-library-evolution
66
// RUN: %target-build-swift -emit-library -o %t/libsecond.dylib -emit-objc-header-path %t/second.h -I %t %S/Inputs/class-stubs-from-objc/second.swift -Xlinker -install_name -Xlinker @executable_path/libsecond.dylib -lfirst -L %t -Xfrontend -enable-resilient-objc-class-stubs
77
// RUN: cp %S/Inputs/class-stubs-from-objc/module.map %t/
8-
// RUN: xcrun %clang %s -I %t -L %t -fmodules -fobjc-arc -o %t/main -lfirst -lsecond
8+
// RUN: xcrun %clang %s -I %t -L %t -fmodules -fobjc-arc -o %t/main -lfirst -lsecond -Wl,-U,_objc_loadClassref
99
// RUN: %target-codesign %t/main %t/libfirst.dylib %t/libsecond.dylib
10-
// RUN: %target-run %t/main %t/libfirst.dylib %t/libsecond.dylib | %FileCheck %s
10+
// RUN: %target-run %t/main %t/libfirst.dylib %t/libsecond.dylib
1111

1212
// REQUIRES: executable_test
1313
// REQUIRES: objc_interop
1414

15-
// XFAIL: *
16-
1715
#import <dlfcn.h>
1816
#import <stdio.h>
1917
#import "second.h"
@@ -39,9 +37,17 @@ int main(int argc, const char * const argv[]) {
3937

4038
DerivedClass *obj = [[DerivedClass alloc] init];
4139

42-
// CHECK: Result is 43
43-
printf("Result is %ld\n", [obj instanceMethod]);
40+
{
41+
long result = [obj instanceMethod];
42+
printf("[obj instanceMethod] == %ld\n", result);
43+
if (result != 43)
44+
exit(EXIT_FAILURE);
45+
}
4446

45-
// CHECK: Result is 31338
46-
printf("Result is %ld\n", [DerivedClass classMethod]);
47+
{
48+
long result = [DerivedClass classMethod];
49+
printf("[obj classMethod] == %ld\n", result);
50+
if (result != 31338)
51+
exit(EXIT_FAILURE);
52+
}
4753
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Check that Objective-C is able to use a resilient class stub emitted
2+
// by the Swift compiler.
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: %target-build-swift -emit-library -emit-module -o %t/libfirst.dylib -emit-objc-header-path %t/first.h %S/Inputs/class-stubs-weak/first.swift -Xlinker -install_name -Xlinker @executable_path/libfirst.dylib -enable-library-evolution
6+
// RUN: %target-build-swift -emit-library -o %t/libsecond.dylib -emit-objc-header-path %t/second.h -I %t %S/Inputs/class-stubs-weak/second.swift -Xlinker -install_name -Xlinker @executable_path/libsecond.dylib -lfirst -L %t -Xfrontend -enable-resilient-objc-class-stubs -DBEFORE
7+
// RUN: cp %S/Inputs/class-stubs-weak/module.map %t/
8+
// RUN: xcrun %clang %s -I %t -L %t -fmodules -fobjc-arc -o %t/main -lfirst -lsecond -Wl,-U,_objc_loadClassref
9+
10+
// Now rebuild the library, omitting the weak-exported class
11+
// RUN: %target-build-swift -emit-library -o %t/libsecond.dylib -I %t %S/Inputs/class-stubs-weak/second.swift -Xlinker -install_name -Xlinker @executable_path/libsecond.dylib -lfirst -L %t -Xfrontend -enable-resilient-objc-class-stubs
12+
13+
// RUN: %target-codesign %t/main %t/libfirst.dylib %t/libsecond.dylib
14+
// RUN: %target-run %t/main %t/libfirst.dylib %t/libsecond.dylib
15+
16+
// REQUIRES: executable_test
17+
// REQUIRES: objc_interop
18+
19+
#import <dlfcn.h>
20+
#import <stdio.h>
21+
#import "second.h"
22+
23+
@implementation DerivedClass (MyCategory)
24+
25+
- (int)instanceMethod {
26+
return [super instanceMethod] + 1;
27+
}
28+
29+
+ (int)classMethod {
30+
return [super classMethod] + 1;
31+
}
32+
33+
@end
34+
35+
int main(int argc, const char * const argv[]) {
36+
// Only test the new behavior on a new enough libobjc.
37+
if (!dlsym(RTLD_NEXT, "_objc_loadClassref")) {
38+
fprintf(stderr, "skipping evolution tests; OS too old\n");
39+
return EXIT_SUCCESS;
40+
}
41+
42+
Class cls = [DerivedClass class];
43+
if (cls) {
44+
printf("Class is not null");
45+
return EXIT_FAILURE;
46+
}
47+
48+
printf("Class is null");
49+
return EXIT_SUCCESS;
50+
}

0 commit comments

Comments
 (0)