Clang Project

clang_source_code/test/CodeGenCXX/blocks.cpp
1// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
2
3// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
4// CHECK: @[[BLOCK_DESCRIPTOR22:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 36, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* null }, align 8
5
6namespace test0 {
7  // CHECK-LABEL: define void @_ZN5test04testEi(
8  // CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(
9  // CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}(
10  void test(int x) {
11    ^{ ^{ (void) x; }; };
12  }
13}
14
15extern void (^out)();
16
17namespace test1 {
18  // Capturing const objects doesn't require a local block.
19  // CHECK-LABEL: define void @_ZN5test15test1Ev()
20  // CHECK:   store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
21  void test1() {
22    const int NumHorsemen = 4;
23    out = ^{ (void) NumHorsemen; };
24  }
25
26  // That applies to structs too...
27  // CHECK-LABEL: define void @_ZN5test15test2Ev()
28  // CHECK:   store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out
29  struct loc { double x, y; };
30  void test2() {
31    const loc target = { 5, 6 };
32    out = ^{ (void) target; };
33  }
34
35  // ...unless they have mutable fields...
36  // CHECK-LABEL: define void @_ZN5test15test3Ev()
37  // CHECK:   [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
38  // CHECK:   [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
39  // CHECK:   store void ()* [[T0]], void ()** @out
40  struct mut { mutable int x; };
41  void test3() {
42    const mut obj = { 5 };
43    out = ^{ (void) obj; };
44  }
45
46  // ...or non-trivial destructors...
47  // CHECK-LABEL: define void @_ZN5test15test4Ev()
48  // CHECK:   [[OBJ:%.*]] = alloca
49  // CHECK:   [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
50  // CHECK:   [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
51  // CHECK:   store void ()* [[T0]], void ()** @out
52  struct scope { int x; ~scope(); };
53  void test4() {
54    const scope obj = { 5 };
55    out = ^{ (void) obj; };
56  }
57
58  // ...or non-trivial copy constructors, but it's not clear how to do
59  // that and still have a constant initializer in '03.
60}
61
62namespace test2 {
63  struct A {
64    A();
65    A(const A &);
66    ~A();
67  };
68
69  struct B {
70    B();
71    B(const B &);
72    ~B();
73  };
74
75  // CHECK-LABEL: define void @_ZN5test24testEv()
76  void test() {
77    __block A a;
78    __block B b;
79    ^{ (void)a; (void)b; };
80  }
81
82  // CHECK-LABEL: define internal void @__Block_byref_object_copy
83  // CHECK: call void @_ZN5test21AC1ERKS0_(
84
85  // CHECK-LABEL: define internal void @__Block_byref_object_dispose
86  // CHECK: call void @_ZN5test21AD1Ev(
87
88  // CHECK-LABEL: define internal void @__Block_byref_object_copy
89  // CHECK: call void @_ZN5test21BC1ERKS0_(
90
91  // CHECK-LABEL: define internal void @__Block_byref_object_dispose
92  // CHECK: call void @_ZN5test21BD1Ev(
93}
94
95// rdar://problem/9334739
96// Make sure we mark destructors for parameters captured in blocks.
97namespace test3 {
98  struct A {
99    A(const A&);
100    ~A();
101  };
102
103  struct B : A {
104  };
105
106  void test(B b) {
107    extern void consume(void(^)());
108    consume(^{ (void) b; });
109  }
110}
111
112// rdar://problem/9971485
113namespace test4 {
114  struct A {
115    A();
116    ~A();
117  };
118
119  void foo(A a);
120
121  void test() {
122    extern void consume(void(^)());
123    consume(^{ return foo(A()); });
124  }
125  // CHECK-LABEL: define void @_ZN5test44testEv()
126  // CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke
127  // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
128  // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
129  // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]* }>*
130  // CHECK:      call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
131  // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
132  // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
133  // CHECK-NEXT: ret void
134}
135
136namespace test5 {
137  struct A {
138    unsigned afield;
139    A();
140    A(const A&);
141    ~A();
142    void foo() const;
143  };
144
145  void doWithBlock(void(^)());
146
147  void test(bool cond) {
148    A x;
149    void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0);
150    doWithBlock(b);
151  }
152
153  // CHECK-LABEL:    define void @_ZN5test54testEb(
154  // CHECK:      [[COND:%.*]] = alloca i8
155  // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4
156  // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
157  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
158  // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
159  // CHECK-NEXT: [[T0:%.*]] = zext i1
160  // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1
161  // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]])
162  // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
163  // CHECK-NEXT: [[T0:%.*]] = load i8, i8* [[COND]], align 1
164  // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
165  // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
166  // CHECK-NEXT: br i1 [[T1]],
167
168  // CHECK-NOT:  br
169  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
170  // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* dereferenceable({{[0-9]+}}) [[X]])
171  // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
172  // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
173  // CHECK-NEXT: br label
174  // CHECK:      br label
175  // CHECK:      phi
176  // CHECK-NEXT: store
177  // CHECK-NEXT: load
178  // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE(
179  // CHECK-NEXT: [[T0:%.*]] = load i1, i1* [[CLEANUP_ACTIVE]]
180  // CHECK-NEXT: br i1 [[T0]]
181  // CHECK:      call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]])
182  // CHECK-NEXT: br label
183  // CHECK:      call void @_ZN5test51AD1Ev([[A]]* [[X]])
184  // CHECK-NEXT: ret void
185}
186
187namespace test6 {
188  struct A {
189    A();
190    ~A();
191  };
192
193  void foo(const A &, void (^)());
194  void bar();
195
196  void test() {
197    // Make sure that the temporary cleanup isn't somehow captured
198    // within the block.
199    foo(A(), ^{ bar(); });
200    bar();
201  }
202
203  // CHECK-LABEL:    define void @_ZN5test64testEv()
204  // CHECK:      [[TEMP:%.*]] = alloca [[A:%.*]], align 1
205  // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]])
206  // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(
207  // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]])
208  // CHECK-NEXT: call void @_ZN5test63barEv()
209  // CHECK-NEXT: ret void
210}
211
212namespace test7 {
213  int f() {
214    static int n;
215    int *const p = &n;
216    return ^{ return *p; }();
217  }
218}
219
220namespace test8 {
221  // <rdar://problem/10832617>: failure to capture this after skipping rebuild
222  // of the 'this' pointer.
223  struct X {
224    int x;
225
226    template<typename T>
227    int foo() {
228      return ^ { return x; }();
229    }
230  };
231
232  template int X::foo<int>();
233}
234
235// rdar://13459289
236namespace test9 {
237  struct B {
238    void *p;
239    B();
240    B(const B&);
241    ~B();
242  };
243
244  void use_block(void (^)());
245  void use_block_2(void (^)(), const B &a);
246
247  // Ensuring that creating a non-trivial capture copy expression
248  // doesn't end up stealing the block registration for the block we
249  // just parsed.  That block must have captures or else it won't
250  // force registration.  Must occur within a block for some reason.
251  void test() {
252    B x;
253    use_block(^{
254        int y;
255        use_block_2(^{ (void)y; }, x);
256    });
257  }
258}
259
260namespace test10 {
261  // Check that 'v' is included in the copy helper function name to indicate
262  // the constructor taking a volatile parameter is called to copy the captured
263  // object.
264
265  // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32c16_ZTSVN6test101BE(
266  // CHECK: call void @_ZN6test101BC1ERVKS0_(
267  // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32c16_ZTSVN6test101BE(
268  // CHECK: call void @_ZN6test101BD1Ev(
269
270  struct B {
271    int a;
272    B();
273    B(const B &);
274    B(const volatile B &);
275    ~B();
276  };
277
278  void test() {
279    volatile B x;
280    ^{ (void)x; };
281  }
282}
283
284// Copy/dispose helper functions and block descriptors of blocks that capture
285// objects that are non-external and non-trivial have internal linkage.
286
287// CHECK-LABEL: define internal void @_ZN12_GLOBAL__N_14testEv(
288// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESCRIPTOR22]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %{{.*}}, align 8
289
290// CHECK-LABEL: define internal void @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
291// CHECK-LABEL: define internal void @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
292
293namespace {
294  struct B {
295    int a;
296    B();
297    B(const B &);
298    ~B();
299  };
300
301  void test() {
302    B x;
303    ^{ (void)x; };
304  }
305}
306
307void callTest() {
308  test();
309}
310