[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1643
+if (Ctx.getBlockVarCopyInits(VD))
+  return true;
+  return false;

rjmccall wrote:
> Can you just ask Sema to check `canThrow` for the expression and pass it down?
Since this changes the existing behavior, I made changes to 
test/CodeGenCXX/block-byref-cxx-objc.cpp to test it. Previously, IRGen would 
emit an invoke to call `_Block_object_assign` when the constructor was marked 
as noexcept.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159388.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @"__copy_helper_block_
 // CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_"
 // CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_"
 // CHECK: call void @_ZN8CopyableC1ERKS_
Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,8 +1,10 @@
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s
+// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
 // CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
@@ -55,34 +57,34 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
-// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
-// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
+// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
 
-// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 6
-// CHECK: %[[V5:.*]] = getelementptr 

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1643
+if (Ctx.getBlockVarCopyInits(VD))
+  return true;
+  return false;

ahatanak wrote:
> rjmccall wrote:
> > Can you just ask Sema to check `canThrow` for the expression and pass it 
> > down?
> Since this changes the existing behavior, I made changes to 
> test/CodeGenCXX/block-byref-cxx-objc.cpp to test it. Previously, IRGen would 
> emit an invoke to call `_Block_object_assign` when the constructor was marked 
> as noexcept.
Perhaps I misunderstood your comment, should I have Sema set a flag or 
something in Expr when it calls a function that can throw?


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-07 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159546.
ahatanak marked an inline comment as done.
ahatanak added a reviewer: rsmith.
ahatanak added a comment.
Herald added a subscriber: jfb.

Address review comments.


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, i

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-07 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1643
+if (Ctx.getBlockVarCopyInits(VD))
+  return true;
+  return false;

rjmccall wrote:
> ahatanak wrote:
> > ahatanak wrote:
> > > rjmccall wrote:
> > > > Can you just ask Sema to check `canThrow` for the expression and pass 
> > > > it down?
> > > Since this changes the existing behavior, I made changes to 
> > > test/CodeGenCXX/block-byref-cxx-objc.cpp to test it. Previously, IRGen 
> > > would emit an invoke to call `_Block_object_assign` when the constructor 
> > > was marked as noexcept.
> > Perhaps I misunderstood your comment, should I have Sema set a flag or 
> > something in Expr when it calls a function that can throw?
> Sema has a `canThrow` predicate that it uses when checking things like the 
> `noexcept` expression.  I was thinking that you could pass that down with the 
> copy expression in the AST for the block capture.
> 
> Constructors can have default-argument expressions that can throw even if the 
> constructor itself can't, so it's important to do it that way.
I moved the code in lib/Sema/SemaExceptionSpec.cpp that  is needed to compute 
the exception specification to a template class in include/AST so that both 
Sema and IRGen can use it. Also, I added a call to ResolveExceptionSpec in 
Sema::CheckCompleteVariableDeclaration to resolve the destructor's exception 
specification and removed the isUnresolvedExceptionSpec check in 
CodeGenFunction::cxxDestructorCanThrow. Richard pointed out that the 
constructor's and destructor's exception specifications should have been 
resolved by the time IRGen is run.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-07 Thread Akira Hatanaka via Phabricator via cfe-commits
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_D

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-07 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

I thought it was okay to skip the work done by `ResolveExceptionSpec` in IRGen 
as long as the exception specifications that are needed have already been 
resolved in Sema. But calling Sema::canThrow in 
Sema::CheckCompleteVariableDeclaration and storing the result in 
BlockDecl::Capture is clearly the better solution since it doesn't introduce 
the complexity introduced in the updated patch.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-07 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Since BlockVarCopyInits is a map with key `VarDecl *`, I think we want to add a 
flag to VarDecl (NonParmVarDeclBits) that indicates whether the copy expression 
can throw or not. Or is there a reason to store the bit in `BlockDecl::Capture` 
instead?


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-08 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159762.
ahatanak added a comment.

Change the value type of BlockVarCopyInits to PointerIntPair. 
The boolean flag indicates whether the copy expression can throw. 
Serialize/deserialize the copy expression and the boolean flag and add a 
regression test to test/PCH.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32bc40bc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32b40b(
+void test() {
+  S s;
+  s.m();
+}
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 }
 //

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-08 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159800.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Modify getBlockVarCopyInits and setBlockVarCopyInits to get and set both the 
copy expression and the boolean flag that indicates whether the expression can 
throw or not.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32bc40bc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32b40b(
+void test() {
+  S s;
+  s.m();
+}
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_

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-08 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: include/clang/AST/ASTContext.h:158
+Expr *CopyExpr;
+bool CanThrow;
+  };

rjmccall wrote:
> Using a PointerIntPair in the implementation of this is still a reasonable 
> choice.  Just make it a proper abstraction, with a constructor with the two 
> arguments and getters for the two fields.
I also needed a function that sets the pointer and flag.



Comment at: lib/CodeGen/CGBlocks.cpp:1682
+  if (IsCopyHelper && Ctx.getBlockVarCopyInits(Var).CanThrow)
+Name += "c";
+}

rjmccall wrote:
> I don't think you need to add `d` to the name of a copy helper.  It's a bit 
> weird, but while copying a `__block` variable can cause its copy helper to 
> run, destroying it immediately afterwards can never cause its destroy helper 
> to run.  That's because a newly-copied `__block` variable always has a 
> reference count of 2: the new reference in the copy and the forwarding 
> reference from the original.
> 
> I think that means you can just add a single letter which specifies whether 
> the corresponding `__block` variable operation is known to be able to throw.
I added 'd' to the name of the copy helper functions only because IRGen 
generates different code depending on whether the destructor can throw or not.

For example, if I compile the following code with -DTHROWS, IRGen uses 'invoke' 
(which jumps to the terminate block) for the calls to `_Block_object_dispose` 
on the EH path whereas it uses 'call' if the destructor doesn't throw.

```
struct S {
  S();
#ifdef THROWS
  ~S() noexcept(false);
#else
  ~S() noexcept(true);
#endif
  S(const S &);
  int a;
};

void test() {
  __block S s0, s1, s2;
  ^{ (void)s0, (void)s1; (void)s2; };
}
```

It seems like IRGen doesn't have to use 'invoke' when emitting a call to  
`_Block_object_dispose` even when the class has a destructor that can throw, if 
I understood your explanation correctly?



Comment at: lib/CodeGen/CGBlocks.cpp:1688
+if (F == BLOCK_FIELD_IS_BLOCK)
+  Name += "b";
+  }

rjmccall wrote:
> Why `rb` for a captured block instead of some single-letter thing?  You don't 
> need to emulate the structure of the flags here.
I can use a single letter here, but I'm already using 'b' for byref captures. 
Perhaps I can use 'o' for non-arc objects, instead of 'r', and use 'r' for 
byref?



Comment at: lib/CodeGen/CGBlocks.cpp:1705
+  IsVolatile, Ctx);
+  Name += llvm::to_string(Str.size()) + "_" + Str;
+  break;

rjmccall wrote:
> The underscore is necessary here because non-trivial destructor strings can 
> start with a number?  Worth a comment.
Yes, that's correct.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-08 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159850.
ahatanak marked 5 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32bc40bc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32b40b(
+void test() {
+  S s;
+  s.m();
+}
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 @@
 
 // 

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159926.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32rc40rc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32r40r(
+void test() {
+  S s;
+  s.m();
+}
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 @@
 
 // 

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1682
+  if (IsCopyHelper && Ctx.getBlockVarCopyInits(Var).CanThrow)
+Name += "c";
+}

rjmccall wrote:
> ahatanak wrote:
> > rjmccall wrote:
> > > I don't think you need to add `d` to the name of a copy helper.  It's a 
> > > bit weird, but while copying a `__block` variable can cause its copy 
> > > helper to run, destroying it immediately afterwards can never cause its 
> > > destroy helper to run.  That's because a newly-copied `__block` variable 
> > > always has a reference count of 2: the new reference in the copy and the 
> > > forwarding reference from the original.
> > > 
> > > I think that means you can just add a single letter which specifies 
> > > whether the corresponding `__block` variable operation is known to be 
> > > able to throw.
> > I added 'd' to the name of the copy helper functions only because IRGen 
> > generates different code depending on whether the destructor can throw or 
> > not.
> > 
> > For example, if I compile the following code with -DTHROWS, IRGen uses 
> > 'invoke' (which jumps to the terminate block) for the calls to 
> > `_Block_object_dispose` on the EH path whereas it uses 'call' if the 
> > destructor doesn't throw.
> > 
> > ```
> > struct S {
> >   S();
> > #ifdef THROWS
> >   ~S() noexcept(false);
> > #else
> >   ~S() noexcept(true);
> > #endif
> >   S(const S &);
> >   int a;
> > };
> > 
> > void test() {
> >   __block S s0, s1, s2;
> >   ^{ (void)s0, (void)s1; (void)s2; };
> > }
> > ```
> > 
> > It seems like IRGen doesn't have to use 'invoke' when emitting a call to  
> > `_Block_object_dispose` even when the class has a destructor that can 
> > throw, if I understood your explanation correctly?
> Right.  It's specifically only true when unwinding after a copy, which is 
> very atypical for C++ code, but nonetheless it's true.  We should make the 
> call `nounwind` in these situations and leave a comment explaining why.  Did 
> my explanation make any sense?
Yes, it makes sense. Since the reference count is two after the `__block` 
variable is copied, calling `_Block_object_dispose` on it won't cause the 
destructor to be called.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 160040.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Define functions inline in the header file.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32rc40rc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32r40r(
+void test() {
+  S s;
+  s.m();
+}
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,

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1725
BlockFieldFlags Flags, bool EHOnly,
+   bool DisposeCannotThrow, VarDecl *Var,
CodeGenFunction &CGF) {

rjmccall wrote:
> Could you replace these two flags with something more semantic, like telling 
> this function what the context of pushing the cleanup is — basically meaning, 
> are we in the copy helper or the destroy helper?  That will let you pull the 
> comment explaining `DisposeCannotThrow` into this function, where it makes a 
> lot more sense.
I thought about passing a single flag instead of passing two flags too. If we 
are going to pass a single flag, should we still use two variables inside the 
function, EHOnly and DisposeCannotThrow, to maintain the readability of the 
code?


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 160046.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Call MarkFunctionReferenced to mark the function `__builtin_operator_new` or 
`__builtin_operator_delete` will call as referenced.


Repository:
  rC Clang

https://reviews.llvm.org/D47757

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  test/CXX/drs/dr2xx.cpp
  test/SemaCUDA/call-host-fn-from-device.cu
  test/SemaCXX/unavailable_aligned_allocation.cpp

Index: test/SemaCXX/unavailable_aligned_allocation.cpp
===
--- test/SemaCXX/unavailable_aligned_allocation.cpp
+++ test/SemaCXX/unavailable_aligned_allocation.cpp
@@ -124,7 +124,73 @@
 // expected-note@-20 2 {{if you supply your own aligned allocation functions}}
 #endif
 
-// No errors if user-defined aligned allocation functions are available.
+// Test that diagnostics are produced when an unavailable aligned deallocation
+// function is called from a deleting destructor.
+struct alignas(256) OveralignedS2 {
+  int a[4];
+  virtual ~OveralignedS2();
+};
+
+OveralignedS2::~OveralignedS2() {}
+
+#ifdef NO_ERRORS
+// expected-no-diagnostics
+#else
+#if defined(IOS)
+// expected-error@-6 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on iOS 11 or newer}}}
+// expected-note@-7 {{if you supply your own aligned allocation functions}}
+#elif defined(TVOS)
+// expected-error@-9 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on tvOS 11 or newer}}}
+// expected-note@-10 {{if you supply your own aligned allocation functions}}
+#elif defined(WATCHOS)
+// expected-error@-12 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on watchOS 4 or newer}}}
+// expected-note@-13 {{if you supply your own aligned allocation functions}}
+#else
+// expected-error@-15 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on macOS 10.13 or newer}}}
+// expected-note@-16 {{if you supply your own aligned allocation functions}}
+#endif
+#endif
+
+void testExplicitOperatorNewDelete() {
+  void *p = operator new(128);
+  operator delete(p);
+  p = operator new[](128);
+  operator delete[](p);
+  p = __builtin_operator_new(128);
+  __builtin_operator_delete(p);
+}
+
+void testExplicitOperatorNewDeleteOveraligned() {
+  void *p = operator new(128, (std::align_val_t)64);
+  operator delete(p, (std::align_val_t)64);
+  p = operator new[](128, (std::align_val_t)64);
+  operator delete[](p, (std::align_val_t)64);
+  p = __builtin_operator_new(128, (std::align_val_t)64);
+  __builtin_operator_delete(p, (std::align_val_t)64);
+}
+
+#ifdef NO_ERRORS
+// expected-no-diagnostics
+#else
+// expected-error@-11 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-12 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-13 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-14 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-15 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-16 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-17 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-18 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-19 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-20 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-21 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-22 {{if you supply your own aligned allocation functions}}
+#endif
+
 void *operator new(std::size_t __sz, std::align_val_t) {
   static char array[256];
   return &array;
Index: test/SemaCUDA/call-host-fn-from-device.cu
===
--- test/SemaCUDA/call-host-fn-from-device.cu
+++ test/SemaCUDA/call-host-fn-from-device.cu
@@ -85,7 +85,7 @@
 }
 
 __host__ __device__ void class_specific_delete(T *t, U *u) {
-  delete t; // ok, call sized device delete even though host has preferable non-sized version
+  delete t; // expected-error {{reference to __host__ function 'operator delete' in __host__ __device__ function}}
   delete u; // ok, call non-sized HD delete rather than sized D delete
 }
 
Index: test/CXX/drs/dr2xx.cpp
===
--- test/CXX/drs/dr2xx.c

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 160053.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Replace the two flags, EHOnly and DisposeCannotThrow, passed to 
pushCaptureCleanup with a single flag ForCopyHelper.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- /dev/null
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- /dev/null
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32rc40rc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32r40r(
+void test() {
+  S s;
+  s.m();
+}
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:

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-10 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339438: [CodeGen] Merge equivalent block copy/helper 
functions. (authored by ahatanak, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50152?vs=160053&id=160110#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  include/clang/AST/ASTContext.h
  lib/AST/ASTContext.cpp
  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/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.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
  test/PCH/block-helpers.cpp
  test/PCH/block-helpers.h

Index: test/PCH/block-helpers.h
===
--- test/PCH/block-helpers.h
+++ test/PCH/block-helpers.h
@@ -0,0 +1,12 @@
+struct S0 {
+  S0();
+  S0(const S0 &) noexcept(false);
+  int a;
+};
+
+struct S {
+  void m() {
+__block S0 x, y;
+^{ (void)x; (void)y; };
+  }
+};
Index: test/PCH/block-helpers.cpp
===
--- test/PCH/block-helpers.cpp
+++ test/PCH/block-helpers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
+
+// The second call to block_object_assign should be an invoke.
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32rc40rc(
+// CHECK: call void @_Block_object_assign(
+// CHECK: invoke void @_Block_object_assign(
+// CHECK: call void @_Block_object_dispose(
+
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_e8_32r40r(
+void test() {
+  S s;
+  s.m();
+}
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_32o(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_20r, void (i8*)* @__destroy_helper_block_4_20r, 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_20r(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: %[[V

[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-15 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rjmccall, arphaman.
Herald added a subscriber: dexonsmith.

Currently, clang generates a new block descriptor global variable for each 
block literal. This patch merges block descriptors that are identical inside 
and across translation units using the same approach taken in r339438.

To enable merging identical block descriptors, the information of each member 
of a block descriptor is encoded into the block descriptor name. Also, the 
linkage of the block descriptor is `linkonce_odr` unless the copy or dispose 
helper is internal.


Repository:
  rC Clang

https://reviews.llvm.org/D50783

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGObjCGNU.cpp
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  test/CodeGenCXX/blocks.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/fragile-arc.m
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -17,7 +17,7 @@
 // helper functions.
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = linkonce_odr hidden constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
 
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
Index: test/CodeGenObjC/fragile-arc.m
===
--- test/CodeGenObjC/fragile-arc.m
+++ test/CodeGenObjC/fragile-arc.m
@@ -126,13 +126,13 @@
 extern void useBlock(void (^block)(void));
 
 //  256 == 0x100 == starts with 1 strong
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 256 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 256 }
 void testBlockLayoutStrong(id x) {
   useBlock(^{ (void) x; });
 }
 
 //  1   == 0x001 == starts with 1 weak
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 1 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 1 }
 void testBlockLayoutWeak(__weak id x) {
   useBlock(^{ (void) x; });
 }
Index: test/CodeGenObjC/arc-blocks.m
===
--- test/CodeGenObjC/arc-blocks.m
+++ test/CodeGenObjC/arc-blocks.m
@@ -2,15 +2,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s
 
 // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_

[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-15 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

A few points I forgot to mention:

- This optimization kicks in only in NonGC mode. I don't think we need to care 
much about GC anymore, so I think that's OK.

- There is a lot of redundancy among the copy/dispose helper function strings 
and the block layout string in the block descriptor name (they all encode the 
information about the captures), which can make the descriptor name long. If 
that becomes a problem, it's possible to encode the information in a way that 
shortens the descriptor name, but that would probably make the function that 
generates the name more complex.


Repository:
  rC Clang

https://reviews.llvm.org/D50783



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-16 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 161137.
ahatanak added a comment.

Try harder to shorten the names of block descriptor global variables.

The strings extracted from the names of the copy and dispose helpers are merged 
whenever it is possible to do so. The block layout string doesn't include 
information about `__strong`, `__weak`, or byref captures unless the 
copy/dispose helpers are missing.


Repository:
  rC Clang

https://reviews.llvm.org/D50783

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  test/CodeGenCXX/blocks.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
  test/CodeGenObjC/fragile-arc.m
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -17,7 +17,11 @@
 // helper functions.
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
+// When the block is non-escaping, copy/dispose helpers aren't generated, so the
+// block layout string must include information about __strong captures.
+
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*ls32l8"]] = linkonce_odr hidden constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
 
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
Index: test/CodeGenObjC/fragile-arc.m
===
--- test/CodeGenObjC/fragile-arc.m
+++ test/CodeGenObjC/fragile-arc.m
@@ -126,13 +126,13 @@
 extern void useBlock(void (^block)(void));
 
 //  256 == 0x100 == starts with 1 strong
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 256 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 256 }
 void testBlockLayoutStrong(id x) {
   useBlock(^{ (void) x; });
 }
 
 //  1   == 0x001 == starts with 1 weak
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 1 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 1 }
 void testBlockLayoutWeak(__weak id x) {
   useBlock(^{ (void) x; });
 }
Index: test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
===
--- test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
+++ test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
@@ -30,7 +30,8 @@
   void (^block4)() = ^{ printf("%c %#lx", ch, fourByte); NSLog(@"%@", strong); };
 
   // Test5
-  // CHECK: Inline block variable layout: 0x0100, BL_STRONG:1, BL_OPERATOR:0
+  // Nothing gets printed here since the descriptor of this block is merged with
+  // the descriptor of Test3's block.
   void (^block5)() = ^{ NSLog(@"%@", strong); printf("%c %#llx", ch, eightByte); };
 
   // Test6
Index: test/CodeGenObjC/arc-blocks.m
===
--- test/CodeGenObjC/arc-blocks.m
+++ test/CodeGenObjC/arc-blocks.m
@@ -2,15 +2,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s
 
 // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitca

[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-16 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:271-276
   llvm::GlobalVariable *global =
-elements.finishAndCreateGlobal("__block_descriptor_tmp",
-   CGM.getPointerAlign(),
-   /*constant*/ true,
-   llvm::GlobalValue::InternalLinkage,
-   AddrSpace);
+  elements.finishAndCreateGlobal(descName, CGM.getPointerAlign(),
+ /*constant*/ true, linkage, AddrSpace);
+
+  if (linkage == llvm::GlobalValue::LinkOnceODRLinkage)
+global->setVisibility(llvm::GlobalValue::HiddenVisibility);

rsmith wrote:
> Would it make sense to also mark this constant as `unnamed_addr`?
Yes. I don't think there is any harm in marking it as `unnamed_addr`. However, 
unfortunately it looks like ld64 doesn't try to merge `unnamed_addr` global 
variables.


Repository:
  rC Clang

https://reviews.llvm.org/D50783



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-16 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 161155.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Mark the block descriptor global variable as `unnamed_addr`.


Repository:
  rC Clang

https://reviews.llvm.org/D50783

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  test/CodeGenCXX/blocks.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
  test/CodeGenObjC/fragile-arc.m
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -17,7 +17,11 @@
 // helper functions.
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
+// When the block is non-escaping, copy/dispose helpers aren't generated, so the
+// block layout string must include information about __strong captures.
+
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*ls32l8"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
 
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
Index: test/CodeGenObjC/fragile-arc.m
===
--- test/CodeGenObjC/fragile-arc.m
+++ test/CodeGenObjC/fragile-arc.m
@@ -126,13 +126,13 @@
 extern void useBlock(void (^block)(void));
 
 //  256 == 0x100 == starts with 1 strong
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 256 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 256 }
 void testBlockLayoutStrong(id x) {
   useBlock(^{ (void) x; });
 }
 
 //  1   == 0x001 == starts with 1 weak
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 1 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 1 }
 void testBlockLayoutWeak(__weak id x) {
   useBlock(^{ (void) x; });
 }
Index: test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
===
--- test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
+++ test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
@@ -30,7 +30,8 @@
   void (^block4)() = ^{ printf("%c %#lx", ch, fourByte); NSLog(@"%@", strong); };
 
   // Test5
-  // CHECK: Inline block variable layout: 0x0100, BL_STRONG:1, BL_OPERATOR:0
+  // Nothing gets printed here since the descriptor of this block is merged with
+  // the descriptor of Test3's block.
   void (^block5)() = ^{ NSLog(@"%@", strong); printf("%c %#llx", ch, eightByte); };
 
   // Test6
Index: test/CodeGenObjC/arc-blocks.m
===
--- test/CodeGenObjC/arc-blocks.m
+++ test/CodeGenObjC/arc-blocks.m
@@ -2,15 +2,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s
 
 // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-/

[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-17 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL340041: [CodeGen] Merge identical block descriptor global 
variables. (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D50783?vs=161155&id=161269#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D50783

Files:
  cfe/trunk/lib/CodeGen/CGBlocks.cpp
  cfe/trunk/lib/CodeGen/CGBlocks.h
  cfe/trunk/lib/CodeGen/CGObjCMac.cpp
  cfe/trunk/lib/CodeGen/CGObjCRuntime.h
  cfe/trunk/test/CodeGenCXX/blocks.cpp
  cfe/trunk/test/CodeGenObjC/arc-blocks.m
  cfe/trunk/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
  cfe/trunk/test/CodeGenObjC/fragile-arc.m
  cfe/trunk/test/CodeGenObjC/noescape.m

Index: cfe/trunk/test/CodeGenObjC/noescape.m
===
--- cfe/trunk/test/CodeGenObjC/noescape.m
+++ cfe/trunk/test/CodeGenObjC/noescape.m
@@ -17,7 +17,11 @@
 // helper functions.
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
+// When the block is non-escaping, copy/dispose helpers aren't generated, so the
+// block layout string must include information about __strong captures.
+
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*ls32l8"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
 
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
Index: cfe/trunk/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
===
--- cfe/trunk/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
+++ cfe/trunk/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
@@ -30,7 +30,8 @@
   void (^block4)() = ^{ printf("%c %#lx", ch, fourByte); NSLog(@"%@", strong); };
 
   // Test5
-  // CHECK: Inline block variable layout: 0x0100, BL_STRONG:1, BL_OPERATOR:0
+  // Nothing gets printed here since the descriptor of this block is merged with
+  // the descriptor of Test3's block.
   void (^block5)() = ^{ NSLog(@"%@", strong); printf("%c %#llx", ch, eightByte); };
 
   // Test6
Index: cfe/trunk/test/CodeGenObjC/fragile-arc.m
===
--- cfe/trunk/test/CodeGenObjC/fragile-arc.m
+++ cfe/trunk/test/CodeGenObjC/fragile-arc.m
@@ -126,13 +126,13 @@
 extern void useBlock(void (^block)(void));
 
 //  256 == 0x100 == starts with 1 strong
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 256 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 256 }
 void testBlockLayoutStrong(id x) {
   useBlock(^{ (void) x; });
 }
 
 //  1   == 0x001 == starts with 1 weak
-// GLOBALS: @__block_descriptor_tmp{{.*}} = internal constant {{.*}}, i32 1 }
+// GLOBALS: @"__block_descriptor{{.*}} = linkonce_odr hidden {{.*}}, i32 1 }
 void testBlockLayoutWeak(__weak id x) {
   useBlock(^{ (void) x; });
 }
Index: cfe/trunk/test/CodeGenObjC/arc-blocks.m
===
--- cfe/trunk/test/CodeGenObjC/arc-blocks.m
+++ cfe/trunk/test/CodeGenObjC/arc-blocks.m
@@ -2,15 +2,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s
 
 // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
-// CHECK-COMMON: @{{.*}} = internal constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*

[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-17 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC340041: [CodeGen] Merge identical block descriptor global 
variables. (authored by ahatanak, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D50783

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  test/CodeGenCXX/blocks.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
  test/CodeGenObjC/fragile-arc.m
  test/CodeGenObjC/noescape.m

Index: lib/CodeGen/CGObjCRuntime.h
===
--- lib/CodeGen/CGObjCRuntime.h
+++ lib/CodeGen/CGObjCRuntime.h
@@ -278,6 +278,10 @@
   const CodeGen::CGBlockInfo &blockInfo) = 0;
   virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
   const CodeGen::CGBlockInfo &blockInfo) = 0;
+  virtual std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
+  const CGBlockInfo &blockInfo) {
+return {};
+  }
 
   /// Returns an i8* which points to the byref layout information.
   virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
Index: lib/CodeGen/CGObjCMac.cpp
===
--- lib/CodeGen/CGObjCMac.cpp
+++ lib/CodeGen/CGObjCMac.cpp
@@ -37,6 +37,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
 
@@ -1085,9 +1086,14 @@
  const CGBlockInfo &blockInfo) override;
   llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
  const CGBlockInfo &blockInfo) override;
+  std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
+  const CGBlockInfo &blockInfo) override;
 
   llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
QualType T) override;
+
+private:
+  void fillRunSkipBlockVars(CodeGenModule &CGM, const CGBlockInfo &blockInfo);
 };
 
 namespace {
@@ -2795,8 +2801,44 @@
   return getConstantGEP(VMContext, Entry, 0, 0);
 }
 
-llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
-const CGBlockInfo &blockInfo) {
+static std::string getBlockLayoutInfoString(
+const SmallVectorImpl &RunSkipBlockVars,
+bool HasCopyDisposeHelpers) {
+  std::string Str;
+  for (const CGObjCCommonMac::RUN_SKIP &R : RunSkipBlockVars) {
+if (R.opcode == CGObjCCommonMac::BLOCK_LAYOUT_UNRETAINED) {
+  // Copy/dispose helpers don't have any information about
+  // __unsafe_unretained captures, so unconditionally concatenate a string.
+  Str += "u";
+} else if (HasCopyDisposeHelpers) {
+  // Information about __strong, __weak, or byref captures has already been
+  // encoded into the names of the copy/dispose helpers. We have to add a
+  // string here only when the copy/dispose helpers aren't generated (which
+  // happens when the block is non-escaping).
+  continue;
+} else {
+  switch (R.opcode) {
+  case CGObjCCommonMac::BLOCK_LAYOUT_STRONG:
+Str += "s";
+break;
+  case CGObjCCommonMac::BLOCK_LAYOUT_BYREF:
+Str += "r";
+break;
+  case CGObjCCommonMac::BLOCK_LAYOUT_WEAK:
+Str += "w";
+break;
+  default:
+continue;
+  }
+}
+Str += llvm::to_string(R.block_var_bytepos.getQuantity());
+Str += "l" + llvm::to_string(R.block_var_size.getQuantity());
+  }
+  return Str;
+}
+
+void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
+   const CGBlockInfo &blockInfo) {
   assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
 
   RunSkipBlockVars.clear();
@@ -2845,9 +2887,22 @@
 UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
fieldOffset, fieldSize);
   }
+}
+
+llvm::Constant *
+CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
+const CGBlockInfo &blockInfo) {
+  fillRunSkipBlockVars(CGM, blockInfo);
   return getBitmapBlockLayout(false);
 }
 
+std::string CGObjCCommonMac::getRCBlockLayoutStr(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+  fillRunSkipBlockVars(CGM, blockInfo);
+  return getBlockLayoutInfoString(RunSkipBlockVars,
+  blockInfo.needsCopyDisposeHelpers());
+}
+
 llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
   QualType T) {
   assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
Index: lib/CodeGen/CGBlock

[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

@tra and @rsmith: Can we move forward and fix the incorrect cuda diagnostics in 
a separate patch?


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

In https://reviews.llvm.org/D47757#1204561, @tra wrote:

> It's a regression. There's a decent chance it breaks someone and this patch, 
> if committed by itself, will end up being rolled back.


Is the regression you are referring to about the static function case? I don't 
see a difference between ToT clang and my patch in the diagnostics they produce 
when I compile the following code:

  __host__ void f();
  static __host__ __device__ void g() { f(); }
  __host__ __device__ void g2() { g(); } 

Both error out when `-fcuda-is-device` is provided. If I comment out the 
definition of g2, it compiles fine.


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

The code you showed does compile with or without `-fcuda-is-device` after 
applying my patch.


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51025: [CodeGen] Fix handling of variables captured by a block that is nested inside a lambda

2018-08-20 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added a reviewer: rjmccall.
Herald added a subscriber: dexonsmith.

Currently IRGen doesn't handle variables captured by a block correctly when the 
variable is captured by reference by a lambda that encloses the block.

For example, in the following code, the type of capture 'x' in the block 
literal is a reference to 'id' because 'x' is captured by reference by the 
enclosing lambda. In this case, copy/dispose functions shouldn't be needed, but 
currently IRGen emits them.

  void test() {
id x;
[&]{ ^{ (void)x; }(); }();
  }

This happens because there are a few places in CGBlocks.cpp that use the 
variable's type ('id' in the example above) instead of the capture type ('id &' 
in the example above).


Repository:
  rC Clang

https://reviews.llvm.org/D51025

Files:
  lib/CodeGen/CGBlocks.cpp
  test/CodeGenObjCXX/block-nested-in-lambda.cpp
  test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- /dev/null
+++ test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+
+// CHECK: %[[BLOCK_CAPTURED0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK:.*]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[LAMBDA_CLASS:.*]], %[[LAMBDA_CLASS]]* %[[THIS:.*]], i32 0, i32 0
+// CHECK: %[[V1:.*]] = load i32*, i32** %[[V0]], align 8
+// CHECK: store i32* %[[V1]], i32** %[[BLOCK_CAPTURED0]], align 8
+// CHECK: %[[BLOCK_CAPTURED1:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK]], i32 0, i32 6
+// CHECK: %[[V2:.*]] = getelementptr inbounds %[[LAMBDA_CLASS]], %[[LAMBDA_CLASS]]* %[[THIS]], i32 0, i32 1
+// CHECK: %[[V3:.*]] = load i32*, i32** %[[V2]], align 8
+// CHECK: store i32* %[[V3]], i32** %[[BLOCK_CAPTURED1]], align 8
+
+void foo1(int &, int &);
+
+void block_in_lambda(int &s1, int &s2) {
+  auto lambda = [&s1, &s2]() {
+auto block = ^{
+  foo1(s1, s2);
+};
+block();
+  };
+
+  lambda();
+}
+
+namespace CaptureByReference {
+
+id getObj();
+void use(id);
+
+// Block copy/dispose helpers aren't needed because 'a' is captured by
+// reference.
+
+// CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// 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, i8*, i64 }* @"__block_descriptor_40_e5_v8@?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+
+void test0() {
+  id a = getObj();
+  [&]{ ^{ a = 0; }(); }();
+}
+
+// Block copy/dispose helpers shouldn't have to retain/release 'a' because it
+// is captured by reference.
+
+// CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @"__block_descriptor_56_8_32s40s_e5_v8@?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
+// CHECK-NOT: call void @objc_storeStrong(
+// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5
+// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5
+// CHECK: %[[BLOCKCOPY_SRC:.*]] = load i8*, i8** %[[V4]], align 8
+// CHECK: store i8* null, i8** %[[V5]], align 8
+// CHECK: call void @objc_storeStrong(i8** %[[V5]], i8* %[[BLOCKCOPY_SRC]])
+// CHECK: %[[V6:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 6
+// CHECK: %[[V7:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[

[PATCH] D51043: [clang][NFC] Fix typo in the name of a note

2018-08-21 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak accepted this revision.
ahatanak added a comment.
This revision is now accepted and ready to land.

Thanks. Yes, it's a typo.


Repository:
  rCXX libc++

https://reviews.llvm.org/D51043



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51025: [CodeGen] Fix handling of variables captured by a block that is nested inside a lambda

2018-08-22 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL340408: [CodeGen] Look at the type of a block capture field 
rather than the type (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D51025?vs=161648&id=161941#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D51025

Files:
  cfe/trunk/lib/CodeGen/CGBlocks.cpp
  cfe/trunk/test/CodeGenObjCXX/block-nested-in-lambda.cpp
  cfe/trunk/test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: cfe/trunk/test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- cfe/trunk/test/CodeGenObjCXX/block-nested-in-lambda.mm
+++ cfe/trunk/test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+
+// CHECK: %[[BLOCK_CAPTURED0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK:.*]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[LAMBDA_CLASS:.*]], %[[LAMBDA_CLASS]]* %[[THIS:.*]], i32 0, i32 0
+// CHECK: %[[V1:.*]] = load i32*, i32** %[[V0]], align 8
+// CHECK: store i32* %[[V1]], i32** %[[BLOCK_CAPTURED0]], align 8
+// CHECK: %[[BLOCK_CAPTURED1:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK]], i32 0, i32 6
+// CHECK: %[[V2:.*]] = getelementptr inbounds %[[LAMBDA_CLASS]], %[[LAMBDA_CLASS]]* %[[THIS]], i32 0, i32 1
+// CHECK: %[[V3:.*]] = load i32*, i32** %[[V2]], align 8
+// CHECK: store i32* %[[V3]], i32** %[[BLOCK_CAPTURED1]], align 8
+
+void foo1(int &, int &);
+
+void block_in_lambda(int &s1, int &s2) {
+  auto lambda = [&s1, &s2]() {
+auto block = ^{
+  foo1(s1, s2);
+};
+block();
+  };
+
+  lambda();
+}
+
+namespace CaptureByReference {
+
+id getObj();
+void use(id);
+
+// Block copy/dispose helpers aren't needed because 'a' is captured by
+// reference.
+
+// CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// 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, i8*, i64 }* @"__block_descriptor_40_e5_v8@?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+
+void test0() {
+  id a = getObj();
+  [&]{ ^{ a = 0; }(); }();
+}
+
+// Block copy/dispose helpers shouldn't have to retain/release 'a' because it
+// is captured by reference.
+
+// CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @"__block_descriptor_56_8_32s40s_e5_v8@?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
+// CHECK-NOT: call void @objc_storeStrong(
+// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5
+// CHECK: %[[V5:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5
+// CHECK: %[[BLOCKCOPY_SRC:.*]] = load i8*, i8** %[[V4]], align 8
+// CHECK: store i8* null, i8** %[[V5]], align 8
+// CHECK: call void @objc_storeStrong(i8** %[[V5]], i8* %[[BLOCKCOPY_SRC]])
+// CHECK: %[[V6:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 6
+// CHECK: %[[V7:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 6
+// CHECK: %[[BLOCKCOPY_SRC2:.*]] = load i8*, i8** %[[V6]], align 8
+// CHECK: store i8* null, i8** %[[V7]], align 8
+// CHECK: call void @objc_storeStrong(i8** %[[V7]], i8* %[[BLOCKCOPY_S

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Richard and Doug, do you have any thoughts on John's suggestion?




Comment at: test/CodeGenObjCXX/arc-list-init-destruct.mm:1
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc 
-fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck 
%s
+

rjmccall wrote:
> Does the corresponding C++ test case (replacing `Class0 *f;` with 
> `HasExplicitNonTrivialDestructor f;`) not reproduce the problem?
I wasn't able to reproduce the problem by changing the type of field 'f' to a 
C++ class with a non-trivial destructor because, if I make that change, 
Class1's destructor declaration gets added in 
Sema::AddImplicitlyDeclaredMembersToClass. I don't fully understand the reason 
behind it, but Class1's destructor declaration is added when the type of one of 
its subobject has a user-declared destructor.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-22 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

In https://reviews.llvm.org/D45898#1104025, @rsmith wrote:

> As it happens, the C++ committee fixed the language wording hole here very 
> recently. The new rule can be found here: http://wg21.link/p0968r0#2227
>  In summary: we should to consider the destructor for all elements of the 
> aggregate to be potentially-invoked.


It doesn't mean that clang should reject the following code, does it?

  // This should compile fine as long as 'Deleted7d d7d' is commented out.
  struct DeletedDtor { ~DeletedDtor() = delete; };
  struct Deleted7d { DeletedDtor a = {}; }; 
  //Deleted7d d7d;

I tried making a helper function out of the code in SK_UserConversion and using 
it in "case SK_ListInitialization". That doesn't seem to work because 
DiagnoseUseOfDecl rejects the code (with error message "error: attempt to use a 
deleted function") above even though the destructor isn't needed (because 'd7d' 
is commented out), so I guess that check should be done in another place.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45015: [Preprocessor] Allow libc++ to detect when aligned allocation is unavailable.

2018-05-22 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

In https://reviews.llvm.org/D45015#1105314, @rsmith wrote:

> Hmm, perhaps our strategy for handling aligned allocation on Darwin should be 
> revisited. We shouldn't be defining `__cpp_aligned_allocation` if we believe 
> it doesn't work -- that will break code that uses aligned allocation where 
> available and falls back to something else where it's unavailable.
>
> @ahatanak: how about this:
>
> - Change the driver to not pass `-faligned-alloc-unavailable` if an explicit 
> `-faligned-allocation` or `-fno-aligned-allocation` flag is given; update 
> Clang's note to suggest explicitly passing `-faligned-allocation` rather than 
> `-Wno-aligned-alloc-unavailable` if the user provides their own aligned 
> allocation function.
> - Change `-faligned-alloc-unavailable` so that it does not define 
> `__cpp_aligned_allocation`.
> - Change Sema's handling of the "aligned allocation unavailable" case so 
> that, after warning on selecting an aligned allocation function, it then 
> removes those functions from the candidate set and tries again.
>
>   That is: on old Darwin, we should not define `__cpp_aligned_allocation` 
> (even in C++17), produce the "no aligned allocation support" warning in C++17 
> mode, and then not try to call the aligned allocation function. But if 
> `-faligned-allocation` or `-fno-aligned-allocation` is specified explicitly, 
> then the user knows what they're doing and they get no warning.


I talked with @vsapsai today and we think this looks like a better idea.

A couple of questions:

- Currently clang errors out when aligned operator new is selected but the OS's 
version is too old to support it. What's the reason we want to change this now 
to be a warning rather than an error?

- So clang no longer needs to define macro `__ALIGNED_ALLOCATION_UNAVAILABLE__` 
and libc++ will use `__cpp_aligned_new` (I think you meant `__cpp_aligned_new`, 
not `__cpp_aligned_allocation`?) to determine whether aligned allocation 
functions should be defined or made available in the header?


Repository:
  rC Clang

https://reviews.llvm.org/D45015



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38708: [AST] Flag the typo-corrected nodes for better tooling

2018-05-23 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.
Herald added a subscriber: llvm-commits.

Could you rebase this patch against ToT?

Also, it's not clear to me why only four Exprs (DeclRefExpr, MemberExpr, 
ObjCIvarRefExpr, and ObjCPropertyRefExpr) should have the IsTypoCorrected flag. 
Can you elaborate on how you chose that set of Exprs and whether you plan to 
add the flag to other Exprs?


Repository:
  rL LLVM

https://reviews.llvm.org/D38708



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36918: [Sema] Take into account the current context when checking the accessibility of a member function pointer

2018-05-23 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 148334.
ahatanak added a comment.

Add a test case for the Chromium failure. Also, simplify a bit by capturing the 
calling context in Sema::DeduceTemplateArguments.


Repository:
  rC Clang

https://reviews.llvm.org/D36918

Files:
  lib/Sema/SemaTemplateDeduction.cpp
  test/SemaCXX/access.cpp


Index: test/SemaCXX/access.cpp
===
--- test/SemaCXX/access.cpp
+++ test/SemaCXX/access.cpp
@@ -169,3 +169,50 @@
   }
   void bar() { foo(); }
 }
+
+namespace OverloadedMemberFunctionPointer {
+  template
+  void func0() {}
+
+  template
+  void func1() {}
+
+  template
+  void func2(void(*fn)()) {} // expected-note 2 {{candidate function not 
viable: no overload of 'func}}
+
+  class C {
+  private:
+friend void friendFunc();
+void overloadedMethod();
+  protected:
+void overloadedMethod(int);
+  public:
+void overloadedMethod(int, int);
+void method() {
+  func2(&func0);
+  func2(&func1);
+}
+  };
+
+  void friendFunc() {
+func2(&func0);
+func2(&func1);
+  }
+
+  void nonFriendFunc() {
+func2(&func0); // expected-error {{no 
matching function for call to 'func2'}}
+func2(&func1); // expected-error {{no 
matching function for call to 'func2'}}
+  }
+
+  // r325321 caused an assertion failure when the following code was compiled.
+  class A {
+template  static bool foo1() { return true; }
+
+  public:
+void init(bool c) {
+  if (c) {
+auto f = foo1;
+  }
+}
+  };
+}
Index: lib/Sema/SemaTemplateDeduction.cpp
===
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3803,10 +3803,17 @@
   return Result;
   }
 
+  // Capture the context in which the function call is made. This is the 
context
+  // that is needed when the accessibility of a class member used as a template
+  // argument is checked.
+  DeclContext *CallingCtx = CurContext;
+
   return FinishTemplateArgumentDeduction(
   FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
-  &OriginalCallArgs, PartialOverloading,
-  [&]() { return CheckNonDependent(ParamTypesForArgChecking); });
+  &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
+ContextRAII SavedContext(*this, CallingCtx);
+return CheckNonDependent(ParamTypesForArgChecking);
+  });
 }
 
 QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,


Index: test/SemaCXX/access.cpp
===
--- test/SemaCXX/access.cpp
+++ test/SemaCXX/access.cpp
@@ -169,3 +169,50 @@
   }
   void bar() { foo(); }
 }
+
+namespace OverloadedMemberFunctionPointer {
+  template
+  void func0() {}
+
+  template
+  void func1() {}
+
+  template
+  void func2(void(*fn)()) {} // expected-note 2 {{candidate function not viable: no overload of 'func}}
+
+  class C {
+  private:
+friend void friendFunc();
+void overloadedMethod();
+  protected:
+void overloadedMethod(int);
+  public:
+void overloadedMethod(int, int);
+void method() {
+  func2(&func0);
+  func2(&func1);
+}
+  };
+
+  void friendFunc() {
+func2(&func0);
+func2(&func1);
+  }
+
+  void nonFriendFunc() {
+func2(&func0); // expected-error {{no matching function for call to 'func2'}}
+func2(&func1); // expected-error {{no matching function for call to 'func2'}}
+  }
+
+  // r325321 caused an assertion failure when the following code was compiled.
+  class A {
+template  static bool foo1() { return true; }
+
+  public:
+void init(bool c) {
+  if (c) {
+auto f = foo1;
+  }
+}
+  };
+}
Index: lib/Sema/SemaTemplateDeduction.cpp
===
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3803,10 +3803,17 @@
   return Result;
   }
 
