ahatanak updated this revision to Diff 159250.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.
Address review comments.
Repository:
rC Clang
https://reviews.llvm.org/D50152
Files:
lib/CodeGen/CGBlocks.cpp
lib/CodeGen/CGBlocks.h
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGNonTrivialStruct.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGen/blocks-1.c
test/CodeGen/blocks.c
test/CodeGen/sanitize-thread-no-checking-at-run-time.m
test/CodeGenCXX/block-byref-cxx-objc.cpp
test/CodeGenCXX/blocks.cpp
test/CodeGenCXX/cxx-block-objects.cpp
test/CodeGenObjC/arc-blocks.m
test/CodeGenObjC/debug-info-block-helper.m
test/CodeGenObjC/debug-info-blocks.m
test/CodeGenObjC/mrc-weak.m
test/CodeGenObjC/strong-in-c-struct.m
test/CodeGenObjCXX/arc-blocks.mm
test/CodeGenObjCXX/lambda-to-block.mm
test/CodeGenObjCXX/mrc-weak.mm
Index: test/CodeGenObjCXX/mrc-weak.mm
===================================================================
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
// CHECK: call void @use_block
// CHECK: call void @objc_destroyWeak
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
// CHECK: @objc_copyWeak
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
// CHECK: @objc_destroyWeak
void test8(void) {
@@ -142,8 +142,8 @@
// CHECK: call void @objc_destroyWeak
// CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK: define internal void @__copy_helper
-// CHECK: define internal void @__destroy_helper
+// CHECK: define linkonce_odr hidden void @__copy_helper
+// CHECK: define linkonce_odr hidden void @__destroy_helper
void test9_baseline(void) {
Foo *p = get_object();
use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===================================================================
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
void hasLambda(Copyable x) {
takesBlock([x] () { });
}
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @"__copy_helper_block_
// CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_"
// CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_"
// CHECK: call void @_ZN8CopyableC1ERKS_
Index: test/CodeGenObjCXX/arc-blocks.mm
===================================================================
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s
// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s
+// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s
// CHECK: [[A:.*]] = type { i64, [10 x i8*] }
// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }
// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
// CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
@@ -55,34 +57,34 @@
// Check that copy/dispose helper functions are exception safe.
-// CHECK-LABEL: define internal void @__copy_helper_block_(
-// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
-// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
+// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
-// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 6
-// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_DEST]], i32 0, i32 6
+// CHECK: %[[V9:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_SOURCE]], i32 0, i32 5
+// CHECK: %[[V10:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_DEST]], i32 0, i32 5
+// CHECK: %[[BLOCKCOPY_SRC2:.*]] = load i8*, i8** %[[V9]], align 8
+// CHECK: store i8* null, i8** %[[V10]], align 8
+// CHECK: call void @objc_storeStrong(i8** %[[V10]], i8* %[[BLOCKCOPY_SRC2]])
+
+// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_SOURCE]], i32 0, i32 6
+// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_DEST]], i32 0, i32 6
// CHECK: %[[BLOCKCOPY_SRC:.*]] = load i8*, i8** %[[V4]], align 8
// CHECK: %[[V6:.*]] = bitcast i8** %[[V5]] to i8*
// CHECK: call void @_Block_object_assign(i8* %[[V6]], i8* %[[BLOCKCOPY_SRC]], i32 8)
-// CHECK: %[[V7:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 7
-// CHECK: %[[V8:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_DEST]], i32 0, i32 7
+// CHECK: %[[V7:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_SOURCE]], i32 0, i32 7
+// CHECK: %[[V8:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_DEST]], i32 0, i32 7
// CHECK: call void @objc_copyWeak(i8** %[[V8]], i8** %[[V7]])
-// CHECK: %[[V9:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 5
-// CHECK: %[[V10:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_DEST]], i32 0, i32 5
-// CHECK: %[[BLOCKCOPY_SRC2:.*]] = load i8*, i8** %[[V9]], align 8
-// CHECK: store i8* null, i8** %[[V10]], align 8
-// CHECK: call void @objc_storeStrong(i8** %[[V10]], i8* %[[BLOCKCOPY_SRC2]])
-
-// CHECK: %[[V11:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 8
-// CHECK: %[[V12:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_DEST]], i32 0, i32 8
+// CHECK: %[[V11:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_SOURCE]], i32 0, i32 8
+// CHECK: %[[V12:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_DEST]], i32 0, i32 8
// CHECK: invoke void @_ZN5test12S0C1ERKS0_(%[[STRUCT_TEST1_S0]]* %[[V12]], %[[STRUCT_TEST1_S0]]* dereferenceable(4) %[[V11]])
// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
// CHECK: [[INVOKE_CONT]]:
-// CHECK: %[[V13:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 9
-// CHECK: %[[V14:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_DEST]], i32 0, i32 9
+// CHECK: %[[V13:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_SOURCE]], i32 0, i32 9
+// CHECK: %[[V14:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK_DEST]], i32 0, i32 9
// CHECK: invoke void @_ZN5test12S0C1ERKS0_(%[[STRUCT_TEST1_S0]]* %[[V14]], %[[STRUCT_TEST1_S0]]* dereferenceable(4) %[[V13]])
// CHECK: to label %[[INVOKE_CONT4:.*]] unwind label %[[LPAD3:.*]]
@@ -100,40 +102,41 @@
// CHECK: br label %[[EHCLEANUP]]
// CHECK: [[EHCLEANUP]]:
-// CHECK: call void @objc_storeStrong(i8** %[[V10]], i8* null)
// CHECK: call void @objc_destroyWeak(i8** %[[V8]])
// CHECK: %[[V21:.*]] = load i8*, i8** %[[V5]], align 8
// CHECK: call void @_Block_object_dispose(i8* %[[V21]], i32 8)
+// CHECK: call void @objc_storeStrong(i8** %[[V10]], i8* null)
// CHECK: br label %[[EH_RESUME:.*]]
// CHECK: [[EH_RESUME]]:
// CHECK: resume { i8*, i32 }
// CHECK: [[TERMINATE_LPAD]]:
// CHECK: call void @__clang_call_terminate(
-// CHECK-O1-LABEL: define internal void @__copy_helper_block_(
+// CHECK-O1-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
// CHECK-O1: tail call void @objc_release({{.*}}) {{.*}} !clang.imprecise_release
-
-// CHECK: define internal void @__destroy_helper_block_(
-// CHECK: %[[BLOCK:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
-// CHECK: %[[V2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK]], i32 0, i32 6
-// CHECK: %[[V3:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK]], i32 0, i32 7
-// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK]], i32 0, i32 5
-// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK]], i32 0, i32 8
-// CHECK: %[[V6:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK]], i32 0, i32 9
+// CHECK-NOEXCP: define linkonce_odr hidden void @__copy_helper_block_8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+
+// CHECK: define linkonce_odr hidden void @__destroy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+// CHECK: %[[BLOCK:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
+// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK]], i32 0, i32 6
+// CHECK: %[[V3:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK]], i32 0, i32 7
+// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK]], i32 0, i32 8
+// CHECK: %[[V6:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>* %[[BLOCK]], i32 0, i32 9
// CHECK: invoke void @_ZN5test12S0D1Ev(%[[STRUCT_TEST1_S0]]* %[[V6]])
// CHECK: to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
// CHECK: [[INVOKE_CONT]]:
// CHECK: invoke void @_ZN5test12S0D1Ev(%[[STRUCT_TEST1_S0]]* %[[V5]])
// CHECK: to label %[[INVOKE_CONT2:.*]] unwind label %[[LPAD1:.*]]
// CHECK: [[INVOKE_CONT2]]:
-// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* null)
// CHECK: call void @objc_destroyWeak(i8** %[[V3]])
// CHECK: %[[V7:.*]] = load i8*, i8** %[[V2]], align 8
// CHECK: call void @_Block_object_dispose(i8* %[[V7]], i32 8)
+// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* null)
// CHECK: ret void
// CHECK: [[LPAD]]:
@@ -147,21 +150,28 @@
// CHECK: br label %[[EHCLEANUP]]
// CHECK: [[EHCLEANUP]]:
-// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* null)
// CHECK: call void @objc_destroyWeak(i8** %[[V3]])
// CHECK: %[[V14:.*]] = load i8*, i8** %[[V2]], align 8
// CHECK: call void @_Block_object_dispose(i8* %[[V14]], i32 8)
+// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* null)
// CHECK: br label %[[EH_RESUME]]
// CHECK: [[EH_RESUME]]:
// CHECK: resume { i8*, i32 }
// CHECK: [[TERMINATE_LPAD]]:
// CHECK: call void @__clang_call_terminate(
-// CHECK-O1-LABEL: define internal void @__destroy_helper_block_(
+// CHECK-O1-LABEL: define linkonce_odr hidden void @__destroy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
// CHECK-O1: tail call void @objc_release({{.*}}) {{.*}} !clang.imprecise_release
// CHECK-O1: tail call void @objc_release({{.*}}) {{.*}} !clang.imprecise_release
+// CHECK-NOEXCP: define linkonce_odr hidden void @__destroy_helper_block_8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+
+namespace {
+struct TrivialInternal {
+ int a;
+};
+}
struct S0 {
S0();
@@ -177,6 +187,10 @@
__weak id t1 = getObj();
id t2 = getObj();
S0 t3, t4;
- ^{ (void)t0; (void)t1; (void)t2; (void)t3; (void)t4; };
+ // Capturing a non-external type doesn't cause the copy/dispose helpers to be
+ // internal unless the captured type has a non-trivial copy constructor or
+ // destructor.
+ TrivialInternal t5;
+ ^{ (void)t0; (void)t1; (void)t2; (void)t3; (void)t4; (void)t5; };
}
}
Index: test/CodeGenObjC/strong-in-c-struct.m
===================================================================
--- test/CodeGenObjC/strong-in-c-struct.m
+++ test/CodeGenObjC/strong-in-c-struct.m
@@ -419,11 +419,11 @@
// CHECK: call void @__destructor_8_s16(
// CHECK: ret void
-// CHECK: define internal void @__copy_helper_block_.1(i8*, i8*)
+// CHECK: define linkonce_odr hidden void @__copy_helper_block_8_32n13_8_8_t0w16_s16(i8*, i8*)
// CHECK: call void @__copy_constructor_8_8_t0w16_s16(
// CHECK: ret void
-// CHECK: define internal void @__destroy_helper_block_.2(
+// CHECK: define linkonce_odr hidden void @__destroy_helper_block_8_32n5_8_s16(
// CHECK: call void @__destructor_8_s16(
// CHECK: ret void
Index: test/CodeGenObjC/mrc-weak.m
===================================================================
--- test/CodeGenObjC/mrc-weak.m
+++ test/CodeGenObjC/mrc-weak.m
@@ -139,10 +139,10 @@
// CHECK: call void @use_block
// CHECK: call void @objc_destroyWeak
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
// CHECK: @objc_copyWeak
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
// CHECK: @objc_destroyWeak
void test8(void) {
@@ -162,26 +162,26 @@
// CHECK: call void @objc_destroyWeak
// CHECK-LABEL: define void @test9_baseline()
-// CHECK: define internal void @__copy_helper
-// CHECK: define internal void @__destroy_helper
+// CHECK: define linkonce_odr hidden void @__copy_helper
+// CHECK: define linkonce_odr hidden void @__destroy_helper
void test9_baseline(void) {
Foo *p = get_object();
use_block(^{ [p run]; });
}
// CHECK-LABEL: define void @test9()
-// CHECK-NOT: define internal void @__copy_helper
-// CHECK-NOT: define internal void @__destroy_helper
+// CHECK-NOT: define linkonce_odr hidden void @__copy_helper
+// CHECK-NOT: define linkonce_odr hidden void @__destroy_helper
// CHECK: define void @test9_fin()
void test9(void) {
__unsafe_unretained Foo *p = get_object();
use_block(^{ [p run]; });
}
void test9_fin() {}
// CHECK-LABEL: define void @test10()
-// CHECK-NOT: define internal void @__copy_helper
-// CHECK-NOT: define internal void @__destroy_helper
+// CHECK-NOT: define linkonce_odr hidden void @__copy_helper
+// CHECK-NOT: define linkonce_odr hidden void @__destroy_helper
// CHECK: define void @test10_fin()
void test10(void) {
typedef __unsafe_unretained Foo *UnsafeFooPtr;
Index: test/CodeGenObjC/debug-info-blocks.m
===================================================================
--- test/CodeGenObjC/debug-info-blocks.m
+++ test/CodeGenObjC/debug-info-blocks.m
@@ -59,9 +59,9 @@
if ((self = [super init])) {
// CHECK-DAG: [[DBG_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
// CHECK-DAG: [[COPY_LINE]] = !DILocation(line: [[@LINE+7]], scope: ![[COPY_SP:[0-9]+]])
- // CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_"
+ // CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_8_32r"
// CHECK-DAG: [[DESTROY_LINE]] = !DILocation(line: [[@LINE+5]], scope: ![[DESTROY_SP:[0-9]+]])
- // CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_"
+ // CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_8_32r"
// CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
// CHECK-DAG: !DILocalVariable(arg: 2, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
// CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[DESTROY_SP]], {{.*}}, flags: DIFlagArtificial)
Index: test/CodeGenObjC/debug-info-block-helper.m
===================================================================
--- test/CodeGenObjC/debug-info-block-helper.m
+++ test/CodeGenObjC/debug-info-block-helper.m
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -debug-info-kind=limited -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s -o - | FileCheck %s
extern void foo(void(^)(void));
-// CHECK: !DISubprogram(name: "__destroy_helper_block_"
+// CHECK: !DISubprogram(name: "__destroy_helper_block_8_32r40b48b"
@interface NSObject {
struct objc_object *isa;
Index: test/CodeGenObjC/arc-blocks.m
===================================================================
--- test/CodeGenObjC/arc-blocks.m
+++ test/CodeGenObjC/arc-blocks.m
@@ -1,6 +1,17 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT %s
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK-UNOPT: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32b, void (i8*)* @__destroy_helper_block_8_32b, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
+// CHECK-UNOPT: @{{.*}} = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK-UNOPT: @{{.*}} = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK-UNOPT: @{{.*}} = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK-UNOPT: @{{.*}} = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK-UNOPT: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i8* } { i64 0, i64 48, void (i8*, i8*)* @__copy_helper_block_8_32s, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @{{.*}}, i32 0, i32 0) }, align 8
+// CHECK: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = internal constant { i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 } { i64 0, i64 40, void (i8*, i8*)* @__copy_helper_block_8_32rb, void (i8*)* @__destroy_helper_block_8_32s, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.47, i32 0, i32 0), i64 256 }, align 8
+
// This shouldn't crash.
void test0(id (^maker)(void)) {
maker();
@@ -43,7 +54,7 @@
extern void test2_helper(id (^)(void));
test2_helper(^{ return x; });
-// CHECK-LABEL: define internal void @__copy_helper_block_(i8*, i8*) #{{[0-9]+}} {
+// CHECK: define linkonce_odr hidden void @__copy_helper_block_8_32s(i8*, i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: [[T0:%.*]] = load i8*, i8**
// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8**
@@ -53,7 +64,8 @@
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: ret void
-// CHECK-LABEL: define internal void @__destroy_helper_block_(i8*) #{{[0-9]+}} {
+
+// CHECK: define linkonce_odr hidden void @__destroy_helper_block_8_32s(i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: [[T0:%.*]] = load i8*, i8**
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[T1]], i32 0, i32 5
@@ -155,10 +167,10 @@
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: ret void
- // CHECK-LABEL: define internal void @__copy_helper_block_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} {
+ // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32b(i8*, i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
- // CHECK-LABEL: define internal void @__destroy_helper_block_.{{[0-9]+}}(i8*) #{{[0-9]+}} {
+ // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32b(i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
}
@@ -211,6 +223,8 @@
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 6
// 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
// CHECK: store i32 -1040187392,
+ // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %{{.*}}, i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP9]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: store i8* [[T0]], i8**
// CHECK: call void @test6_helper(
@@ -236,14 +250,6 @@
// CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
// CHECK-NEXT: ret void
-
- // CHECK-LABEL: define internal void @__copy_helper_block_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} {
- // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
- // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
-
- // CHECK-LABEL: define internal void @__destroy_helper_block_.{{[0-9]+}}(i8*) #{{[0-9]+}} {
- // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
- // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
}
void test7(void) {
@@ -276,12 +282,12 @@
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK: ret void
- // CHECK-LABEL: define internal void @__copy_helper_block_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} {
+ // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32w(i8*, i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: getelementptr
// CHECK-NEXT: getelementptr
// CHECK-NEXT: call void @objc_copyWeak(
- // CHECK-LABEL: define internal void @__destroy_helper_block_.{{[0-9]+}}(i8*) #{{[0-9]+}} {
+ // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32w(i8*) unnamed_addr #{{[0-9]+}} {
// CHECK: getelementptr
// CHECK-NEXT: call void @objc_destroyWeak(
}
@@ -631,6 +637,8 @@
// CHECK-UNOPT-NEXT: store i8* null, i8** [[X]]
// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]],
// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-UNOPT: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 4
+// CHECK-UNOPT: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP44]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8*, i8** [[X]],
// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
@@ -642,25 +650,6 @@
// CHECK-UNOPT-NEXT: ret void
extern void test18_helper(id (^)(void));
test18_helper(^{ return x; });
-
-// CHECK-UNOPT-LABEL: define internal void @__copy_helper_block_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} {
-// CHECK-UNOPT: [[T0:%.*]] = load i8*, i8**
-// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
-// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8*, i8**
-// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
-// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[SRC]], i32 0, i32 5
-// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[DST]], i32 0, i32 5
-// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8*, i8** [[T0]]
-// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]]
-// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) [[NUW]]
-// CHECK-UNOPT-NEXT: ret void
-
-// CHECK-UNOPT-LABEL: define internal void @__destroy_helper_block_.{{[0-9]+}}(i8*) #{{[0-9]+}} {
-// CHECK-UNOPT: [[T0:%.*]] = load i8*, i8**
-// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
-// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[T1]], i32 0, i32 5
-// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
-// CHECK-UNOPT-NEXT: ret void
}
// Ensure that we don't emit helper code in copy/dispose routines for variables
@@ -670,33 +659,12 @@
(^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })();
}
-// CHECK-LABEL: testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
-// CHECK-UNOPT-LABEL: testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
+// CHECK-LABEL: define void @testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers
+// %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>* %{{.*}}, i32 0, i32 4
+// store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i8* }* @[[BLOCK_DESCRIPTOR_TMP46]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
-// CHECK-UNOPT: @__copy_helper_block
-// CHECK-UNOPT: alloca
-// CHECK-UNOPT-NEXT: alloca
-// CHECK-UNOPT-NEXT: store
-// CHECK-UNOPT-NEXT: store
-// CHECK-UNOPT-NEXT: load
-// CHECK-UNOPT-NEXT: bitcast
-// CHECK-UNOPT-NEXT: load
-// CHECK-UNOPT-NEXT: bitcast
-// CHECK-UNOPT-NEXT: getelementptr
-// CHECK-UNOPT-NEXT: getelementptr
-// CHECK-UNOPT-NEXT: load
-// CHECK-UNOPT-NEXT: store
-// CHECK-UNOPT-NEXT: call void @objc_storeStrong
-// CHECK-UNOPT-NEXT: ret
-
-// CHECK-UNOPT: @__destroy_helper_block
-// CHECK-UNOPT: alloca
-// CHECK-UNOPT-NEXT: store
-// CHECK-UNOPT-NEXT: load
-// CHECK-UNOPT-NEXT: bitcast
-// CHECK-UNOPT-NEXT: getelementptr
-// CHECK-UNOPT-NEXT: call void @objc_storeStrong
-// CHECK-UNOPT-NEXT: ret
+// CHECK-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
+// CHECK-UNOPT-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke
// rdar://13588325
void test19_sink(void (^)(int));
@@ -712,6 +680,8 @@
// Block setup. We skip most of this. Note the bare retain.
// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, void (i8*, i8*)*, void (i8*)*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP48]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]],
// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
@@ -762,12 +732,6 @@
// CHECK-UNOPT: store i8* [[RETAINED]], i8** [[BLOCKCAPTURED]]
// CHECK-UNOPT: call void @objc_storeStrong(i8** [[CAPTUREFIELD]], i8* null)
-// CHECK-LABEL: define internal void @__copy_helper_block
-// CHECK: [[BLOCKSOURCE:%.*]] = bitcast i8* %{{.*}} to <[[BLOCKTY]]>*
-// CHECK: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCKSOURCE]], i32 0, i32 5
-// CHECK: [[BLOCKCOPYSRC:%.*]] = load i8*, i8** [[CAPTUREFIELD]]
-// CHECK: call i8* @objc_retain(i8* [[BLOCKCOPYSRC]])
-
void test20_callee(void (^)());
void test20(const id x) {
test20_callee(^{ (void)x; });
Index: test/CodeGenCXX/cxx-block-objects.cpp
===================================================================
--- test/CodeGenCXX/cxx-block-objects.cpp
+++ test/CodeGenCXX/cxx-block-objects.cpp
@@ -25,9 +25,9 @@
return 0;
}
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_
// CHECK: call void @_ZN1AC1ERKS_
-// CHECK-LABEL:define internal void @__destroy_helper_block_
+// CHECK-LABEL:define linkonce_odr hidden void @__destroy_helper_block_
// CHECK: call void @_ZN1AD1Ev
Index: test/CodeGenCXX/blocks.cpp
===================================================================
--- test/CodeGenCXX/blocks.cpp
+++ test/CodeGenCXX/blocks.cpp
@@ -252,3 +252,51 @@
});
}
}
+
+namespace test10 {
+ // Check that 'v' is included in the copy helper function name to indicate
+ // the constructor taking a volatile parameter is called to copy the captured
+ // object.
+
+ // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32c16_ZTSVN6test101BE(
+ // CHECK: call void @_ZN6test101BC1ERVKS0_(
+ // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32c16_ZTSVN6test101BE(
+ // CHECK: call void @_ZN6test101BD1Ev(
+
+ struct B {
+ int a;
+ B();
+ B(const B &);
+ B(const volatile B &);
+ ~B();
+ };
+
+ void test() {
+ volatile B x;
+ ^{ (void)x; };
+ }
+}
+
+// Copy/dispose helper functions that capture objects of non-external types
+// should have internal linkage.
+
+// CHECK-LABEL: define internal void @__copy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
+// CHECK-LABEL: define internal void @__destroy_helper_block_8_32c22_ZTSN12_GLOBAL__N_11BE(
+
+namespace {
+ struct B {
+ int a;
+ B();
+ B(const B &);
+ ~B();
+ };
+
+ void test() {
+ B x;
+ ^{ (void)x; };
+ }
+}
+
+void callTest() {
+ test();
+}
Index: test/CodeGenCXX/block-byref-cxx-objc.cpp
===================================================================
--- test/CodeGenCXX/block-byref-cxx-objc.cpp
+++ test/CodeGenCXX/block-byref-cxx-objc.cpp
@@ -1,28 +1,54 @@
-// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - -fblocks | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -triple %itanium_abi_triple -o - -fblocks -fexceptions | FileCheck %s
// rdar://8594790
struct A {
int x;
A(const A &);
A();
- ~A();
+ ~A() noexcept(false);
};
-int main()
-{
- __block A BYREF_VAR;
- ^{ BYREF_VAR.x = 1234; };
+struct B {
+ int x;
+ B(const B &);
+ B();
+ ~B();
+};
+
+int testA() {
+ __block A a0, a1;
+ ^{ a0.x = 1234; a1.x = 5678; };
return 0;
}
// CHECK-LABEL: define internal void @__Block_byref_object_copy_
// CHECK: call {{.*}} @_ZN1AC1ERKS_
// CHECK-LABEL: define internal void @__Block_byref_object_dispose_
// CHECK: call {{.*}} @_ZN1AD1Ev
-// CHECK-LABEL: define internal void @__copy_helper_block_
-// CHECK: call {{.*}}void @_Block_object_assign
-// CHECK-LABEL: define internal void @__destroy_helper_block_
-// CHECK: call {{.*}}void @_Block_object_dispose
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32bdc40bdc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32bd40bd(
+// CHECK: invoke void @_Block_object_dispose(
+// CHECK: call void @_Block_object_dispose(
+// CHECK: invoke void @_Block_object_dispose(
+
+int testB() {
+ __block B b0, b1;
+ ^{ b0.x = 1234; b1.x = 5678; };
+ return 0;
+}
+
+// CHECK-LABEL: define internal void @__Block_byref_object_copy_
+// CHECK: call {{.*}} @_ZN1BC1ERKS_
+// CHECK-LABEL: define internal void @__Block_byref_object_dispose_
+// CHECK: call {{.*}} @_ZN1BD1Ev
+
+// CHECK: define linkonce_odr hidden void @__copy_helper_block_e8_32bc40bc(
+// CHECK: define linkonce_odr hidden void @__destroy_helper_block_e8_32b40b(
// rdar://problem/11135650
namespace test1 {
Index: test/CodeGen/sanitize-thread-no-checking-at-run-time.m
===================================================================
--- test/CodeGen/sanitize-thread-no-checking-at-run-time.m
+++ test/CodeGen/sanitize-thread-no-checking-at-run-time.m
@@ -35,7 +35,7 @@
void test2(id x) {
extern void test2_helper(id (^)(void));
test2_helper(^{ return x; });
-// TSAN: define internal void @__destroy_helper_block_(i8*) [[ATTR:#[0-9]+]]
+// TSAN: define linkonce_odr hidden void @__destroy_helper_block_8_32r(i8*) unnamed_addr [[ATTR:#[0-9]+]]
}
// TSAN: attributes [[ATTR]] = { noinline nounwind {{.*}} "sanitize_thread_no_checking_at_run_time" {{.*}} }
Index: test/CodeGen/blocks.c
===================================================================
--- test/CodeGen/blocks.c
+++ test/CodeGen/blocks.c
@@ -1,4 +1,9 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - -fblocks | FileCheck %s
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i32, i32 }
+
+// CHECK: @[[BLOCK_DESCRIPTOR_TMP21:.*]] = internal constant { i32, i32, void (i8*, i8*)*, void (i8*)*, i8*, i8* } { i32 0, i32 24, void (i8*, i8*)* @__copy_helper_block_4_20b, void (i8*)* @__destroy_helper_block_4_20b, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i8* null }, align 4
+
void (^f)(void) = ^{};
// rdar://6768379
@@ -27,6 +32,32 @@
^ { i = 1; }();
};
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_4_20b(i8*, i8*) unnamed_addr
+// CHECK: %[[_ADDR:.*]] = alloca i8*, align 4
+// CHECK-NEXT: %[[_ADDR1:.*]] = alloca i8*, align 4
+// CHECK-NEXT: store i8* %0, i8** %[[_ADDR]], align 4
+// CHECK-NEXT: store i8* %1, i8** %[[_ADDR1]], align 4
+// CHECK-NEXT: %[[V2:.*]] = load i8*, i8** %[[_ADDR1]], align 4
+// CHECK-NEXT: %[[BLOCK_SOURCE:.*]] = bitcast i8* %[[V2]] to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>*
+// CHECK-NEXT: %[[V3:.*]] = load i8*, i8** %[[_ADDR]], align 4
+// CHECK-NEXT: %[[BLOCK_DEST:.*]] = bitcast i8* %[[V3]] to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>*
+// CHECK-NEXT: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK_SOURCE]], i32 0, i32 5
+// CHECK-NEXT: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK_DEST]], i32 0, i32 5
+// CHECK-NEXT: %[[BLOCKCOPY_SRC:.*]] = load i8*, i8** %[[V4]], align 4
+// CHECK-NEXT: %[[V6:.*]] = bitcast i8** %[[V5]] to i8*
+// CHECK-NEXT: call void @_Block_object_assign(i8* %[[V6]], i8* %[[BLOCKCOPY_SRC]], i32 8)
+// CHECK-NEXT: ret void
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_4_20b(i8*) unnamed_addr
+// CHECK: %[[_ADDR:.*]] = alloca i8*, align 4
+// CHECK-NEXT: store i8* %0, i8** %[[_ADDR]], align 4
+// CHECK-NEXT: %[[V1:.*]] = load i8*, i8** %[[_ADDR]], align 4
+// CHECK-NEXT: %[[BLOCK:.*]] = bitcast i8* %[[V1]] to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>*
+// CHECK-NEXT: %[[V2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: %[[V3:.*]] = load i8*, i8** %[[V2]], align 4
+// CHECK-NEXT: call void @_Block_object_dispose(i8* %[[V3]], i32 8)
+// CHECK-NEXT: ret void
+
typedef double ftype(double);
// It's not clear that we *should* support this syntax, but until that decision
// is made, we should support it properly and not crash.
@@ -85,30 +116,8 @@
__block int i;
(^ { i = x; })();
}
-// CHECK-LABEL: testConstCaptureInCopyAndDestroyHelpers_block_invoke
-
-// CHECK: @__copy_helper_block
-// CHECK: alloca
-// CHECK-NEXT: alloca
-// CHECK-NEXT: store
-// CHECK-NEXT: store
-// CHECK-NEXT: load
-// CHECK-NEXT: bitcast
-// CHECK-NEXT: load
-// CHECK-NEXT: bitcast
-// CHECK-NEXT: getelementptr
-// CHECK-NEXT: getelementptr
-// CHECK-NEXT: load
-// CHECK-NEXT: bitcast
-// CHECK-NEXT: call void @_Block_object_assign
-// CHECK-NEXT: ret
-
-// CHECK: @__destroy_helper_block
-// CHECK: alloca
-// CHECK-NEXT: store
-// CHECK-NEXT: load
-// CHECK-NEXT: bitcast
-// CHECK-NEXT: getelementptr
-// CHECK-NEXT: load
-// CHECK-NEXT: call void @_Block_object_dispose
-// CHECK-NEXT: ret
+// CHECK-LABEL: define void @testConstCaptureInCopyAndDestroyHelpers(
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %{{.*}}, i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i32, i32, void (i8*, i8*)*, void (i8*)*, i8*, i8* }* @[[BLOCK_DESCRIPTOR_TMP21]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 4
+
+// CHECK-LABEL: define internal void @__testConstCaptureInCopyAndDestroyHelpers_block_invoke
Index: test/CodeGen/blocks-1.c
===================================================================
--- test/CodeGen/blocks-1.c
+++ test/CodeGen/blocks-1.c
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 %s -emit-llvm -o %t -fblocks
-// RUN: grep "_Block_object_dispose" %t | count 17
-// RUN: grep "__copy_helper_block_" %t | count 14
-// RUN: grep "__destroy_helper_block_" %t | count 14
+// RUN: grep "_Block_object_dispose" %t | count 12
+// RUN: grep "__copy_helper_block_" %t | count 9
+// RUN: grep "__destroy_helper_block_" %t | count 9
// RUN: grep "__Block_byref_object_copy_" %t | count 2
// RUN: grep "__Block_byref_object_dispose_" %t | count 2
// RUN: grep "i32 135)" %t | count 2
-// RUN: grep "_Block_object_assign" %t | count 10
+// RUN: grep "_Block_object_assign" %t | count 5
int printf(const char *, ...);
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1745,15 +1745,19 @@
bool IsLambdaConversionToBlock,
bool BuildGlobalBlock);
+ /// Check if \p T is of a C++ class type whose destructor can throw.
+ static bool cxxDestructorCanThrow(QualType CaptureTy);
+
llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
llvm::Constant *GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID);
llvm::Constant *GenerateObjCAtomicGetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID);
llvm::Value *EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty);
- void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags);
+ void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags,
+ bool CanThrow);
class AutoVarEmission;
@@ -1776,7 +1780,7 @@
/// \param LoadBlockVarAddr Indicates whether we need to emit a load from
/// \p Addr to get the address of the __block structure.
void enterByrefCleanup(CleanupKind Kind, Address Addr, BlockFieldFlags Flags,
- bool LoadBlockVarAddr);
+ bool LoadBlockVarAddr, bool CanThrow);
void setBlockContextParameter(const ImplicitParamDecl *D, unsigned argNum,
llvm::Value *ptr);
@@ -1799,6 +1803,11 @@
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
+
+ /// Annotate the function with an attribute that disables TSan checking at
+ /// runtime.
+ void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn);
+
/// Emit code for the start of a function.
/// \param Loc The location to be associated with the function.
/// \param StartLoc The location of the function body.
@@ -3602,6 +3611,19 @@
CXXDtorType Type,
const CXXRecordDecl *RD);
+ // Return the copy constructor name with the prefix "__copy_constructor_"
+ // removed.
+ static std::string getNonTrivialCopyConstructorStr(QualType QT,
+ CharUnits Alignment,
+ bool IsVolatile,
+ ASTContext &Ctx);
+
+ // Return the destructor name with the prefix "__destructor_" removed.
+ static std::string getNonTrivialDestructorStr(QualType QT,
+ CharUnits Alignment,
+ bool IsVolatile,
+ ASTContext &Ctx);
+
// These functions emit calls to the special functions of non-trivial C
// structs.
void defaultInitNonTrivialCStructVar(LValue Dst);
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -772,9 +772,11 @@
return false;
}
-static void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
- Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
- Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
+void CodeGenFunction::markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
+ if (SanOpts.has(SanitizerKind::Thread)) {
+ Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
+ Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
+ }
}
static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) {
@@ -887,10 +889,6 @@
(OMD->getSelector().isUnarySelector() && II->isStr(".cxx_destruct"))) {
markAsIgnoreThreadCheckingAtRuntime(Fn);
}
- } else if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- IdentifierInfo *II = FD->getIdentifier();
- if (II && II->isStr("__destroy_helper_block_"))
- markAsIgnoreThreadCheckingAtRuntime(Fn);
}
}
Index: lib/CodeGen/CGNonTrivialStruct.cpp
===================================================================
--- lib/CodeGen/CGNonTrivialStruct.cpp
+++ lib/CodeGen/CGNonTrivialStruct.cpp
@@ -283,8 +283,9 @@
struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>,
DestructedTypeVisitor<GenDestructorFuncName> {
using Super = DestructedTypeVisitor<GenDestructorFuncName>;
- GenDestructorFuncName(CharUnits DstAlignment, ASTContext &Ctx)
- : GenUnaryFuncName<GenDestructorFuncName>("__destructor_", DstAlignment,
+ GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment,
+ ASTContext &Ctx)
+ : GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment,
Ctx) {}
void visitWithKind(QualType::DestructionKind DK, QualType FT,
const FieldDecl *FD, CharUnits CurStructOffset) {
@@ -824,11 +825,28 @@
IsVolatile, *this, std::array<Address, 1>({{DstPtr}}));
}
+std::string
+CodeGenFunction::getNonTrivialCopyConstructorStr(QualType QT,
+ CharUnits Alignment,
+ bool IsVolatile,
+ ASTContext &Ctx) {
+ GenBinaryFuncName<false> GenName("", Alignment, Alignment, Ctx);
+ return GenName.getName(QT, IsVolatile);
+}
+
+std::string
+CodeGenFunction::getNonTrivialDestructorStr(QualType QT, CharUnits Alignment,
+ bool IsVolatile, ASTContext &Ctx) {
+ GenDestructorFuncName GenName("", Alignment, Ctx);
+ return GenName.getName(QT, IsVolatile);
+}
+
void CodeGenFunction::callCStructDestructor(LValue Dst) {
bool IsVolatile = Dst.isVolatile();
Address DstPtr = Dst.getAddress();
QualType QT = Dst.getType();
- GenDestructorFuncName GenName(DstPtr.getAlignment(), getContext());
+ GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(),
+ getContext());
std::string FuncName = GenName.getName(QT, IsVolatile);
callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile,
*this, std::array<Address, 1>({{DstPtr}}));
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -1717,7 +1717,8 @@
if (emission.Variable->getType().isObjCGCWeak())
Flags |= BLOCK_FIELD_IS_WEAK;
enterByrefCleanup(NormalAndEHCleanup, emission.Addr, Flags,
- /*LoadBlockVarAddr*/ false);
+ /*LoadBlockVarAddr*/ false,
+ cxxDestructorCanThrow(emission.Variable->getType()));
}
}
Index: lib/CodeGen/CGBlocks.h
===================================================================
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -231,6 +231,11 @@
/// and their layout meta-data has been generated.
bool HasCapturedVariableLayout : 1;
+ /// Indicates whether an object of a non-external C++ class is captured. This
+ /// bit is used to determine the linkage of the block copy/destroy helper
+ /// functions.
+ bool CapturesNonExternalType : 1;
+
/// The mapping of allocated indexes within the block.
llvm::DenseMap<const VarDecl*, Capture> Captures;
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CGBlocks.h"
+#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
@@ -25,6 +26,7 @@
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/ScopedPrinter.h"
#include <algorithm>
#include <cstdio>
@@ -34,8 +36,8 @@
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
- LocalAddress(Address::invalid()), StructureType(nullptr), Block(block),
- DominatingIP(nullptr) {
+ CapturesNonExternalType(false), LocalAddress(Address::invalid()),
+ StructureType(nullptr), Block(block), DominatingIP(nullptr) {
// Skip asm prefix, if any. 'name' is usually taken directly from
// the mangled name of the enclosing function.
@@ -464,6 +466,8 @@
} else if (CI.hasCopyExpr()) {
info.NeedsCopyDispose = true;
info.HasCXXObject = true;
+ if (!variable->getType()->getAsCXXRecordDecl()->isExternallyVisible())
+ info.CapturesNonExternalType = true;
// So do C structs that require non-trivial copy construction or
// destruction.
@@ -480,6 +484,8 @@
if (!record->hasTrivialDestructor()) {
info.HasCXXObject = true;
info.NeedsCopyDispose = true;
+ if (!record->isExternallyVisible())
+ info.CapturesNonExternalType = true;
}
}
}
@@ -1498,13 +1504,17 @@
struct BlockCaptureManagedEntity {
BlockCaptureEntityKind Kind;
BlockFieldFlags Flags;
- const BlockDecl::Capture &CI;
- const CGBlockInfo::Capture &Capture;
+ const BlockDecl::Capture *CI;
+ const CGBlockInfo::Capture *Capture;
BlockCaptureManagedEntity(BlockCaptureEntityKind Type, BlockFieldFlags Flags,
const BlockDecl::Capture &CI,
const CGBlockInfo::Capture &Capture)
- : Kind(Type), Flags(Flags), CI(CI), Capture(Capture) {}
+ : Kind(Type), Flags(Flags), CI(&CI), Capture(&Capture) {}
+
+ bool operator<(const BlockCaptureManagedEntity &Other) const {
+ return Capture->getOffset() < Other.Capture->getOffset();
+ }
};
} // end anonymous namespace
@@ -1583,17 +1593,22 @@
if (Info.first != BlockCaptureEntityKind::None)
ManagedCaptures.emplace_back(Info.first, Info.second, CI, Capture);
}
+
+ // Sort the captures by offset.
+ llvm::sort(ManagedCaptures.begin(), ManagedCaptures.end());
}
namespace {
/// Release a __block variable.
struct CallBlockRelease final : EHScopeStack::Cleanup {
Address Addr;
BlockFieldFlags FieldFlags;
- bool LoadBlockVarAddr;
+ bool LoadBlockVarAddr, CanThrow;
- CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue)
- : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue) {}
+ CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue,
+ bool CT)
+ : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue),
+ CanThrow(CT) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::Value *BlockVarAddr;
@@ -1604,11 +1619,112 @@
BlockVarAddr = Addr.getPointer();
}
- CGF.BuildBlockRelease(BlockVarAddr, FieldFlags);
+ CGF.BuildBlockRelease(BlockVarAddr, FieldFlags, CanThrow);
}
};
} // end anonymous namespace
+bool CodeGenFunction::cxxDestructorCanThrow(QualType T) {
+ if (const auto *RD = T->getAsCXXRecordDecl())
+ if (const CXXDestructorDecl *DD = RD->getDestructor())
+ if (const auto FPT = DD->getType()->getAs<FunctionProtoType>())
+ // Conservatively assume the destructor can throw if the exception
+ // specification is unresolved.
+ return isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) ||
+ FPT->canThrow();
+ return false;
+}
+
+/// Check if \p VD has a copy initialization expression that calls a
+/// constructor that can throw.
+static bool cxxConstructorCanThrow(const VarDecl *VD, ASTContext &Ctx) {
+ if (VD->getType()->getAsCXXRecordDecl())
+ if (Ctx.getBlockVarCopyInits(VD))
+ return true;
+ return false;
+}
+
+static std::string getCopyDestroyHelperFuncName(
+ const SmallVectorImpl<BlockCaptureManagedEntity> &Captures,
+ CharUnits BlockAlignment, bool IsCopyHelper, CodeGenModule &CGM) {
+ ASTContext &Ctx = CGM.getContext();
+ std::unique_ptr<ItaniumMangleContext> MC(
+ ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics()));
+
+ std::string Name =
+ IsCopyHelper ? "__copy_helper_block_" : "__destroy_helper_block_";
+ if (CGM.getLangOpts().Exceptions)
+ Name += "e";
+ if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
+ Name += "a";
+ Name += llvm::to_string(BlockAlignment.getQuantity()) + "_";
+
+ for (const BlockCaptureManagedEntity &E : Captures) {
+ const BlockDecl::Capture &CI = *E.CI;
+ BlockFieldFlags Flags = E.Flags;
+ QualType CaptureTy = CI.getVariable()->getType();
+ Name += llvm::to_string(E.Capture->getOffset().getQuantity());
+
+ switch (E.Kind) {
+ case BlockCaptureEntityKind::CXXRecord: {
+ Name += "c";
+ SmallString<256> Str;
+ llvm::raw_svector_ostream Out(Str);
+ MC->mangleTypeName(CaptureTy, Out);
+ Name += llvm::to_string(Str.size()) + Str.c_str();
+ break;
+ }
+ case BlockCaptureEntityKind::ARCWeak:
+ Name += "w";
+ break;
+ case BlockCaptureEntityKind::ARCStrong:
+ Name += "s";
+ break;
+ case BlockCaptureEntityKind::BlockObject: {
+ const VarDecl *Var = CI.getVariable();
+ unsigned F = Flags.getBitMask();
+ if (F & BLOCK_FIELD_IS_BYREF) {
+ Name += "b";
+ if (F & BLOCK_FIELD_IS_WEAK)
+ Name += "w";
+ else {
+ if (CodeGenFunction::cxxDestructorCanThrow(CaptureTy))
+ Name += "d";
+ if (IsCopyHelper && cxxConstructorCanThrow(Var, Ctx))
+ Name += "c";
+ }
+ } else {
+ assert(F & BLOCK_FIELD_IS_OBJECT);
+ Name += "r";
+ if (F == BLOCK_FIELD_IS_BLOCK)
+ Name += "b";
+ }
+ break;
+ }
+ case BlockCaptureEntityKind::NonTrivialCStruct: {
+ bool IsVolatile = CaptureTy.isVolatileQualified();
+ CharUnits Alignment =
+ BlockAlignment.alignmentAtOffset(E.Capture->getOffset());
+
+ Name += "n";
+ std::string Str;
+ if (IsCopyHelper)
+ Str = CodeGenFunction::getNonTrivialCopyConstructorStr(
+ CaptureTy, Alignment, IsVolatile, Ctx);
+ else
+ Str = CodeGenFunction::getNonTrivialDestructorStr(CaptureTy, Alignment,
+ IsVolatile, Ctx);
+ Name += llvm::to_string(Str.size()) + "_" + Str;
+ break;
+ }
+ case BlockCaptureEntityKind::None:
+ llvm_unreachable("unexpected block capture kind");
+ }
+ }
+
+ return Name;
+}
+
static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
Address Field, QualType CaptureType,
BlockFieldFlags Flags, bool EHOnly,
@@ -1634,15 +1750,30 @@
case BlockCaptureEntityKind::BlockObject: {
if (!EHOnly || CGF.getLangOpts().Exceptions) {
CleanupKind Kind = EHOnly ? EHCleanup : NormalAndEHCleanup;
- CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true);
+ bool CanThrow = CGF.cxxDestructorCanThrow(CaptureType);
+ CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true,
+ CanThrow);
}
break;
}
case BlockCaptureEntityKind::None:
llvm_unreachable("unexpected BlockCaptureEntityKind");
}
}
+static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType,
+ llvm::Function *Fn,
+ const CGFunctionInfo &FI,
+ CodeGenModule &CGM) {
+ if (CapturesNonExternalType) {
+ CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
+ } else {
+ Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ Fn->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+ CGM.SetLLVMFunctionAttributes(nullptr, FI, Fn);
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn);
+ }
+}
/// Generate the copy-helper function for a block closure object:
/// static void block_copy_helper(block_t *dst, block_t *src);
/// The runtime will have previously initialized 'dst' by doing a
@@ -1653,6 +1784,16 @@
/// the contents of an individual __block variable to the heap.
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
+ SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
+ computeCopyInfoForBlockCapture);
+ std::string FuncName =
+ getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign,
+ /*IsCopyHelper*/ true, CGM);
+
+ if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
+ return Func;
+
ASTContext &C = getContext();
FunctionArgList args;
@@ -1671,11 +1812,11 @@
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__copy_helper_block_", &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
+ FuncName, &CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__copy_helper_block_");
+ = &CGM.getContext().Idents.get(FuncName);
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
@@ -1685,8 +1826,8 @@
false,
false);
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
+ setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
+ CGM);
StartFunction(FD, C.VoidTy, Fn, FI, args);
ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1699,13 +1840,9 @@
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
- SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
- computeCopyInfoForBlockCapture);
-
for (const auto &CopiedCapture : CopiedCaptures) {
- const BlockDecl::Capture &CI = CopiedCapture.CI;
- const CGBlockInfo::Capture &capture = CopiedCapture.Capture;
+ const BlockDecl::Capture &CI = *CopiedCapture.CI;
+ const CGBlockInfo::Capture &capture = *CopiedCapture.Capture;
QualType captureType = CI.getVariable()->getType();
BlockFieldFlags flags = CopiedCapture.Flags;
@@ -1759,17 +1896,8 @@
dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
};
- const VarDecl *variable = CI.getVariable();
- bool copyCanThrow = false;
- if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) {
- const Expr *copyExpr =
- CGM.getContext().getBlockVarCopyInits(variable);
- if (copyExpr) {
- copyCanThrow = true; // FIXME: reuse the noexcept logic
- }
- }
-
- if (copyCanThrow) {
+ if (CI.isByRef() &&
+ cxxConstructorCanThrow(CI.getVariable(), CGM.getContext())) {
EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
} else {
EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
@@ -1844,6 +1972,16 @@
/// variable.
llvm::Constant *
CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
+ SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
+ computeDestroyInfoForBlockCapture);
+ std::string FuncName =
+ getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign,
+ /*IsCopyHelper*/ false, CGM);
+
+ if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
+ return Func;
+
ASTContext &C = getContext();
FunctionArgList args;
@@ -1859,21 +1997,23 @@
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__destroy_helper_block_", &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
+ FuncName, &CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__destroy_helper_block_");
+ = &CGM.getContext().Idents.get(FuncName);
FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(),
SourceLocation(),
SourceLocation(), II, C.VoidTy,
nullptr, SC_Static,
false, false);
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
+ setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
+ CGM);
StartFunction(FD, C.VoidTy, Fn, FI, args);
+ markAsIgnoreThreadCheckingAtRuntime(Fn);
+
ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1884,13 +2024,9 @@
CodeGenFunction::RunCleanupsScope cleanups(*this);
- SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
- computeDestroyInfoForBlockCapture);
-
for (const auto &DestroyedCapture : DestroyedCaptures) {
- const BlockDecl::Capture &CI = DestroyedCapture.CI;
- const CGBlockInfo::Capture &capture = DestroyedCapture.Capture;
+ const BlockDecl::Capture &CI = *DestroyedCapture.CI;
+ const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture;
BlockFieldFlags flags = DestroyedCapture.Flags;
Address srcField =
@@ -1937,7 +2073,7 @@
field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
llvm::Value *value = CGF.Builder.CreateLoad(field);
- CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
+ CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER, false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const override {
@@ -2567,19 +2703,25 @@
}
}
-void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
+void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags,
+ bool CanThrow) {
llvm::Value *F = CGM.getBlockObjectDispose();
llvm::Value *args[] = {
Builder.CreateBitCast(V, Int8PtrTy),
llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
};
- EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors?
+
+ if (CanThrow)
+ EmitRuntimeCallOrInvoke(F, args);
+ else
+ EmitNounwindRuntimeCall(F, args);
}
void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr,
BlockFieldFlags Flags,
- bool LoadBlockVarAddr) {
- EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr);
+ bool LoadBlockVarAddr, bool CanThrow) {
+ EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr,
+ CanThrow);
}
/// Adjust the declaration of something from the blocks API.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits