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