+  // Capture the context in which the function call is made. This is the context
+  // that is needed when the accessibility of a class member used as a template
+  // argument is checked.
+  DeclContext *CallingCtx = CurContext;
+
   return FinishTemplateArgumentDeduction(
   FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
-  &OriginalCallArgs, PartialOverloading,
-  [&]() { return CheckNonDependent(ParamTypesForArgChecking); });
+  &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
+ContextRAII SavedContext(*this, CallingCtx);
+return CheckNonDependent(ParamTypesForArgChecking);
+  });
 }
 
 QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47290: [Sema] -Wformat-pedantic only for NSInteger/NSUInteger %zu/%zi on Darwin

2018-05-24 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: test/SemaObjC/format-size-spec-nsinteger.m:18
+  NSUInteger j = 0;
+  NSLog(@"max NSInteger = %zi", i);  // CHECK: values of type 'NSInteger' 
should not be used as format arguments; add an explicit cast to 'long' instead
+  NSLog(@"max NSUinteger = %zu", j); // CHECK: values of type 'NSUInteger' 
should not be used as format arguments; add an explicit cast to 'unsigned long' 
instead

This test looks identical to 
test/SemaObjC/format-size-spec-nsinteger-nopedantic.m except for the CHECK 
lines. You can probably merge the two files if you separate the CHECK lines 
from the lines that call NSLog (see test/Sema/format-strings-darwin.c for 
example).


Repository:
  rC Clang

https://reviews.llvm.org/D47290



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47354: [CodeGen][Darwin] Set the calling-convention of a thread-local variable initialization function to fix calling-convention mismatch

2018-05-24 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rjmccall, t.p.northover.

There is a bug in IRGen where the calling convention of initialization 
functions for thread-local static members of c++ template classes isn't set. 
This caused InstCombine to remove a call to an initialization function because 
of the mismatch in the calling conventions between the initialization function 
and the call.

For example, when the following piece of code (this is in 
test/CodeGenCXX/cxx11-thread-local.cpp) is compiled,

  int g();
  template struct V { static thread_local int m; };
  template thread_local int V::m = g();
  int e = V::m;

IRGen generates the following IR:

  @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @__cxx_global_var_init.9
  
  define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1VIiE1mE() #2 {
call cxx_fast_tlscc void @_ZTHN1VIiE1mE() ; this calls 
@__cxx_global_var_init.9
ret i32* @_ZN1VIiE1mE
  }
  
  ; this function is missing the calling convention "cxx_fast_tlscc".
  
  define internal void @__cxx_global_var_init.9() #0 section 
"__TEXT,__StaticInit,regular,pure_instructions" {
...
  }

To fix the bug, this patch sets the calling convention of the initialization 
functions to 'cxx_fast_tlscc'. Alternatively, I could remove 'cxx_fast_tlscc' 
from the call instruction, but I suppose we don't want to do so for performance 
reasons.

rdar://problem/40447463


Repository:
  rC Clang

https://reviews.llvm.org/D47354

Files:
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/cxx11-thread-local.cpp


Index: test/CodeGenCXX/cxx11-thread-local.cpp
===
--- test/CodeGenCXX/cxx11-thread-local.cpp
+++ test/CodeGenCXX/cxx11-thread-local.cpp
@@ -166,7 +166,8 @@
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE()
 // CHECK: ret {{.*}}* @_ZN1XIiE1mE
 
-// CHECK: define internal {{.*}} @[[VF_M_INIT]]()
+// LINUX: define internal void @[[VF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[VF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
@@ -178,7 +179,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIfE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[XF_M_INIT]]()
+// LINUX: define internal void @[[XF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*)
@@ -268,7 +270,8 @@
 // LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 // DARWIN-LABEL: define internal cxx_fast_tlscc i32* 
@_ZTWN12_GLOBAL__N_16anon_iE()
 
-// CHECK: define internal {{.*}} @[[V_M_INIT]]()
+// LINUX: define internal void @[[V_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[V_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
@@ -280,7 +283,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIiE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[X_M_INIT]]()
+// LINUX: define internal void @[[X_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[X_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*)
Index: lib/CodeGen/ItaniumCXXABI.cpp
===
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -2450,8 +2450,12 @@
 if (InitIsInitFunc) {
   if (Init) {
 llvm::CallInst *CallVal = Builder.CreateCall(Init);
-if (isThreadWrapperReplaceable(VD, CGM))
+if (isThreadWrapperReplaceable(VD, CGM)) {
   CallVal->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
+  llvm::Function *Fn =
+  
cast(cast(Init)->getAliasee());
+  Fn->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
+}
   }
 } else {
   // Don't know whether we have an init function. Call it if it exists.


Index: test/CodeGenCXX/cxx11-thread-local.cpp
===
--- test/CodeGenCXX/cxx11-thread-local.cpp
+++ test/CodeGenCXX/cxx11-thread-local.cpp
@@ -166,7 +166,8 @@
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE()
 // CHECK: ret {{.*}}* @_ZN1XIiE1mE
 
-// CHECK: define internal {{.*}} @[[VF_M_INIT]]()
+// LINUX: define internal void @[[VF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[VF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
@@ -178,7 +179,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIfE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[XF_M_INIT]]()
+// LINUX: define internal void @[[XF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIfE1mE)
 // DARWIN-NOT: comdat
 //

[PATCH] D47354: [CodeGen][Darwin] Set the calling-convention of a thread-local variable initialization function to fix calling-convention mismatch

2018-05-29 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL333447: [CodeGen][Darwin] Set the calling-convention of 
thread-local variable (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D47354?vs=148531&id=148954#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D47354

Files:
  cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
  cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp


Index: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
===
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -166,7 +166,8 @@
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE()
 // CHECK: ret {{.*}}* @_ZN1XIiE1mE
 
-// CHECK: define internal {{.*}} @[[VF_M_INIT]]()
+// LINUX: define internal void @[[VF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[VF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
@@ -178,7 +179,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIfE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[XF_M_INIT]]()
+// LINUX: define internal void @[[XF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*)
@@ -268,7 +270,8 @@
 // LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 // DARWIN-LABEL: define internal cxx_fast_tlscc i32* 
@_ZTWN12_GLOBAL__N_16anon_iE()
 
-// CHECK: define internal {{.*}} @[[V_M_INIT]]()
+// LINUX: define internal void @[[V_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[V_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
@@ -280,7 +283,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIiE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[X_M_INIT]]()
+// LINUX: define internal void @[[X_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[X_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*)
Index: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
===
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2450,8 +2450,12 @@
 if (InitIsInitFunc) {
   if (Init) {
 llvm::CallInst *CallVal = Builder.CreateCall(Init);
-if (isThreadWrapperReplaceable(VD, CGM))
+if (isThreadWrapperReplaceable(VD, CGM)) {
   CallVal->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
+  llvm::Function *Fn =
+  
cast(cast(Init)->getAliasee());
+  Fn->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
+}
   }
 } else {
   // Don't know whether we have an init function. Call it if it exists.


Index: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
===
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -166,7 +166,8 @@
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE()
 // CHECK: ret {{.*}}* @_ZN1XIiE1mE
 
-// CHECK: define internal {{.*}} @[[VF_M_INIT]]()
+// LINUX: define internal void @[[VF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[VF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
@@ -178,7 +179,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIfE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[XF_M_INIT]]()
+// LINUX: define internal void @[[XF_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIfE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*)
@@ -268,7 +270,8 @@
 // LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 // DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 
-// CHECK: define internal {{.*}} @[[V_M_INIT]]()
+// LINUX: define internal void @[[V_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[V_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
@@ -280,7 +283,8 @@
 // CHECK: store i64 1, i64* @_ZGVN1VIiE1mE
 // CHECK: br label
 
-// CHECK: define internal {{.*}} @[[X_M_INIT]]()
+// LINUX: define internal void @[[X_M_INIT]]()
+// DARWIN: define internal cxx_fast_tlscc void @[[X_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIiE1mE)
 // DARWIN-NOT: comdat
 // CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*)
Index: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
===

[PATCH] D36915: [Sema] Diagnose local variables and parameters captured by lambda and block expressions in a default argument

2017-09-29 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping.

Any comments on this patch or alternate approaches?


https://reviews.llvm.org/D36915



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36918: [Sema] Take into account the current context when checking the accessibility of a member function pointer

2017-09-29 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


https://reviews.llvm.org/D36918



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38606: [CodeGen] Emit a helper function for __builtin_os_log_format to reduce code size

2017-10-05 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.

We found that the IR IRGen emits when expanding __builtin_os_log_format is 
quite big and has a lot of redundancy.

For example, when clang compiles the following code:

  void foo1(void *buf) {
__builtin_os_log_format(buf, "%d %d", 11, 22);
  }

The IR looks like this:

  define void @foo1(i8* %buf) #0 {
  entry:
%buf.addr = alloca i8*, align 8
store i8* %buf, i8** %buf.addr, align 8
%0 = load i8*, i8** %buf.addr, align 8
%summary = getelementptr i8, i8* %0, i64 0
store i8 0, i8* %summary, align 1
%numArgs = getelementptr i8, i8* %0, i64 1
store i8 2, i8* %numArgs, align 1
%argDescriptor = getelementptr i8, i8* %0, i64 2
store i8 0, i8* %argDescriptor, align 1
%argSize = getelementptr i8, i8* %0, i64 3
store i8 4, i8* %argSize, align 1
%1 = getelementptr i8, i8* %0, i64 4
%2 = bitcast i8* %1 to i32*
store i32 11, i32* %2, align 1
%argDescriptor1 = getelementptr i8, i8* %0, i64 8
store i8 0, i8* %argDescriptor1, align 1
%argSize2 = getelementptr i8, i8* %0, i64 9
store i8 4, i8* %argSize2, align 1
%3 = getelementptr i8, i8* %0, i64 10
%4 = bitcast i8* %3 to i32*
store i32 22, i32* %4, align 1
ret void
  }

The IR generated when compiling a similar call like 
"__builtin_os_log_format(buf, "%d %d", 33, 44)" is almost the same except for 
the values of the integer constants stored, so there is an opportunity for code 
reductionton here.

To reduce code size, this patch modifies IRGen to emit a helper function that 
can be used by different call sites that call __builtin_os_log_format in a 
program. When compiling with -Oz, the generated helper function is marked as 
linkonce_odr, hidden, and noinline so that the linker can merge identical 
helper functions from different translation units. When compiling with other 
optimization levels, the function is marked as 'internal' and the generated IR 
should look mostly the same after inlining.

This patch also fixes a bug where the generated IR writes past the buffer when 
%m is the last directive. For example, the size of 'buf' in the following code 
is 4 but IRGen emits a store that writes a 4-byte value at buf+4.

  char buf[__builtin_os_log_format_buffer_size("%m")];
  __builtin_os_log_format(buf, "%m");

Original patch was written by Duncan.

rdar://problem/34065973
dar://problem/34196543


https://reviews.llvm.org/D38606

Files:
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/builtins.c
  test/CodeGenObjC/os_log.m

Index: test/CodeGenObjC/os_log.m
===
--- test/CodeGenObjC/os_log.m
+++ test/CodeGenObjC/os_log.m
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O2 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O0 | FileCheck %s -check-prefix=CHECK-O0
 
 // Make sure we emit clang.arc.use before calling objc_release as part of the
 // cleanup. This way we make sure the object will not be released until the
@@ -12,28 +13,67 @@
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 // CHECK-LABEL: define i8* @test_builtin_os_log
+// CHECK-O0-LABEL: define i8* @test_builtin_os_log
+// CHECK: (i8* returned %[[BUF:.*]])
+// CHECK-O0: (i8* %[[BUF:.*]])
 void *test_builtin_os_log(void *buf) {
   return __builtin_os_log_format(buf, "capabilities: %@", GenString());
 
-  // CHECK: store i8 2, i8*
-  // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* {{.*}}, i64 1
-  // CHECK: store i8 1, i8* [[NUM_ARGS]]
-  //
-  // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* {{.*}}, i64 2
-  // CHECK: store i8 64, i8* [[ARG1_DESC]]
-  // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* {{.*}}, i64 3
-  // CHECK: store i8 8, i8* [[ARG1_SIZE]]
-  // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* {{.*}}, i64 4
-  // CHECK: [[ARG1_CAST:%.*]] = bitcast i8* [[ARG1]] to
-
-  // CHECK: [[STRING:%.*]] = {{.*}} call {{.*}} @GenString()
-  // CHECK: [[STRING_CAST:%.*]] = bitcast {{.*}} [[STRING]] to
-  // CHECK: call {{.*}} @objc_retainAutoreleasedReturnValue(i8* [[STRING_CAST]])
-  // CHECK: store {{.*}} [[STRING]], {{.*}} [[ARG1_CAST]]
-
-  // CHECK: call void (...) @clang.arc.use({{.*}} [[STRING]])
-  // CHECK: call void @objc_release(i8* [[STRING_CAST]])
-  // CHECK: ret i8*
+  // CHECK: %[[CALL:.*]] = tail call %[[V0:.*]]* (...) @GenString()
+  // CHECK: %[[V0]] = bitcast %[[V0]]* %[[CALL]] to i8*
+  // CHECK: %[[V1:.*]] = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %[[V0]])
+  // CHECK: %[[V2:.*]] = ptrtoint %[[V0]]* %[[CALL]] to i64
+  // CHECK: store i8 2, i8* %[[BUF]], align 1
+  // CHECK: %[[NUMARGS_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+  // CHECK: store i8 1, i8* %[[NUMARGS_I]], align 1
+  // CHECK: %[[ARGDESCRIPTOR_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+  // CHECK: store i8 64, i8* %[[ARGDESCRIPTOR_I]], align

[PATCH] D38606: [CodeGen] Emit a helper function for __builtin_os_log_format to reduce code size

2017-10-05 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 117955.
ahatanak added a comment.

Always mark the helper function as linkonce_odr and hidden.


https://reviews.llvm.org/D38606

Files:
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/builtins.c
  test/CodeGenObjC/os_log.m

Index: test/CodeGenObjC/os_log.m
===
--- test/CodeGenObjC/os_log.m
+++ test/CodeGenObjC/os_log.m
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O2 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O0 | FileCheck %s -check-prefix=CHECK-O0
 
 // Make sure we emit clang.arc.use before calling objc_release as part of the
 // cleanup. This way we make sure the object will not be released until the
@@ -12,28 +13,67 @@
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 // CHECK-LABEL: define i8* @test_builtin_os_log
+// CHECK-O0-LABEL: define i8* @test_builtin_os_log
+// CHECK: (i8* returned %[[BUF:.*]])
+// CHECK-O0: (i8* %[[BUF:.*]])
 void *test_builtin_os_log(void *buf) {
   return __builtin_os_log_format(buf, "capabilities: %@", GenString());
 
-  // CHECK: store i8 2, i8*
-  // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* {{.*}}, i64 1
-  // CHECK: store i8 1, i8* [[NUM_ARGS]]
-  //
-  // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* {{.*}}, i64 2
-  // CHECK: store i8 64, i8* [[ARG1_DESC]]
-  // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* {{.*}}, i64 3
-  // CHECK: store i8 8, i8* [[ARG1_SIZE]]
-  // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* {{.*}}, i64 4
-  // CHECK: [[ARG1_CAST:%.*]] = bitcast i8* [[ARG1]] to
-
-  // CHECK: [[STRING:%.*]] = {{.*}} call {{.*}} @GenString()
-  // CHECK: [[STRING_CAST:%.*]] = bitcast {{.*}} [[STRING]] to
-  // CHECK: call {{.*}} @objc_retainAutoreleasedReturnValue(i8* [[STRING_CAST]])
-  // CHECK: store {{.*}} [[STRING]], {{.*}} [[ARG1_CAST]]
-
-  // CHECK: call void (...) @clang.arc.use({{.*}} [[STRING]])
-  // CHECK: call void @objc_release(i8* [[STRING_CAST]])
-  // CHECK: ret i8*
+  // CHECK: %[[CALL:.*]] = tail call %[[V0:.*]]* (...) @GenString()
+  // CHECK: %[[V0]] = bitcast %[[V0]]* %[[CALL]] to i8*
+  // CHECK: %[[V1:.*]] = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %[[V0]])
+  // CHECK: %[[V2:.*]] = ptrtoint %[[V0]]* %[[CALL]] to i64
+  // CHECK: store i8 2, i8* %[[BUF]], align 1
+  // CHECK: %[[NUMARGS_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+  // CHECK: store i8 1, i8* %[[NUMARGS_I]], align 1
+  // CHECK: %[[ARGDESCRIPTOR_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+  // CHECK: store i8 64, i8* %[[ARGDESCRIPTOR_I]], align 1
+  // CHECK: %[[ARGSIZE_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+  // CHECK: store i8 8, i8* %[[ARGSIZE_I]], align 1
+  // CHECK: %[[ARGDATA_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+  // CHECK: %[[ARGDATACAST_I:.*]] = bitcast i8* %[[ARGDATA_I]] to i64*
+  // CHECK: store i64 %[[V2]], i64* %[[ARGDATACAST_I]], align 1
+  // CHECK: tail call void (...) @clang.arc.use(%[[V0]]* %[[CALL]])
+  // CHECK: tail call void @objc_release(i8* %[[V0]])
+  // CHECK: ret i8* %[[BUF]]
+
+  // clang.arc.use is used and removed in IR optimizations. At O0, we should not
+  // emit clang.arc.use, since it will not be removed and we will have a link
+  // error.
+  // CHECK-O0: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+  // CHECK-O0: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+  // CHECK-O0: %[[V0:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+  // CHECK-O0: %[[CALL:.*]] = call %[[V0]]* (...) @GenString()
+  // CHECK-O0: %[[V1:.*]] = bitcast %[[V0]]* %[[CALL]] to i8*
+  // CHECK-O0: %[[V2:.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* %[[V1]])
+  // CHECK-O0: %[[V3:.*]] = bitcast i8* %[[V2]] to %[[V0]]*
+  // CHECK-O0: %[[V4:.*]] = ptrtoint %[[V0]]* %[[V3]] to i64
+  // CHECK-O0: call void @__os_log_helper_1_2_1_8_64(i8* %[[V0]], i64 %[[V4]])
+  // CHECK-O0: %[[V5:.*]] = bitcast %[[V0]]* %[[V3]] to i8*
+  // CHECK-O0-NOT call void (...) @clang.arc.use({{.*}}
+  // CHECK-O0: call void @objc_release(i8* %[[V5]])
+  // CHECK-O0: ret i8* %[[V0]]
 }
 
+// CHECK-O0-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_1_8_64
+// CHECK-O0: (i8* %[[BUFFER:.*]], i64 %[[ARG0:.*]])
+
+// CHECK-O0: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK-O0: %[[ARG0_ADDR:.*]] = alloca i64, align 8
+// CHECK-O0: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK-O0: store i64 %[[ARG0]], i64* %[[ARG0_ADDR]], align 8
+// CHECK-O0: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK-O0: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK-O0: store i8 2, i8* %[[SUMMARY]], align 1
+// CHECK-O0: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK-O0: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK-O0: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK-O0: store i8 6

[PATCH] D38606: [CodeGen] Emit a helper function for __builtin_os_log_format to reduce code size

2017-10-05 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

I think you are right. The linkage should be linkonce_odr even when not 
compiling with -Oz. I've fixed it in the latest patch.


https://reviews.llvm.org/D38606



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38606: [CodeGen] Emit a helper function for __builtin_os_log_format to reduce code size

2017-10-06 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL315045: [CodeGen] Emit a helper function for 
__builtin_os_log_format to reduce (authored by ahatanak).

Changed prior to commit:
  https://reviews.llvm.org/D38606?vs=117955&id=117957#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38606

Files:
  cfe/trunk/lib/CodeGen/CGBuiltin.cpp
  cfe/trunk/lib/CodeGen/CodeGenFunction.h
  cfe/trunk/test/CodeGen/builtins.c
  cfe/trunk/test/CodeGenObjC/os_log.m

Index: cfe/trunk/test/CodeGen/builtins.c
===
--- cfe/trunk/test/CodeGen/builtins.c
+++ cfe/trunk/test/CodeGen/builtins.c
@@ -378,229 +378,385 @@
 #ifdef __x86_64__
 
 // CHECK-LABEL: define void @test_builtin_os_log
-// CHECK: (i8* [[BUF:%.*]], i32 [[I:%.*]], i8* [[DATA:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i32 %[[I:.*]], i8* %[[DATA:.*]])
 void test_builtin_os_log(void *buf, int i, const char *data) {
   volatile int len;
-  // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
-  // CHECK: store i32 [[I]], i32* [[I_ADDR:%.*]], align 4
-  // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
+  // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+  // CHECK: %[[I_ADDR:.*]] = alloca i32, align 4
+  // CHECK: %[[DATA_ADDR:.*]] = alloca i8*, align 8
+  // CHECK: %[[LEN:.*]] = alloca i32, align 4
+  // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+  // CHECK: store i32 %[[I]], i32* %[[I_ADDR]], align 4
+  // CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8
 
-  // CHECK: store volatile i32 34
+  // CHECK: store volatile i32 34, i32* %[[LEN]]
   len = __builtin_os_log_format_buffer_size("%d %{public}s %{private}.16P", i, data, data);
 
-  // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
-  // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
-  // CHECK: store i8 3, i8* [[SUMMARY]]
-  // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
-  // CHECK: store i8 4, i8* [[NUM_ARGS]]
-  //
-  // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
-  // CHECK: store i8 0, i8* [[ARG1_DESC]]
-  // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
-  // CHECK: store i8 4, i8* [[ARG1_SIZE]]
-  // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
-  // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
-  // CHECK: [[I2:%.*]] = load i32, i32* [[I_ADDR]]
-  // CHECK: store i32 [[I2]], i32* [[ARG1_INT]]
-
-  // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 8
-  // CHECK: store i8 34, i8* [[ARG2_DESC]]
-  // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 9
-  // CHECK: store i8 8, i8* [[ARG2_SIZE]]
-  // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 10
-  // CHECK: [[ARG2_PTR:%.*]] = bitcast i8* [[ARG2]] to i8**
-  // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA_ADDR]]
-  // CHECK: store i8* [[DATA2]], i8** [[ARG2_PTR]]
-
-  // CHECK: [[ARG3_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 18
-  // CHECK: store i8 17, i8* [[ARG3_DESC]]
-  // CHECK: [[ARG3_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 19
-  // CHECK: store i8 4, i8* [[ARG3_SIZE]]
-  // CHECK: [[ARG3:%.*]] = getelementptr i8, i8* [[BUF2]], i64 20
-  // CHECK: [[ARG3_INT:%.*]] = bitcast i8* [[ARG3]] to i32*
-  // CHECK: store i32 16, i32* [[ARG3_INT]]
-
-  // CHECK: [[ARG4_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 24
-  // CHECK: store i8 49, i8* [[ARG4_DESC]]
-  // CHECK: [[ARG4_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 25
-  // CHECK: store i8 8, i8* [[ARG4_SIZE]]
-  // CHECK: [[ARG4:%.*]] = getelementptr i8, i8* [[BUF2]], i64 26
-  // CHECK: [[ARG4_PTR:%.*]] = bitcast i8* [[ARG4]] to i8**
-  // CHECK: [[DATA3:%.*]] = load i8*, i8** [[DATA_ADDR]]
-  // CHECK: store i8* [[DATA3]], i8** [[ARG4_PTR]]
-
+  // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]]
+  // CHECK: %[[V2:.*]] = load i32, i32* %[[I_ADDR]]
+  // CHECK: %[[V3:.*]] = load i8*, i8** %[[DATA_ADDR]]
+  // CHECK: %[[V4:.*]] = ptrtoint i8* %[[V3]] to i64
+  // CHECK: %[[V5:.*]] = load i8*, i8** %[[DATA_ADDR]]
+  // CHECK: %[[V6:.*]] = ptrtoint i8* %[[V5]] to i64
+  // CHECK: call void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49(i8* %[[V1]], i32 %[[V2]], i64 %[[V4]], i32 16, i64 %[[V6]])
   __builtin_os_log_format(buf, "%d %{public}s %{private}.16P", i, data, data);
 }
 
-// CHECK-LABEL: define void @test_builtin_os_log_errno
-// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]])
-void test_builtin_os_log_errno(void *buf, const char *data) {
-  volatile int len;
-  // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
-  // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
-
-  // CHECK: store volatile i32 2
-  len = __builtin_os_log_format_buffer_size("%S");
-
-  // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
-  // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
-  // CHECK: store i8 2, i8* [[SUMMARY]]
-  // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]

[PATCH] D36918: [Sema] Take into account the current context when checking the accessibility of a member function pointer

2017-10-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


https://reviews.llvm.org/D36918



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36918: [Sema] Take into account the current context when checking the accessibility of a member function pointer

2017-10-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 118119.
ahatanak added a comment.

Address review comments.


https://reviews.llvm.org/D36918

Files:
  lib/Sema/SemaAccess.cpp
  test/SemaCXX/access.cpp


Index: test/SemaCXX/access.cpp
===
--- test/SemaCXX/access.cpp
+++ test/SemaCXX/access.cpp
@@ -169,3 +169,38 @@
   }
   void bar() { foo(); }
 }
