ahatanak updated this revision to Diff 159553.
ahatanak added a comment.

Remove a stale comment and add an assertion to check the destructor's exception 
specification has been resolved.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ComputeExceptionSpec.h
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExceptionSpec.cpp
  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,59 @@
-// 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 &) noexcept(true);
+	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_32b40b(
+// CHECK: call void @_Block_object_assign(
+// CHECK: call void @_Block_object_assign(
+
+// CHECK: define linkonce_odr hidden void @__destroy_helper_block_e8_32b40b(
+// CHECK: call void @_Block_object_dispose(
+// CHECK: call void @_Block_object_dispose(
 
 // 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/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ComputeExceptionSpec.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
@@ -185,10 +186,26 @@
   return FnT->hasExceptionSpec();
 }
 
+namespace {
+class ComputeExceptionSpec
+    : public ComputeExceptionSpecBase<ComputeExceptionSpec> {
+public:
+  ComputeExceptionSpec(ASTContext &C, const LangOptions &LO, Sema &S)
+      : ComputeExceptionSpecBase<ComputeExceptionSpec>(C, LO), S(S) {}
+
+  const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
+                                                const FunctionProtoType *FPT);
+
+private:
+  Sema &S;
+};
+} // namespace
+
 const FunctionProtoType *
-Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
+ComputeExceptionSpec::ResolveExceptionSpec(SourceLocation Loc,
+                                           const FunctionProtoType *FPT) {
   if (FPT->getExceptionSpecType() == EST_Unparsed) {
-    Diag(Loc, diag::err_exception_spec_not_parsed);
+    S.Diag(Loc, diag::err_exception_spec_not_parsed);
     return nullptr;
   }
 
@@ -205,19 +222,25 @@
 
   // Compute or instantiate the exception specification now.
   if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
-    EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
+    S.EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
   else
-    InstantiateExceptionSpec(Loc, SourceDecl);
+    S.InstantiateExceptionSpec(Loc, SourceDecl);
 
   const FunctionProtoType *Proto =
-    SourceDecl->getType()->castAs<FunctionProtoType>();
+      SourceDecl->getType()->castAs<FunctionProtoType>();
   if (Proto->getExceptionSpecType() == clang::EST_Unparsed) {
-    Diag(Loc, diag::err_exception_spec_not_parsed);
+    S.Diag(Loc, diag::err_exception_spec_not_parsed);
     Proto = nullptr;
   }
   return Proto;
 }
 
+const FunctionProtoType *
+Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
+  return ComputeExceptionSpec(Context, getLangOpts(), *this)
+      .ResolveExceptionSpec(Loc, FPT);
+}
+
 void
 Sema::UpdateExceptionSpec(FunctionDecl *FD,
                           const FunctionProtoType::ExceptionSpecInfo &ESI) {
@@ -936,361 +959,8 @@
                                   New->getLocation());
 }
 
