| // RUN: rm -rf %t |
| // RUN: split-file %s %t |
| |
| // Test 1: Check IR from library implementation (visibility attributes) |
| // RUN: %clang_cc1 -triple arm64-apple-darwin -fobjc-arc \ |
| // RUN: -fobjc-direct-precondition-thunk -emit-llvm -o - %t/foo.m \ |
| // RUN: -I %t | FileCheck %s --check-prefix=FOO_M |
| |
| // Test 2: Check IR from main (consumer) |
| // RUN: %clang_cc1 -triple arm64-apple-darwin -fobjc-arc \ |
| // RUN: -fobjc-direct-precondition-thunk -emit-llvm -o - %t/main.m \ |
| // RUN: -I %t | FileCheck %s --check-prefix=MAIN_M |
| |
| //--- foo.h |
| // Header for libFoo |
| __attribute__((objc_root_class)) |
| @interface Foo |
| // Direct properties with default hidden visibility |
| @property (nonatomic, direct) int privateValue; |
| |
| // Direct properties with explicit default visibility |
| @property (nonatomic, direct) int exportedValue __attribute__((visibility("default"))); |
| |
| + (instancetype)alloc; |
| - (instancetype)initWithprivateValue:(int)x exportedValue:(int)y; |
| // Default hidden visibility |
| - (int)instanceMethod:(int)x __attribute__((objc_direct)); |
| + (int)classMethod:(int)x __attribute__((objc_direct)); |
| |
| // Explicit default visibility (should be exported) |
| - (int)exportedInstanceMethod:(int)x __attribute__((objc_direct, visibility("default"))); |
| + (int)exportedClassMethod:(int)x __attribute__((objc_direct, visibility("default"))); |
| @end |
| |
| //--- foo.m |
| |
| // libFoo does not have thunks because the true implementation is not used internally. |
| // FOO_M-NOT: @{{.*}}_thunk |
| #import "foo.h" |
| |
| @implementation Foo |
| |
| // FOO_M-LABEL: define internal ptr @"\01-[Foo initWithprivateValue:exportedValue:]" |
| - (instancetype)initWithprivateValue:(int)x exportedValue:(int)y { |
| _privateValue = x; |
| _exportedValue = y; |
| return self; |
| } |
| |
| // FOO_M-LABEL: define hidden i32 @"-[Foo instanceMethod:]D" |
| - (int)instanceMethod:(int)x { |
| // Compiler is smart enough to know that self is non-nil, so we dispatch to |
| // true implementation. |
| // FOO_M: call i32 @"-[Foo privateValue]D" |
| // FOO_M: call i32 @"-[Foo exportedValue]D" |
| return x + [self privateValue] + [self exportedValue]; |
| } |
| |
| // Hidden property getter and setter (default visibility) |
| // FOO_M-LABEL: define hidden i32 @"-[Foo privateValue]D" |
| |
| // Exported property getter and setter (explicit default visibility) |
| // FOO_M-LABEL: define dso_local i32 @"-[Foo exportedValue]D" |
| |
| // FOO_M-LABEL: define hidden i32 @"+[Foo classMethod:]D" |
| + (int)classMethod:(int)x { |
| return x * 3; |
| } |
| |
| // FOO_M-LABEL: define dso_local i32 @"-[Foo exportedInstanceMethod:]D" |
| - (int)exportedInstanceMethod:(int)x { |
| // FOO_M: call i32 @"-[Foo privateValue]D" |
| // FOO_M: call i32 @"-[Foo exportedValue]D" |
| return x + [self privateValue] + [self exportedValue]; |
| } |
| |
| // FOO_M-LABEL: define dso_local i32 @"+[Foo exportedClassMethod:]D" |
| + (int)exportedClassMethod:(int)x { |
| return x * 5; |
| } |
| |
| // Hidden property getter and setter (default visibility) |
| // FOO_M-LABEL: define hidden void @"-[Foo setPrivateValue:]D" |
| |
| // Exported property getter and setter (explicit default visibility) |
| // FOO_M-LABEL: define dso_local void @"-[Foo setExportedValue:]D" |
| |
| @end |
| |
| //--- main.m |
| // Consumer of libFoo (separate linkage unit) |
| #import "foo.h" |
| |
| int printf(const char *, ...); |
| |
| int main() { |
| Foo *obj = [[Foo alloc] initWithprivateValue:10 exportedValue:20]; |
| printf("Allocated Foo\n"); |
| |
| // MAIN_M: call void @"-[Foo setExportedValue:]D_thunk" |
| [obj setExportedValue:30]; |
| |
| // MAIN_M: call i32 @"-[Foo exportedValue]D_thunk" |
| printf("Reset exportedValue: %d\n", [obj exportedValue]); |
| |
| // MAIN_M: call i32 @"-[Foo exportedInstanceMethod:]D_thunk" |
| printf("Exported instance: %d\n", [obj exportedInstanceMethod:10]); |
| |
| // MAIN_M: call i32 @"+[Foo exportedClassMethod:]D_thunk" |
| printf("Exported class: %d\n", [Foo exportedClassMethod:10]); |
| |
| return 0; |
| } |
| |
| // Thunks are generated during compilation |
| // MAIN_M-LABEL: define linkonce_odr hidden void @"-[Foo setExportedValue:]D_thunk" |
| // MAIN_M-LABEL: define linkonce_odr hidden i32 @"-[Foo exportedValue]D_thunk" |
| // MAIN_M-LABEL: define linkonce_odr hidden i32 @"-[Foo exportedInstanceMethod:]D_thunk" |
| // MAIN_M-LABEL: define linkonce_odr hidden i32 @"+[Foo exportedClassMethod:]D_thunk" |