+
+namespace OverloadedMemberFunctionPointer {
+  template
+  void func0() {}
+
+  template
+  void func1() {}
+
+  template
+  void func2(void(*fn)()) {} // expected-note 2 {{candidate function not 
viable: no overload of 'func}}
+
+  class C {
+  private:
+friend void friendFunc();
+void overloadedMethod();
+  protected:
+void overloadedMethod(int);
+  public:
+void overloadedMethod(int, int);
+void method() {
+  func2(&func0);
+  func2(&func1);
+}
+  };
+
+  void friendFunc() {
+func2(&func0);
+func2(&func1);
+  }
+
+  void nonFriendFunc() {
+func2(&func0); // expected-error {{no 
matching function for call to 'func2'}}
+func2(&func1); // expected-error {{no 
matching function for call to 'func2'}}
+  }
+}
Index: lib/Sema/SemaAccess.cpp
===
--- lib/Sema/SemaAccess.cpp
+++ lib/Sema/SemaAccess.cpp
@@ -1793,6 +1793,11 @@
 
   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
   /*no instance context*/ QualType());
+
+  if (IsAccessible(*this, EffectiveContext(CurScope->getEntity()), Entity) ==
+  ::AR_accessible)
+return AR_accessible;
+
   Entity.setDiag(diag::err_access)
 << Ovl->getSourceRange();
 


Index: test/SemaCXX/access.cpp
===
--- test/SemaCXX/access.cpp
+++ test/SemaCXX/access.cpp
@@ -169,3 +169,38 @@
   }
   void bar() { foo(); }
 }
+
+namespace OverloadedMemberFunctionPointer {
+  template
+  void func0() {}
+
+  template
+  void func1() {}
+
+  template
+  void func2(void(*fn)()) {} // expected-note 2 {{candidate function not viable: no overload of 'func}}
+
+  class C {
+  private:
+friend void friendFunc();
+void overloadedMethod();
+  protected:
+void overloadedMethod(int);
+  public:
+void overloadedMethod(int, int);
+void method() {
+  func2(&func0);
+  func2(&func1);
+}
+  };
+
+  void friendFunc() {
+func2(&func0);
+func2(&func1);
+  }
+
+  void nonFriendFunc() {
+func2(&func0); // expected-error {{no matching function for call to 'func2'}}
+func2(&func1); // expected-error {{no matching function for call to 'func2'}}
+  }
+}
Index: lib/Sema/SemaAccess.cpp
===
--- lib/Sema/SemaAccess.cpp
+++ lib/Sema/SemaAccess.cpp
@@ -1793,6 +1793,11 @@
 
   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
   /*no instance context*/ QualType());
+
+  if (IsAccessible(*this, EffectiveContext(CurScope->getEntity()), Entity) ==
+  ::AR_accessible)
+return AR_accessible;
+
   Entity.setDiag(diag::err_access)
 << Ovl->getSourceRange();
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36918: [Sema] Take into account the current context when checking the accessibility of a member function pointer

2017-10-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/Sema/SemaAccess.cpp:1798
+  EffectiveContext EC(CurScope->getEntity());
+  if (IsAccessible(*this, EC, Entity) == ::AR_accessible)
+return AR_accessible;

Rakete wrote:
> You don't need that scope resolution operator there. Also, I guess you don't 
> have to create `EC`, you can just pass 
> `EffectiveContext(CurScope->getEntity())` directly to `IsAccessible`.
The scope resolution operator is needed here because IsAccessible's return type 
is AccessResult defined at the top of SemaAccess.cpp, not the one defined in 
Sema.h. If I remove the scope resolution operator, clang issues a warning 
("comparison of two values with different enumeration types").

EffectiveContext is passed as a temporary now as you suggested.


https://reviews.llvm.org/D36918



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38659: [Sema][ObjC] Preserve syntactic sugar when removing ARCReclaimReturnedObject cast

2017-10-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.

This is a follow-up patch to r314370.

Rather than throwing away the enclosing parentheses in maybeUndoReclaimObject, 
this patch walks down the expression until an ARCReclaimReturnedObject cast is 
found and removes just the cast, preserving the syntactic sugar expressions 
(parens and casts) that were visited up to that point.

rdar://problem/34705720


https://reviews.llvm.org/D38659

Files:
  lib/Sema/SemaExprObjC.cpp
  test/CodeGenObjC/arc-bridged-cast.m


Index: test/CodeGenObjC/arc-bridged-cast.m
===
--- test/CodeGenObjC/arc-bridged-cast.m
+++ test/CodeGenObjC/arc-bridged-cast.m
@@ -102,5 +102,6 @@
   // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue(
   // CHECK-NOT: call void @objc_release(
   CFStringRef r = (__bridge CFStringRef)(CreateNSString());
+  r = (__bridge CFStringRef)((NSString *)(CreateNSString()));
   return r;
 }
Index: lib/Sema/SemaExprObjC.cpp
===
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -4317,14 +4317,37 @@
 
 /// Look for an ObjCReclaimReturnedObject cast and destroy it.
 static Expr *maybeUndoReclaimObject(Expr *e) {
-  // For now, we just undo operands that are *immediately* reclaim
-  // expressions, which prevents the vast majority of potential
-  // problems here.  To catch them all, we'd need to rebuild arbitrary
-  // value-propagating subexpressions --- we can't reliably rebuild
-  // in-place because of expression sharing.
-  if (auto *ice = dyn_cast(e->IgnoreParens()))
-if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
-  return ice->getSubExpr();
+  Expr *curExpr = e, *prevExpr = nullptr;
+
+  // Walk down the expression until we hit an implicit cast of kind
+  // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+  while (true) {
+if (auto *pe = dyn_cast(curExpr)) {
+  prevExpr = curExpr;
+  curExpr = pe->getSubExpr();
+  continue;
+}
+
+if (auto *ce = dyn_cast(curExpr)) {
+  if (auto *ice = dyn_cast(ce))
+if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+  if (!prevExpr)
+return ice->getSubExpr();
+  if (auto *pe = dyn_cast(prevExpr))
+pe->setSubExpr(ice->getSubExpr());
+  else
+cast(prevExpr)->setSubExpr(ice->getSubExpr());
+  return e;
+}
+
+  prevExpr = curExpr;
+  curExpr = ce->getSubExpr();
+  continue;
+}
+
+// Break out of the loop if curExpr is neither a Paren nor a Cast.
+break;
+  }
 
   return e;
 }


Index: test/CodeGenObjC/arc-bridged-cast.m
===
--- test/CodeGenObjC/arc-bridged-cast.m
+++ test/CodeGenObjC/arc-bridged-cast.m
@@ -102,5 +102,6 @@
   // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue(
   // CHECK-NOT: call void @objc_release(
   CFStringRef r = (__bridge CFStringRef)(CreateNSString());
+  r = (__bridge CFStringRef)((NSString *)(CreateNSString()));
   return r;
 }
Index: lib/Sema/SemaExprObjC.cpp
===
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -4317,14 +4317,37 @@
 
 /// Look for an ObjCReclaimReturnedObject cast and destroy it.
 static Expr *maybeUndoReclaimObject(Expr *e) {
-  // For now, we just undo operands that are *immediately* reclaim
-  // expressions, which prevents the vast majority of potential
-  // problems here.  To catch them all, we'd need to rebuild arbitrary
-  // value-propagating subexpressions --- we can't reliably rebuild
-  // in-place because of expression sharing.
-  if (auto *ice = dyn_cast(e->IgnoreParens()))
-if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
-  return ice->getSubExpr();
+  Expr *curExpr = e, *prevExpr = nullptr;
+
+  // Walk down the expression until we hit an implicit cast of kind
+  // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+  while (true) {
+if (auto *pe = dyn_cast(curExpr)) {
+  prevExpr = curExpr;
+  curExpr = pe->getSubExpr();
+  continue;
+}
+
+if (auto *ce = dyn_cast(curExpr)) {
+  if (auto *ice = dyn_cast(ce))
+if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+  if (!prevExpr)
+return ice->getSubExpr();
+  if (auto *pe = dyn_cast(prevExpr))
+pe->setSubExpr(ice->getSubExpr());
+  else
+cast(prevExpr)->setSubExpr(ice->getSubExpr());
+  return e;
+}
+
+  prevExpr = curExpr;
+  curExpr = ce->getSubExpr();
+  continue;
+}
+
+// Break out of the loop if curExpr is neither a Paren nor a Cast.
+break;
+  }
 
   return e;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38659: [Sema][ObjC] Preserve syntactic sugar when removing ARCReclaimReturnedObject cast

2017-10-09 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL315261: [Sema][ObjC] Preserve syntactic sugar when removing 
(authored by ahatanak).

Changed prior to commit:
  https://reviews.llvm.org/D38659?vs=118121&id=118302#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38659

Files:
  cfe/trunk/lib/Sema/SemaExprObjC.cpp
  cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m


Index: cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
===
--- cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
+++ cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
@@ -102,5 +102,6 @@
   // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue(
   // CHECK-NOT: call void @objc_release(
   CFStringRef r = (__bridge CFStringRef)(CreateNSString());
+  r = (__bridge CFStringRef)((NSString *)(CreateNSString()));
   return r;
 }
Index: cfe/trunk/lib/Sema/SemaExprObjC.cpp
===
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp
@@ -4317,14 +4317,37 @@
 
 /// Look for an ObjCReclaimReturnedObject cast and destroy it.
 static Expr *maybeUndoReclaimObject(Expr *e) {
-  // For now, we just undo operands that are *immediately* reclaim
-  // expressions, which prevents the vast majority of potential
-  // problems here.  To catch them all, we'd need to rebuild arbitrary
-  // value-propagating subexpressions --- we can't reliably rebuild
-  // in-place because of expression sharing.
-  if (auto *ice = dyn_cast(e->IgnoreParens()))
-if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
-  return ice->getSubExpr();
+  Expr *curExpr = e, *prevExpr = nullptr;
+
+  // Walk down the expression until we hit an implicit cast of kind
+  // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+  while (true) {
+if (auto *pe = dyn_cast(curExpr)) {
+  prevExpr = curExpr;
+  curExpr = pe->getSubExpr();
+  continue;
+}
+
+if (auto *ce = dyn_cast(curExpr)) {
+  if (auto *ice = dyn_cast(ce))
+if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+  if (!prevExpr)
+return ice->getSubExpr();
+  if (auto *pe = dyn_cast(prevExpr))
+pe->setSubExpr(ice->getSubExpr());
+  else
+cast(prevExpr)->setSubExpr(ice->getSubExpr());
+  return e;
+}
+
+  prevExpr = curExpr;
+  curExpr = ce->getSubExpr();
+  continue;
+}
+
+// Break out of the loop if curExpr is neither a Paren nor a Cast.
+break;
+  }
 
   return e;
 }


Index: cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
===
--- cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
+++ cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
@@ -102,5 +102,6 @@
   // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue(
   // CHECK-NOT: call void @objc_release(
   CFStringRef r = (__bridge CFStringRef)(CreateNSString());
+  r = (__bridge CFStringRef)((NSString *)(CreateNSString()));
   return r;
 }
Index: cfe/trunk/lib/Sema/SemaExprObjC.cpp
===
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp
@@ -4317,14 +4317,37 @@
 
 /// Look for an ObjCReclaimReturnedObject cast and destroy it.
 static Expr *maybeUndoReclaimObject(Expr *e) {
-  // For now, we just undo operands that are *immediately* reclaim
-  // expressions, which prevents the vast majority of potential
-  // problems here.  To catch them all, we'd need to rebuild arbitrary
-  // value-propagating subexpressions --- we can't reliably rebuild
-  // in-place because of expression sharing.
-  if (auto *ice = dyn_cast(e->IgnoreParens()))
-if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
-  return ice->getSubExpr();
+  Expr *curExpr = e, *prevExpr = nullptr;
+
+  // Walk down the expression until we hit an implicit cast of kind
+  // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+  while (true) {
+if (auto *pe = dyn_cast(curExpr)) {
+  prevExpr = curExpr;
+  curExpr = pe->getSubExpr();
+  continue;
+}
+
+if (auto *ce = dyn_cast(curExpr)) {
+  if (auto *ice = dyn_cast(ce))
+if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+  if (!prevExpr)
+return ice->getSubExpr();
+  if (auto *pe = dyn_cast(prevExpr))
+pe->setSubExpr(ice->getSubExpr());
+  else
+cast(prevExpr)->setSubExpr(ice->getSubExpr());
+  return e;
+}
+
+  prevExpr = curExpr;
+  curExpr = ce->getSubExpr();
+  continue;
+}
+
+// Break out of the loop if curExpr is neither a Paren nor a Cast.
+break;
+  }
 
   return e;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman

[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-08-23 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

In https://reviews.llvm.org/D47757#1211276, @tra wrote:

> I've confirmed that the patch does not break anything in our CUDA code, so 
> it's good to go as far as CUDA is concerned.


Thanks. @rsmith, do you have any other comments about the patch?


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-30 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50783: [CodeGen] Merge identical block descriptor global variables

2018-08-31 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

The GNUstep documentation I found replaces '@' with '\1'. Would that fix the 
problem?

https://github.com/gnustep/libobjc2/blob/master/ABIDoc/abi.tex


Repository:
  rC Clang

https://reviews.llvm.org/D50783



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-31 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 163612.
ahatanak marked 3 inline comments as done.
ahatanak added a comment.

Move the call that checks the element's destructor into 
InitListChecker::CheckStructUnionTypes.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,51 @@
   // amount of time.
   struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}};
 }
+
+namespace ElementDestructor {
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate initialization
+  // occurs. Produce a diagnostic if an element's destructor isn't accessible.
+
+  class X { int f; ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+
+  void test0() {
+auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}}
+  }
+
+  struct S0 { int f; ~S0() = delete; }; // expected-note 3 {{'~S0' has been explicitly marked deleted here}}
+  struct S1 { S0 s0; int f; };
+
+  S1 test1() {
+auto *t = new S1 { .f = 1 }; // expected-error {{attempt to use a deleted function}}
+return {2}; // expected-error {{attempt to use a deleted function}}
+  }
+
+  // Check if the type of an array element has a destructor.
+  struct S2 { S0 a[4]; };
+
+  void test2() {
+auto *t = new S2 {1,2,3,4}; // expected-error {{attempt to use a deleted function}}
+  }
+
+#if __cplusplus >= 201703L
+  namespace BaseDestructor {
+ struct S0 { int f; ~S0() = delete; }; // expected-note {{'~S0' has been explicitly marked deleted here}}
+
+// Check destructor of base class.
+struct S3 : S0 {};
+
+void test3() {
+  S3 s3 = {1}; // expected-error {{attempt to use a deleted function}}
+}
+  }
+#endif
+
+  // A's destructor doesn't have to be accessible from the context of C's
+  // initialization.
+  struct A { friend struct B; private: ~A(); };
+  struct B { B(); A a; };
+  struct C { B b; };
+  C c = { B() };
+}
Index: test/CodeGenObjCXX/arc-list-init-destruct.mm
===
--- /dev/null
+++ test/CodeGenObjCXX/arc-list-init-destruct.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc -fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[V0:.*]] = type opaque
+// CHECK: %[[STRUCT_CLASS1:.*]] = type { %[[V0]]* }
+
+@interface Class0;
+@end
+
+struct Class1 {
+  Class0 *f;
+};
+
+struct Container {
+  Class1 a;
+  bool b;
+};
+
+bool getBool() {
+  return false;
+}
+
+Class0 *g;
+
+// CHECK: define {{.*}} @_Z4testv()
+// CHECK: invoke zeroext i1 @_Z7getBoolv()
+// CHECK: landingpad { i8*, i32 }
+// CHECK: call void @_ZN6Class1D1Ev(%[[STRUCT_CLASS1]]* %{{.*}})
+// CHECK: br label
+
+// CHECK: define linkonce_odr void @_ZN6Class1D1Ev(
+
+Container test() {
+  return {{g}, getBool()};
+}
Index: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1818,6 +1818,17 @@
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
+static bool checkElementDestructor(CXXRecordDecl *CXXRD, QualType RecType,
+   SourceLocation Loc, Sema &SemaRef) {
+  CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+  SemaRef.CheckDestructorAccess(
+  Loc, Destructor, SemaRef.PDiag(diag::err_access_dtor_temp) << RecType);
+  SemaRef.MarkFunctionReferenced(Loc, Destructor);
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return false;
+  return true;
+}
+
 void InitListChecker::CheckStructUnionTypes(
 const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
 CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1835,6 +1846,32 @@
 return;
   }
 
