xref: /llvm-project/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m (revision fa71f9e87aee87c899a6ed600c1748aeb1c1a05d)
1// 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
2// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
3// RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
4// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
5// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
6// RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=MSGS
7// Note: This line below is for tvos for which the driver passes through to use the ios9.0 runtime.
8// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
9// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s -fobjc-exceptions -fexceptions | FileCheck %s --check-prefix=CALLS
10
11#define nil (id)0
12
13@interface NSObject
14+ (id)alloc;
15+ (id)allocWithZone:(void*)zone;
16+ (id)alloc2;
17- (id)retain;
18- (void)release;
19- (id)autorelease;
20@end
21
22// CHECK-LABEL: define {{.*}}void @test1
23void test1(id x) {
24  // MSGS: {{call.*@objc_msgSend}}
25  // MSGS: {{call.*@objc_msgSend}}
26  // MSGS: {{call.*@objc_msgSend}}
27  // MSGS: {{call.*@objc_msgSend}}
28  // MSGS: {{call.*@objc_msgSend}}
29  // CALLS: {{call.*@objc_alloc}}
30  // CALLS: {{call.*@objc_allocWithZone}}
31
32  // Note that calls to the intrinsics are not allowed for
33  // retain/release/autorelease they're marked `thisreturn`, which isn't
34  // guaranteed to be true for classes that define their own `-retain`, for
35  // example. Be sure to keep these as normal function calls:
36  // CALLS: {{call.*@objc_retain}}
37  // CALLS: {{call.*@objc_release}}
38  // CALLS: {{tail call.*@objc_autorelease}}
39  [NSObject alloc];
40  [NSObject allocWithZone:nil];
41  [x retain];
42  [x release];
43  [x autorelease];
44}
45
46// CHECK-LABEL: define {{.*}}void @check_invoke
47void check_invoke(void) {
48  // MSGS: {{invoke.*@objc_msgSend}}
49  // MSGS: {{invoke.*@objc_msgSend}}
50  // CALLS: {{invoke.*@objc_alloc}}
51  // CALLS: {{invoke.*@objc_allocWithZone}}
52  @try {
53    [NSObject alloc];
54    [NSObject allocWithZone:nil];
55  } @catch (...) {
56  }
57}
58
59// CHECK-LABEL: define {{.*}}void @test2
60void test2(void* x) {
61  // MSGS: {{call.*@objc_msgSend}}
62  // MSGS: {{call.*@objc_msgSend}}
63  // MSGS: {{call.*@objc_msgSend}}
64  // CALLS: {{call.*@objc_msgSend}}
65  // CALLS: {{call.*@objc_msgSend}}
66  // CALLS: {{call.*@objc_msgSend}}
67  [NSObject alloc2];
68  [NSObject allocWithZone:(void*)-1];
69  [NSObject allocWithZone:x];
70}
71
72@class A;
73@interface B
74+ (A*) alloc;
75+ (A*) allocWithZone:(void*)zone;
76- (A*) alloc;
77- (A*) allocWithZone:(void*)zone;
78- (A*) retain;
79- (A*) autorelease;
80@end
81
82// CHECK-LABEL: define {{.*}}void @test_alloc_class_ptr
83A* test_alloc_class_ptr(void) {
84  // CALLS: {{call.*@objc_alloc}}
85  // CALLS-NEXT: ret
86  return [B alloc];
87}
88
89// CHECK-LABEL: define {{.*}}void @test_alloc_class_ptr
90A* test_allocWithZone_class_ptr(void) {
91  // CALLS: {{call.*@objc_allocWithZone}}
92  // CALLS-NEXT: ret
93  return [B allocWithZone:nil];
94}
95
96// Only call objc_alloc on a Class, not an instance
97// CHECK-LABEL: define {{.*}}void @test_alloc_instance
98void test_alloc_instance(A *a) {
99  // CALLS: {{call.*@objc_alloc}}
100  // CALLS: {{call.*@objc_allocWithZone}}
101  // CALLS: {{call.*@objc_msgSend}}
102  // CALLS: {{call.*@objc_msgSend}}
103  [A alloc];
104  [A allocWithZone:nil];
105  [a alloc];
106  [a allocWithZone:nil];
107}
108
109// Make sure we get a bitcast on the return type as the
110// call will return ptr which we have to cast to A*
111// CHECK-LABEL: define {{.*}}void @test_retain_class_ptr
112A* test_retain_class_ptr(B *b) {
113  // CALLS: {{call.*@objc_retain}}
114  // CALLS-NEXT: ret
115  return [b retain];
116}
117
118// Make sure we get a bitcast on the return type as the
119// call will return ptr which we have to cast to A*
120// CHECK-LABEL: define {{.*}}void @test_autorelease_class_ptr
121A* test_autorelease_class_ptr(B *b) {
122  // CALLS: {{tail call.*@objc_autorelease}}
123  // CALLS-NEXT: ret
124  return [b autorelease];
125}
126
127
128@interface C
129+ (id)allocWithZone:(int)intArg;
130- (float) retain;
131@end
132
133// Make sure we only accept pointer types
134// CHECK-LABEL: define {{.*}}void @test_allocWithZone_int
135C* test_allocWithZone_int(void) {
136  // MSGS: {{call.*@objc_msgSend}}
137  // CALLS: {{call.*@objc_msgSend}}
138  return [C allocWithZone:3];
139}
140
141// Make sure we use a message and not a call as the return type is
142// not a pointer type.
143// CHECK-LABEL: define {{.*}}void @test_cannot_message_return_float
144float test_cannot_message_return_float(C *c) {
145  // MSGS: {{call.*@objc_msgSend}}
146  // CALLS: {{call.*@objc_msgSend}}
147  return [c retain];
148}
149
150@interface TestSelf
151+ (instancetype)alloc;
152+ (instancetype)allocWithZone:(void*)zone;
153+ (id)classMeth;
154- (id)instanceMeth;
155@end
156
157@implementation TestSelf
158// CHECK-LABEL: define internal ptr @"\01+[TestSelf classMeth]"(
159+ (id)classMeth {
160  // MSGS: {{call.*@objc_msgSend}}
161  // MSGS: {{call.*@objc_msgSend}}
162  // CALLS: {{call.*@objc_allocWithZone\(}}
163  // CALLS: {{call.*@objc_alloc\(}}
164  [self allocWithZone:nil];
165  return [self alloc];
166}
167// CHECK-LABEL: define internal ptr @"\01-[TestSelf instanceMeth]"(
168- (id)instanceMeth {
169  // MSGS: {{call.*@objc_msgSend}}
170  // MSGS: {{call.*@objc_msgSend}}
171  // CALLS: {{call.*@objc_msgSend}}
172  // CALLS: {{call.*@objc_msgSend}}
173  [self allocWithZone:nil];
174  return [self alloc];
175}
176@end
177
178@interface NSString : NSObject
179+ (void)retain_self;
180- (void)retain_super;
181@end
182
183@implementation NSString
184
185// Make sure we can convert a message to a dynamic receiver to a call
186// CHECK-LABEL: define {{.*}}void @retain_self
187+ (void)retain_self {
188  // MSGS: {{call.*@objc_msgSend}}
189  // CALLS: {{call.*@objc_retain}}
190  [self retain];
191}
192
193// Make sure we never convert a message to super to a call
194// CHECK-LABEL: define {{.*}}void @retain_super
195- (void)retain_super {
196  // MSGS: {{call.*@objc_msgSend}}
197  // CALLS: {{call.*@objc_msgSend}}
198  [super retain];
199}
200
201@end
202
203@class Ety;
204
205// CHECK-LABEL: define {{.*}}void @testException_release
206void testException_release(NSObject *a) {
207  // MSGS: {{invoke.*@objc_msgSend}}
208  // CALLS: invoke{{.*}}void @objc_release(ptr %
209  @try {
210    [a release];
211  } @catch (Ety *e) {
212  }
213}
214
215// CHECK-LABEL: define {{.*}}void @testException_autorelease
216void testException_autorelease(NSObject *a) {
217  @try {
218    // MSGS: {{invoke.*@objc_msgSend}}
219    // CALLS: invoke{{.*}}objc_autorelease(ptr %
220    [a autorelease];
221  } @catch (Ety *e) {
222  }
223}
224
225// CHECK-LABEL: define {{.*}}void @testException_retain
226void testException_retain(NSObject *a) {
227  @try {
228    // MSGS: {{invoke.*@objc_msgSend}}
229    // CALLS: invoke{{.*}}@objc_retain(ptr %
230    [a retain];
231  } @catch (Ety *e) {
232  }
233}
234
235
236// CHECK-LABEL: define {{.*}}void @testException_alloc(
237void testException_alloc(void) {
238  @try {
239    // MSGS: {{invoke.*@objc_msgSend}}
240    // CALLS: invoke{{.*}}@objc_alloc(ptr %
241    [A alloc];
242  } @catch (Ety *e) {
243  }
244}
245
246// CHECK-LABEL: define {{.*}}void @testException_allocWithZone
247void testException_allocWithZone(void) {
248  @try {
249    // MSGS: {{invoke.*@objc_msgSend}}
250    // CALLS: invoke{{.*}}@objc_allocWithZone(ptr %
251    [A allocWithZone:nil];
252  } @catch (Ety *e) {
253  }
254}
255