Skip to content

Commit c374044

Browse files
committed
Execution tests for Objective-C resilient class stubs
Fixes <rdar://49090613>, except they're disabled for the time being.
1 parent d348867 commit c374044

File tree

5 files changed

+144
-0
lines changed

5 files changed

+144
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_struct)) -enable-library-evolution %S/../Inputs/resilient_struct.swift -emit-module -emit-module-path %t/resilient_struct.swiftmodule
4+
// RUN: %target-codesign %t/%target-library-name(resilient_struct)
5+
6+
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_objc_class)) -I %t -L %t -lresilient_struct -enable-library-evolution %S/../Inputs/resilient_objc_class.swift -emit-module -emit-module-path %t/resilient_objc_class.swiftmodule -Xfrontend -enable-resilient-objc-class-stubs
7+
// RUN: %target-codesign %t/%target-library-name(resilient_objc_class)
8+
9+
// RUN: %target-build-swift %s -L %t -I %t -lresilient_struct -lresilient_objc_class -o %t/main %target-rpath(%t) -Xfrontend -enable-resilient-objc-class-stubs
10+
// RUN: %target-codesign %t/main
11+
12+
// RUN: %target-run %t/main %t/%target-library-name(resilient_struct) %t/%target-library-name(resilient_objc_class)
13+
14+
// REQUIRES: executable_test
15+
// REQUIRES: objc_interop
16+
17+
import StdlibUnittest
18+
import Foundation
19+
import resilient_objc_class
20+
21+
// Old OS versions do not have this hook.
22+
let loadClassrefMissing = {
23+
nil == dlsym(UnsafeMutableRawPointer(bitPattern: -2),
24+
"objc_loadClassref")
25+
}()
26+
27+
var ResilientClassTestSuite = TestSuite("ResilientClass")
28+
29+
class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
30+
31+
@objc protocol MyProtocol {
32+
func myMethod() -> Int
33+
}
34+
35+
extension ResilientNSObjectSubclass : MyProtocol {
36+
@objc func myMethod() -> Int { return 42 }
37+
}
38+
39+
ResilientClassTestSuite.test("category on my class")
40+
.skip(.custom({ loadClassrefMissing },
41+
reason: "class stubs support not present"))
42+
.code {
43+
print(ResilientNSObjectSubclass.self)
44+
let o = ResilientNSObjectSubclass()
45+
expectEqual(42, (o as MyProtocol).myMethod())
46+
}
47+
48+
@objc protocol AnotherProtocol {
49+
func anotherMethod() -> Int
50+
}
51+
52+
extension ResilientNSObjectOutsideParent : AnotherProtocol {
53+
@objc func anotherMethod() -> Int { return 69 }
54+
}
55+
56+
ResilientClassTestSuite.test("category on other class")
57+
.skip(.custom({ loadClassrefMissing },
58+
reason: "class stubs support not present"))
59+
.code {
60+
let o = ResilientNSObjectOutsideParent()
61+
expectEqual(69, (o as AnotherProtocol).anotherMethod())
62+
}
63+
64+
@_optimize(none) func blackHole<T>(_: T) {}
65+
66+
@_optimize(none) func forceMetadata() {
67+
blackHole(ResilientNSObjectSubclass())
68+
}
69+
70+
if loadClassrefMissing {
71+
ResilientClassTestSuite.test("RealizeResilientClass")
72+
.crashOutputMatches("class ResilientNSObjectSubclass requires missing Objective-C runtime feature")
73+
.code {
74+
expectCrashLater()
75+
print("About to crash...")
76+
forceMetadata()
77+
}
78+
}
79+
80+
runAllTests()
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import first
2+
3+
public class DerivedClass : BaseClass {}

validation-test/Runtime/class_stubs.m

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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-from-objc/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-from-objc/second.swift -Xlinker -install_name -Xlinker @executable_path/libsecond.dylib -lfirst -L %t -Xfrontend -enable-resilient-objc-class-stubs
7+
// 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
9+
// 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
11+
12+
// REQUIRES: executable_test
13+
// REQUIRES: objc_interop
14+
15+
// XFAIL: *
16+
17+
#import <dlfcn.h>
18+
#import <stdio.h>
19+
#import "second.h"
20+
21+
@implementation DerivedClass (MyCategory)
22+
23+
- (int)instanceMethod {
24+
return [super instanceMethod] + 1;
25+
}
26+
27+
+ (int)classMethod {
28+
return [super classMethod] + 1;
29+
}
30+
31+
@end
32+
33+
int main(int argc, const char * const argv[]) {
34+
// Only test the new behavior on a new enough libobjc.
35+
if (!dlsym(RTLD_NEXT, "_objc_loadClassref")) {
36+
fprintf(stderr, "skipping evolution tests; OS too old\n");
37+
return EXIT_SUCCESS;
38+
}
39+
40+
DerivedClass *obj = [[DerivedClass alloc] init];
41+
42+
// CHECK: Result is 43
43+
printf("Result is %ld\n", [obj instanceMethod]);
44+
45+
// CHECK: Result is 31338
46+
printf("Result is %ld\n", [DerivedClass classMethod]);
47+
}

0 commit comments

Comments
 (0)