+  // Check if destructors of base classes and members are accessible.
+  //
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate
+  // initialization occurs.
+  if (!VerifyOnly)
+if (auto *CXXRD = DeclType->getAsCXXRecordDecl()) {
+  SourceLocation Loc = IList->getBeginLoc();
+  for (auto &Base : Bases)
+if (auto *CXXRDMember = Base.getType()->getAsCXXRecordDecl())
+  if (!checkElementDestructor(CXXRDMember, Base.getType(), Loc,
+  SemaRef)) {
+hadError = true;
+return;
+  }
+
+  for (FieldDecl *FD : CXXRD->fields()) {
+QualType ET = SemaRef.Context.getBaseElementType(FD->getType(

[PATCH] D51564: Distinguish `__block` variables that are captured by escaping blocks from those that aren't

2018-08-31 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added a reviewer: rjmccall.
Herald added a subscriber: dexonsmith.

This patch changes the way `__block` variables that aren't captured by escaping 
blocks are handled:

- Since non-escaping blocks on the stack never get copied to the heap (see 
https://reviews.llvm.org/D49303), Sema shouldn't error out when the type of a 
non-escaping `__block` variable doesn't have an accessible copy constructor.

- IRGen doesn't have to use the specialized byref structure (see 
https://clang.llvm.org/docs/Block-ABI-Apple.html#id8) for a non-escaping 
`__block` variable anymore. Instead IRGen can emit the variable as a normal 
variable and copy the reference to the block literal . Byref copy/dispose 
helpers aren't needed either.

rdar://problem/39352313


Repository:
  rC Clang

https://reviews.llvm.org/D51564

Files:
  include/clang/AST/Decl.h
  include/clang/Sema/ScopeInfo.h
  lib/AST/Decl.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/ScopeInfo.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprObjC.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CodeGen/block-byref-aggr.c
  test/CodeGen/blocks-seq.c
  test/CodeGen/exceptions.c
  test/CodeGen/personality.c
  test/CodeGenCXX/block-capture.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/debug-info-blocks.cpp
  test/CodeGenObjC/arc-no-arc-exceptions.m
  test/CodeGenObjC/arc-unoptimized-byref-var.m
  test/CodeGenObjC/blocks-1.m
  test/CodeGenObjC/noescape.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/PCH/block-helpers.cpp
  test/SemaObjCXX/blocks.mm
  test/SemaObjCXX/noescape.mm

Index: test/SemaObjCXX/noescape.mm
===
--- test/SemaObjCXX/noescape.mm
+++ test/SemaObjCXX/noescape.mm
@@ -8,6 +8,7 @@
   void m();
 };
 
+void escapingFunc0(BlockTy);
 void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
 void noescapeFunc1(id, [[clang::noescape]] BlockTy);
 void noescapeFunc2(__attribute__((noescape)) int *); // expected-note {{previous declaration is here}}
@@ -127,3 +128,27 @@
 -(void) m1:(int*) p {
 }
 @end
+
+struct S6 {
+  S6();
+  S6(const S6 &) = delete; // expected-note 3 {{'S6' has been explicitly marked deleted here}}
+  int f;
+};
+
+void test1() {
+  id a;
+  // __block variables that are not captured by escaping blocks don't
+  // necessitate having accessible copy constructors.
+  __block S6 b0;
+  __block S6 b1; // expected-error {{call to deleted constructor of 'S6'}}
+  __block S6 b2; // expected-error {{call to deleted constructor of 'S6'}}
+  __block S6 b3; // expected-error {{call to deleted constructor of 'S6'}}
+
+  noescapeFunc0(a, ^{ (void)b0; });
+  escapingFunc0(^{ (void)b1; });
+  {
+noescapeFunc0(a, ^{ (void)b0; (void)b1; });
+  }
+  noescapeFunc0(a, ^{ escapingFunc0(^{ (void)b2; }); });
+  escapingFunc0(^{ noescapeFunc0(a, ^{ (void)b3; }); });
+}
Index: test/SemaObjCXX/blocks.mm
===
--- test/SemaObjCXX/blocks.mm
+++ test/SemaObjCXX/blocks.mm
@@ -76,21 +76,27 @@
 }
 
 // Make sure we successfully instantiate the copy constructor of a
-// __block variable's type.
+// __block variable's type when the variable is captured by an escaping block.
 namespace N2 {
   template  struct A {
 A() {}
 A(const A &other) {
   int invalid[-n]; // expected-error 2 {{array with a negative size}}
 }
+void m() {}
   };
 
+  typedef void (^BlockFnTy)();
+  void func(BlockFnTy);
+
   void test1() {
 __block A<1> x; // expected-note {{requested here}}
+func(^{ x.m(); });
   }
 
   template  void test2() {
 __block A x; // expected-note {{requested here}}
+func(^{ x.m(); });
   }
   template void test2<2>();
 }
Index: test/PCH/block-helpers.cpp
===
--- test/PCH/block-helpers.cpp
+++ test/PCH/block-helpers.cpp
@@ -1,6 +1,26 @@
 // RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
 // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
 
+// CHECK: %[[STRUCT_BLOCK_BYREF_X:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_X]]*, i32, i32, i8*, i8*, %[[STRUCT_S0:.*]] }
+// CHECK: %[[STRUCT_S0]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_BYREF_Y:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_Y]]*, i32, i32, i8*, i8*, %[[STRUCT_S0]] }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+
+// Check that byref structs are allocated for x and y.
+
+// CHECK-LABEL: define linkonce_odr void @_ZN1S1mEv(
+// CHECK: %[[X:.*]] = alloca %[[STRUCT_BLOCK_BYREF_X]], align 8
+// CHECK: %[[Y:.*]] = alloca %[[STRUCT_BLOCK_BYREF_Y]], align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESC

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/Sema/SemaInit.cpp:1827-1829
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return false;
+  return true;

rsmith wrote:
> Usual Clang convention is to return `true` on error.
I also renamed the function to hasAccessibleDestructor to make it clearer what 
the function does.



Comment at: lib/Sema/SemaInit.cpp:1856
+if (auto *CXXRD = DeclType->getAsCXXRecordDecl()) {
+  SourceLocation Loc = IList->getBeginLoc();
+  for (auto &Base : Bases)

rsmith wrote:
> It's a minor thing, but I think it'd be preferable to point the diagnostic at 
> the relevant init list element, or at the close brace if the initializer was 
> omitted.
The function that checks the destructor (hasAccessibleDestructor) is called in 
five different places now.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 163871.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Point the diagnostic at either the relevant init list element or at the close 
brace.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,51 @@
   // amount of time.
   struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}};
 }
+
+namespace ElementDestructor {
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate initialization
+  // occurs. Produce a diagnostic if an element's destructor isn't accessible.
+
+  class X { int f; ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+
+  void test0() {
+auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}}
+  }
+
+  struct S0 { int f; ~S0() = delete; }; // expected-note 3 {{'~S0' has been explicitly marked deleted here}}
+  struct S1 { S0 s0; int f; };
+
+  S1 test1() {
+auto *t = new S1 { .f = 1 }; // expected-error {{attempt to use a deleted function}}
+return {2}; // expected-error {{attempt to use a deleted function}}
+  }
+
+  // Check if the type of an array element has a destructor.
+  struct S2 { S0 a[4]; };
+
+  void test2() {
+auto *t = new S2 {1,2,3,4}; // expected-error {{attempt to use a deleted function}}
+  }
+
+#if __cplusplus >= 201703L
+  namespace BaseDestructor {
+ struct S0 { int f; ~S0() = delete; }; // expected-note {{'~S0' has been explicitly marked deleted here}}
+
+// Check destructor of base class.
+struct S3 : S0 {};
+
+void test3() {
+  S3 s3 = {1}; // expected-error {{attempt to use a deleted function}}
+}
+  }
+#endif
+
+  // A's destructor doesn't have to be accessible from the context of C's
+  // initialization.
+  struct A { friend struct B; private: ~A(); };
+  struct B { B(); A a; };
+  struct C { B b; };
+  C c = { B() };
+}
Index: test/CodeGenObjCXX/arc-list-init-destruct.mm
===
--- /dev/null
+++ test/CodeGenObjCXX/arc-list-init-destruct.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc -fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[V0:.*]] = type opaque
+// CHECK: %[[STRUCT_CLASS1:.*]] = type { %[[V0]]* }
+
+@interface Class0;
+@end
+
+struct Class1 {
+  Class0 *f;
+};
+
+struct Container {
+  Class1 a;
+  bool b;
+};
+
+bool getBool() {
+  return false;
+}
+
+Class0 *g;
+
+// CHECK: define {{.*}} @_Z4testv()
+// CHECK: invoke zeroext i1 @_Z7getBoolv()
+// CHECK: landingpad { i8*, i32 }
+// CHECK: call void @_ZN6Class1D1Ev(%[[STRUCT_CLASS1]]* %{{.*}})
+// CHECK: br label
+
+// CHECK: define linkonce_odr void @_ZN6Class1D1Ev(
+
+Container test() {
+  return {{g}, getBool()};
+}
Index: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1818,6 +1818,30 @@
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
+/// Check if the type of a class element has an accessible destructor.
+///
+/// Aggregate initialization requires a class element's destructor be
+/// accessible per 11.6.1 [dcl.init.aggr]:
+///
+/// The destructor for each element of class type is potentially invoked
+/// (15.4 [class.dtor]) from the context where the aggregate initialization
+/// occurs.
+static bool hasAccessibleDestructor(QualType ElementType, SourceLocation Loc,
+Sema &SemaRef) {
+  auto *CXXRD = ElementType->getAsCXXRecordDecl();
+  if (!CXXRD)
+return false;
+
+  CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+  SemaRef.CheckDestructorAccess(Loc, Destructor,
+SemaRef.PDiag(diag::err_access_dtor_temp)
+<< ElementType);
+  SemaRef.MarkFunctionReferenced(Loc, Destructor);
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return true;
+  return false;
+}
+
 void InitListChecker::CheckStructUnionTypes(
 const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
 CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1838,6 +1862,15 @@
   if (DeclType->isUnionType() && IList->getNumInits() == 0) {
 RecordDecl *RD = DeclType->getAs()->getDecl();
 
+if (!VerifyOnly)
+  for (FieldDecl *FD : RD->fields()) {
+QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
+if (hasAccessibleDestructor(ET, IList->getEndLo

[PATCH] D51564: Distinguish `__block` variables that are captured by escaping blocks from those that aren't

2018-09-05 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: include/clang/AST/Decl.h:977
+
+unsigned EscapingByref : 1;
   };

rjmccall wrote:
> This doesn't actually seem to be initialized anywhere.
VarDecl's constructor in Decl.cpp initializes it to false.

```
  AllBits = 0;
  VarDeclBits.SClass = SC;
  // Everything else is implicitly initialized to false.
```



Comment at: lib/CodeGen/CGBlocks.cpp:497
+  return VD->isNonEscapingByref() ?
+ CGF.getContext().getLValueReferenceType(VD->getType()) : 
VD->getType();
 }

rjmccall wrote:
> Do you need to worry about the variable already having a reference type?
Yes, I found out that the previous patch didn't handle `__block` variables with 
reference types correctly and caused assertion failures. To fix this, I made 
changes in computeBlockInfo so that the `__block` qualifier is ignored if the 
variable already has a reference type (I'm treating `__block T&` as `T&` ). 
There are no changes to this function.



Comment at: lib/CodeGen/CGBlocks.cpp:1310
 
-  if (capture.fieldType()->isReferenceType())
+  if (capture.fieldType()->isReferenceType() || variable->isNonEscapingByref())
 addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType()));

rjmccall wrote:
> Isn't the field type already a reference type in this case?
> 
> You should leave a comment that you're relying on that, of course.
I added an assertion that checks non-escaping variable fields have reference 
types.



Comment at: lib/Sema/Sema.cpp:1451
+  // Call this function before popping the current function scope.
+  markEscapingByrefs(*FunctionScopes.back(), *this);
+

rjmccall wrote:
> Why before?
I remember I had to move the call to markEscapingByrefs to this place because 
it was making clang crash. It crashed when markEscapingByrefs triggered a call 
to PushFunctionScope, which caused clearing out PreallocatedFunctionScope, but 
I can't reproduce the crash anymore. I don't think markEscapingByrefs can cause 
PushFunctionScope to be called, so I'm moving the call back to the original 
location.


Repository:
  rC Clang

https://reviews.llvm.org/D51564



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51564: Distinguish `__block` variables that are captured by escaping blocks from those that aren't

2018-09-05 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 164069.
ahatanak marked 11 inline comments as done.
ahatanak added a comment.

Address review comments. Fix bugs in the handling of `__block` variables that 
have reference types.


Repository:
  rC Clang

https://reviews.llvm.org/D51564

Files:
  include/clang/AST/Decl.h
  include/clang/Sema/ScopeInfo.h
  lib/AST/Decl.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/ScopeInfo.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CodeGen/block-byref-aggr.c
  test/CodeGen/blocks-seq.c
  test/CodeGen/exceptions.c
  test/CodeGen/personality.c
  test/CodeGenCXX/block-capture.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/debug-info-blocks.cpp
  test/CodeGenCXX/noescape.cpp
  test/CodeGenObjC/arc-no-arc-exceptions.m
  test/CodeGenObjC/arc-unoptimized-byref-var.m
  test/CodeGenObjC/blocks-1.m
  test/CodeGenObjC/noescape.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/PCH/block-helpers.cpp
  test/SemaObjCXX/blocks.mm
  test/SemaObjCXX/noescape.mm

Index: test/SemaObjCXX/noescape.mm
===
--- test/SemaObjCXX/noescape.mm
+++ test/SemaObjCXX/noescape.mm
@@ -8,6 +8,7 @@
   void m();
 };
 
+void escapingFunc0(BlockTy);
 void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
 void noescapeFunc1(id, [[clang::noescape]] BlockTy);
 void noescapeFunc2(__attribute__((noescape)) int *); // expected-note {{previous declaration is here}}
@@ -127,3 +128,27 @@
 -(void) m1:(int*) p {
 }
 @end
+
+struct S6 {
+  S6();
+  S6(const S6 &) = delete; // expected-note 3 {{'S6' has been explicitly marked deleted here}}
+  int f;
+};
+
+void test1() {
+  id a;
+  // __block variables that are not captured by escaping blocks don't
+  // necessitate having accessible copy constructors.
+  __block S6 b0;
+  __block S6 b1; // expected-error {{call to deleted constructor of 'S6'}}
+  __block S6 b2; // expected-error {{call to deleted constructor of 'S6'}}
+  __block S6 b3; // expected-error {{call to deleted constructor of 'S6'}}
+
+  noescapeFunc0(a, ^{ (void)b0; });
+  escapingFunc0(^{ (void)b1; });
+  {
+noescapeFunc0(a, ^{ (void)b0; (void)b1; });
+  }
+  noescapeFunc0(a, ^{ escapingFunc0(^{ (void)b2; }); });
+  escapingFunc0(^{ noescapeFunc0(a, ^{ (void)b3; }); });
+}
Index: test/SemaObjCXX/blocks.mm
===
--- test/SemaObjCXX/blocks.mm
+++ test/SemaObjCXX/blocks.mm
@@ -76,21 +76,27 @@
 }
 
 // Make sure we successfully instantiate the copy constructor of a
-// __block variable's type.
+// __block variable's type when the variable is captured by an escaping block.
 namespace N2 {
   template  struct A {
 A() {}
 A(const A &other) {
   int invalid[-n]; // expected-error 2 {{array with a negative size}}
 }
+void m() {}
   };
 
+  typedef void (^BlockFnTy)();
+  void func(BlockFnTy);
+
   void test1() {
 __block A<1> x; // expected-note {{requested here}}
+func(^{ x.m(); });
   }
 
   template  void test2() {
 __block A x; // expected-note {{requested here}}
+func(^{ x.m(); });
   }
   template void test2<2>();
 }
Index: test/PCH/block-helpers.cpp
===
--- test/PCH/block-helpers.cpp
+++ test/PCH/block-helpers.cpp
@@ -1,6 +1,26 @@
 // RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
 // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
 
+// CHECK: %[[STRUCT_BLOCK_BYREF_X:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_X]]*, i32, i32, i8*, i8*, %[[STRUCT_S0:.*]] }
+// CHECK: %[[STRUCT_S0]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_BYREF_Y:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_Y]]*, i32, i32, i8*, i8*, %[[STRUCT_S0]] }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+
+// Check that byref structs are allocated for x and y.
+
+// CHECK-LABEL: define linkonce_odr void @_ZN1S1mEv(
+// CHECK: %[[X:.*]] = alloca %[[STRUCT_BLOCK_BYREF_X]], align 8
+// CHECK: %[[Y:.*]] = alloca %[[STRUCT_BLOCK_BYREF_Y]], align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_BLOCK_BYREF_X]]* %[[X]] to i8*
+// CHECK: store i8* %[[V0]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: %[[BLOCK_CAPTURED10:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, 

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-06 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC341629: [Sema] Check that the destructor for each element of 
class type is (authored by ahatanak, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,51 @@
   // amount of time.
   struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}};
 }
