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