From c405aa768190880c02535572bcc7e3b04c75da95 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Sat, 20 Oct 2018 05:45:01 +0000 Subject: [PATCH] [CodeGen] Use the mangle context owned by CodeGenModule to correctly mangle types of lambda objects captured by a block instead of creating a new mangle context everytime a captured field type is mangled. This fixes a bug in IRGen's block helper merging code that was introduced in r339438 where two blocks capturing two distinct lambdas would end up sharing helper functions and the block descriptor. This happened because the ID number used to distinguish lambdas defined in the same context is reset everytime a mangled context is created. rdar://problem/45314494 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@344833 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGBlocks.cpp | 4 +- test/CodeGenObjCXX/lambda-to-block.mm | 60 ++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index c2e5f1a5a1..b7ad9207f2 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -1817,8 +1817,6 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, CodeGenModule &CGM) { std::string Str; ASTContext &Ctx = CGM.getContext(); - std::unique_ptr MC( - ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())); const BlockDecl::Capture &CI = *E.CI; QualType CaptureTy = CI.getVariable()->getType(); @@ -1844,7 +1842,7 @@ static std::string getBlockCaptureStr(const BlockCaptureManagedEntity &E, Str += "c"; SmallString<256> TyStr; llvm::raw_svector_ostream Out(TyStr); - MC->mangleTypeName(CaptureTy, Out); + CGM.getCXXABI().getMangleContext().mangleTypeName(CaptureTy, Out); Str += llvm::to_string(TyStr.size()) + TyStr.c_str(); break; } diff --git a/test/CodeGenObjCXX/lambda-to-block.mm b/test/CodeGenObjCXX/lambda-to-block.mm index cbb4ce161d..a21c8232f0 100644 --- a/test/CodeGenObjCXX/lambda-to-block.mm +++ b/test/CodeGenObjCXX/lambda-to-block.mm @@ -3,16 +3,74 @@ // rdar://31385153 // Shouldn't crash! +// CHECK: %[[STRUCT_COPYABLE:.*]] = type { i8 } +// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } +// CHECK: %[[CLASS_ANON:.*]] = type { %[[STRUCT_COPYABLE]] } +// CHECK: %[[CLASS_ANON_0:.*]] = type { %[[STRUCT_COPYABLE]] } +// CHECK: %[[CLASS_ANON_1:.*]] = type { %[[STRUCT_COPYABLE]] } +// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[STRUCT_COPYABLE]] } + +// CHECK: @[[BLOCK_DESC0:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 33, i8* bitcast (void (i8*, i8*)* @[[COPY_HELPER0:.*__copy_helper_block_.*]] to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block{{.*}} to i8*), {{.*}}}, align 8 +// CHECK: @[[BLOCK_DESC1:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 33, i8* bitcast (void (i8*, i8*)* @[[COPY_HELPER1:.*__copy_helper_block_.*]] to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block{{.*}} to i8*), {{.*}}}, align 8 +// CHECK: @[[BLOCK_DESC2:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 33, i8* bitcast (void (i8*, i8*)* @[[COPY_HELPER2:.*__copy_helper_block_.*]] to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block{{.*}} to i8*), {{.*}}}, align 8 +// CHECK: @[[BLOCK_DESC3:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 33, i8* bitcast (void (i8*, i8*)* @[[COPY_HELPER3:.*__copy_helper_block_.*]] to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block{{.*}} to i8*), {{.*}}}, align 8 + +// CHECK: define void @_Z9hasLambda8Copyable( +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON]] }>, align 8 +// CHECK: %[[BLOCK1:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_0]] }>, align 8 +// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON]] }>* %[[BLOCK]], i32 0, i32 4 +// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESC0]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 +// CHECK: %[[BLOCK_DESCRIPTOR6:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_0]] }>* %[[BLOCK1]], i32 0, i32 4 +// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESC1]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR6]], align 8 + void takesBlock(void (^)(void)); struct Copyable { Copyable(const Copyable &x); }; +// Check that each block has its block descriptor and helper function. + void hasLambda(Copyable x) { takesBlock([x] () { }); + takesBlock([x] () { }); } -// CHECK-LABEL: define internal void @"__copy_helper_block_ +// CHECK: define internal void @[[COPY_HELPER0]] // CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_" +// CHECK: define internal void @[[COPY_HELPER1]] + +// CHECK: define void @_Z17testHelperMerging8Copyable( +// CHECK: %[[CALL:.*]] = call void ()* @[[CONV_FUNC0:.*]](%[[CLASS_ANON_1]]* +// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(void ()* %[[CALL]]) +// CHECK: %[[CALL1:.*]] = call void ()* @[[CONV_FUNC0]](%[[CLASS_ANON_1]]* +// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(void ()* %[[CALL1]]) +// CHECK: %[[CALL2:.*]] = call void ()* @[[CONV_FUNC1:.*]](%[[CLASS_ANON_2]]* +// CHECK: call void @_Z10takesBlockU13block_pointerFvvE(void ()* %[[CALL2]]) + +// CHECK: define internal void ()* @[[CONV_FUNC0]]( +// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_1]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_1]] }>* %{{.*}}, i32 0, i32 4 +// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESC2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 + +// CHECK: define internal void ()* @[[CONV_FUNC1]]( +// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_2]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, %[[CLASS_ANON_2]] }>* %{{.*}}, i32 0, i32 4 +// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESC3]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 + // CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_" // CHECK: call void @_ZN8CopyableC1ERKS_ + +// CHECK: define internal void @[[COPY_HELPER2]] +// CHECK: define internal void @[[COPY_HELPER3]] + +void testHelperMerging(Copyable x) { + auto lambda0 = [x]{}; + auto lambda1 = [x]{}; + takesBlock(lambda0); + + // This block has the same helper functions and a descriptor as the block + // created above. + takesBlock(lambda0); + + // This block has different helper functions and a descriptor as the blocks + // created above. + takesBlock(lambda1); +} -- 2.40.0