+
+namespace ElementDestructor {
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate initialization
+  // occurs. Produce a diagnostic if an element's destructor isn't accessible.
+
+  class X { int f; ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+
+  void test0() {
+auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}}
+  }
+
+  struct S0 { int f; ~S0() = delete; }; // expected-note 3 {{'~S0' has been explicitly marked deleted here}}
+  struct S1 { S0 s0; int f; };
+
+  S1 test1() {
+auto *t = new S1 { .f = 1 }; // expected-error {{attempt to use a deleted function}}
+return {2}; // expected-error {{attempt to use a deleted function}}
+  }
+
+  // Check if the type of an array element has a destructor.
+  struct S2 { S0 a[4]; };
+
+  void test2() {
+auto *t = new S2 {1,2,3,4}; // expected-error {{attempt to use a deleted function}}
+  }
+
+#if __cplusplus >= 201703L
+  namespace BaseDestructor {
+ struct S0 { int f; ~S0() = delete; }; // expected-note {{'~S0' has been explicitly marked deleted here}}
+
+// Check destructor of base class.
+struct S3 : S0 {};
+
+void test3() {
+  S3 s3 = {1}; // expected-error {{attempt to use a deleted function}}
+}
+  }
+#endif
+
+  // A's destructor doesn't have to be accessible from the context of C's
+  // initialization.
+  struct A { friend struct B; private: ~A(); };
+  struct B { B(); A a; };
+  struct C { B b; };
+  C c = { B() };
+}
Index: test/CodeGenObjCXX/arc-list-init-destruct.mm
===
--- test/CodeGenObjCXX/arc-list-init-destruct.mm
+++ test/CodeGenObjCXX/arc-list-init-destruct.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc -fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[V0:.*]] = type opaque
+// CHECK: %[[STRUCT_CLASS1:.*]] = type { %[[V0]]* }
+
+@interface Class0;
+@end
+
+struct Class1 {
+  Class0 *f;
+};
+
+struct Container {
+  Class1 a;
+  bool b;
+};
+
+bool getBool() {
+  return false;
+}
+
+Class0 *g;
+
+// CHECK: define {{.*}} @_Z4testv()
+// CHECK: invoke zeroext i1 @_Z7getBoolv()
+// CHECK: landingpad { i8*, i32 }
+// CHECK: call void @_ZN6Class1D1Ev(%[[STRUCT_CLASS1]]* %{{.*}})
+// CHECK: br label
+
+// CHECK: define linkonce_odr void @_ZN6Class1D1Ev(
+
+Container test() {
+  return {{g}, getBool()};
+}
Index: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1818,6 +1818,30 @@
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
+/// Check if the type of a class element has an accessible destructor.
+///
+/// Aggregate initialization requires a class element's destructor be
+/// accessible per 11.6.1 [dcl.init.aggr]:
+///
+/// The destructor for each element of class type is potentially invoked
+/// (15.4 [class.dtor]) from the context where the aggregate initialization
+/// occurs.
+static bool hasAccessibleDestructor(QualType ElementType, SourceLocation Loc,
+Sema &SemaRef) {
+  auto *CXXRD = ElementType->getAsCXXRecordDecl();
+  if (!CXXRD)
+return false;
+
+  CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+  SemaRef.CheckDestructorAccess(Loc, Destructor,
+SemaRef.PDiag(diag::err_access_dtor_temp)
+<< ElementType);
+  SemaRef.MarkFunctionReferenced(Loc, Destructor);
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return true;
+  return false;
+}
+
 void InitListChecker::CheckStructUnionTypes(
 const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
 CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1838,6 +1862,15 @@
   if (DeclType->isUnionType() && IList->getNumInits() == 0) {
 RecordDecl *RD = DeclType->getAs()->getDecl();
 
+if (!VerifyOnly)
+  for (FieldDecl *FD : RD->fields()) {
+QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
+if (hasA

[PATCH] D51564: Distinguish `__block` variables that are captured by escaping blocks from those that aren't

2018-09-08 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL341754: Distinguish `__block` variables that are captured by 
escaping blocks (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D51564?vs=164069&id=164576#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D51564

Files:
  cfe/trunk/include/clang/AST/Decl.h
  cfe/trunk/include/clang/Sema/ScopeInfo.h
  cfe/trunk/lib/AST/Decl.cpp
  cfe/trunk/lib/CodeGen/CGBlocks.cpp
  cfe/trunk/lib/CodeGen/CGClass.cpp
  cfe/trunk/lib/CodeGen/CGDecl.cpp
  cfe/trunk/lib/CodeGen/CGExpr.cpp
  cfe/trunk/lib/CodeGen/CodeGenFunction.h
  cfe/trunk/lib/Sema/ScopeInfo.cpp
  cfe/trunk/lib/Sema/Sema.cpp
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaExpr.cpp
  cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
  cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
  cfe/trunk/test/CodeGen/block-byref-aggr.c
  cfe/trunk/test/CodeGen/blocks-seq.c
  cfe/trunk/test/CodeGen/exceptions.c
  cfe/trunk/test/CodeGen/personality.c
  cfe/trunk/test/CodeGenCXX/block-capture.cpp
  cfe/trunk/test/CodeGenCXX/blocks.cpp
  cfe/trunk/test/CodeGenCXX/debug-info-blocks.cpp
  cfe/trunk/test/CodeGenCXX/noescape.cpp
  cfe/trunk/test/CodeGenObjC/arc-no-arc-exceptions.m
  cfe/trunk/test/CodeGenObjC/arc-unoptimized-byref-var.m
  cfe/trunk/test/CodeGenObjC/blocks-1.m
  cfe/trunk/test/CodeGenObjC/noescape.m
  cfe/trunk/test/CodeGenObjCXX/arc-blocks.mm
  cfe/trunk/test/PCH/block-helpers.cpp
  cfe/trunk/test/SemaObjCXX/blocks.mm
  cfe/trunk/test/SemaObjCXX/noescape.mm

Index: cfe/trunk/lib/CodeGen/CGDecl.cpp
===
--- cfe/trunk/lib/CodeGen/CGDecl.cpp
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp
@@ -1212,8 +1212,8 @@
 
   AutoVarEmission emission(D);
 
-  bool isByRef = D.hasAttr();
-  emission.IsByRef = isByRef;
+  bool isEscapingByRef = D.isEscapingByref();
+  emission.IsEscapingByRef = isEscapingByRef;
 
   CharUnits alignment = getContext().getDeclAlign(&D);
 
@@ -1252,8 +1252,8 @@
   // in OpenCL.
   if ((!getLangOpts().OpenCL ||
Ty.getAddressSpace() == LangAS::opencl_constant) &&
-  (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
-   CGM.isTypeConstant(Ty, true))) {
+  (CGM.getCodeGenOpts().MergeAllConstants && !NRVO &&
+   !isEscapingByRef && CGM.isTypeConstant(Ty, true))) {
 EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
 
 // Signal this condition to later callbacks.
@@ -1305,7 +1305,7 @@
 } else {
   CharUnits allocaAlignment;
   llvm::Type *allocaTy;
-  if (isByRef) {
+  if (isEscapingByRef) {
 auto &byrefInfo = getBlockByrefInfo(&D);
 allocaTy = byrefInfo.Type;
 allocaAlignment = byrefInfo.ByrefAlignment;
@@ -1505,7 +1505,7 @@
   }
 
   // Initialize the structure of a __block variable.
-  if (emission.IsByRef)
+  if (emission.IsEscapingByRef)
 emitByrefStructureInit(emission);
 
   // Initialize the variable here if it doesn't have a initializer and it is a
@@ -1515,7 +1515,7 @@
   type.isNonTrivialToPrimitiveDefaultInitialize() ==
   QualType::PDIK_Struct) {
 LValue Dst = MakeAddrLValue(emission.getAllocatedAddress(), type);
-if (emission.IsByRef)
+if (emission.IsEscapingByRef)
   drillIntoBlockVariable(*this, Dst, &D);
 defaultInitNonTrivialCStructVar(Dst);
 return;
@@ -1527,7 +1527,7 @@
   // Check whether this is a byref variable that's potentially
   // captured and moved by its own initializer.  If so, we'll need to
   // emit the initializer first, then copy into the variable.
-  bool capturedByInit = emission.IsByRef && isCapturedBy(D, Init);
+  bool capturedByInit = emission.IsEscapingByRef && isCapturedBy(D, Init);
 
   Address Loc =
 capturedByInit ? emission.Addr : emission.getObjectAddress(*this);
@@ -1721,7 +1721,8 @@
   // If this is a block variable, call _Block_object_destroy
   // (on the unforwarded address). Don't enter this cleanup if we're in pure-GC
   // mode.
-  if (emission.IsByRef && CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
+  if (emission.IsEscapingByRef &&
+  CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
 BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF;
 if (emission.Variable->getType().isObjCGCWeak())
   Flags |= BLOCK_FIELD_IS_WEAK;
Index: cfe/trunk/lib/CodeGen/CGExpr.cpp
===
--- cfe/trunk/lib/CodeGen/CGExpr.cpp
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp
@@ -2486,7 +2486,7 @@
   }
 
   assert(isa(CurCodeDecl));
-  Address addr = GetAddrOfBlockDecl(VD, VD->hasAttr());
+  Address addr = GetAddrOfBlockDecl(VD);
   return MakeAddrLValue(addr, T, AlignmentSource::Decl);
 }
   }
@@ -2538,7 +2538,7 @@
 }
 
 // Drill into block byref variables.
-bool isBlockByref = VD->hasAttr();
+bool isBlockByref =

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 156332.
ahatanak added a comment.

Fix a bug where the capture cleanups weren't pushed when 
BlockDecl::doesNotEscape() returns true.

Test that, when ARC is enabled, captures are retained and copied into the stack 
block object and destroyed when the stack block object goes out of scope.


Repository:
  rC Clang

https://reviews.llvm.org/D49303

Files:
  docs/Block-ABI-Apple.rst
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: lib/CodeGen/CGBlocks.h
===
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
   BLOCK_HAS_CXX_OBJ =   (1 << 26),
   BLOCK_IS_GLOBAL = (1 << 28),
@@ -214,7 +215,8 @@
   ///

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 156404.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Add a comment that explains the meaning of BLOCK_IS_NOESCAPE to the docs. 
Rename function needsCopyDispose to needsCopyDisposeHelpers.


Repository:
  rC Clang

https://reviews.llvm.org/D49303

Files:
  docs/Block-ABI-Apple.rst
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  test/CodeGenObjC/noescape.m

Index: test/CodeGenObjC/noescape.m
===
--- test/CodeGenObjC/noescape.m
+++ test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: lib/CodeGen/CGBlocks.h
===
--- lib/CodeGen/CGBlocks.h
+++ lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
   BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
   BLOCK_HAS_CXX_OBJ =   (1 << 26),
   BLOCK_IS_GLOBAL = (1 << 28),
@@ -214,7 +215,8 @@
   /// no non-constant captures.
   bool CanBeGlobal : 1;
 
-  /// True if the blo

[PATCH] D49303: [CodeGen][ObjC] Treat non-escaping blocks as global blocks to make copy/dispose a no-op

2018-07-20 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
ahatanak marked an inline comment as done.
Closed by commit rL337580: [CodeGen][ObjC] Make copying and disposing of a 
non-escaping block (authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D49303?vs=156404&id=156530#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D49303

Files:
  cfe/trunk/docs/Block-ABI-Apple.rst
  cfe/trunk/lib/CodeGen/CGBlocks.cpp
  cfe/trunk/lib/CodeGen/CGBlocks.h
  cfe/trunk/test/CodeGenObjC/noescape.m

Index: cfe/trunk/test/CodeGenObjC/noescape.m
===
--- cfe/trunk/test/CodeGenObjC/noescape.m
+++ cfe/trunk/test/CodeGenObjC/noescape.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-NOARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -fobjc-arc -o - %s | FileCheck -check-prefix CHECK -check-prefix CHECK-ARC %s
 
 typedef void (^BlockTy)(void);
 
@@ -12,6 +13,12 @@
 void noescapeFunc2(__attribute__((noescape)) id);
 void noescapeFunc3(__attribute__((noescape)) union U);
 
+// Block descriptors of non-escaping blocks don't need pointers to copy/dispose
+// helper functions.
+
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*]] = internal constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
+
 // CHECK-LABEL: define void @test0(
 // CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
 // CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
@@ -69,3 +76,41 @@
   ^(int *__attribute__((noescape)) p0){}(p);
   b(p);
 }
+
+// If the block is non-escaping, set the BLOCK_IS_NOESCAPE and BLOCK_IS_GLOBAL
+// bits of field 'flags' and set the 'isa' field to 'NSConcreteGlobalBlock'.
+
+// CHECK: define void @test6(i8* %{{.*}}, i8* %[[B:.*]])
+// CHECK: %{{.*}} = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK-NOARC: store i8* %[[B]], i8** %[[B_ADDR]], align 8
+// CHECK-ARC: store i8* null, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* %[[B]])
+// CHECK-ARC: %[[V0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[BLOCK_ISA:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 0
+// CHECK: store i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i8** %[[BLOCK_ISA]], align 8
+// CHECK: %[[BLOCK_FLAGS:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 1
+// CHECK: store i32 -796917760, i32* %[[BLOCK_FLAGS]], align 8
+// CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 4
+// CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @[[BLOCK_DESCIPTOR_TMP_2]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
+// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: call void @noescapeFunc0(
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
+// CHECK-ARC: call void @objc_storeStrong(i8** %[[B_ADDR]], i8* null)
+
+// Non-escaping blocks don't need copy/dispose helper functions.
+
+// CHECK-NOT: define internal void @__copy_helper_block_
+// CHECK-NOT: define internal void @__destroy_helper_block_
+
+void func(id);
+
+void test6(id a, id b) {
+  noescapeFunc0(a, ^{ func(b); });
+}
Index: cfe/trunk/lib/CodeGen/CGBlocks.h
===
--- cfe/trunk/lib/CodeGen/CGBlocks.h
+++ cfe/trunk/lib/CodeGen/CGBlocks.h
@@ -54,6 +54,7 @@
 };
 
 enum BlockLiteralFlags {
+  BLOCK_IS_NOESCAPE  =  (1 << 23),
 

[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-23 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added a reviewer: rjmccall.
Herald added a subscriber: dexonsmith.

Block copy/dispose helper functions currently aren’t exception-safe. When an 
exception is thrown in a copy function, the function exits without destroying 
or releasing C++ objects, ObjC objects, and `__block` objects that have already 
been copied. Similarly, dispose functions don't release ObjC objects and 
`__block objects` that are yet to be released when an exception is thrown.


Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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]], %

[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-23 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Note that in order to destruct C++ objects, I'm using pushDestroy which pushes 
a NormalCleanup when exception handling isn't enabled. This is different from 
PushDestructorCleanup which always pushes a NormalAndEHCleanup, but I think 
using pushDestroy is more correct since I don't think we need to do a cleanup 
on the EH path when exception isn't enabled.


Repository:
  rC Clang

https://reviews.llvm.org/D49718



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-24 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157095.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.

I think I should be able to merge pushBlockObjectRelease and enterByrefCleanup, 
but the BlockFieldFlags that are passed are different. We set 
BLOCK_FIELD_IS_WEAK in addition to BLOCK_FIELD_IS_BYREF when isObjCGCWeak() 
returns true and we are emitting the copy/dispose helper functions, but when 
enterByrefCleanup is called from EmitAutoVarCleanups, only BLOCK_FIELD_IS_BYREF 
is set.

In https://reviews.llvm.org/D49718#1173068, @rjmccall wrote:

> I don't think it makes any difference because we shouldn't be emitting 
> cleanup paths when exceptions are disabled.  I don't think there's an 
> intended difference in semantics between those two destructor-cleanup paths, 
> at least.


OK, I see.

If it doesn't make any difference, I think I can push NormalAndEHCleanup 
unconditionally when copying a BlockObject capture instead of pushing 
NormalCleanup when EH is disabled. I made that change in the updated patch.


Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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: 

[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-24 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1905
+case BlockCaptureEntityKind::None:
+  llvm_unreachable("unexpected BlockCaptureEntityKind");
 }

rjmccall wrote:
> These two switches differ only in (1) what kind of cleanup they push and (2) 
> a small optimization that can easily be conditionalized by the request to 
> push an EH-only cleanup.
Merged the two switch statements into helper function pushCaptureCleanup.


Repository:
  rC Clang

https://reviews.llvm.org/D49718



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-24 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157149.
ahatanak added a comment.

Merge pushBlockObjectRelease and enterByrefCleanup.

In https://reviews.llvm.org/D49718#1174113, @rjmccall wrote:

> Heh, okay.  It looks like the runtime doesn't do anything different, but I 
> think it's probably more correct to always pass `BLOCK_FIELD_IS_WEAK` when 
> destroying a `__weak` block in GC modes.


I tried passing `BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF` to the call to 
enterByrefCleanup in EmitAutoVarCleanups, but it looks like 
test/CodeGenObjC/blocks.m fails if I do so. The test was committed in r125823 
and there is a comment that says " We're not supposed to pass 
BLOCK_FIELD_IS_WEAK here".

http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20110214/038996.html

Should we change the check in the test?


Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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*, %[[S

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157373.
ahatanak added a comment.

Check if destructors are accessible from InitListChecker's constructor. Add 
test cases for designated initializer and brace elision.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,24 @@
   // amount of time.
   struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}};
 }
+
+namespace ElementDestructor {
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate initialization
+  // occurs. Produce a diagnostic if an element's destructor isn't accessible.
+
+  class X { int f; ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+
+  void test0() {
+auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}}
+  }
+
+  struct S0 { int f; ~S0() = delete; }; // expected-note 2 {{'~S0' has been explicitly marked deleted here}}
+  struct S1 { S0 s0; int f; };
+
+  S1 test1() {
+auto *t = new S1 { .f = 1 }; // expected-error {{attempt to use a deleted function}}
+return {2}; // expected-error {{attempt to use a deleted function}}
+  }
+}
Index: test/CodeGenObjCXX/arc-list-init-destruct.mm
===
--- /dev/null
+++ test/CodeGenObjCXX/arc-list-init-destruct.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc -fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[V0:.*]] = type opaque
+// CHECK: %[[STRUCT_CLASS1:.*]] = type { %[[V0]]* }
+
+@interface Class0;
+@end
+
+struct Class1 {
+  Class0 *f;
+};
+
+struct Container {
+  Class1 a;
+  bool b;
+};
+
+bool getBool() {
+  return false;
+}
+
+Class0 *g;
+
+// CHECK: define {{.*}} @_Z4testv()
+// CHECK: invoke zeroext i1 @_Z7getBoolv()
+// CHECK: landingpad { i8*, i32 }
+// CHECK: call void @_ZN6Class1D1Ev(%[[STRUCT_CLASS1]]* %{{.*}})
+// CHECK: br label
+
+// CHECK: define linkonce_odr void @_ZN6Class1D1Ev(
+
+Container test() {
+  return {{g}, getBool()};
+}
Index: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -815,6 +815,27 @@
   }
 }
 
+static bool checkMemberDestructor(CXXRecordDecl *CXXRD, QualType RecType,
+  SourceLocation Loc, bool IsMember,
+  Sema &SemaRef) {
+  if (IsMember) {
+CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+SemaRef.CheckDestructorAccess(
+Loc, Destructor, SemaRef.PDiag(diag::err_access_dtor_temp) << RecType);
+SemaRef.MarkFunctionReferenced(Loc, Destructor);
+if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+  return false;
+  }
+
+  for (FieldDecl *FD : CXXRD->fields())
+if (auto *CXXRDMember = FD->getType()->getAsCXXRecordDecl())
+  if (!checkMemberDestructor(CXXRDMember, FD->getType(), Loc, true,
+ SemaRef))
+return false;
+
+  return true;
+}
+
 InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
  InitListExpr *IL, QualType &T,
  bool VerifyOnly,
@@ -838,6 +859,16 @@
 if (RequiresSecondPass && !hadError)
   FillInEmptyInitializations(Entity, FullyStructuredList,
  RequiresSecondPass, nullptr, 0);
+
+// Check if destructors of members are accessible.
+//
+// The destructor for each element of class type is potentially invoked
+// (15.4 [class.dtor]) from the context where the aggregate
+// initialization occurs.
+if (auto *CXXRD = T->getAsCXXRecordDecl())
+  if (!checkMemberDestructor(CXXRD, T, IL->getLocStart(),
+ /*IsMember*/ false, S))
+hadError = true;
   }
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157380.
ahatanak added a comment.

Set the BLOCK_FIELD_IS_WEAK bit of the flag passed to the call to 
enterByrefCleanup in EmitAutoVarCleanups and fix test case 
test/CodeGenObjC/blocks.m.


Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenObjC/blocks.m
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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: in

[PATCH] D47757: [Sema] Produce diagnostics when unavailable aligned allocation/deallocation functions are called

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D47757



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157395.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Document the meaning of enterByrefCleanup's parameters.


Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenObjC/blocks.m
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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: invoke void @_ZN5test12S0C1ERKS0_(%[[STRUCT_TEST1_S0]]* %

[PATCH] D49119: [Sema][ObjC] Issue a warning when a method declared in a protocol is non-escaping but the corresponding method in the implementation is escaping.

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157398.
ahatanak added a comment.

Add a test case for an interface conforming to a non-escaping protocol.

In https://reviews.llvm.org/D49119#1164285, @vsapsai wrote:

> Also I had a few ideas for tests when the warning isn't required and it is 
> absent. But I'm not sure they are actually valuable. If you are interested, 
> we can discuss it in more details.


Could you elaborate on what kind of tests you have in mind?

> Another feedback is an idea for potential improvement: have a note pointing 
> to the place where protocol conformity is declared. Currently the warning 
> looks like
> 
>   code_review.m:16:19: warning: parameter of overriding method should be 
> annotated with __attribute__((noescape))
> [-Wmissing-noescape]
>   -(void) m0:(int*) p { // expected-warning {{parameter of overriding method 
> should be annotated with __attri...
> ^
>   code_review.m:2:44: note: parameter of overridden method is annotated with 
> __attribute__((noescape))
>   -(void) m0:(int*)__attribute__((noescape)) p; // expected-note {{parameter 
> of overridden method is annotate...
>  ^
> 
> 
> and we can see the method both in implementation and in protocol. But in some 
> cases it might be unclear where exactly that protocol was added to your 
> class. I'm not sure this change is sufficiently useful, it's more for 
> discussion.

I think it's possible to add a note that helps the user find where the category 
conforming to the non-escaping protocol is declared.


Repository:
  rC Clang

https://reviews.llvm.org/D49119

Files:
  lib/Sema/SemaDeclObjC.cpp
  test/SemaObjCXX/noescape.mm


Index: test/SemaObjCXX/noescape.mm
===
--- test/SemaObjCXX/noescape.mm
+++ test/SemaObjCXX/noescape.mm
@@ -88,3 +88,30 @@
 
   S5<&noescapeFunc2> ne1;
 }
+
+@protocol NoescapeProt
+-(void) m0:(int*)__attribute__((noescape)) p; // expected-note 2 {{parameter 
of overridden method is annotated with __attribute__((noescape))}}
+@end
+
+__attribute__((objc_root_class))
+@interface C3
+-(void) m0:(int*) p;
+@end
+
+@interface C3 () 
+@end
+
+@implementation C3
+-(void) m0:(int*) p { // expected-warning {{parameter of overriding method 
should be annotated with __attribute__((noescape))}}
+}
+@end
+
+__attribute__((objc_root_class))
+@interface C4 
+-(void) m0:(int*) p; // expected-warning {{parameter of overriding method 
should be annotated with __attribute__((noescape))}}
+@end
+
+@implementation C4
+-(void) m0:(int*) p {
+}
+@end
Index: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -109,6 +109,16 @@
   return true;
 }
 
+static void diagnoseNoescape(const ParmVarDecl *NewMD, const ParmVarDecl 
*OldMD,
+ Sema &S) {
+  // A parameter of the overriding method should be annotated with noescape
+  // if the corresponding parameter of the overridden method is annotated.
+  if (OldMD->hasAttr() && !NewMD->hasAttr()) {
+S.Diag(NewMD->getLocation(), 
diag::warn_overriding_method_missing_noescape);
+S.Diag(OldMD->getLocation(), diag::note_overridden_marked_noescape);
+  }
+}
+
 void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
const ObjCMethodDecl *Overridden) {
   if (Overridden->hasRelatedResultType() && 
@@ -192,13 +202,7 @@
   Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
 }
 
-// A parameter of the overriding method should be annotated with noescape
-// if the corresponding parameter of the overridden method is annotated.
-if (oldDecl->hasAttr() && !newDecl->hasAttr()) 
{
-  Diag(newDecl->getLocation(),
-   diag::warn_overriding_method_missing_noescape);
-  Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
-}
+diagnoseNoescape(newDecl, oldDecl, *this);
   }
 }
 
@@ -4643,6 +4647,22 @@
 << ObjCMethod->getDeclName();
 }
   }
