[PATCH] D58164: Block+lambda: allow reference capture

2020-03-09 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe4dfc9f5bda3: Fix the type of the capture passed to 
LambdaIntroducer::addCapture in… (authored by ahatanak).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
+++ clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: %[[S:.*]] = type { i32 }
+// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* }
+// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] }
 
 // 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
@@ -33,7 +36,7 @@
 // reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"(
 // 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\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
@@ -46,10 +49,60 @@
 // is captured by reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"(
 // 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\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
+void test1() {
+  id a = getObj(), b = getObj(), c = getObj();
+  [, b, c]{ ^{ a = 0; use(b); use(c); }(); }();
+}
+
+struct S {
+  int val() const;
+  int a;
+  S();
+  S(const S&);
+  S =(const S&);
+  S(S&&);
+  S =(S&&);
+};
+
+S getS();
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0
+// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8
+// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8
+
+int test2() {
+  S s;
+  auto fn = [&](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0
+// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]])
+
+int test3() {
+  const S  = getS();
+  auto fn = [=](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
 // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
 // CHECK-NOT: call void @llvm.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, 

[PATCH] D58164: Block+lambda: allow reference capture

2020-03-07 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added a comment.
This revision is now accepted and ready to land.

Okay, I think this is a reasonable fix.   If @rsmith has thoughts about this, I 
guess they'll have to happen post-review.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2020-03-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 248371.
ahatanak changed the repository for this revision from rC Clang to rG LLVM 
Github Monorepo.
ahatanak added a comment.
Herald added a subscriber: ributzka.

Rebase and ping.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
+++ clang/test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: %[[S:.*]] = type { i32 }
+// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* }
+// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] }
 
 // 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
@@ -33,7 +36,7 @@
 // reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"(
 // 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\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
@@ -46,10 +49,60 @@
 // is captured by reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"(
 // 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\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
+void test1() {
+  id a = getObj(), b = getObj(), c = getObj();
+  [, b, c]{ ^{ a = 0; use(b); use(c); }(); }();
+}
+
+struct S {
+  int val() const;
+  int a;
+  S();
+  S(const S&);
+  S =(const S&);
+  S(S&&);
+  S =(S&&);
+};
+
+S getS();
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0
+// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8
+// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8
+
+int test2() {
+  S s;
+  auto fn = [&](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0
+// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]])
+
+int test3() {
+  const S  = getS();
+  auto fn = [=](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
 // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
 // CHECK-NOT: call void @llvm.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** 

[PATCH] D58164: Block+lambda: allow reference capture

2019-07-26 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 212016.
ahatanak added a comment.

Rebase.

I think the fix is correct. When the lambda expression for the generic lambda 
is built, `BuildLambdaExpr` passes a `Capture` object in 
`LambdaScopeInfo::Captures` to `BuildCaptureField` to build the closure class 
field for the capture, so it should be okay to read the type of the field and 
pass it to `LambdaScopeInfo::addCapture` when rebuilding the lambda scope info.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164

Files:
  lib/Sema/SemaDecl.cpp
  test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- test/CodeGenObjCXX/block-nested-in-lambda.mm
+++ test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: %[[S:.*]] = type { i32 }
+// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* }
+// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] }
 
 // 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
@@ -33,7 +36,7 @@
 // reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"(
 // 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\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
@@ -46,10 +49,60 @@
 // is captured by reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"(
 // 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\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
+void test1() {
+  id a = getObj(), b = getObj(), c = getObj();
+  [, b, c]{ ^{ a = 0; use(b); use(c); }(); }();
+}
+
+struct S {
+  int val() const;
+  int a;
+  S();
+  S(const S&);
+  S =(const S&);
+  S(S&&);
+  S =(S&&);
+};
+
+S getS();
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0
+// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8
+// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8
+
+int test2() {
+  S s;
+  auto fn = [&](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0
+// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]])
+
+int test3() {
+  const S  = getS();
+  auto fn = [=](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
 // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
 // CHECK-NOT: call void 

[PATCH] D58164: Block+lambda: allow reference capture

2019-06-28 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Okay.  In that case, yeah, it'd be good to get Richard's opinion about the 
right way to get that information here.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-06-28 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Currently a block captures a variable (POD or non-POD) by reference if the 
enclosing lambda captures it by reference and captures by copy if the enclosing 
lambda captures by copy.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-06-27 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

I'm not sure we've ever written down what the semantics of the block capture 
are actually supposed to be in this situation.  I guess capturing a reference 
is the right thing to do?  Is that what we generally do if this is a POD type?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-06-14 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a reviewer: rsmith.
ahatanak added a comment.

Richard, could you shed light on why it's done this way?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-06-14 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

I think I now have a better idea of what's causing the crash in IRGen.

The root of the problem is that, when `RebuildLambdaScopeInfo` is called to 
rebuild the scope info for the generic lambda, the type of the captured 
variable (`s` in `test2` and `test3` in 
`test/CodeGenObjCXX/block-nested-in-lambda.mm`) is passed to  `addCapture`, 
which is different from the type of the non-static member of the closure 
object. For example, the member type of the generic lambda in `test2` is `S&` 
whereas the type of variable `s` is `S`. `Sema::ActOnBlockStmtExpr` in 
SemaExpr.cpp uses the type passed to `addCapture` to determine whether copying 
from the lambda member to the field in the block structure requires a copy 
constructor, but since it isn't passed the correct type, it incorrectly 
determines that a copy constructor is needed when the capture is a by-reference 
capture (for example, in `test2`) and isn't needed when the capture is a 
by-copy capture (for example, in `test3`), which causes crashes in IRGen.

I think the fix is to pass the correct capture type, which I think is whatever 
`I->getType()` returns, to `addCapture` in `RebuildLambdaScopeInfo`, but I'm 
wondering whether there is a reason `VD->getType()` has to be called here when 
the other two cases (this and VLA) uses `I->getType()`.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-06-14 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 204882.
ahatanak added a comment.

- Add another test case which has a block nested inside a lambda and causes 
clang to crash.
- Fix the capture type passed to `addCapture` in `RebuildLambdaScopeInfo`.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164

Files:
  lib/Sema/SemaDecl.cpp
  test/CodeGenObjCXX/block-nested-in-lambda.mm

Index: test/CodeGenObjCXX/block-nested-in-lambda.mm
===
--- test/CodeGenObjCXX/block-nested-in-lambda.mm
+++ test/CodeGenObjCXX/block-nested-in-lambda.mm
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s
 
 // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
+// CHECK: %[[S:.*]] = type { i32 }
+// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* }
+// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] }
 
 // 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
@@ -33,7 +36,7 @@
 // reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"(
 // 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\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
@@ -46,10 +49,60 @@
 // is captured by reference.
 
 // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev(
-// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"(
+// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"(
 // 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\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8
 
+void test1() {
+  id a = getObj(), b = getObj(), c = getObj();
+  [, b, c]{ ^{ a = 0; use(b); use(c); }(); }();
+}
+
+struct S {
+  int val() const;
+  int a;
+  S();
+  S(const S&);
+  S =(const S&);
+  S(S&&);
+  S =(S&&);
+};
+
+S getS();
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0
+// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8
+// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8
+
+int test2() {
+  S s;
+  auto fn = [&](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
+// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}})
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0
+// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]])
+
+int test3() {
+  const S  = getS();
+  auto fn = [=](const auto a){
+return ^{
+  return s.val();
+}();
+  };
+  return fn(123);
+}
+
 // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s(
 // CHECK-NOT: call void @llvm.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 

[PATCH] D58164: Block+lambda: allow reference capture

2019-02-21 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

I agree.  There should just never be a copy expression if the capture is of 
reference type, and there should therefore be no need to special-case that in 
IRGen.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-14 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak requested changes to this revision.
ahatanak added a comment.
This revision now requires changes to proceed.

Sorry, I didn't mean to accept this yet. I think this is something that is 
better fixed in Sema.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-14 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.

Sorry, I was misunderstanding the problem.

I was trying to understand why the crash goes away if I change the generic 
lambda to a non-generic one. What I found was that, when the lambda is generic, 
`captureInBlock` is passed a  `CaptureType` that isn't an lvalue reference type 
and therefore performs copy initialization and sets the copy expression of the 
Capture to a non-null expression. This happens because 
`isVariableAlreadyCapturedInScopeInfo` doesn't assign the correct type (which 
should be an `LValueReferenceType`) to `CaptureType` when the variable is 
captured by reference.

I think this can be fixed if we check whether `CaptureType` is a reference 
capture in `isVariableAlreadyCapturedInScopeInfo` and, if it is, turn it into 
an lvalue reference type.




Comment at: test/CodeGenCXX/lambda-capturing-block.cpp:1
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -S -emit-llvm -std=c++17 
-fblocks -fcxx-exceptions -o - %s | FileCheck %s
+

I think you can simplify the test case a bit more:

- remove -fcxx-exceptions.
- remove 'extern "C"'.
- remove the derp's move constructor and destructor.
- remove the try/catch and just call 'c.cancel' in the function.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-13 Thread JF Bastien via Phabricator via cfe-commits
jfb added a comment.

I talked to Akira in meatspace, and it seems like this updated patch does the 
right thing. He suggested changing the AST as a longer-term solution, but for 
now this approach seems simple enough.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-13 Thread JF Bastien via Phabricator via cfe-commits
jfb updated this revision to Diff 186752.
jfb added a comment.

- Check for references when looking for copyexpr directly.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164

Files:
  lib/CodeGen/CGBlocks.cpp
  test/CodeGenCXX/lambda-capturing-block.cpp


Index: test/CodeGenCXX/lambda-capturing-block.cpp
===
--- /dev/null
+++ test/CodeGenCXX/lambda-capturing-block.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -S -emit-llvm -std=c++17 
-fblocks -fcxx-exceptions -o - %s | FileCheck %s
+
+extern "C" {
+
+struct derp {
+derp() {}
+derp(const derp& _Src) {}
+derp(derp&& _Src) {}
+~derp() {}
+void cancel() const{}
+};
+
+// CHECK-LABEL: test(
+void test() {
+  derp c;  
+  auto b = [&](auto const& func) noexcept {
+auto block = ^() {
+  try {
+func();
+  } catch (...) {
+c.cancel();
+  }
+};
+block();
+  };
+   
+  b([](){});
+}
+
+}
Index: lib/CodeGen/CGBlocks.cpp
===
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -622,7 +622,7 @@
   }
 
 // So do types that require non-trivial copy construction.
-} else if (CI.hasCopyExpr()) {
+} else if (CI.hasCopyExpr() && VT->getAsCXXRecordDecl()) {
   info.NeedsCopyDispose = true;
   info.HasCXXObject = true;
   if (!VT->getAsCXXRecordDecl()->isExternallyVisible())


Index: test/CodeGenCXX/lambda-capturing-block.cpp
===
--- /dev/null
+++ test/CodeGenCXX/lambda-capturing-block.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -S -emit-llvm -std=c++17 -fblocks -fcxx-exceptions -o - %s | FileCheck %s
+
+extern "C" {
+
+struct derp {
+derp() {}
+derp(const derp& _Src) {}
+derp(derp&& _Src) {}
+~derp() {}
+void cancel() const{}
+};
+
+// CHECK-LABEL: test(
+void test() {
+  derp c;	
+  auto b = [&](auto const& func) noexcept {
+auto block = ^() {
+  try {
+func();
+  } catch (...) {
+c.cancel();
+  }
+};
+block();
+  };
+	
+  b([](){});
+}
+
+}
Index: lib/CodeGen/CGBlocks.cpp
===
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -622,7 +622,7 @@
   }
 
 // So do types that require non-trivial copy construction.
-} else if (CI.hasCopyExpr()) {
+} else if (CI.hasCopyExpr() && VT->getAsCXXRecordDecl()) {
   info.NeedsCopyDispose = true;
   info.HasCXXObject = true;
   if (!VT->getAsCXXRecordDecl()->isExternallyVisible())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-13 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

I think the root of the problem is that `BlockDecl` knows the captured variable 
but doesn't know the type of the capture. The type of the variable and the type 
of the capture can be different if the block is nested inside a lambda or 
another block, which is why `CI.hasCopyExpr()` can return a non-null value when 
`VT` is a lvalue reference:

  `-FunctionDecl 0x11306dc28  line:11:6 test 'void ()'
  |-DeclStmt 0x11306ddb0 
  | `-VarDecl 0x11306dd20  col:8 used c 'derp' callinit
  ...
  | |-CXXRecordDecl 0x11306dec0  col:12 implicit class 
definition
  ...
  | | |-FieldDecl 0x11309cc58  col:7 implicit 'derp &'
  ...
  | | |   |   `-BlockDecl 0x11309cb28  
line:15:18
  | | |   | |-capture nested Var 0x11306dd20 'c' 'derp'


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-13 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

The code is crashing here because the loop in `computeBlockInfo` is trying to 
capture a variable that is captured by reference by the enclosing lambda as if 
it were captured by value. This is the type of VT:

  LValueReferenceType 0x1138008c0 'struct derp &'
  `-RecordType 0x113052580 'struct derp'
`-CXXRecord 0x1130524e8 'derp'

So in this case, the type doesn't require non-trivial copy construction.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58164/new/

https://reviews.llvm.org/D58164



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


[PATCH] D58164: Block+lambda: allow reference capture

2019-02-12 Thread JF Bastien via Phabricator via cfe-commits
jfb created this revision.
jfb added reviewers: rjmccall, ahatanak.
Herald added subscribers: cfe-commits, dexonsmith, jkorous.
Herald added a project: clang.

Capturing a C++ object by reference wasn't quite working when mixing block and 
lambda.


Repository:
  rC Clang

https://reviews.llvm.org/D58164

Files:
  lib/CodeGen/CGBlocks.cpp
  test/CodeGenCXX/lambda-capturing-block.cpp


Index: test/CodeGenCXX/lambda-capturing-block.cpp
===
--- /dev/null
+++ test/CodeGenCXX/lambda-capturing-block.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -S -emit-llvm -std=c++17 
-fblocks -fcxx-exceptions -o - %s | FileCheck %s
+
+extern "C" {
+
+struct derp {
+derp() {}
+derp(const derp& _Src) {}
+derp(derp&& _Src) {}
+~derp() {}
+void cancel() const{}
+};
+
+// CHECK-LABEL: test(
+void test() {
+  derp c;  
+  auto b = [&](auto const& func) noexcept {
+auto block = ^() {
+  try {
+func();
+  } catch (...) {
+c.cancel();
+  }
+};
+block();
+  };
+   
+  b([](){});
+}
+
+}
Index: lib/CodeGen/CGBlocks.cpp
===
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -625,8 +625,13 @@
 } else if (CI.hasCopyExpr()) {
   info.NeedsCopyDispose = true;
   info.HasCXXObject = true;
-  if (!VT->getAsCXXRecordDecl()->isExternallyVisible())
-info.CapturesNonExternalType = true;
+  if (auto *T = VT->getAsTagDecl()) {
+if (T->isExternallyVisible())
+  info.CapturesNonExternalType = true;
+  } else if (auto *P = VT->getPointeeCXXRecordDecl()) {
+if (P->isExternallyVisible())
+  info.CapturesNonExternalType = true;
+  }
 
 // So do C structs that require non-trivial copy construction or
 // destruction.


Index: test/CodeGenCXX/lambda-capturing-block.cpp
===
--- /dev/null
+++ test/CodeGenCXX/lambda-capturing-block.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin -S -emit-llvm -std=c++17 -fblocks -fcxx-exceptions -o - %s | FileCheck %s
+
+extern "C" {
+
+struct derp {
+derp() {}
+derp(const derp& _Src) {}
+derp(derp&& _Src) {}
+~derp() {}
+void cancel() const{}
+};
+
+// CHECK-LABEL: test(
+void test() {
+  derp c;	
+  auto b = [&](auto const& func) noexcept {
+auto block = ^() {
+  try {
+func();
+  } catch (...) {
+c.cancel();
+  }
+};
+block();
+  };
+	
+  b([](){});
+}
+
+}
Index: lib/CodeGen/CGBlocks.cpp
===
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -625,8 +625,13 @@
 } else if (CI.hasCopyExpr()) {
   info.NeedsCopyDispose = true;
   info.HasCXXObject = true;
-  if (!VT->getAsCXXRecordDecl()->isExternallyVisible())
-info.CapturesNonExternalType = true;
+  if (auto *T = VT->getAsTagDecl()) {
+if (T->isExternallyVisible())
+  info.CapturesNonExternalType = true;
+  } else if (auto *P = VT->getPointeeCXXRecordDecl()) {
+if (P->isExternallyVisible())
+  info.CapturesNonExternalType = true;
+  }
 
 // So do C structs that require non-trivial copy construction or
 // destruction.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits