1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
2
3#define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
4
5id test0_helper(void) __attribute__((ns_returns_retained));
6void test0() {
7  PRECISE_LIFETIME id x = test0_helper();
8  x = 0;
9  // CHECK:      [[X:%.*]] = alloca i8*
10  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper()
11  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
12
13  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
14  // CHECK-NEXT: store i8* null, i8** [[X]]
15  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
16  // CHECK-NOT:  clang.imprecise_release
17
18  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
19  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
20  // CHECK-NOT:  clang.imprecise_release
21
22  // CHECK-NEXT: ret void
23}
24
25// rdar://problem/9821110
26@interface Test1
27- (char*) interior __attribute__((objc_returns_inner_pointer));
28// Should we allow this on properties? Yes! see // rdar://14990439
29@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));
30@end
31extern Test1 *test1_helper(void);
32
33// CHECK-LABEL: define void @test1a()
34void test1a(void) {
35  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
36  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
37  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
38  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
39  // CHECK-NEXT: store [[TEST1]]* [[T3]]
40  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
41  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
42  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
43  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
44  // CHECK-NEXT: [[T4:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
45  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
46  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
47  // CHECK-NEXT: store i8* [[T6]], i8**
48  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
49  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
50  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
51  // CHECK-NEXT: ret void
52  Test1 *ptr = test1_helper();
53  char *c = [(ptr) interior];
54}
55
56// CHECK-LABEL: define void @test1b()
57void test1b(void) {
58  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
59  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
60  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
61  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
62  // CHECK-NEXT: store [[TEST1]]* [[T3]]
63  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
64  // CHECK-NEXT: [[T1:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
65  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
66  // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
67  // CHECK-NEXT: store i8* [[T3]], i8**
68  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
69  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
70  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
71  // CHECK-NOT:  clang.imprecise_release
72  // CHECK-NEXT: ret void
73  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
74  char *c = [ptr interior];
75}
76
77void test1c(void) {
78  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
79  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
80  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
81  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
82  // CHECK-NEXT: store [[TEST1]]* [[T3]]
83  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
84  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
85  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
86  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
87  // CHECK-NEXT: [[T4:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
88  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
89  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
90  // CHECK-NEXT: store i8* [[T6]], i8**
91  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
92  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
93  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
94  // CHECK-NEXT: ret void
95  Test1 *ptr = test1_helper();
96  char *pc = ptr.PropertyReturnsInnerPointer;
97}
98
99void test1d(void) {
100  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
101  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
102  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
103  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
104  // CHECK-NEXT: store [[TEST1]]* [[T3]]
105  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
106  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
107  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
108  // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
109  // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @OBJC_SELECTOR_REFERENCES_
110  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*
111  // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
112  // CHECK-NEXT: store i8* [[CALL1]], i8**
113  // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]**
114  // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
115  // CHECK-NEXT: call void @objc_release(i8* [[TEN]])
116  // CHECK-NEXT: ret void
117  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
118  char *pc = ptr.PropertyReturnsInnerPointer;
119}
120
121@interface Test2 {
122@public
123  id ivar;
124}
125@end
126// CHECK-LABEL:      define void @test2(
127void test2(Test2 *x) {
128  x->ivar = 0;
129  // CHECK:      [[X:%.*]] = alloca [[TEST2:%.*]]*
130  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8*
131  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
132  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST2]]*
133  // CHECK-NEXT: store [[TEST2]]* [[T2]], [[TEST2]]** [[X]],
134
135  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]],
136  // CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2.ivar"
137  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
138  // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8* [[T1]], i64 [[OFFSET]]
139  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8**
140  // CHECK-NEXT: [[T4:%.*]] = load i8** [[T3]],
141  // CHECK-NEXT: store i8* null, i8** [[T3]],
142  // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]]
143  // CHECK-NOT:  imprecise
144
145  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]]
146  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
147  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
148
149  // CHECK-NEXT: ret void
150}
151
152// CHECK-LABEL:      define void @test3(i8*
153void test3(PRECISE_LIFETIME id x) {
154  // CHECK:      [[X:%.*]] = alloca i8*,
155  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]]
156  // CHECK-NEXT: store i8* [[T0]], i8** [[X]],
157
158  // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
159  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
160  // CHECK-NOT:  imprecise_release
161
162  // CHECK-NEXT: ret void
163}
164
165// CHECK: attributes [[NUW]] = { nounwind }
166