forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			258 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
// 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: {{tail 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: {{tail 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) {
 | 
						|
  }
 | 
						|
}
 |