1 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
3 #define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
5 id test0_helper(void) __attribute__((ns_returns_retained));
7 PRECISE_LIFETIME id x = test0_helper();
9 // CHECK: [[X:%.*]] = alloca ptr
10 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[X]])
11 // CHECK-NEXT: [[CALL:%.*]] = call ptr @test0_helper()
12 // CHECK-NEXT: store ptr [[CALL]], ptr [[X]]
14 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]
15 // CHECK-NEXT: store ptr null, ptr [[X]]
16 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]
17 // CHECK-NOT: clang.imprecise_release
19 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]
20 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]
21 // CHECK-NOT: clang.imprecise_release
23 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[X]])
24 // CHECK-NEXT: ret void
27 // precise lifetime should suppress extension
28 // should work for calls via property syntax, too
30 - (char*) interior __attribute__((objc_returns_inner_pointer));
31 // Should we allow this on properties? Yes!
32 @property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));
34 extern Test1 *test1_helper(void);
36 // CHECK-LABEL: define{{.*}} void @test1a_message()
37 void test1a_message(void) {
38 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
39 // CHECK: [[C:%.*]] = alloca ptr, align 8
40 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
41 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
42 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
43 // CHECK-NEXT: store ptr [[T0]]
44 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
45 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
46 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
47 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
48 // CHECK-NEXT: [[T6:%.*]] = call ptr
49 // CHECK-NEXT: store ptr [[T6]], ptr
50 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
51 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
52 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
53 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
54 // CHECK-NEXT: ret void
55 Test1 *ptr = test1_helper();
56 char *c = [(ptr) interior];
60 // CHECK-LABEL: define{{.*}} void @test1a_property()
61 void test1a_property(void) {
62 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
63 // CHECK: [[C:%.*]] = alloca ptr, align 8
64 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
65 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
66 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
67 // CHECK-NEXT: store ptr [[T0]]
68 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
69 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
70 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
71 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
72 // CHECK-NEXT: [[T6:%.*]] = call ptr
73 // CHECK-NEXT: store ptr [[T6]], ptr
74 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
75 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
76 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
77 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
78 // CHECK-NEXT: ret void
79 Test1 *ptr = test1_helper();
80 char *c = ptr.interior;
84 // CHECK-LABEL: define{{.*}} void @test1b_message()
85 void test1b_message(void) {
86 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
87 // CHECK: [[C:%.*]] = alloca ptr, align 8
88 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
89 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
90 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
91 // CHECK-NEXT: store ptr [[T0]]
92 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
93 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
94 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
95 // CHECK-NEXT: [[T3:%.*]] = call ptr
96 // CHECK-NEXT: store ptr [[T3]], ptr
97 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
98 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
99 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
100 // CHECK-NOT: clang.imprecise_release
101 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
102 // CHECK-NEXT: ret void
103 PRECISE_LIFETIME Test1 *ptr = test1_helper();
104 char *c = [ptr interior];
107 // CHECK-LABEL: define{{.*}} void @test1b_property()
108 void test1b_property(void) {
109 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
110 // CHECK: [[C:%.*]] = alloca ptr, align 8
111 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
112 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
113 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
114 // CHECK-NEXT: store ptr [[T0]]
115 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
116 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
117 // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
118 // CHECK-NEXT: [[T3:%.*]] = call ptr
119 // CHECK-NEXT: store ptr [[T3]], ptr
120 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
121 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
122 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
123 // CHECK-NOT: clang.imprecise_release
124 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
125 // CHECK-NEXT: ret void
126 PRECISE_LIFETIME Test1 *ptr = test1_helper();
127 char *c = ptr.interior;
130 // CHECK-LABEL: define{{.*}} void @test1c_message()
131 void test1c_message(void) {
132 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
133 // CHECK: [[PC:%.*]] = alloca ptr, align 8
134 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
135 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
136 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
137 // CHECK-NEXT: store ptr [[T0]]
138 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
139 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
140 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
141 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
142 // CHECK-NEXT: [[T6:%.*]] = call ptr
143 // CHECK-NEXT: store ptr [[T6]], ptr
144 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
145 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
146 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
147 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
148 // CHECK-NEXT: ret void
149 Test1 *ptr = test1_helper();
150 char *pc = [ptr PropertyReturnsInnerPointer];
153 // CHECK-LABEL: define{{.*}} void @test1c_property()
154 void test1c_property(void) {
155 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
156 // CHECK: [[PC:%.*]] = alloca ptr, align 8
157 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
158 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
159 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
160 // CHECK-NEXT: store ptr [[T0]]
161 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
162 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
163 // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
164 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
165 // CHECK-NEXT: [[T6:%.*]] = call ptr
166 // CHECK-NEXT: store ptr [[T6]], ptr
167 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
168 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
169 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
170 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
171 // CHECK-NEXT: ret void
172 Test1 *ptr = test1_helper();
173 char *pc = ptr.PropertyReturnsInnerPointer;
176 // CHECK-LABEL: define{{.*}} void @test1d_message()
177 void test1d_message(void) {
178 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
179 // CHECK: [[PC:%.*]] = alloca ptr, align 8
180 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
181 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
182 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
183 // CHECK-NEXT: store ptr [[T0]]
184 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
185 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
186 // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
187 // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])
188 // CHECK-NEXT: store ptr [[CALL1]], ptr
189 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
190 // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr
191 // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])
192 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
193 // CHECK-NEXT: ret void
194 PRECISE_LIFETIME Test1 *ptr = test1_helper();
195 char *pc = [ptr PropertyReturnsInnerPointer];
198 // CHECK-LABEL: define{{.*}} void @test1d_property()
199 void test1d_property(void) {
200 // CHECK: [[PTR:%.*]] = alloca ptr, align 8
201 // CHECK: [[PC:%.*]] = alloca ptr, align 8
202 // CHECK: call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
203 // CHECK: [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
204 // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
205 // CHECK-NEXT: store ptr [[T0]]
206 // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
207 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
208 // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
209 // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])
210 // CHECK-NEXT: store ptr [[CALL1]], ptr
211 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
212 // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr
213 // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])
214 // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
215 // CHECK-NEXT: ret void
216 PRECISE_LIFETIME Test1 *ptr = test1_helper();
217 char *pc = ptr.PropertyReturnsInnerPointer;
225 // CHECK-LABEL: define{{.*}} void @test2(
226 void test2(Test2 *x) {
228 // CHECK: [[X:%.*]] = alloca ptr
229 // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]
230 // CHECK-NEXT: store ptr [[T1]], ptr [[X]],
232 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],
233 // CHECK-NEXT: [[OFFSET:%.*]] = load i64, ptr @"OBJC_IVAR_$_Test2.ivar"
234 // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8, ptr [[T0]], i64 [[OFFSET]]
235 // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T2]],
236 // CHECK-NEXT: store ptr null, ptr [[T2]],
237 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T4]]) [[NUW]]
238 // CHECK-NOT: imprecise
240 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]
241 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
243 // CHECK-NEXT: ret void
246 // CHECK-LABEL: define{{.*}} void @test3(ptr
247 void test3(PRECISE_LIFETIME id x) {
248 // CHECK: [[X:%.*]] = alloca ptr,
249 // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]
250 // CHECK-NEXT: store ptr [[T0]], ptr [[X]],
252 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]
253 // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
254 // CHECK-NOT: imprecise_release
256 // CHECK-NEXT: ret void
259 // CHECK: attributes [[NUW]] = { nounwind }