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