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