blob: 3d7fcfddbe275161ba6b32a353d374cde92898b4 [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(
5 // CHECK: define internal void @__test_block_invoke_{{.*}}(
6 // CHECK: define internal void @__block_global_{{.*}}(
7 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()
122 // CHECK: define internal void @__test_block_invoke
123 // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
John McCalld963c372011-08-17 21:34:14 +0000124 // CHECK-NEXT: bitcast i8*
125 // CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
126 // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
John McCalld963c372011-08-17 21:34:14 +0000127 // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
128 // CHECK-NEXT: ret void
129}
130
John McCallb99785b2011-11-10 09:22:44 +0000131namespace test5 {
132 struct A {
133 unsigned afield;
134 A();
135 A(const A&);
136 ~A();
137 void foo() const;
138 };
139
140 void doWithBlock(void(^)());
141
142 void test(bool cond) {
143 A x;
144 void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0);
145 doWithBlock(b);
146 }
147
148 // CHECK: define void @_ZN5test54testEb(
149 // CHECK: [[COND:%.*]] = alloca i8
150 // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4
151 // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
152 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
153 // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
John McCallb99785b2011-11-10 09:22:44 +0000154 // CHECK-NEXT: [[T0:%.*]] = zext i1
155 // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1
156 // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]])
157 // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
158 // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]], align 1
159 // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
John McCall6f103ba2011-11-10 10:43:54 +0000160 // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
John McCallb99785b2011-11-10 09:22:44 +0000161 // CHECK-NEXT: br i1 [[T1]],
162
163 // CHECK-NOT: br
164 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
165 // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* [[X]])
166 // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
167 // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
168 // CHECK-NEXT: br label
169 // CHECK: br label
170 // CHECK: phi
171 // CHECK-NEXT: store
172 // CHECK-NEXT: load
173 // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE(
174 // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]]
175 // CHECK-NEXT: br i1 [[T0]]
176 // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]])
177 // CHECK-NEXT: br label
178 // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[X]])
179 // CHECK-NEXT: ret void
180}
John McCall538773c2011-11-11 03:19:12 +0000181
182namespace test6 {
183 struct A {
184 A();
185 ~A();
186 };
187
188 void foo(const A &, void (^)());
189 void bar();
190
191 void test() {
192 // Make sure that the temporary cleanup isn't somehow captured
193 // within the block.
194 foo(A(), ^{ bar(); });
195 bar();
196 }
197
198 // CHECK: define void @_ZN5test64testEv()
199 // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1
200 // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]])
201 // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(
202 // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]])
203 // CHECK-NEXT: call void @_ZN5test63barEv()
204 // CHECK-NEXT: ret void
205}
Richard Smith2d6a5672012-01-14 04:30:29 +0000206
207namespace test7 {
208 int f() {
209 static int n;
210 int *const p = &n;
211 return ^{ return *p; }();
212 }
213}