+
+  // Warn if a method declared in a protocol to which a category or
+  // extension conforms is non-escaping and the implementation's method is
+  // escaping.
+  for (auto *C : IDecl->visible_categories())
+for (auto &P : C->protocols())
+  if (auto *IMD = P->lookupMethod(ObjCMethod->getSelector(),
+  ObjCMethod->isInstanceMethod())) {
+assert(ObjCMethod->parameters().size() ==
+   IMD->parameters().size() &&
+   "Methods have different number of parameters");
+auto OI = IMD->param_begin(), OE = IMD->param_end();
+auto NI = ObjCMethod->param_begin();
+for (; OI != OE; ++OI, ++NI)
+  diagnoseNoescape(*NI, *OI, *this);
+  }
 }
   } else {
 cast(ClassDecl)->addDecl(Ob

[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:2582
 /// yet; if a cleanup is required for the variable itself, that needs
 /// to be done externally.
+void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr,

rjmccall wrote:
> Please document the meaning of the parameters here.
One more question: I think documentation comments for public APIs are normally 
in the header file. Should we move these comments to CodeGenFunction.h? 


Repository:
  rC Clang

https://reviews.llvm.org/D49718



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49718: [CodeGen][ObjC] Make block copy/dispose helper function exception-safe.

2018-07-26 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC338041: [CodeGen][ObjC] Make block copy/dispose helper 
functions exception-safe. (authored by ahatanak, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D49718?vs=157395&id=157514#toc

Repository:
  rC Clang

https://reviews.llvm.org/D49718

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenObjC/blocks.m
  test/CodeGenObjCXX/arc-blocks.mm

Index: test/CodeGenObjC/blocks.m
===
--- test/CodeGenObjC/blocks.m
+++ test/CodeGenObjC/blocks.m
@@ -79,10 +79,9 @@
   // Then we initialize the block, blah blah blah.
   // CHECK:  call void @test2_helper(
 
-  // Finally, kill the variable with BLOCK_FIELD_IS_BYREF.  We're not
-  // supposed to pass BLOCK_FIELD_IS_WEAK here.
+  // Finally, kill the variable with BLOCK_FIELD_IS_BYREF.
   // CHECK:  [[T0:%.*]] = bitcast [[WEAK_T]]* [[WEAKX]] to i8*
-  // CHECK:  call void @_Block_object_dispose(i8* [[T0]], i32 8)
+  // CHECK:  call void @_Block_object_dispose(i8* [[T0]], i32 24)
 
   __attribute__((objc_gc(weak))) __block Test2 *weakX = x;
   test2_helper(^{ [weakX destroy]; });
Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %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 -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
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
 
@@ -47,3 +50,133 @@
   // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
   // CHECK-NEXT: ret void
 }
+
+namespace test1 {
+
+// 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: %[[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: %[[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: 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

[PATCH] D49119: [Sema][ObjC] Issue a warning when a method declared in a protocol is non-escaping but the corresponding method in the implementation is escaping.

2018-07-27 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Thanks, I'll update the patch and commit it today.

In https://reviews.llvm.org/D49119#1176139, @vsapsai wrote:

> In https://reviews.llvm.org/D49119#1176047, @ahatanak wrote:
>
> > In https://reviews.llvm.org/D49119#1164285, @vsapsai wrote:
> >
> > > Also I had a few ideas for tests when the warning isn't required and it 
> > > is absent. But I'm not sure they are actually valuable. If you are 
> > > interested, we can discuss it in more details.
> >
> >
> > Could you elaborate on what kind of tests you have in mind?
>
>
>
>
> - declaring `noescape` on implementation when nothing like that was mentioned 
> in interface or protocols;


Maybe we should consider this, but I don't think this is incorrect 
functionally. If you pass an object to such methods, clang's IRGen will just 
emit the unoptimized code that is emitted for calls to functions/methods taking 
escaping parameters (e.g., no 'nocapture' on parameters, no stack block 
optimization implemented in r337580). The opposite case (non-escaping interface 
and escaping implementation) is incorrect and can cause problems, so we need 
some diagnostics.

> - have class method and instance method with the same name, only one of them 
> is `noescape`, test that we don't show spurious warning in this case;

I can add a test case for this.

> - try selector names that look similar but are different, like `-foo`, 
> `-foo:`, `-foo::` This test suggestion isn't really related to `noescape`, I 
> just got carried away.




Repository:
  rC Clang

https://reviews.llvm.org/D49119



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49119: [Sema][ObjC] Issue a warning when a method declared in a protocol is non-escaping but the corresponding method in the implementation is escaping.

2018-07-27 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157815.
ahatanak added a comment.

- Produce a note that tells users where the class extension conforming to the 
protocol containing the non-escaping method is declared.
- Add a class method that has the same name as the instance method and check 
that no spurious warnings are issued.


Repository:
  rC Clang

https://reviews.llvm.org/D49119

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclObjC.cpp
  test/SemaObjCXX/noescape.mm

Index: test/SemaObjCXX/noescape.mm
===
--- test/SemaObjCXX/noescape.mm
+++ test/SemaObjCXX/noescape.mm
@@ -88,3 +88,42 @@
 
   S5<&noescapeFunc2> ne1;
 }
+
+@protocol NoescapeProt
+-(void) m0:(int*)__attribute__((noescape)) p; // expected-note 2 {{parameter of overridden method is annotated with __attribute__((noescape))}}
++(void) m1:(int*)__attribute__((noescape)) p;
+-(void) m1:(int*) p;
+@end
+
+__attribute__((objc_root_class))
+@interface C3
+-(void) m0:(int*) p;
++(void) m1:(int*)__attribute__((noescape)) p;
+-(void) m1:(int*) p;
+@end
+
+@interface C3 ()  // expected-note {{class extension conforms to protocol 'NoescapeProt' which defines method 'm0:'}}
+@end
+
+@implementation C3
+-(void) m0:(int*) p { // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+}
++(void) m1:(int*)__attribute__((noescape)) p {
+}
+-(void) m1:(int*) p {
+}
+@end
+
+__attribute__((objc_root_class))
+@interface C4 
+-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+@end
+
+@implementation C4
+-(void) m0:(int*) p {
+}
++(void) m1:(int*)__attribute__((noescape)) p {
+}
+-(void) m1:(int*) p {
+}
+@end
Index: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -109,6 +109,30 @@
   return true;
 }
 
+/// Issue a warning if the parameter of the overridden method is non-escaping
+/// but the parameter of the overriding method is not.
+static bool diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
+ Sema &S) {
+  if (OldD->hasAttr() && !NewD->hasAttr()) {
+S.Diag(NewD->getLocation(), diag::warn_overriding_method_missing_noescape);
+S.Diag(OldD->getLocation(), diag::note_overridden_marked_noescape);
+return false;
+  }
+
+  return true;
+}
+
+/// Produce additional diagnostics if a category conforms to a protocol that
+/// defines a method taking a non-escaping parameter.
+static void diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
+ const ObjCCategoryDecl *CD,
+ const ObjCProtocolDecl *PD, Sema &S) {
+  if (!diagnoseNoescape(NewD, OldD, S))
+S.Diag(CD->getLocation(), diag::note_cat_conform_to_noescape_prot)
+<< CD->IsClassExtension() << PD
+<< cast(NewD->getDeclContext());
+}
+
 void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
const ObjCMethodDecl *Overridden) {
   if (Overridden->hasRelatedResultType() && 
@@ -192,13 +216,7 @@
   Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
 }
 
-// A parameter of the overriding method should be annotated with noescape
-// if the corresponding parameter of the overridden method is annotated.
-if (oldDecl->hasAttr() && !newDecl->hasAttr()) {
-  Diag(newDecl->getLocation(),
-   diag::warn_overriding_method_missing_noescape);
-  Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
-}
+diagnoseNoescape(newDecl, oldDecl, *this);
   }
 }
 
@@ -4643,6 +4661,22 @@
 << ObjCMethod->getDeclName();
 }
   }
+
+  // Warn if a method declared in a protocol to which a category or
+  // extension conforms is non-escaping and the implementation's method is
+  // escaping.
+  for (auto *C : IDecl->visible_categories())
+for (auto &P : C->protocols())
+  if (auto *IMD = P->lookupMethod(ObjCMethod->getSelector(),
+  ObjCMethod->isInstanceMethod())) {
+assert(ObjCMethod->parameters().size() ==
+   IMD->parameters().size() &&
+   "Methods have different number of parameters");
+auto OI = IMD->param_begin(), OE = IMD->param_end();
+auto NI = ObjCMethod->param_begin();
+for (; OI != OE; ++OI, ++NI)
+  diagnoseNoescape(*NI, *OI, C, P, *this);
+  }
 }
   } else {
 cast(ClassDecl)->addDecl(ObjCMethod);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1733,6 +1733,8 @@
   "__attribute__((noescape

[PATCH] D49119: [Sema][ObjC] Issue a warning when a method declared in a protocol is non-escaping but the corresponding method in the implementation is escaping.

2018-07-27 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC338189: [Sema][ObjC] Warn when a method declared in a 
protocol takes a (authored by ahatanak, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D49119

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclObjC.cpp
  test/SemaObjCXX/noescape.mm

Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1733,6 +1733,8 @@
   "__attribute__((noescape))">, InGroup;
 def note_overridden_marked_noescape : Note<
   "parameter of overridden method is annotated with __attribute__((noescape))">;
+def note_cat_conform_to_noescape_prot : Note<
+  "%select{category|class extension}0 conforms to protocol %1 which defines method %2">;
 
 def err_covariant_return_inaccessible_base : Error<
   "invalid covariant return for virtual function: %1 is a "
Index: test/SemaObjCXX/noescape.mm
===
--- test/SemaObjCXX/noescape.mm
+++ test/SemaObjCXX/noescape.mm
@@ -88,3 +88,42 @@
 
   S5<&noescapeFunc2> ne1;
 }
+
+@protocol NoescapeProt
+-(void) m0:(int*)__attribute__((noescape)) p; // expected-note 2 {{parameter of overridden method is annotated with __attribute__((noescape))}}
++(void) m1:(int*)__attribute__((noescape)) p;
+-(void) m1:(int*) p;
+@end
+
+__attribute__((objc_root_class))
+@interface C3
+-(void) m0:(int*) p;
++(void) m1:(int*)__attribute__((noescape)) p;
+-(void) m1:(int*) p;
+@end
+
+@interface C3 ()  // expected-note {{class extension conforms to protocol 'NoescapeProt' which defines method 'm0:'}}
+@end
+
+@implementation C3
+-(void) m0:(int*) p { // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+}
++(void) m1:(int*)__attribute__((noescape)) p {
+}
+-(void) m1:(int*) p {
+}
+@end
+
+__attribute__((objc_root_class))
+@interface C4 
+-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+@end
+
+@implementation C4
+-(void) m0:(int*) p {
+}
++(void) m1:(int*)__attribute__((noescape)) p {
+}
+-(void) m1:(int*) p {
+}
+@end
Index: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -109,6 +109,30 @@
   return true;
 }
 
+/// Issue a warning if the parameter of the overridden method is non-escaping
+/// but the parameter of the overriding method is not.
+static bool diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
+ Sema &S) {
+  if (OldD->hasAttr() && !NewD->hasAttr()) {
+S.Diag(NewD->getLocation(), diag::warn_overriding_method_missing_noescape);
+S.Diag(OldD->getLocation(), diag::note_overridden_marked_noescape);
+return false;
+  }
+
+  return true;
+}
+
+/// Produce additional diagnostics if a category conforms to a protocol that
+/// defines a method taking a non-escaping parameter.
+static void diagnoseNoescape(const ParmVarDecl *NewD, const ParmVarDecl *OldD,
+ const ObjCCategoryDecl *CD,
+ const ObjCProtocolDecl *PD, Sema &S) {
+  if (!diagnoseNoescape(NewD, OldD, S))
+S.Diag(CD->getLocation(), diag::note_cat_conform_to_noescape_prot)
+<< CD->IsClassExtension() << PD
+<< cast(NewD->getDeclContext());
+}
+
 void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
const ObjCMethodDecl *Overridden) {
   if (Overridden->hasRelatedResultType() && 
@@ -192,13 +216,7 @@
   Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
 }
 
-// A parameter of the overriding method should be annotated with noescape
-// if the corresponding parameter of the overridden method is annotated.
-if (oldDecl->hasAttr() && !newDecl->hasAttr()) {
-  Diag(newDecl->getLocation(),
-   diag::warn_overriding_method_missing_noescape);
-  Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
-}
+diagnoseNoescape(newDecl, oldDecl, *this);
   }
 }
 
@@ -4643,6 +4661,22 @@
 << ObjCMethod->getDeclName();
 }
   }
