blob: 81eef0e0282260af5a0e07d0241f902c69011301 [file] [log] [blame]
John McCallbb699b02011-02-07 18:37:40 +00001// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
2
3namespace test0 {
4 // CHECK: define void @_ZN5test04testEi(
Fariborz Jahanian4904bf42012-06-26 16:06:38 +00005 // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(
6 // CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}(
John McCallbb699b02011-02-07 18:37:40 +00007 void test(int x) {
8 ^{ ^{ (void) x; }; };
9 }
10}
John McCall461c9c12011-02-08 03:07:00 +000011
12extern void (^out)();
13
14namespace test1 {
15 // Capturing const objects doesn't require a local block.
16 // CHECK: define void @_ZN5test15test1Ev()
17 // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
18 void test1() {
19 const int NumHorsemen = 4;
20 out = ^{ (void) NumHorsemen; };
21 }
22
23 // That applies to structs too...
24 // CHECK: define void @_ZN5test15test2Ev()
25 // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
26 struct loc { double x, y; };
27 void test2() {
28 const loc target = { 5, 6 };
29 out = ^{ (void) target; };
30 }
31
32 // ...unless they have mutable fields...
33 // CHECK: define void @_ZN5test15test3Ev()
Chris Lattner9cbe4f02011-07-09 17:41:47 +000034 // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
John McCall461c9c12011-02-08 03:07:00 +000035 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
36 // CHECK: store void ()* [[T0]], void ()** @out
37 struct mut { mutable int x; };
38 void test3() {
39 const mut obj = { 5 };
40 out = ^{ (void) obj; };
41 }
42
43 // ...or non-trivial destructors...
44 // CHECK: define void @_ZN5test15test4Ev()
45 // CHECK: [[OBJ:%.*]] = alloca
Chris Lattner9cbe4f02011-07-09 17:41:47 +000046 // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
John McCall461c9c12011-02-08 03:07:00 +000047 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
48 // CHECK: store void ()* [[T0]], void ()** @out
49 struct scope { int x; ~scope(); };
50 void test4() {
51 const scope obj = { 5 };
52 out = ^{ (void) obj; };
53 }
54
55 // ...or non-trivial copy constructors, but it's not clear how to do
56 // that and still have a constant initializer in '03.
57}
John McCallf0c11f72011-03-31 08:03:29 +000058
59namespace test2 {
60 struct A {
61 A();
62 A(const A &);
63 ~A();
64 };
65
66 struct B {
67 B();
68 B(const B &);
69 ~B();
70 };
71
72 // CHECK: define void @_ZN5test24testEv()
73 void test() {
74 __block A a;
75 __block B b;
76 }
77
78 // CHECK: define internal void @__Block_byref_object_copy
79 // CHECK: call void @_ZN5test21AC1ERKS0_(
80
81 // CHECK: define internal void @__Block_byref_object_dispose
82 // CHECK: call void @_ZN5test21AD1Ev(
83
84 // CHECK: define internal void @__Block_byref_object_copy
85 // CHECK: call void @_ZN5test21BC1ERKS0_(
86
87 // CHECK: define internal void @__Block_byref_object_dispose
88 // CHECK: call void @_ZN5test21BD1Ev(
89}
John McCall642a75f2011-04-28 02:15:35 +000090
91// rdar://problem/9334739
92// Make sure we mark destructors for parameters captured in blocks.
93namespace test3 {
94 struct A {
95 A(const A&);
96 ~A();
97 };
98
99 struct B : A {
100 };
101
102 void test(B b) {
103 extern void consume(void(^)());
104 consume(^{ (void) b; });
105 }
106}
John McCalld963c372011-08-17 21:34:14 +0000107
108// rdar://problem/9971485
109namespace test4 {
110 struct A {
111 A();
112 ~A();
113 };
114
115 void foo(A a);
116
117 void test() {
118 extern void consume(void(^)());
119 consume(^{ return foo(A()); });
120 }
121 // CHECK: define void @_ZN5test44testEv()
Fariborz Jahanian4904bf42012-06-26 16:06:38 +0000122 // CHECK: define internal void @___ZN5test44testEv_block_invoke
Adrian Prantl836e7c92013-03-14 17:53:33 +0000123 // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
124 // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
125 // CHECK-NEXT: load i8*
126 // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*
Adrian Prantl9b97adf2013-03-29 19:20:35 +0000127 // CHECK: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
John McCalld963c372011-08-17 21:34:14 +0000128 // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
John McCalld963c372011-08-17 21:34:14 +0000129 // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
130 // CHECK-NEXT: ret void
131}
132
John McCallb99785b2011-11-10 09:22:44 +0000133namespace test5 {
134 struct A {
135 unsigned afield;
136 A();
137 A(const A&);
138 ~A();
139 void foo() const;
140 };
141
142 void doWithBlock(void(^)());
143
144 void test(bool cond) {
145 A x;
146 void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0);
147 doWithBlock(b);
148 }
149
150 // CHECK: define void @_ZN5test54testEb(
151 // CHECK: [[COND:%.*]] = alloca i8
152 // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4
153 // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
154 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
155 // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
John McCallb99785b2011-11-10 09:22:44 +0000156 // CHECK-NEXT: [[T0:%.*]] = zext i1
157 // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1
158 // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]])
159 // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
160 // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]], align 1
161 // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
John McCall6f103ba2011-11-10 10:43:54 +0000162 // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
John McCallb99785b2011-11-10 09:22:44 +0000163 // CHECK-NEXT: br i1 [[T1]],
164
165 // CHECK-NOT: br
166 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
167 // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* [[X]])
168 // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
169 // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
170 // CHECK-NEXT: br label
171 // CHECK: br label
172 // CHECK: phi
173 // CHECK-NEXT: store
174 // CHECK-NEXT: load
175 // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE(
176 // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]]
177 // CHECK-NEXT: br i1 [[T0]]
178 // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]])
179 // CHECK-NEXT: br label
180 // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[X]])
181 // CHECK-NEXT: ret void
182}
John McCall538773c2011-11-11 03:19:12 +0000183
184namespace test6 {
185 struct A {
186 A();
187 ~A();
188 };
189
190 void foo(const A &, void (^)());
191 void bar();
192
193 void test() {
194 // Make sure that the temporary cleanup isn't somehow captured
195 // within the block.
196 foo(A(), ^{ bar(); });
197 bar();
198 }
199
200 // CHECK: define void @_ZN5test64testEv()
201 // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1
202 // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]])
203 // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(
204 // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]])
205 // CHECK-NEXT: call void @_ZN5test63barEv()
206 // CHECK-NEXT: ret void
207}
Richard Smith2d6a5672012-01-14 04:30:29 +0000208
209namespace test7 {
210 int f() {
211 static int n;
212 int *const p = &n;
213 return ^{ return *p; }();
214 }
215}
Douglas Gregorec79d872012-02-24 17:41:38 +0000216
217namespace test8 {
218 // <rdar://problem/10832617>: failure to capture this after skipping rebuild
219 // of the 'this' pointer.
220 struct X {
221 int x;
222
223 template<typename T>
224 int foo() {
225 return ^ { return x; }();
226 }
227 };
228
229 template int X::foo<int>();
230}
John McCallb760f112013-03-22 02:10:40 +0000231
232// rdar://13459289
233namespace test9 {
234 struct B {
235 void *p;
236 B();
237 B(const B&);
238 ~B();
239 };
240
241 void use_block(void (^)());
242 void use_block_2(void (^)(), const B &a);
243
244 // Ensuring that creating a non-trivial capture copy expression
245 // doesn't end up stealing the block registration for the block we
246 // just parsed. That block must have captures or else it won't
247 // force registration. Must occur within a block for some reason.
248 void test() {
249 B x;
250 use_block(^{
251 int y;
252 use_block_2(^{ (void)y; }, x);
253 });
254 }
255}