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

login
register
mail settings
Submitter Jason Merrill
Date April 24, 2013, 1:37 p.m.
Message ID <5177E015.8020200@redhat.com>
Download mbox | patch
Permalink /patch/239208/
State New
Headers show

Comments

Jason Merrill - April 24, 2013, 1:37 p.m.
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

Patch

commit 91c5b39225cda83fe8bdb299fb30b85702059b6b
Author: Jason Merrill <jason@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 (expr));
+  tree type;
+  if (explicit_init_p)
+    {
+      type = make_auto ();
+      type = do_auto_deduction (type, expr, type);
+    }
+  else
+    type = non_reference (unlowered_expr_type (expr));
   if (!type || WILDCARD_TYPE_P (type))
     {
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
       DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true;
+      DECLTYPE_FOR_INIT_CAPTURE (type) = explicit_init_p;
       SET_TYPE_STRUCTURAL_EQUALITY (type);
     }
   return type;
@@ -9396,7 +9404,10 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
   char *buf;
   tree type, member, name;
 
-  type = lambda_capture_field_type (initializer);
+  if (TREE_CODE (initializer) == TREE_LIST)
+    initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
+						   tf_warning_or_error);
+  type = lambda_capture_field_type (initializer, explicit_init_p);
   if (by_reference_p)
     {
       type = build_reference_type (type);
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C
new file mode 100644
index 0000000..edada40
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init5.C
@@ -0,0 +1,11 @@ 
+// Test for paren and brace initializers
+// { dg-options "-std=c++1y" }
+// { dg-do run }
+
+#include <initializer_list>
+
+int main()
+{
+  if ([x(42)]{ return x; }() != 42) __builtin_abort();
+  if ([x{1,2}]{ return x.begin()[0]; }() != 1) __builtin_abort();
+}

commit 3dc4bbcecb08ba63614ccba90cb6f20ff993a724
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Apr 24 09:26:15 2013 -0400

    	N3648: init-captures are named.
    	* semantics.c (add_capture): Don't prepend "__" to init-captures.
    	(build_capture_proxy): Adjust.
    	* error.c (dump_simple_decl): Check DECL_NORMAL_CAPTURE_P.

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 7a8c0bc..4681e84 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -934,7 +934,7 @@  dump_simple_decl (tree t, tree type, int flags)
     pp_string (cxx_pp, "...");
   if (DECL_NAME (t))
     {
-      if (DECL_CLASS_SCOPE_P (t) && LAMBDA_TYPE_P (DECL_CONTEXT (t)))
+      if (TREE_CODE (t) == FIELD_DECL && DECL_NORMAL_CAPTURE_P (t))
 	{
 	  pp_character (cxx_pp, '<');
 	  pp_string (cxx_pp, IDENTIFIER_POINTER (DECL_NAME (t)) + 2);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index da66168..e4bb1ed 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9369,7 +9369,10 @@  build_capture_proxy (tree member)
     object = TREE_OPERAND (object, 0);
 
   /* Remove the __ inserted by add_capture.  */
-  name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
+  if (DECL_NORMAL_CAPTURE_P (member))
+    name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
+  else
+    name = DECL_NAME (member);
 
   type = lambda_proxy_type (object);
   var = build_decl (input_location, VAR_DECL, name, type);
@@ -9422,11 +9425,17 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
      won't find the field with name lookup.  We can't just leave the name
      unset because template instantiation uses the name to find
      instantiated fields.  */
-  buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
-  buf[1] = buf[0] = '_';
-  memcpy (buf + 2, IDENTIFIER_POINTER (id),
-	  IDENTIFIER_LENGTH (id) + 1);
-  name = get_identifier (buf);
+  if (!explicit_init_p)
+    {
+      buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
+      buf[1] = buf[0] = '_';
+      memcpy (buf + 2, IDENTIFIER_POINTER (id),
+	      IDENTIFIER_LENGTH (id) + 1);
+      name = get_identifier (buf);
+    }
+  else
+    /* But captures with explicit initializers are named.  */
+    name = id;
 
   /* If TREE_TYPE isn't set, we're still in the introducer, so check
      for duplicates.  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C
new file mode 100644
index 0000000..3ebf479
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init6.C
@@ -0,0 +1,12 @@ 
+// Test that simple captures are not named in the closure type, but
+// initialized captures are named.
+// { dg-options "-std=c++1y" }
+
+int main()
+{
+  int i;
+  auto lam = [i,j=42]{};
+  lam.j;
+  lam.j.foo;			// { dg-error "::j" }
+  lam.i;			// { dg-error "no member" }
+}