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