Re: C++ PATCH to add capture initializers to -std=c++1y

2013-04-24 Thread Jason Merrill

On 04/22/2013 03:19 PM, Jason Merrill wrote:

The only thing missing from our implementation is support for
list-initialization as well as = initialization; I'll add that soon.


These patches add that and parenthesized initializers, and also conform 
to the proposal that init-captures be nameable in the closure object.


Tested x86_64-pc-linux-gnu, applying to trunk.

Jason

commit 91c5b39225cda83fe8bdb299fb30b85702059b6b
Author: Jason Merrill ja...@redhat.com
Date:   Tue Apr 23 23:28:50 2013 -0400

	N3648: Allow braced and parenthesized initializers.
	* parser.c (cp_parser_lambda_introducer): Use cp_parser_initializer.
	* pt.c (tsubst) [DECLTYPE_TYPE]: Handle DECLTYPE_FOR_INIT_CAPTURE.
	* semantics.c (lambda_capture_field_type): Use do_auto_deduction.
	(add_capture): Collapse a parenthesized initializer into a single
	expression.
	* cp-tree.h (DECLTYPE_FOR_INIT_CAPTURE): New.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d96340a..6254c7d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -90,6 +90,7 @@ c-common.h, not after.
   LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR)
   DECL_FINAL_P (in FUNCTION_DECL)
   QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
+  DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
   ICS_THIS_FLAG (in _CONV)
   DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -97,6 +98,7 @@ c-common.h, not after.
   TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
   TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
   FNDECL_USED_AUTO (in FUNCTION_DECL)
+  DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
   ICS_BAD_FLAG (in _CONV)
   FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -3590,10 +3592,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
   (DECLTYPE_TYPE_CHECK (NODE))-type_common.string_flag
 
 /* These flags indicate that we want different semantics from normal
-   decltype: lambda capture just drops references, lambda proxies look
-   through implicit dereference.  */
+   decltype: lambda capture just drops references, init capture
+   uses auto semantics, lambda proxies look through implicit dereference.  */
 #define DECLTYPE_FOR_LAMBDA_CAPTURE(NODE) \
   TREE_LANG_FLAG_0 (DECLTYPE_TYPE_CHECK (NODE))
+#define DECLTYPE_FOR_INIT_CAPTURE(NODE) \
+  TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE))
 #define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \
   TREE_LANG_FLAG_2 (DECLTYPE_TYPE_CHECK (NODE))
 
@@ -5780,7 +5784,7 @@ extern tree finish_trait_expr			(enum cp_trait_kind, tree, tree);
 extern tree build_lambda_expr   (void);
 extern tree build_lambda_object			(tree);
 extern tree begin_lambda_type   (tree);
-extern tree lambda_capture_field_type		(tree);
+extern tree lambda_capture_field_type		(tree, bool);
 extern tree lambda_return_type			(tree);
 extern tree lambda_proxy_type			(tree);
 extern tree lambda_function			(tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 0456dd2..cb26292 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8548,17 +8548,18 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 	}
 
   /* Find the initializer for this capture.  */
-  if (cp_lexer_next_token_is (parser-lexer, CPP_EQ))
+  if (cp_lexer_next_token_is (parser-lexer, CPP_EQ)
+	  || cp_lexer_next_token_is (parser-lexer, CPP_OPEN_PAREN)
+	  || cp_lexer_next_token_is (parser-lexer, CPP_OPEN_BRACE))
 	{
-	  /* An explicit expression exists.  */
-	  cp_lexer_consume_token (parser-lexer);
+	  bool direct, non_constant;
+	  /* An explicit initializer exists.  */
 	  if (cxx_dialect  cxx1y)
 	pedwarn (input_location, 0,
 		 lambda capture initializers 
 		 only available with -std=c++1y or -std=gnu++1y);
-	  capture_init_expr = cp_parser_assignment_expression (parser,
-			   /*cast_p=*/true,
-			   idk);
+	  capture_init_expr = cp_parser_initializer (parser, direct,
+		 non_constant);
 	  explicit_init_p = true;
 	}
   else
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5f4d7a2..36e839f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11825,7 +11825,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	--c_inhibit_evaluation_warnings;
 
 	if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
-	  type = lambda_capture_field_type (type);
+	  type = lambda_capture_field_type (type,
+	DECLTYPE_FOR_INIT_CAPTURE (t));
 	else if (DECLTYPE_FOR_LAMBDA_PROXY (t))
 	  type = lambda_proxy_type (type);
 	else
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d4f0f82..da66168 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9123,14 +9123,22 @@ lambda_function (tree lambda)
The caller should add REFERENCE_TYPE for capture by reference.  */
 
 tree
