303 lines · cpp
1// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s2 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 84 5namespace 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 14extern void (^out)();15 16namespace 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 @out20 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 @out28 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 @out38 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:%.*]] = alloca47 // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],48 // CHECK: store ptr [[BLOCK]], ptr @out49 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 do56 // that and still have a constant initializer in '03.57}58 59namespace 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_copy80 // CHECK: call void @_ZN5test21AC1ERKS0_(81 82 // CHECK-LABEL: define internal void @__Block_byref_object_dispose83 // CHECK: call void @_ZN5test21AD1Ev(84 85 // CHECK-LABEL: define internal void @__Block_byref_object_copy86 // CHECK: call void @_ZN5test21BC1ERKS0_(87 88 // CHECK-LABEL: define internal void @__Block_byref_object_dispose89 // CHECK: call void @_ZN5test21BD1Ev(90}91 92// Make sure we mark destructors for parameters captured in blocks.93namespace 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 108namespace 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_invoke122 // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1123 // CHECK-NEXT: store ptr [[BLOCKDESC:%.*]], ptr {{.*}}, align 8124 // 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 void128}129 130namespace 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 i8149 // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4150 // CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8151 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8152 // CHECK-NEXT: [[COND_CLEANUP_SAVE:%.*]] = alloca ptr, align 8153 // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1154 // CHECK-NEXT: [[T0:%.*]] = zext i1155 // CHECK-NEXT: store i8 [[T0]], ptr [[COND]], align 1156 // CHECK-NEXT: call void @_ZN5test51AC1Ev(ptr {{[^,]*}} [[X]])157 // CHECK-NEXT: [[T0:%.*]] = load i8, ptr [[COND]], align 1158 // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1159 // CHECK-NEXT: store i1 false, ptr [[CLEANUP_ACTIVE]]160 // CHECK-NEXT: br i1 [[T1]],161 162 // CHECK-NOT: br163 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], ptr [[BLOCK]], i32 0, i32 5164 // 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 8166 // CHECK-NEXT: store i1 true, ptr [[CLEANUP_ACTIVE]]167 // CHECK-NEXT: br label168 // CHECK: br label169 // CHECK: phi170 // CHECK-NEXT: store171 // CHECK-NEXT: load172 // 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 8176 // CHECK-NEXT: call void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[T3]])177 // CHECK-NEXT: br label178 // CHECK: call void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[X]])179 // CHECK-NEXT: ret void180}181 182namespace 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 captured193 // within the block.194 foo(A(), ^{ bar(); });195 bar();196 }197 198 // CHECK-LABEL: define{{.*}} void @_ZN5test64testEv()199 // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1200 // 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 void205}206 207namespace test7 {208 int f() {209 static int n;210 int *const p = &n;211 return ^{ return *p; }();212 }213}214 215namespace 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 229namespace 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 expression241 // doesn't end up stealing the block registration for the block we242 // just parsed. That block must have captures or else it won't243 // 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 253namespace test10 {254 // Check that 'v' is included in the copy helper function name to indicate255 // the constructor taking a volatile parameter is called to copy the captured256 // 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 capture278// 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 8282 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 286namespace {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 300void callTest() {301 test();302}303