diff options
Diffstat (limited to 'test/CodeGenObjC/convert-messages-to-runtime-calls.m')
-rw-r--r-- | test/CodeGenObjC/convert-messages-to-runtime-calls.m | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/test/CodeGenObjC/convert-messages-to-runtime-calls.m b/test/CodeGenObjC/convert-messages-to-runtime-calls.m new file mode 100644 index 000000000000..8ce024fe8094 --- /dev/null +++ b/test/CodeGenObjC/convert-messages-to-runtime-calls.m @@ -0,0 +1,164 @@ +// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls | FileCheck %s --check-prefix=MSGS +// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS +// RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS +// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS +// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS +// RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS +// Note: This line below is for tvos for which the driver passes through to use the ios9.0 runtime. +// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS +// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS + +#define nil (id)0 + +@interface NSObject ++ (id)alloc; ++ (id)allocWithZone:(void*)zone; ++ (id)alloc2; +- (id)retain; +- (void)release; +- (id)autorelease; +@end + +// CHECK-LABEL: define {{.*}}void @test1 +void test1(id x) { + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_alloc}} + // CALLS: {{call.*@objc_allocWithZone}} + // CALLS: {{call.*@objc_retain}} + // CALLS: {{call.*@objc_release}} + // CALLS: {{call.*@objc_autorelease}} + [NSObject alloc]; + [NSObject allocWithZone:nil]; + [x retain]; + [x release]; + [x autorelease]; +} + +// CHECK-LABEL: define {{.*}}void @test2 +void test2(void* x) { + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + [NSObject alloc2]; + [NSObject allocWithZone:(void*)-1]; + [NSObject allocWithZone:x]; +} + +@class A; +@interface B ++ (A*) alloc; ++ (A*) allocWithZone:(void*)zone; +- (A*) alloc; +- (A*) allocWithZone:(void*)zone; +- (A*) retain; +- (A*) autorelease; +@end + +// Make sure we get a bitcast on the return type as the +// call will return i8* which we have to cast to A* +// CHECK-LABEL: define {{.*}}void @test_alloc_class_ptr +A* test_alloc_class_ptr() { + // CALLS: {{call.*@objc_alloc}} + // CALLS-NEXT: bitcast i8* + // CALLS-NEXT: ret + return [B alloc]; +} + +// Make sure we get a bitcast on the return type as the +// call will return i8* which we have to cast to A* +// CHECK-LABEL: define {{.*}}void @test_alloc_class_ptr +A* test_allocWithZone_class_ptr() { + // CALLS: {{call.*@objc_allocWithZone}} + // CALLS-NEXT: bitcast i8* + // CALLS-NEXT: ret + return [B allocWithZone:nil]; +} + +// Only call objc_alloc on a Class, not an instance +// CHECK-LABEL: define {{.*}}void @test_alloc_instance +void test_alloc_instance(A *a) { + // CALLS: {{call.*@objc_alloc}} + // CALLS: {{call.*@objc_allocWithZone}} + // CALLS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + [A alloc]; + [A allocWithZone:nil]; + [a alloc]; + [a allocWithZone:nil]; +} + +// Make sure we get a bitcast on the return type as the +// call will return i8* which we have to cast to A* +// CHECK-LABEL: define {{.*}}void @test_retain_class_ptr +A* test_retain_class_ptr(B *b) { + // CALLS: {{call.*@objc_retain}} + // CALLS-NEXT: bitcast i8* + // CALLS-NEXT: ret + return [b retain]; +} + +// Make sure we get a bitcast on the return type as the +// call will return i8* which we have to cast to A* +// CHECK-LABEL: define {{.*}}void @test_autorelease_class_ptr +A* test_autorelease_class_ptr(B *b) { + // CALLS: {{call.*@objc_autorelease}} + // CALLS-NEXT: bitcast i8* + // CALLS-NEXT: ret + return [b autorelease]; +} + + +@interface C ++ (id)allocWithZone:(int)intArg; +- (float) retain; +@end + +// Make sure we only accept pointer types +// CHECK-LABEL: define {{.*}}void @test_allocWithZone_int +C* test_allocWithZone_int() { + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + return [C allocWithZone:3]; +} + +// Make sure we use a message and not a call as the return type is +// not a pointer type. +// CHECK-LABEL: define {{.*}}void @test_cannot_message_return_float +float test_cannot_message_return_float(C *c) { + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + return [c retain]; +} + +@interface NSString : NSObject ++ (void)retain_self; +- (void)retain_super; +@end + +@implementation NSString + +// Make sure we can convert a message to a dynamic receiver to a call +// CHECK-LABEL: define {{.*}}void @retain_self ++ (void)retain_self { + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_retain}} + [self retain]; +} + +// Make sure we never convert a message to super to a call +// CHECK-LABEL: define {{.*}}void @retain_super +- (void)retain_super { + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + [super retain]; +} + +@end + |