| // RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS |
| // RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS |
| // RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS |
| // RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS |
| // RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS |
| // RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | 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 -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS |
| // RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | 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 @check_invoke |
| void check_invoke() { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: {{invoke.*@objc_alloc}} |
| // CALLS: {{invoke.*@objc_allocWithZone}} |
| @try { |
| [NSObject alloc]; |
| [NSObject allocWithZone:nil]; |
| } @catch (...) { |
| } |
| } |
| |
| // 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 TestSelf |
| + (instancetype)alloc; |
| + (instancetype)allocWithZone:(void*)zone; |
| + (id)classMeth; |
| - (id)instanceMeth; |
| @end |
| |
| @implementation TestSelf |
| // CHECK-LABEL: define internal i8* @"\01+[TestSelf classMeth]"( |
| + (id)classMeth { |
| // MSGS: {{call.*@objc_msgSend}} |
| // MSGS: {{call.*@objc_msgSend}} |
| // CALLS: {{call.*@objc_allocWithZone\(}} |
| // CALLS: {{call.*@objc_alloc\(}} |
| [self allocWithZone:nil]; |
| return [self alloc]; |
| } |
| // CHECK-LABEL: define internal i8* @"\01-[TestSelf instanceMeth]"( |
| - (id)instanceMeth { |
| // MSGS: {{call.*@objc_msgSend}} |
| // MSGS: {{call.*@objc_msgSend}} |
| // CALLS: {{call.*@objc_msgSend}} |
| // CALLS: {{call.*@objc_msgSend}} |
| [self allocWithZone:nil]; |
| return [self alloc]; |
| } |
| @end |
| |
| @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 |
| |
| @class Ety; |
| |
| // CHECK-LABEL: define {{.*}}void @testException_release |
| void testException_release(NSObject *a) { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: invoke{{.*}}void @objc_release(i8* % |
| @try { |
| [a release]; |
| } @catch (Ety *e) { |
| } |
| } |
| |
| // CHECK-LABEL: define {{.*}}void @testException_autorelease |
| void testException_autorelease(NSObject *a) { |
| @try { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: invoke{{.*}}objc_autorelease(i8* % |
| [a autorelease]; |
| } @catch (Ety *e) { |
| } |
| } |
| |
| // CHECK-LABEL: define {{.*}}void @testException_retain |
| void testException_retain(NSObject *a) { |
| @try { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: invoke{{.*}}@objc_retain(i8* % |
| [a retain]; |
| } @catch (Ety *e) { |
| } |
| } |
| |
| |
| // CHECK-LABEL: define {{.*}}void @testException_alloc( |
| void testException_alloc() { |
| @try { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: invoke{{.*}}@objc_alloc(i8* % |
| [A alloc]; |
| } @catch (Ety *e) { |
| } |
| } |
| |
| // CHECK-LABEL: define {{.*}}void @testException_allocWithZone |
| void testException_allocWithZone() { |
| @try { |
| // MSGS: {{invoke.*@objc_msgSend}} |
| // CALLS: invoke{{.*}}@objc_allocWithZone(i8* % |
| [A allocWithZone:nil]; |
| } @catch (Ety *e) { |
| } |
| } |