+
+  // Warn if a method declared in a protocol to which a category or
+  // extension conforms is non-escaping and the implementation's method is
+  // escaping.
+  for (auto *C : IDecl->visible_categories())
+for (auto &P : C->protocols())
+  if (auto *IMD = P->lookupMethod(ObjCMethod->getSelector(),
+  ObjCMethod->isInstanceMethod())) {
+assert(ObjCMethod->parameters().size() ==
+   IMD->parameters().size() &&
+   "Methods have different number of parameters");
+auto

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-01 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rjmccall, arphaman.
Herald added subscribers: dexonsmith, mgrang.

Currently, clang generates different copy or dispose helper functions for each 
block literal on the stack if the block has the possibility of being copied to 
the heap. This patch makes changes to merge equivalent copy and dispose helper 
functions and reduce code size.

To enable merging equivalent copy/dispose functions, the types and offsets of 
the captured objects are encoded into the helper function name. This allows 
IRGen to check whether an equivalent helper function has already been emitted 
and reuse the function instead of generating a new helper function whenever a 
block is defined. In addition, the helper functions are marked as 
`linkonce_odr` to enable merging helper functions that have the same name 
across translation units and marked as `unnamed_addr` to enable the linker's 
deduplication pass to merge functions that have different names but the same 
content.

rdar://problem/22950898


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define linkonce_odr hidden 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,5 +1,6 @@
 // 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 }
@@ -55,10 +56,16 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_s_32_b8_40_w_48_c2S0_56_c2S0_60(
 // 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: %[[V9:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*,

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-01 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: test/CodeGenCXX/block-byref-cxx-objc.cpp:36
+// CHECK: call void @_Block_object_dispose(
+
+int testB() {

Should the second call to @_Block_object_dispose be an invoke if the destructor 
can throw? The FIXME in CodeGenFunction::BuildBlockRelease seems to imply that 
we should consider whether the destructor can throw.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-01 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: test/CodeGenCXX/block-byref-cxx-objc.cpp:36
+// CHECK: call void @_Block_object_dispose(
+
+int testB() {

ahatanak wrote:
> Should the second call to @_Block_object_dispose be an invoke if the 
> destructor can throw? The FIXME in CodeGenFunction::BuildBlockRelease seems 
> to imply that we should consider whether the destructor can throw.
I mean the first call, not the second call. If the call to A's destructor 
throws when the first object is being destructed, the second object should be 
destructed on the EH path.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-01 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 158640.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Use llvm::sort.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define linkonce_odr hidden 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,5 +1,6 @@
 // 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 }
@@ -55,10 +56,16 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_s_32_b8_40_w_48_c2S0_56_c2S0_60(
 // 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: %[[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: %[[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

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 158774.
ahatanak marked 3 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define linkonce_odr hidden 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,5 +1,6 @@
 // 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 }
@@ -55,10 +56,16 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_s_32_b8_40_w_48_c20_ZN5test12S0C1ERKS0__56_c20_ZN5test12S0C1ERKS0__60(
 // 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: %[[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: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TE

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1638
+switch (E.Kind) {
+case BlockCaptureEntityKind::CXXRecord: {
+  Name += "c";

rjmccall wrote:
> I forget whether this case has already filtered out trivial 
> copy-constructors, but if not, you should consider doing that here.
E.Kind is set to CXXRecord only when the copy constructor is non-trivial (or 
the destructor is non-trivial if this is a destroy helper). Both 
computeCopyInfoForBlockCapture and computeDestroyInfoForBlockCapture filter out 
types with trivial copy constructors or destructors.



Comment at: lib/CodeGen/CGBlocks.cpp:1647
+unsigned Qs;
+cast(CE)->getConstructor()->isCopyConstructor(Qs);
+if (Qs & Qualifiers::Volatile)

rjmccall wrote:
> This doesn't always have to be a copy constructor.  I mean, maybe this 
> procedure works anyway, but the constructor used to copy an object isn't 
> always a copy constructor.  Blame constructor templates.
I've made changes to use the name of the constructor function that is used to 
copy the capture instead of using the volatility of the copy constructor's 
argument.

I'm not sure when a function that is not a copy constructor would be used to 
copy a captured object though. The comment in function captureInBlock in 
SemaExpr.cpp says that the the blocks spec requires a const copy constructor.



Comment at: lib/CodeGen/CGBlocks.cpp:1651
+  }
+  std::string Str = CaptureTy->getAsCXXRecordDecl()->getName();
+  Name += llvm::to_string(Str.size()) + Str;

rjmccall wrote:
> The name of a C++ class is not unique; you need to use the mangler.   
> Ideally, you would find a way to mangle all the C++ types in the context of 
> the same mangler instance so that substitutions could be reused across it.
> 
> You also need to check for a type with non-external linkage and make this 
> helper private if you find one.  (You can still unique within the translation 
> unit, for what it's worth.)
Good catch. test/CodeGenCXX/blocks.cpp checks that helper functions for blocks 
that capture non-external types have internal linkage.


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50205: [libc++] Add availability markup for aligned new/delete

2018-08-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

I just wanted to make sure that this doesn't have the same problem as 
https://reviews.llvm.org/D34556. Is that correct?

The patch was reverted in r306859. https://reviews.llvm.org/D34574#791158 
explains why the approach taken in the patch was wrong.


Repository:
  rCXX libc++

https://reviews.llvm.org/D50205



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 158892.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @"__copy_helper_block_
 // CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_"
 // CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_"
 // CHECK: call void @_ZN8CopyableC1ERKS_
Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,8 +1,10 @@
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s
+// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
 // CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
@@ -55,34 +57,34 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
-// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
-// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_s_32_b8_40_w_48_c15_ZTSN5test12S0E_56_c15_ZTSN5test12S0E_60(
+// 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*

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:492
+if (!RD->isExternallyVisible())
+  info.CapturesNonExternalType = true;
+

rjmccall wrote:
> You only need to do this if you're going to mangle the type name, i.e. if 
> it's actually going to end up as a CXXRecord capture.   It should be easy 
> enough to just set this flag above in the clauses where you recognize 
> interesting C++ record captures.
I modified the test case in test/CodeGenObjCXX/arc-blocks.mm to check that 
capturing a trivial C++ class doesn't cause the helper functions to be 
internal. 


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 159250.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D50152

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGBlocks.h
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/blocks-1.c
  test/CodeGen/blocks.c
  test/CodeGen/sanitize-thread-no-checking-at-run-time.m
  test/CodeGenCXX/block-byref-cxx-objc.cpp
  test/CodeGenCXX/blocks.cpp
  test/CodeGenCXX/cxx-block-objects.cpp
  test/CodeGenObjC/arc-blocks.m
  test/CodeGenObjC/debug-info-block-helper.m
  test/CodeGenObjC/debug-info-blocks.m
  test/CodeGenObjC/mrc-weak.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/CodeGenObjCXX/arc-blocks.mm
  test/CodeGenObjCXX/lambda-to-block.mm
  test/CodeGenObjCXX/mrc-weak.mm

Index: test/CodeGenObjCXX/mrc-weak.mm
===
--- test/CodeGenObjCXX/mrc-weak.mm
+++ test/CodeGenObjCXX/mrc-weak.mm
@@ -119,10 +119,10 @@
 // CHECK:   call void @use_block
 // CHECK:   call void @objc_destroyWeak
 
-// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block
 // CHECK:   @objc_copyWeak
 
-// CHECK-LABEL: define internal void @__destroy_helper_block
+// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block
 // CHECK:   @objc_destroyWeak
 
 void test8(void) {
@@ -142,8 +142,8 @@
 // CHECK:   call void @objc_destroyWeak
 
 // CHECK-LABEL: define void @_Z14test9_baselinev()
-// CHECK:   define internal void @__copy_helper
-// CHECK:   define internal void @__destroy_helper
+// CHECK:   define linkonce_odr hidden void @__copy_helper
+// CHECK:   define linkonce_odr hidden void @__destroy_helper
 void test9_baseline(void) {
   Foo *p = get_object();
   use_block(^{ [p run]; });
Index: test/CodeGenObjCXX/lambda-to-block.mm
===
--- test/CodeGenObjCXX/lambda-to-block.mm
+++ test/CodeGenObjCXX/lambda-to-block.mm
@@ -12,7 +12,7 @@
 void hasLambda(Copyable x) {
   takesBlock([x] () { });
 }
-// CHECK-LABEL: define internal void @__copy_helper_block_
+// CHECK-LABEL: define internal void @"__copy_helper_block_
 // CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_"
 // CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_"
 // CHECK: call void @_ZN8CopyableC1ERKS_
Index: test/CodeGenObjCXX/arc-blocks.mm
===
--- test/CodeGenObjCXX/arc-blocks.mm
+++ test/CodeGenObjCXX/arc-blocks.mm
@@ -1,8 +1,10 @@
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -o - %s | FileCheck -check-prefix CHECK %s
 // RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -fexceptions -fobjc-arc-exceptions -O1 -o - %s | FileCheck -check-prefix CHECK-O1 %s
+// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s
 
 // CHECK: [[A:.*]] = type { i64, [10 x i8*] }
 // CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
+// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
 
 // CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
@@ -55,34 +57,34 @@
 
 // Check that copy/dispose helper functions are exception safe.
 
-// CHECK-LABEL: define internal void @__copy_helper_block_(
-// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
-// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>*
+// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_ea8_32s40b48w56c15_ZTSN5test12S0E60c15_ZTSN5test12S0E(
+// CHECK: %[[BLOCK_SOURCE:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
+// CHECK: %[[BLOCK_DEST:.*]] = bitcast i8* %{{.*}} to <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]], %[[STRUCT_TRIVIAL_INTERNAL]] }>*
 
-// CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8*, %[[STRUCT_TEST1_S0]], %[[STRUCT_TEST1_S0]] }>* %[[BLOCK_SOURCE]], i32 0, i32 6
-// CHECK: %[[V5:.*]] = getelementptr 

[PATCH] D50152: [CodeGen] Merge equivalent block copy/helper functions

2018-08-06 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/CodeGen/CGBlocks.cpp:1691
+
+Name += "_" + llvm::to_string(E.Capture->getOffset().getQuantity());
+  }

rjmccall wrote:
> I feel like this reads a little better if you write the quantity first.  Also 
> I think you can drop the underscore because all of your suffices are easy to 
> compute the length of, so a block that captures 3 strong variables can just 
> be `32s40s48s` or something like that.
> 
> Oh, I guess if you do that you need to do something about how you handle the 
> bit-mask for `BlockObject`, because that could run into the next number.  
> Would it be better to just break this out into cases?  The three current 
> cases are (1) `__block` variables, which can throw, (2) blocks, and (3) 
> object references in non-ARC modes (which for copy/dispose purposes are just 
> `s` again, except we use a different entrypoint because we hadn't exposed 
> `objc_retain` and `objc_release` yet).
I broke this out into several cases based on the flag's value and whether the 
constructor or destructor of a C++ type can throw.



Comment at: test/CodeGenCXX/block-byref-cxx-objc.cpp:36
+// CHECK: call void @_Block_object_dispose(
+
+int testB() {

rjmccall wrote:
> ahatanak wrote:
> > ahatanak wrote:
> > > Should the second call to @_Block_object_dispose be an invoke if the 
> > > destructor can throw? The FIXME in CodeGenFunction::BuildBlockRelease 
> > > seems to imply that we should consider whether the destructor can throw.
> > I mean the first call, not the second call. If the call to A's destructor 
> > throws when the first object is being destructed, the second object should 
> > be destructed on the EH path.
> Yes, I think we should assume that the block runtime correctly propagates 
> exceptions.  The function should not be marked `nothrow`, but call sites can 
> be marked `nothrow` depending on what they do.
> 
> This won't generally be a code-size problem because (1) we do assume that the 
> ObjC retain/release and weak operations can't throw and (2) C++11 makes 
> destructors `noexcept` by default.
I defined two functions, cxxDestructorCanThrow and cxxConstructorCanThrow, that 
are called to find out whether the `__block` object has a destructor or 
constructor that can throw.  

These functions can return true even when the destructor or constructor cannot 
throw, but that should be conservatively correct ('invoke' is emitted in some 
cases even when the function doesn't throw).


Repository:
  rC Clang

https://reviews.llvm.org/D50152



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D41039: Add support for attribute "trivial_abi"

2018-02-05 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
ahatanak marked 2 inline comments as done.
Closed by commit rC324269: Add support for attribute 'trivial_abi'. 
(authored by ahatanak, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D41039?vs=129397&id=132880#toc

Repository:
  rC Clang

https://reviews.llvm.org/D41039

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/Decl.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/Type.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/DeclCXX.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaType.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CodeGenCXX/trivial_abi.cpp
  test/CodeGenObjCXX/trivial_abi.mm
  test/Misc/pragma-attribute-supported-attributes-list.test
  test/SemaObjCXX/attr-trivial-abi.mm

Index: include/clang/Sema/Sema.h
===
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2236,7 +2236,17 @@
 
   bool CheckNontrivialField(FieldDecl *FD);
   void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM);
+
+  enum TrivialABIHandling {
+/// The triviality of a method unaffected by "trivial_abi".
+TAH_IgnoreTrivialABI,
+
+/// The triviality of a method affected by "trivial_abi".
+TAH_ConsiderTrivialABI
+  };
+
   bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+  TrivialABIHandling TAH = TAH_IgnoreTrivialABI,
   bool Diagnose = false);
   CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
   void ActOnLastBitfield(SourceLocation DeclStart,
@@ -5796,6 +5806,11 @@
   SourceLocation BaseLoc);
 
   void CheckCompletedCXXClass(CXXRecordDecl *Record);
+
+  /// Check that the C++ class annoated with "trivial_abi" satisfies all the
+  /// conditions that are needed for the attribute to have an effect.
+  void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD);
+
   void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
  Decl *TagDecl,
  SourceLocation LBrac,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2881,6 +2881,9 @@
 def err_invalid_attribute_on_virtual_function : Error<
   "%0 attribute cannot be applied to virtual functions">;
 
+def ext_cannot_use_trivial_abi : ExtWarn<
+  "'trivial_abi' cannot be applied to %0">, InGroup;
+
 // Availability attribute
 def warn_availability_unknown_platform : Warning<
   "unknown platform %0 in availability macro">, InGroup;
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2242,6 +2242,48 @@
   }];
 }
 
+def TrivialABIDocs : Documentation {
+  let Category = DocCatVariable;
+  let Content = [{
+The ``trivial_abi`` attribute can be applied to a C++ class, struct, or union.
+It instructs the compiler to pass and return the type using the C ABI for the
+underlying type when the type would otherwise be considered non-trivial for the
+purpose of calls.
+A class annotated with `trivial_abi` can have non-trivial destructors or copy/move constructors without automatically becoming non-trivial for the purposes of calls. For example:
+
+  .. code-block:: c++
+
+// A is trivial for the purposes of calls because `trivial_abi` makes the
+// user-provided special functions trivial.
+struct __attribute__((trivial_abi)) A {
+  ~A();
+  A(const A &);
+  A(A &&);
+  int x;
+};
+
+// B's destructor and copy/move constructor are considered trivial for the
+// purpose of calls because A is trivial.
+struct B {
+  A a;
+};
+
+If a type is trivial for the purposes of calls, has a non-trivial destructor,
+and is passed as an argument by value, the convention is that the callee will
+destroy the object before returning.
+
+Attribute ``trivial_abi`` has no effect in the following cases:
+
+- The class directly declares a virtual base or virtual methods.
+- The class has a base class that is non-trivial for the purposes of calls.
+- The class has a non-static data member whose type is non-trivial for the
+purposes of calls, which includes:
+ - classes that are non-trivial for the purposes of calls
+ - __weak-qualified types in Objective-C++

[PATCH] D41039: Add support for attribute "trivial_abi"

2018-02-05 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL324269: Add support for attribute 'trivial_abi'. 
(authored by ahatanak, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D41039?vs=129397&id=132881#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D41039

Files:
  cfe/trunk/include/clang/AST/ASTContext.h
  cfe/trunk/include/clang/AST/Decl.h
  cfe/trunk/include/clang/AST/DeclCXX.h
  cfe/trunk/include/clang/AST/Type.h
  cfe/trunk/include/clang/Basic/Attr.td
  cfe/trunk/include/clang/Basic/AttrDocs.td
  cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/AST/ASTContext.cpp
  cfe/trunk/lib/AST/DeclCXX.cpp
  cfe/trunk/lib/AST/Type.cpp
  cfe/trunk/lib/CodeGen/CGCall.cpp
  cfe/trunk/lib/CodeGen/CGDecl.cpp
  cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
  cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
  cfe/trunk/lib/Sema/SemaChecking.cpp
  cfe/trunk/lib/Sema/SemaDeclAttr.cpp
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
  cfe/trunk/lib/Sema/SemaType.cpp
  cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
  cfe/trunk/lib/Serialization/ASTWriter.cpp
  cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
  cfe/trunk/test/CodeGenCXX/trivial_abi.cpp
  cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm
  cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
  cfe/trunk/test/SemaObjCXX/attr-trivial-abi.mm

Index: cfe/trunk/include/clang/AST/DeclCXX.h
===
--- cfe/trunk/include/clang/AST/DeclCXX.h
+++ cfe/trunk/include/clang/AST/DeclCXX.h
@@ -437,14 +437,25 @@
 /// which have been declared but not yet defined.
 unsigned HasTrivialSpecialMembers : 6;
 
+/// These bits keep track of the triviality of special functions for the
+/// purpose of calls. Only the bits corresponding to SMF_CopyConstructor,
+/// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+unsigned HasTrivialSpecialMembersForCall : 6;
+
 /// \brief The declared special members of this class which are known to be
 /// non-trivial.
 ///
 /// This excludes any user-declared but not user-provided special members
 /// which have been declared but not yet defined, and any implicit special
 /// members which have not yet been declared.
 unsigned DeclaredNonTrivialSpecialMembers : 6;
 
+/// These bits keep track of the declared special members that are
+/// non-trivial for the purpose of calls.
+/// Only the bits corresponding to SMF_CopyConstructor,
+/// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+unsigned DeclaredNonTrivialSpecialMembersForCall : 6;
+
 /// \brief True when this class has a destructor with no semantic effect.
 unsigned HasIrrelevantDestructor : 1;
 
@@ -1349,28 +1360,50 @@
 return data().HasTrivialSpecialMembers & SMF_CopyConstructor;
   }
 
+  bool hasTrivialCopyConstructorForCall() const {
+return data().HasTrivialSpecialMembersForCall & SMF_CopyConstructor;
+  }
+
   /// \brief Determine whether this class has a non-trivial copy constructor
   /// (C++ [class.copy]p6, C++11 [class.copy]p12)
   bool hasNonTrivialCopyConstructor() const {
 return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor ||
!hasTrivialCopyConstructor();
   }
 
+  bool hasNonTrivialCopyConstructorForCall() const {
+return (data().DeclaredNonTrivialSpecialMembersForCall &
+SMF_CopyConstructor) ||
+   !hasTrivialCopyConstructorForCall();
+  }
+
   /// \brief Determine whether this class has a trivial move constructor
   /// (C++11 [class.copy]p12)
   bool hasTrivialMoveConstructor() const {
 return hasMoveConstructor() &&
(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
   }
 
+  bool hasTrivialMoveConstructorForCall() const {
+return hasMoveConstructor() &&
+   (data().HasTrivialSpecialMembersForCall & SMF_MoveConstructor);
+  }
+
   /// \brief Determine whether this class has a non-trivial move constructor
   /// (C++11 [class.copy]p12)
   bool hasNonTrivialMoveConstructor() const {
 return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
(needsImplicitMoveConstructor() &&
 !(data().HasTrivialSpecialMembers & SMF_MoveConstructor));
   }
 
+  bool hasNonTrivialMoveConstructorForCall() const {
+return (data().DeclaredNonTrivialSpecialMembersForCall &
+SMF_MoveConstructor) ||
+   (needsImplicitMoveConstructor() &&
+!(data().HasTrivialSpecialMembersForCall & SMF_MoveConstructor));
+  }
+
   /// \brief Determine whether this class has a trivial copy assignment operator
   /// (C++ [class.copy]p11, C++11 [class.copy]p25)
   bool hasTrivialCopyAssignment() const {
@@ -1405,12 +1438,25 @@
 return data().HasTrivialSpecialMembers & SMF_Destructor;
   }

[PATCH] D42776: [Sema] Fix an assertion failure in constant expression evaluation of calls to functions with default arguments

2018-02-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/AST/ExprConstant.cpp:1165-1173
+  auto LB = Temporaries.lower_bound(Key);
+
+  // If an element with key Key is found, reset the value and return it. This
+  // can happen if Key is part of a default argument expression.
+  if (LB != Temporaries.end() && LB->first == Key)
+return LB->second = APValue();
+

erik.pilkington wrote:
> I think that the problem is more subtle than this. This static assert errors 
> (previously clang would assert) when it really it should be fine.
> ```
> constexpr const int &x(const int &p = 0) { return p; }
> static_assert(&x() != &x());
> ```
> Because default arguments are allocated on the caller side, both the calls to 
> `x()` call createTemporary for the same MaterializeTemporaryExpr in the same 
> CallStackFrame, when really that MTE should correspond to two distinct 
> values. This patch just hides that underlying problem by recycling the value 
> created during the first call during the second call.
> 
> Maybe we could have a fancier key that incorporates a node on the caller 
> side, such as the CXXDefaultArgExpr as well at the MTE, and store that fancy 
> key in APValue::LValueBases? That would allow us generate distinct values for 
> these MTEs, and also remember what expression originated it. What do you 
> think about that?
> 
> There is small discussion about this problem here: 
> https://bugs.llvm.org/show_bug.cgi?id=33140
Thank you Erik for explaining the problem and pointing me to the PR. 

I ended up using a version number that is updated every time 
VisitCXXDefaultArgExpr is called. I initially tried using CXXDefaultArgExpr and 
the void* pointer as the key, but discovered that that wouldn't fix the 
assertion failure when compiling the first test case in PR33140 since 
InitListExpr uses the same CXXConstructExpr (and hence the same 
CXXDefaultArgExpr) to initialize the array.

Let me know if there are other cases I haven't thought about.



Comment at: test/SemaCXX/constexpr-default-arg.cpp:3
+
+// expected-no-diagnostics
+

lebedev.ri wrote:
> Down the line, it won't be obvious *what* this testcase is checking.
> At the very least wrap it into `namespace rdar_problem_36505742 {}`
I added comments that explain what it's trying to check.


https://reviews.llvm.org/D42776



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42776: [Sema] Fix an assertion failure in constant expression evaluation of calls to functions with default arguments

2018-02-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 133947.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address Erik's and Roman's review comments.


https://reviews.llvm.org/D42776

Files:
  include/clang/AST/APValue.h
  lib/AST/APValue.cpp
  lib/AST/ExprConstant.cpp
  test/SemaCXX/constexpr-default-arg.cpp

Index: test/SemaCXX/constexpr-default-arg.cpp
===
--- /dev/null
+++ test/SemaCXX/constexpr-default-arg.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+namespace default_arg_temporary {
+
+constexpr bool equals(const float& arg = 1.0f) {
+  return arg == 1.0f;
+}
+
+constexpr const int &x(const int &p = 0) {
+  return p;
+}
+
+struct S {
+  constexpr S(const int &a = 0) {}
+};
+
+void test_default_arg2() {
+  // This piece of code used to cause an assertion failure in
+  // CallStackFrame::createTemporary because the same MTE is used to initilize
+  // both elements of the array (see PR33140).
+  constexpr S s[2] = {};
+
+  // This piece of code used to cause an assertion failure in
+  // CallStackFrame::createTemporary because multiple CXXDefaultArgExpr share
+  // the same MTE (see PR33140).
+  static_assert(equals() && equals(), "");
+
+  // Test that constant expression evaluation produces distinct lvalues for
+  // each call.
+  static_assert(&x() != &x(), "");
+}
+
+}
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -438,7 +438,8 @@
 
 // Note that we intentionally use std::map here so that references to
 // values are stable.
-typedef std::map MapTy;
+typedef std::pair KeyTy;
+typedef std::map MapTy;
 typedef MapTy::const_iterator temp_iterator;
 /// Temporaries - Temporary lvalues materialized within this stack frame.
 MapTy Temporaries;
@@ -465,11 +466,12 @@
APValue *Arguments);
 ~CallStackFrame();
 
-APValue *getTemporary(const void *Key) {
-  MapTy::iterator I = Temporaries.find(Key);
+APValue *getTemporary(const void *Key, unsigned Version = 0) {
+  MapTy::iterator I = Temporaries.find(KeyTy(Key, Version));
   return I == Temporaries.end() ? nullptr : &I->second;
 }
-APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
+APValue &createTemporary(const void *Key, bool IsLifetimeExtended,
+ unsigned Version = 0);
   };
 
   /// Temporarily override 'this'.
@@ -584,6 +586,17 @@
 /// initialized after CurrentCall and CallStackDepth.
 CallStackFrame BottomFrame;
 
+/// Keep track of the version of MTEs that are used by CXXDefaultArgExpr.
+/// The version number is updated every time VisitCXXDefaultArgExpr is
+/// called.
+unsigned getDefaultArgNum() const { return CurDefaultArgNum; }
+void setDefaultArgNum() {
+  assert(CurDefaultArgNum == 0 && "CurDefaultArgNum hasn't been cleared");
+  CurDefaultArgNum = ++NextDefaultArgNum;
+}
+void clearDefaultArgNum() { CurDefaultArgNum = 0; }
+unsigned CurDefaultArgNum = 0, NextDefaultArgNum = 0;
+
 /// A stack of values whose lifetimes end at the end of some surrounding
 /// evaluation frame.
 llvm::SmallVector CleanupStack;
@@ -1161,8 +1174,9 @@
 }
 
 APValue &CallStackFrame::createTemporary(const void *Key,
- bool IsLifetimeExtended) {
-  APValue &Result = Temporaries[Key];
+ bool IsLifetimeExtended,
+ unsigned Version) {
+  APValue &Result = Temporaries[KeyTy(Key, Version)];
   assert(Result.isUninit() && "temporary created multiple times");
   Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
   return Result;
@@ -3147,7 +3161,7 @@
 return CompleteObject();
   }
 } else {
-  BaseVal = Frame->getTemporary(Base);
+  BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
   assert(BaseVal && "missing value for temporary");
 }
 
@@ -4529,6 +4543,17 @@
 
   bool ZeroInitialization(const Expr *E) { return Error(E); }
 
+  struct DefaultArgRAII {
+EvalInfo &Info;
+
+DefaultArgRAII(EvalInfo &Info) : Info(Info) {
+  Info.setDefaultArgNum();
+}
+~DefaultArgRAII() {
+  Info.clearDefaultArgNum();
+}
+  };
+
 public:
   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
 
@@ -4563,8 +4588,10 @@
 { return StmtVisitorTy::Visit(E->getResultExpr()); }
   bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
 { return StmtVisitorTy::Visit(E->getReplacement()); }
-  bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
-{ return StmtVisitorTy::Visit(E->getExpr()); }
+  bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
+DefaultArgRAII RAII(Info);
+return StmtVisitorTy::Visit(E->getExpr()

[PATCH] D42776: [Sema] Fix an assertion failure in constant expression evaluation of calls to functions with default arguments

2018-02-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/AST/ExprConstant.cpp:597
+}
+void clearDefaultArgNum() { CurDefaultArgNum = 0; }
+unsigned CurDefaultArgNum = 0, NextDefaultArgNum = 0;

rsmith wrote:
> This is wrong: these scopes can nest, so you can't just reset the number to 0 
> when you're done. You should restore the prior number when you're done here, 
> to divide up evaluation into CXXDefaultArgExpr scopes. (Technically, I think 
> it would also be correct to leave the number alone when you leave one of 
> these scopes, but only because a scope for a particular parameter's default 
> argument can't nest within another scope for the same default argument 
> expression -- and even that might not be true in the presence of template 
> instantiation.)
Do you mean VisitCXXDefaultArgExpr can be called the second time before the 
first call returns? Do you have an example code that would cause that to happen 
(which I can perhaps add as a test case)?

It seemed to me that that would happen only if you used a lambda expression for 
the default argument, but I thought the current standard doesn't allow using 
lambda expressions in constant expressions.


https://reviews.llvm.org/D42776



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42776: [Sema] Fix an assertion failure in constant expression evaluation of calls to functions with default arguments

2018-02-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

OK, I see. It's pretty easy to come up with an example.

  constexpr int foo1(int a = 12) {
return a * a;
  }
  
  constexpr int foo2(int a = foo1()) {
return a - 12;
  }


https://reviews.llvm.org/D42776



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D41228: [ObjC] Enable __strong pointers in structs under ARC

2018-02-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 133994.
ahatanak marked 8 inline comments as done.
ahatanak added a comment.

Address review comments and feedback I got from John offline.

The main changes are in CGNonTrivialStruct.cpp. I cleaned up the class 
hierarchy and used variadic template functions in CGNonTrivialStruct.cpp to 
enable sharing code between the class creating the function name and the class 
emitting IR for the special functions. I also made changes so that memset is 
used instead of a loop to default-initialize a large array (see 
test_constructor_destructor_IDArray in test/CodeGenObjC/strong-in-c-struct.m).


https://reviews.llvm.org/D41228

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Decl.h
  include/clang/AST/Type.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ASTContext.cpp
  lib/AST/Decl.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGDeclCXX.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CMakeLists.txt
  lib/CodeGen/CodeGenFunction.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/JumpDiagnostics.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  test/ARCMT/checking.m
  test/CodeGenObjC/nontrivial-c-struct-exception.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/Lexer/has_feature_objc_arc.m
  test/SemaObjC/arc-decls.m
  test/SemaObjC/arc-system-header.m
  test/SemaObjC/strong-in-c-struct.m

Index: test/SemaObjC/strong-in-c-struct.m
===
--- /dev/null
+++ test/SemaObjC/strong-in-c-struct.m
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks  -fobjc-runtime=ios-11.0 -fsyntax-only -verify %s
+
+typedef struct {
+  id a;
+} Strong;
+
+void callee_variadic(const char *, ...);
+
+void test_variadic(void) {
+  Strong t;
+  callee_variadic("s", t); // expected-error {{cannot pass non-trivial C object of type 'Strong' by value to variadic function}}
+}
+
+void test_jump0(int cond) {
+  switch (cond) {
+  case 0:
+;
+Strong x; // expected-note {{jump bypasses initialization of variable of non-trivial C struct type}}
+break;
+  case 1: // expected-error {{cannot jump from switch statement to this case label}}
+x.a = 0;
+break;
+  }
+}
+
+void test_jump1(void) {
+  static void *ips[] = { &&L0 };
+L0:  // expected-note {{possible target of indirect goto}}
+  ;
+  Strong x; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+  goto *ips; // expected-error {{cannot jump}}
+}
+
+typedef void (^BlockTy)(void);
+void func(BlockTy);
+void func2(Strong);
+
+void test_block_scope0(int cond) {
+  Strong x; // expected-note {{jump enters lifetime of block which captures a C struct that is non-trivial to destroy}}
+  switch (cond) {
+  case 0:
+func(^{ func2(x); });
+break;
+  default: // expected-error {{cannot jump from switch statement to this case label}}
+break;
+  }
+}
+
+void test_block_scope1(void) {
+  static void *ips[] = { &&L0 };
+L0:  // expected-note {{possible target of indirect goto}}
+  ;
+  Strong x; // expected-note {{jump exits scope of variable with non-trivial destructor}} expected-note {{jump exits lifetime of block which captures a C struct that is non-trivial to destroy}}
+  func(^{ func2(x); });
+  goto *ips; // expected-error {{cannot jump}}
+}
Index: test/SemaObjC/arc-system-header.m
===
--- test/SemaObjC/arc-system-header.m
+++ test/SemaObjC/arc-system-header.m
@@ -23,8 +23,7 @@
 }
 
 void test5(struct Test5 *p) {
-  p->field = 0; // expected-error {{'field' is unavailable in ARC}}
-// expected-note@arc-system-header.h:25 {{field has non-trivial ownership qualification}}
+  p->field = 0;
 }
 
 id test6() {
@@ -49,8 +48,7 @@
 
 extern void doSomething(Test9 arg);
 void test9() {
-Test9 foo2 = {0, 0}; // expected-error {{'field' is unavailable in ARC}}
- // expected-note@arc-system-header.h:56 {{field has non-trivial ownership qualification}}
+Test9 foo2 = {0, 0};
 doSomething(foo2);
 }
 #endif
Index: test/SemaObjC/arc-decls.m
===
--- test/SemaObjC/arc-decls.m
+++ test/SemaObjC/arc-decls.m
@@ -3,7 +3,7 @@
 // rdar://8843524
 
 struct A {
-id x; // expected-error {{ARC forbids Objective-C objects in struct}}
+id x;
 };
 
 union u {
@@ -13,7 +13,7 @@
 @interface I {
struct A a; 
struct B {
-id y[10][20]; // expected-error {{ARC forbids Objective-C objects in struct}}
+id y[10][20];
 id z;
} b;
 
@@ -23,7 +23,7 @@
 
 // rdar://10260525
 struct r10260525 {
-  id (^block) (); // expected-error {{ARC forbids blocks in struct}}
+  id (^block) ();
 };
 
 struct S { 
Index: test/Lexer/has_feature_objc_arc.m
===
--- test/Lexer/has_feature_objc_arc.

[PATCH] D10831: Attach attribute "trap-func-name" to IR function

2018-02-14 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

AMDGPUAnnotateKernelFeatures::addFeatureAttributes looks for an llvm.trap 
instruction and adds attribute "amdgpu-queue-ptr" to the function if it finds 
one.

Other than that, it looks like your idea would work too.


Repository:
  rL LLVM

https://reviews.llvm.org/D10831



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   6   7   8   9   10   >