-static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) {
-  CanThrowResult R = CT_Cannot;
-  for (const Stmt *SubStmt : E->children()) {
-    R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt)));
-    if (R == CT_Can)
-      break;
-  }
-  return R;
-}
-
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
-  // As an extension, we assume that __attribute__((nothrow)) functions don't
-  // throw.
-  if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
-    return CT_Cannot;
-
-  QualType T;
-
-  // In C++1z, just look at the function type of the callee.
-  if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) {
-    E = cast<CallExpr>(E)->getCallee();
-    T = E->getType();
-    if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
-      // Sadly we don't preserve the actual type as part of the "bound member"
-      // placeholder, so we need to reconstruct it.
-      E = E->IgnoreParenImpCasts();
-
-      // Could be a call to a pointer-to-member or a plain member access.
-      if (auto *Op = dyn_cast<BinaryOperator>(E)) {
-        assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI);
-        T = Op->getRHS()->getType()
-              ->castAs<MemberPointerType>()->getPointeeType();
-      } else {
-        T = cast<MemberExpr>(E)->getMemberDecl()->getType();
-      }
-    }
-  } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D))
-    T = VD->getType();
-  else
-    // If we have no clue what we're calling, assume the worst.
-    return CT_Can;
-
-  const FunctionProtoType *FT;
-  if ((FT = T->getAs<FunctionProtoType>())) {
-  } else if (const PointerType *PT = T->getAs<PointerType>())
-    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
-  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
-    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
-  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
-    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
-  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
-    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
-
-  if (!FT)
-    return CT_Can;
-
-  FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
-  if (!FT)
-    return CT_Can;
-
-  return FT->canThrow();
-}
-
-static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
-  if (DC->isTypeDependent())
-    return CT_Dependent;
-
-  if (!DC->getTypeAsWritten()->isReferenceType())
-    return CT_Cannot;
-
-  if (DC->getSubExpr()->isTypeDependent())
-    return CT_Dependent;
-
-  return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
-}
-
-static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
-  if (DC->isTypeOperand())
-    return CT_Cannot;
-
-  Expr *Op = DC->getExprOperand();
-  if (Op->isTypeDependent())
-    return CT_Dependent;
-
-  const RecordType *RT = Op->getType()->getAs<RecordType>();
-  if (!RT)
-    return CT_Cannot;
-
-  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
-    return CT_Cannot;
-
-  if (Op->Classify(S.Context).isPRValue())
-    return CT_Cannot;
-
-  return CT_Can;
-}
-
 CanThrowResult Sema::canThrow(const Expr *E) {
-  // C++ [expr.unary.noexcept]p3:
-  //   [Can throw] if in a potentially-evaluated context the expression would
-  //   contain:
-  switch (E->getStmtClass()) {
-  case Expr::CXXThrowExprClass:
-    //   - a potentially evaluated throw-expression
-    return CT_Can;
-
-  case Expr::CXXDynamicCastExprClass: {
-    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
-    //     where T is a reference type, that requires a run-time check
-    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
-    if (CT == CT_Can)
-      return CT;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-  case Expr::CXXTypeidExprClass:
-    //   - a potentially evaluated typeid expression applied to a glvalue
-    //     expression whose type is a polymorphic class type
-    return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
-
-    //   - a potentially evaluated call to a function, member function, function
-    //     pointer, or member function pointer that does not have a non-throwing
-    //     exception-specification
-  case Expr::CallExprClass:
-  case Expr::CXXMemberCallExprClass:
-  case Expr::CXXOperatorCallExprClass:
-  case Expr::UserDefinedLiteralClass: {
-    const CallExpr *CE = cast<CallExpr>(E);
-    CanThrowResult CT;
-    if (E->isTypeDependent())
-      CT = CT_Dependent;
-    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
-      CT = CT_Cannot;
-    else
-      CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
-    if (CT == CT_Can)
-      return CT;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-  case Expr::CXXConstructExprClass:
-  case Expr::CXXTemporaryObjectExprClass: {
-    CanThrowResult CT = canCalleeThrow(*this, E,
-        cast<CXXConstructExpr>(E)->getConstructor());
-    if (CT == CT_Can)
-      return CT;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-  case Expr::CXXInheritedCtorInitExprClass:
-    return canCalleeThrow(*this, E,
-                          cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
-
-  case Expr::LambdaExprClass: {
-    const LambdaExpr *Lambda = cast<LambdaExpr>(E);
-    CanThrowResult CT = CT_Cannot;
-    for (LambdaExpr::const_capture_init_iterator
-             Cap = Lambda->capture_init_begin(),
-             CapEnd = Lambda->capture_init_end();
-         Cap != CapEnd; ++Cap)
-      CT = mergeCanThrow(CT, canThrow(*Cap));
-    return CT;
-  }
-
-  case Expr::CXXNewExprClass: {
-    CanThrowResult CT;
-    if (E->isTypeDependent())
-      CT = CT_Dependent;
-    else
-      CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
-    if (CT == CT_Can)
-      return CT;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-  case Expr::CXXDeleteExprClass: {
-    CanThrowResult CT;
-    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
-    if (DTy.isNull() || DTy->isDependentType()) {
-      CT = CT_Dependent;
-    } else {
-      CT = canCalleeThrow(*this, E,
-                          cast<CXXDeleteExpr>(E)->getOperatorDelete());
-      if (const RecordType *RT = DTy->getAs<RecordType>()) {
-        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-        const CXXDestructorDecl *DD = RD->getDestructor();
-        if (DD)
-          CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
-      }
-      if (CT == CT_Can)
-        return CT;
-    }
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-  case Expr::CXXBindTemporaryExprClass: {
-    // The bound temporary has to be destroyed again, which might throw.
-    CanThrowResult CT = canCalleeThrow(*this, E,
-      cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
-    if (CT == CT_Can)
-      return CT;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-    // ObjC message sends are like function calls, but never have exception
-    // specs.
-  case Expr::ObjCMessageExprClass:
-  case Expr::ObjCPropertyRefExprClass:
-  case Expr::ObjCSubscriptRefExprClass:
-    return CT_Can;
-
-    // All the ObjC literals that are implemented as calls are
-    // potentially throwing unless we decide to close off that
-    // possibility.
-  case Expr::ObjCArrayLiteralClass:
-  case Expr::ObjCDictionaryLiteralClass:
-  case Expr::ObjCBoxedExprClass:
-    return CT_Can;
-
-    // Many other things have subexpressions, so we have to test those.
-    // Some are simple:
-  case Expr::CoawaitExprClass:
-  case Expr::ConditionalOperatorClass:
-  case Expr::CompoundLiteralExprClass:
-  case Expr::CoyieldExprClass:
-  case Expr::CXXConstCastExprClass:
-  case Expr::CXXReinterpretCastExprClass:
-  case Expr::CXXStdInitializerListExprClass:
-  case Expr::DesignatedInitExprClass:
-  case Expr::DesignatedInitUpdateExprClass:
-  case Expr::ExprWithCleanupsClass:
-  case Expr::ExtVectorElementExprClass:
-  case Expr::InitListExprClass:
-  case Expr::ArrayInitLoopExprClass:
-  case Expr::MemberExprClass:
-  case Expr::ObjCIsaExprClass:
-  case Expr::ObjCIvarRefExprClass:
-  case Expr::ParenExprClass:
-  case Expr::ParenListExprClass:
-  case Expr::ShuffleVectorExprClass:
-  case Expr::ConvertVectorExprClass:
-  case Expr::VAArgExprClass:
-    return canSubExprsThrow(*this, E);
-
-    // Some might be dependent for other reasons.
-  case Expr::ArraySubscriptExprClass:
-  case Expr::OMPArraySectionExprClass:
-  case Expr::BinaryOperatorClass:
-  case Expr::DependentCoawaitExprClass:
-  case Expr::CompoundAssignOperatorClass:
-  case Expr::CStyleCastExprClass:
-  case Expr::CXXStaticCastExprClass:
-  case Expr::CXXFunctionalCastExprClass:
-  case Expr::ImplicitCastExprClass:
-  case Expr::MaterializeTemporaryExprClass:
-  case Expr::UnaryOperatorClass: {
-    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
-    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
-  }
-
-    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
-  case Expr::StmtExprClass:
-    return CT_Can;
-
-  case Expr::CXXDefaultArgExprClass:
-    return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
-
-  case Expr::CXXDefaultInitExprClass:
-    return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
-
-  case Expr::ChooseExprClass:
-    if (E->isTypeDependent() || E->isValueDependent())
-      return CT_Dependent;
-    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
-
-  case Expr::GenericSelectionExprClass:
-    if (cast<GenericSelectionExpr>(E)->isResultDependent())
-      return CT_Dependent;
-    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
-
-    // Some expressions are always dependent.
-  case Expr::CXXDependentScopeMemberExprClass:
-  case Expr::CXXUnresolvedConstructExprClass:
-  case Expr::DependentScopeDeclRefExprClass:
-  case Expr::CXXFoldExprClass:
-    return CT_Dependent;
-
-  case Expr::AsTypeExprClass:
-  case Expr::BinaryConditionalOperatorClass:
-  case Expr::BlockExprClass:
-  case Expr::CUDAKernelCallExprClass:
-  case Expr::DeclRefExprClass:
-  case Expr::ObjCBridgedCastExprClass:
-  case Expr::ObjCIndirectCopyRestoreExprClass:
-  case Expr::ObjCProtocolExprClass:
-  case Expr::ObjCSelectorExprClass:
-  case Expr::ObjCAvailabilityCheckExprClass:
-  case Expr::OffsetOfExprClass:
-  case Expr::PackExpansionExprClass:
-  case Expr::PseudoObjectExprClass:
-  case Expr::SubstNonTypeTemplateParmExprClass:
-  case Expr::SubstNonTypeTemplateParmPackExprClass:
-  case Expr::FunctionParmPackExprClass:
-  case Expr::UnaryExprOrTypeTraitExprClass:
-  case Expr::UnresolvedLookupExprClass:
-  case Expr::UnresolvedMemberExprClass:
-  case Expr::TypoExprClass:
-    // FIXME: Can any of the above throw?  If so, when?
-    return CT_Cannot;
-
-  case Expr::AddrLabelExprClass:
-  case Expr::ArrayTypeTraitExprClass:
-  case Expr::AtomicExprClass:
-  case Expr::TypeTraitExprClass:
-  case Expr::CXXBoolLiteralExprClass:
-  case Expr::CXXNoexceptExprClass:
-  case Expr::CXXNullPtrLiteralExprClass:
-  case Expr::CXXPseudoDestructorExprClass:
-  case Expr::CXXScalarValueInitExprClass:
-  case Expr::CXXThisExprClass:
-  case Expr::CXXUuidofExprClass:
-  case Expr::CharacterLiteralClass:
-  case Expr::ExpressionTraitExprClass:
-  case Expr::FloatingLiteralClass:
-  case Expr::GNUNullExprClass:
-  case Expr::ImaginaryLiteralClass:
-  case Expr::ImplicitValueInitExprClass:
-  case Expr::IntegerLiteralClass:
-  case Expr::FixedPointLiteralClass:
-  case Expr::ArrayInitIndexExprClass:
-  case Expr::NoInitExprClass:
-  case Expr::ObjCEncodeExprClass:
-  case Expr::ObjCStringLiteralClass:
-  case Expr::ObjCBoolLiteralExprClass:
-  case Expr::OpaqueValueExprClass:
-  case Expr::PredefinedExprClass:
-  case Expr::SizeOfPackExprClass:
-  case Expr::StringLiteralClass:
-    // These expressions can never throw.
-    return CT_Cannot;
-
-  case Expr::MSPropertyRefExprClass:
-  case Expr::MSPropertySubscriptExprClass:
-    llvm_unreachable("Invalid class for expression");
-
-#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
-#define STMT_RANGE(Base, First, Last)
-#define LAST_STMT_RANGE(BASE, FIRST, LAST)
-#define EXPR(CLASS, PARENT)
-#define ABSTRACT_STMT(STMT)
-#include "clang/AST/StmtNodes.inc"
-  case Expr::NoStmtClass:
-    llvm_unreachable("Invalid class for expression");
-  }
-  llvm_unreachable("Bogus StmtClass");
+  return ComputeExceptionSpec(Context, getLangOpts(), *this).canThrow(E);
 }
 
 } // end namespace clang
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11761,6 +11761,13 @@
         Expr *init = result.getAs<Expr>();
         Context.setBlockVarCopyInits(var, init);
       }
+      // The destructor's exception spefication is needed when IRGen generates
+      // block copy/destroy functions. Resolve it here.
+      if (const CXXRecordDecl *RD = type->getAsCXXRecordDecl())
+        if (CXXDestructorDecl *DD = RD->getDestructor()) {
+          auto *FPT = DD->getType()->getAs<FunctionProtoType>();
+          ResolveExceptionSpec(poi, FPT);
+        }
     }
   }
 
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,19 +12,22 @@
 //===----------------------------------------------------------------------===//
 
 #include "CGBlocks.h"
+#include "CGCXXABI.h"
 #include "CGDebugInfo.h"
 #include "CGObjCRuntime.h"
 #include "CGOpenCLRuntime.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "ConstantEmitter.h"
 #include "TargetInfo.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/ComputeExceptionSpec.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
 #include "llvm/ADT/SmallSet.h"
 #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 +37,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 +467,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 +485,8 @@
         if (!record->hasTrivialDestructor()) {
           info.HasCXXObject = true;
           info.NeedsCopyDispose = true;
+          if (!record->isExternallyVisible())
+            info.CapturesNonExternalType = true;
         }
       }
     }
@@ -1498,13 +1505,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 +1594,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 +1620,126 @@
       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()) {
+      const auto FPT = DD->getType()->getAs<FunctionProtoType>();
+      assert(!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
+             "exception specification is unresolved");
+      return FPT->canThrow();
+    }
+  return false;
+}
+
+namespace {
+class ComputeExceptionSpec
+    : public ComputeExceptionSpecBase<ComputeExceptionSpec> {
+public:
+  ComputeExceptionSpec(ASTContext &C, const LangOptions &LO)
+      : ComputeExceptionSpecBase<ComputeExceptionSpec>(C, LO) {}
+};
+} // namespace
+
+/// Check if \p VD has a copy initialization expression that calls a
+/// constructor that can throw.
+static bool cxxConstructorCanThrow(const VarDecl *VD, ASTContext &Ctx,
+                                   const LangOptions &LangOpts) {
+  if (VD->getType()->getAsCXXRecordDecl())
+    if (const Expr *CopyExpr = Ctx.getBlockVarCopyInits(VD)) {
+      if (const auto *EC = dyn_cast<ExprWithCleanups>(CopyExpr))
+        CopyExpr = EC->getSubExpr();
+      return ComputeExceptionSpec(Ctx, LangOpts).canThrow(CopyExpr);
+    }
+  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, CGM.getLangOpts()))
+            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 +1765,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 +1799,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 +1827,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 +1841,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 +1855,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 +1911,9 @@
           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(),
