1// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -std=c++1z -emit-llvm -o - %s | FileCheck %s 2 3// Shouldn't crash! 4 5// CHECK: %[[CLASS_ANON:.*]] = type { i8 } 6// CHECK: %[[CLASS_ANON_0:.*]] = type { i8 } 7// CHECK: %[[CLASS_ANON_1:.*]] = type { i8 } 8// CHECK: %[[CLASS_ANON_2:.*]] = type { i8 } 9 10// CHECK: @[[BLOCK_DESC0:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER0:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 11// CHECK: @[[BLOCK_DESC1:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER1:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 12// CHECK: @[[BLOCK_DESC2:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER2:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 13// CHECK: @[[BLOCK_DESC3:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER3:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 14 15// CHECK: define{{.*}} void @_Z9hasLambda8Copyable( 16// CHECK: %[[BLOCK:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON]] }>, align 8 17// CHECK: %[[BLOCK1:.*]] = alloca <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON_0]] }>, align 8 18// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON]] }>, ptr %[[BLOCK]], i32 0, i32 4 19// CHECK: store ptr @[[BLOCK_DESC0]], ptr %[[BLOCK_DESCRIPTOR]], align 8 20// CHECK: %[[BLOCK_DESCRIPTOR6:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON_0]] }>, ptr %[[BLOCK1]], i32 0, i32 4 21// CHECK: store ptr @[[BLOCK_DESC1]], ptr %[[BLOCK_DESCRIPTOR6]], align 8 22 23void takesBlock(void (^)(void)); 24 25struct Copyable { 26 Copyable(const Copyable &x); 27}; 28 29// Check that each block has its block descriptor and helper function. 30 31void hasLambda(Copyable x) { 32 takesBlock([x] () { }); 33 takesBlock([x] () { }); 34} 35// CHECK: define internal void @[[COPY_HELPER0]] 36// CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_" 37// CHECK: define internal void @[[COPY_HELPER1]] 38 39// CHECK: define{{.*}} void @_Z17testHelperMerging8Copyable( 40// CHECK: %[[CALL:.*]] = call noundef ptr @[[CONV_FUNC0:.*]](ptr 41// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(ptr noundef %[[CALL]]) 42// CHECK: %[[CALL1:.*]] = call noundef ptr @[[CONV_FUNC0]](ptr 43// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(ptr noundef %[[CALL1]]) 44// CHECK: %[[CALL2:.*]] = call noundef ptr @[[CONV_FUNC1:.*]](ptr 45// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(ptr noundef %[[CALL2]]) 46 47// CHECK: define internal noundef ptr @[[CONV_FUNC0]]( 48// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON_1]] }>, ptr %{{.*}}, i32 0, i32 4 49// CHECK: store ptr @[[BLOCK_DESC2]], ptr %[[BLOCK_DESCRIPTOR]], align 8 50 51// CHECK: define internal noundef ptr @[[CONV_FUNC1]]( 52// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds nuw <{ ptr, i32, i32, ptr, ptr, %[[CLASS_ANON_2]] }>, ptr %{{.*}}, i32 0, i32 4 53// CHECK: store ptr @[[BLOCK_DESC3]], ptr %[[BLOCK_DESCRIPTOR]], align 8 54 55// CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_" 56// CHECK: call void @_ZN8CopyableC1ERKS_ 57 58// CHECK: define internal void @[[COPY_HELPER2]] 59// CHECK: define internal void @[[COPY_HELPER3]] 60 61void testHelperMerging(Copyable x) { 62 auto lambda0 = [x]{}; 63 auto lambda1 = [x]{}; 64 takesBlock(lambda0); 65 66 // This block has the same helper functions and a descriptor as the block 67 // created above. 68 takesBlock(lambda0); 69 70 // This block has different helper functions and a descriptor as the blocks 71 // created above. 72 takesBlock(lambda1); 73} 74