-lambda_capture_field_type (tree expr)
+lambda_capture_field_type (tree expr, bool explicit_init_p)
 {
-  tree type = non_reference (unlowered_expr_type 

C++ PATCH to add capture initializers to -std=c++1y

2013-04-22 Thread Jason Merrill
At the Bristol C++ meeting we voted to accept generalized lambda capture 
initializers (e.g. [x = 42, y = std::move(y)]{ ... }), which were part 
of the initial implementation of lambdas in GCC, so initial support for 
C++1y is just a matter of checking cxx_dialect to avoid the pedwarn.


The only thing missing from our implementation is support for 
list-initialization as well as = initialization; I'll add that soon.


Tested x86_64-pc-linux-gnu, applying to trunk.
commit a920644105779dceffd5912822b10b331457a227
Author: Jason Merrill ja...@redhat.com
Date:   Mon Apr 22 12:56:01 2013 -0400

	N3648

	* parser.c (cp_parser_lambda_introducer): Make lambda capture init
	pedwarn unconditional except in C++1y mode.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 1893482..1fbc9bd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8518,9 +8518,10 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 	{
 	  /* An explicit expression exists.  */
 	  cp_lexer_consume_token (parser-lexer);
-  pedwarn (input_location, OPT_Wpedantic,
-   ISO C++ does not allow initializers 
-   in lambda expression capture lists);
+	  if (cxx_dialect  cxx1y)
+	pedwarn (input_location, 0,
+		 lambda capture initializers 
+		 only available with -std=c++1y or -std=gnu++1y);
 	  capture_init_expr = cp_parser_assignment_expression (parser,
 			   /*cast_p=*/true,
 			   idk);
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C
deleted file mode 100644
index 9b5ab79..000
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext.C
+++ /dev/null
@@ -1,27 +0,0 @@
-// Testcase for an extension to allow return type deduction when the lambda
-// contains more than just a single return-statement.
-
-// { dg-options -std=c++0x }
-// { dg-do run }
-
-bool b;
-template class T
-T f (T t)
-{
-  return [=] {
-auto i = t+1;
-if (b)
-  return i+1;
-else
-  return i+1;
-  }();
-}
-
-int main()
-{
-  // Pointless, but well-formed.
-  [] { return 1; return 2; }();
-
-  if (f(1) != 3)
-return 1;
-}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C
deleted file mode 100644
index 03c94e9..000
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C
+++ /dev/null
@@ -1,8 +0,0 @@
-// Test for the explicit initializer extension
-// { dg-options -std=c++0x }
-
-int main()
-{
-  int j = [i = 2]{sizeof(i); return i;}();
-  return (j != 2);
-}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C b/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C
new file mode 100644
index 000..1181a80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-deduce-mult.C
@@ -0,0 +1,27 @@
+// Testcase for an extension to allow return type deduction when the lambda
+// contains more than just a single return-statement.
+
+// { dg-options -std=c++1y }
+// { dg-do run }
+
+bool b;
+template class T
+T f (T t)
+{
+  return [=] {
+auto i = t+1;
+if (b)
+  return i+1;
+else
+  return i+1;
+  }();
+}
+
+int main()
+{
+  // Pointless, but well-formed.
+  [] { return 1; return 2; }();
+
+  if (f(1) != 3)
+return 1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init.C
new file mode 100644
index 000..a443642
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init.C
@@ -0,0 +1,8 @@
+// Test for the explicit initializer extension of C++1y
+// { dg-options -std=c++1y }
+
+int main()
+{
+  int j = [i = 2]{sizeof(i); return i;}();
+  return (j != 2);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C
new file mode 100644
index 000..6411fca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init1.C
@@ -0,0 +1,13 @@
+// N3648: capture init
+// { dg-options -std=c++1y -w }
+// { dg-do run }
+
+int main()
+{
+  int x = 41;
+  auto r = [x = x+1]{ return x; }();
+  if (r != 42) __builtin_abort();
+
+  static auto *p = r;
+  [x=r]{ if (x != p) __builtin_abort(); }();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C
new file mode 100644
index 000..068621d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init2.C
@@ -0,0 +1,13 @@
+// N3648: redundancy and capture init
+// { dg-options -std=c++1y -pedantic-errors }
+
+int main()
+{
+  int x = 42;
+  [=,x]{};			// { dg-error redundant }
+  [=,x]{};
+  [,x]{};			// { dg-error redundant }
+  [,x]{};
+  [=,x=24]{};
+  [,r=x]{};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C
new file mode 100644
index 000..9044be6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init3.C
@@ -0,0 +1,11 @@
+// N3648: capture init at non-block scope
+// { dg-options -std=c++1y -w }
+// { dg-do run }
+
+int i = 42;
+int j = [x=i]{ return x; }();
+
+int