+                                   getLangOpts())) {
           EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
         } else {
           EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
@@ -1844,6 +1988,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 +2013,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 +2040,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 +2089,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 +2719,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.
Index: include/clang/AST/ComputeExceptionSpec.h
===================================================================
--- /dev/null
+++ include/clang/AST/ComputeExceptionSpec.h
@@ -0,0 +1,431 @@
+//===- ComputeExceptionSpec.h - Compute exception spec ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Base class for computing exception specification.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_COMPUTE_EXCEPTION_SPEC_H
+#define LLVM_CLANG_AST_COMPUTE_EXCEPTION_SPEC_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+template <class Derived> class ComputeExceptionSpecBase {
+public:
+  ComputeExceptionSpecBase(ASTContext &C, const LangOptions &LO)
+      : Ctx(C), LangOpts(LO) {}
+  CanThrowResult canThrow(const Expr *E);
+  const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
+                                                const FunctionProtoType *FPT);
+
+private:
+  CanThrowResult canSubExprsThrow(const Expr *E);
+  CanThrowResult canCalleeThrow(const Expr *E, const Decl *D);
+  CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC);
+  CanThrowResult canTypeidThrow(const CXXTypeidExpr *DC);
+  Derived &getDerived() { return static_cast<Derived &>(*this); }
+
+  ASTContext &Ctx;
+  const LangOptions &LangOpts;
+};
+
+template <class Derived>
+CanThrowResult
+ComputeExceptionSpecBase<Derived>::canSubExprsThrow(const Expr *E) {
+  CanThrowResult R = CT_Cannot;
+  for (const Stmt *SubStmt : E->children()) {
+    R = mergeCanThrow(R, canThrow(cast<Expr>(SubStmt)));
+    if (R == CT_Can)
+      break;
+  }
+  return R;
+}
+
+/// The base version does nothing and just returns the prototype that is passed.
+/// An assertion fails if the exception specification hasn't been resolved.
+template <class Derived>
+const FunctionProtoType *
+ComputeExceptionSpecBase<Derived>::ResolveExceptionSpec(
+    SourceLocation Loc, const FunctionProtoType *FPT) {
+  assert(!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
+         "exception specification is unresolved");
+  return FPT;
+}
+
+template <class Derived>
+CanThrowResult
+ComputeExceptionSpecBase<Derived>::canCalleeThrow(const Expr *E,
+                                                  const Decl *D) {
+  // As an extension, we assume that __attribute__((nothrow)) functions don't
+  // throw.
+  if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
+    return CT_Cannot;
+
+  QualType T;
+
+  // In C++1z, just look at the function type of the callee.
+  if (LangOpts.CPlusPlus17 && isa<CallExpr>(E)) {
+    E = cast<CallExpr>(E)->getCallee();
+    T = E->getType();
+    if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
+      // Sadly we don't preserve the actual type as part of the "bound member"
+      // placeholder, so we need to reconstruct it.
+      E = E->IgnoreParenImpCasts();
+
+      // Could be a call to a pointer-to-member or a plain member access.
+      if (auto *Op = dyn_cast<BinaryOperator>(E)) {
+        assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI);
+        T = Op->getRHS()
+                ->getType()
+                ->castAs<MemberPointerType>()
+                ->getPointeeType();
+      } else {
+        T = cast<MemberExpr>(E)->getMemberDecl()->getType();
+      }
+    }
+  } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D))
+    T = VD->getType();
+  else
+    // If we have no clue what we're calling, assume the worst.
+    return CT_Can;
+
+  const FunctionProtoType *FT;
+  if ((FT = T->getAs<FunctionProtoType>())) {
+  } else if (const PointerType *PT = T->getAs<PointerType>())
+    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
+  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
+  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
+    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
+  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
+    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
+
+  if (!FT)
+    return CT_Can;
+
+  FT = getDerived().ResolveExceptionSpec(E->getLocStart(), FT);
+  if (!FT)
+    return CT_Can;
+
+  return FT->canThrow();
+}
+
+template <class Derived>
+CanThrowResult ComputeExceptionSpecBase<Derived>::canDynamicCastThrow(
+    const CXXDynamicCastExpr *DC) {
+  if (DC->isTypeDependent())
+    return CT_Dependent;
+
+  if (!DC->getTypeAsWritten()->isReferenceType())
+    return CT_Cannot;
+
+  if (DC->getSubExpr()->isTypeDependent())
+    return CT_Dependent;
+
+  return DC->getCastKind() == clang::CK_Dynamic ? CT_Can : CT_Cannot;
+}
+
+template <class Derived>
+CanThrowResult
+ComputeExceptionSpecBase<Derived>::canTypeidThrow(const CXXTypeidExpr *DC) {
+  if (DC->isTypeOperand())
+    return CT_Cannot;
+
+  Expr *Op = DC->getExprOperand();
+  if (Op->isTypeDependent())
+    return CT_Dependent;
+
+  const RecordType *RT = Op->getType()->getAs<RecordType>();
+  if (!RT)
+    return CT_Cannot;
+
+  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
+    return CT_Cannot;
+
+  if (Op->Classify(Ctx).isPRValue())
+    return CT_Cannot;
+
+  return CT_Can;
+}
+
+template <class Derived>
+CanThrowResult ComputeExceptionSpecBase<Derived>::canThrow(const Expr *E) {
+  // C++ [expr.unary.noexcept]p3:
+  //   [Can throw] if in a potentially-evaluated context the expression would
+  //   contain:
+  switch (E->getStmtClass()) {
+  case Expr::CXXThrowExprClass:
+    //   - a potentially evaluated throw-expression
+    return CT_Can;
+
+  case Expr::CXXDynamicCastExprClass: {
+    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
+    //     where T is a reference type, that requires a run-time check
+    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
+    if (CT == CT_Can)
+      return CT;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+  case Expr::CXXTypeidExprClass:
+    //   - a potentially evaluated typeid expression applied to a glvalue
+    //     expression whose type is a polymorphic class type
+    return canTypeidThrow(cast<CXXTypeidExpr>(E));
+
+    //   - a potentially evaluated call to a function, member function, function
+    //     pointer, or member function pointer that does not have a non-throwing
+    //     exception-specification
+  case Expr::CallExprClass:
+  case Expr::CXXMemberCallExprClass:
+  case Expr::CXXOperatorCallExprClass:
+  case Expr::UserDefinedLiteralClass: {
+    const CallExpr *CE = cast<CallExpr>(E);
+    CanThrowResult CT;
+    if (E->isTypeDependent())
+      CT = CT_Dependent;
+    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
+      CT = CT_Cannot;
+    else
+      CT = canCalleeThrow(E, CE->getCalleeDecl());
+    if (CT == CT_Can)
+      return CT;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+  case Expr::CXXConstructExprClass:
+  case Expr::CXXTemporaryObjectExprClass: {
+    CanThrowResult CT =
+        canCalleeThrow(E, cast<CXXConstructExpr>(E)->getConstructor());
+    if (CT == CT_Can)
+      return CT;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+  case Expr::CXXInheritedCtorInitExprClass:
+    return canCalleeThrow(E,
+                          cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
+
+  case Expr::LambdaExprClass: {
+    const LambdaExpr *Lambda = cast<LambdaExpr>(E);
+    CanThrowResult CT = CT_Cannot;
+    for (LambdaExpr::const_capture_init_iterator
+             Cap = Lambda->capture_init_begin(),
+             CapEnd = Lambda->capture_init_end();
+         Cap != CapEnd; ++Cap)
+      CT = mergeCanThrow(CT, canThrow(*Cap));
+    return CT;
+  }
+
+  case Expr::CXXNewExprClass: {
+    CanThrowResult CT;
+    if (E->isTypeDependent())
+      CT = CT_Dependent;
+    else
+      CT = canCalleeThrow(E, cast<CXXNewExpr>(E)->getOperatorNew());
+    if (CT == CT_Can)
+      return CT;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+  case Expr::CXXDeleteExprClass: {
+    CanThrowResult CT;
+    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
+    if (DTy.isNull() || DTy->isDependentType()) {
+      CT = CT_Dependent;
+    } else {
+      CT = canCalleeThrow(E, cast<CXXDeleteExpr>(E)->getOperatorDelete());
+      if (const RecordType *RT = DTy->getAs<RecordType>()) {
+        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+        const CXXDestructorDecl *DD = RD->getDestructor();
+        if (DD)
+          CT = mergeCanThrow(CT, canCalleeThrow(E, DD));
+      }
+      if (CT == CT_Can)
+        return CT;
+    }
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+  case Expr::CXXBindTemporaryExprClass: {
+    // The bound temporary has to be destroyed again, which might throw.
+    CanThrowResult CT = canCalleeThrow(
+        E, cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
+    if (CT == CT_Can)
+      return CT;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+    // ObjC message sends are like function calls, but never have exception
+    // specs.
+  case Expr::ObjCMessageExprClass:
+  case Expr::ObjCPropertyRefExprClass:
+  case Expr::ObjCSubscriptRefExprClass:
+    return CT_Can;
+
+    // All the ObjC literals that are implemented as calls are
+    // potentially throwing unless we decide to close off that
+    // possibility.
+  case Expr::ObjCArrayLiteralClass:
+  case Expr::ObjCDictionaryLiteralClass:
+  case Expr::ObjCBoxedExprClass:
+    return CT_Can;
+
+    // Many other things have subexpressions, so we have to test those.
+    // Some are simple:
+  case Expr::CoawaitExprClass:
+  case Expr::ConditionalOperatorClass:
+  case Expr::CompoundLiteralExprClass:
+  case Expr::CoyieldExprClass:
+  case Expr::CXXConstCastExprClass:
+  case Expr::CXXReinterpretCastExprClass:
+  case Expr::CXXStdInitializerListExprClass:
+  case Expr::DesignatedInitExprClass:
+  case Expr::DesignatedInitUpdateExprClass:
+  case Expr::ExprWithCleanupsClass:
+  case Expr::ExtVectorElementExprClass:
+  case Expr::InitListExprClass:
+  case Expr::ArrayInitLoopExprClass:
+  case Expr::MemberExprClass:
+  case Expr::ObjCIsaExprClass:
+  case Expr::ObjCIvarRefExprClass:
+  case Expr::ParenExprClass:
+  case Expr::ParenListExprClass:
+  case Expr::ShuffleVectorExprClass:
+  case Expr::ConvertVectorExprClass:
+  case Expr::VAArgExprClass:
+    return canSubExprsThrow(E);
+
+    // Some might be dependent for other reasons.
+  case Expr::ArraySubscriptExprClass:
+  case Expr::OMPArraySectionExprClass:
+  case Expr::BinaryOperatorClass:
+  case Expr::DependentCoawaitExprClass:
+  case Expr::CompoundAssignOperatorClass:
+  case Expr::CStyleCastExprClass:
+  case Expr::CXXStaticCastExprClass:
+  case Expr::CXXFunctionalCastExprClass:
+  case Expr::ImplicitCastExprClass:
+  case Expr::MaterializeTemporaryExprClass:
+  case Expr::UnaryOperatorClass: {
+    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
+    return mergeCanThrow(CT, canSubExprsThrow(E));
+  }
+
+    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
+  case Expr::StmtExprClass:
+    return CT_Can;
+
+  case Expr::CXXDefaultArgExprClass:
+    return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
+
+  case Expr::CXXDefaultInitExprClass:
+    return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
+
+  case Expr::ChooseExprClass:
+    if (E->isTypeDependent() || E->isValueDependent())
+      return CT_Dependent;
+    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
+
+  case Expr::GenericSelectionExprClass:
+    if (cast<GenericSelectionExpr>(E)->isResultDependent())
+      return CT_Dependent;
+    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
+
+    // Some expressions are always dependent.
+  case Expr::CXXDependentScopeMemberExprClass:
+  case Expr::CXXUnresolvedConstructExprClass:
+  case Expr::DependentScopeDeclRefExprClass:
+  case Expr::CXXFoldExprClass:
+    return CT_Dependent;
+
+  case Expr::AsTypeExprClass:
+  case Expr::BinaryConditionalOperatorClass:
+  case Expr::BlockExprClass:
+  case Expr::CUDAKernelCallExprClass:
+  case Expr::DeclRefExprClass:
+  case Expr::ObjCBridgedCastExprClass:
+  case Expr::ObjCIndirectCopyRestoreExprClass:
+  case Expr::ObjCProtocolExprClass:
+  case Expr::ObjCSelectorExprClass:
+  case Expr::ObjCAvailabilityCheckExprClass:
+  case Expr::OffsetOfExprClass:
+  case Expr::PackExpansionExprClass:
+  case Expr::PseudoObjectExprClass:
+  case Expr::SubstNonTypeTemplateParmExprClass:
+  case Expr::SubstNonTypeTemplateParmPackExprClass:
+  case Expr::FunctionParmPackExprClass:
+  case Expr::UnaryExprOrTypeTraitExprClass:
+  case Expr::UnresolvedLookupExprClass:
+  case Expr::UnresolvedMemberExprClass:
+  case Expr::TypoExprClass:
+    // FIXME: Can any of the above throw?  If so, when?
+    return CT_Cannot;
+
+  case Expr::AddrLabelExprClass:
+  case Expr::ArrayTypeTraitExprClass:
+  case Expr::AtomicExprClass:
+  case Expr::TypeTraitExprClass:
+  case Expr::CXXBoolLiteralExprClass:
+  case Expr::CXXNoexceptExprClass:
+  case Expr::CXXNullPtrLiteralExprClass:
+  case Expr::CXXPseudoDestructorExprClass:
+  case Expr::CXXScalarValueInitExprClass:
+  case Expr::CXXThisExprClass:
+  case Expr::CXXUuidofExprClass:
+  case Expr::CharacterLiteralClass:
+  case Expr::ExpressionTraitExprClass:
+  case Expr::FloatingLiteralClass:
+  case Expr::GNUNullExprClass:
+  case Expr::ImaginaryLiteralClass:
+  case Expr::ImplicitValueInitExprClass:
+  case Expr::IntegerLiteralClass:
+  case Expr::FixedPointLiteralClass:
+  case Expr::ArrayInitIndexExprClass:
+  case Expr::NoInitExprClass:
+  case Expr::ObjCEncodeExprClass:
+  case Expr::ObjCStringLiteralClass:
+  case Expr::ObjCBoolLiteralExprClass:
+  case Expr::OpaqueValueExprClass:
+  case Expr::PredefinedExprClass:
+  case Expr::SizeOfPackExprClass:
+  case Expr::StringLiteralClass:
+    // These expressions can never throw.
+    return CT_Cannot;
+
+  case Expr::MSPropertyRefExprClass:
+  case Expr::MSPropertySubscriptExprClass:
+    llvm_unreachable("Invalid class for expression");
+
+#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
+#define STMT_RANGE(Base, First, Last)
+#define LAST_STMT_RANGE(BASE, FIRST, LAST)
+#define EXPR(CLASS, PARENT)
+#define ABSTRACT_STMT(STMT)
+#include "clang/AST/StmtNodes.inc"
+  case Expr::NoStmtClass:
+    llvm_unreachable("Invalid class for expression");
+  }
+  llvm_unreachable("Bogus StmtClass");
+}
+
+} // namespace clang
+
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to