public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
@ 2013-11-02 10:03 Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 1/3] " Adam Butcher
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher

Hi Jason,

I've got the tsubst solution for implicit parameter packs working now.  I've
also improved the efficiency of incremental template parameter synthesis and
added some testcases.  All C++14 generic lambda examples pass and no new
regressions.

Cheers,
Adam

Patch summary (3):

  Refactor implicit function template implementation and fix 58534,
    58536, 58548, 58549 and 58637.
  Support implicit parameter packs.
  Add some generic lambda test cases.

 gcc/cp/decl.c                                      |  30 +-
 gcc/cp/parser.c                                    | 331 +++++++++++++++------
 gcc/cp/parser.h                                    |  19 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C   |  25 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C    |  42 +++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C  |  10 +
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C    |  51 ++++
 .../g++.dg/cpp1y/lambda-generic-variadic.C         |  15 +
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C      |  25 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C  |  25 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C   |   4 +
 gcc/testsuite/g++.dg/cpp1y/lambda-generic.C        |  23 ++
 gcc/testsuite/g++.dg/cpp1y/pr58534.C               |   9 +
 gcc/testsuite/g++.dg/cpp1y/pr58536.C               |  12 +
 gcc/testsuite/g++.dg/cpp1y/pr58548.C               |  10 +
 gcc/testsuite/g++.dg/cpp1y/pr58549.C               |  10 +
 gcc/testsuite/g++.dg/cpp1y/pr58637.C               |   7 +
 gcc/tree.c                                         |  22 ++
 gcc/tree.h                                         |   5 +
 19 files changed, 561 insertions(+), 114 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58534.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58536.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58548.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58549.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58637.C

-- 
1.8.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [C++ PATCH 1/3] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
  2013-11-08 19:10   ` [C++ PATCH] " Jason Merrill
  2013-11-02 10:03 ` [C++ PATCH 3/3] Add some generic lambda test cases Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 2/3] Support implicit parameter packs Adam Butcher
  2 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher

gcc/
	* tree.c (grow_tree_vec_stat): New function ...
	* tree.h (grow_tree_vec_stat) (grow_tree_vec): ... and its declaration
	and macro front-end.

gcc/cp/
	PR c++/58534
	PR c++/58536
	PR c++/58548
	PR c++/58549
	PR c++/58637
	* parser.h (struct cp_parser): New members implicit_template_parms,
	implicit_template_scope and auto_is_implicit_function_template_parm_p.
	* parser.c (add_implicit_template_parms): Refactor as ...
	(synthesize_implicit_template_parm): ... this to append a new template
	type parm to the current template parameter list (introducing a new list
	if necessary).
	(cp_parser_new): Initialize new cp_parser members.
	(cp_parser_parameter_declaration_clause): Consider auto as implicit
	template parm when parsing a parameter declaration (unless paring an
	explicit specialization).
	(cp_parser_parameter_declaration_list): Remove local
	implicit_template_parms counter and reset cp_parser implicit template
	state when complete.
	(cp_parser_lambda_expression): Reset implicit template cp_parser members
	whilst generating lambda class.
	(cp_parser_function_definition_after_declarator): Reset implicit
	template cp_parser members whilst parsing function definition.
	(make_generic_type_name): Respell '<autoN>' as 'auto:N' which works
	better with template diagnostics.
	(cp_parser_simple_type_specifier): Synthesize implicit template parm on
	parsing 'auto' if auto_is_implicit_function_template_parm_p and provide
	diagnostics ...
	* decl.c (grokdeclarator): ... that were previously done here.

gcc/testsuite/g++.dg/
	* cpp1y/pr58534.C: New testcase.
	* cpp1y/pr58536.C: New testcase.
	* cpp1y/pr58548.C: New testcase.
	* cpp1y/pr58549.C: New testcase.
	* cpp1y/pr58637.C: New testcase.
---
 gcc/cp/decl.c                        |  30 +---
 gcc/cp/parser.c                      | 278 +++++++++++++++++++++++------------
 gcc/cp/parser.h                      |  19 +++
 gcc/testsuite/g++.dg/cpp1y/pr58534.C |   9 ++
 gcc/testsuite/g++.dg/cpp1y/pr58536.C |  12 ++
 gcc/testsuite/g++.dg/cpp1y/pr58548.C |  10 ++
 gcc/testsuite/g++.dg/cpp1y/pr58549.C |  10 ++
 gcc/testsuite/g++.dg/cpp1y/pr58637.C |   7 +
 gcc/tree.c                           |  22 +++
 gcc/tree.h                           |   5 +
 10 files changed, 281 insertions(+), 121 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58534.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58536.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58548.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58549.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58637.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 09c1daa..786814c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10375,33 +10375,11 @@ grokdeclarator (const cp_declarator *declarator,
 
       if (type_uses_auto (type))
 	{
-	  if (template_parm_flag)
-	    {
-	      error ("template parameter declared %<auto%>");
-	      type = error_mark_node;
-	    }
-	  else if (decl_context == CATCHPARM)
-	    {
-	      error ("catch parameter declared %<auto%>");
-	      type = error_mark_node;
-	    }
-	  else if (current_class_type && LAMBDA_TYPE_P (current_class_type))
-	    {
-	      if (cxx_dialect < cxx1y)
-		pedwarn (location_of (type), 0,
-			 "use of %<auto%> in lambda parameter declaration "
-			 "only available with "
-			 "-std=c++1y or -std=gnu++1y");
-	    }
-	  else if (cxx_dialect < cxx1y)
-	    pedwarn (location_of (type), 0,
-		     "use of %<auto%> in parameter declaration "
-		     "only available with "
-		     "-std=c++1y or -std=gnu++1y");
+	  if (cxx_dialect >= cxx1y)
+	    error ("%<auto%> parameter not permitted in this context");
 	  else
-	    pedwarn (location_of (type), OPT_Wpedantic,
-		     "ISO C++ forbids use of %<auto%> in parameter "
-		     "declaration");
+	    error ("parameter declared %<auto%>");
+	  type = error_mark_node;
 	}
 
       /* A parameter declared as an array of T is really a pointer to T.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bbc8e75..b699ac4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2107,8 +2107,8 @@ static bool cp_parser_ctor_initializer_opt_and_function_body
 static tree cp_parser_late_parsing_omp_declare_simd
   (cp_parser *, tree);
 
-static tree add_implicit_template_parms
-  (cp_parser *, size_t, tree);
+static tree synthesize_implicit_template_parm
+  (cp_parser *);
 static tree finish_fully_implicit_template
   (cp_parser *, tree);
 
@@ -3443,7 +3443,10 @@ cp_parser_new (void)
   parser->num_template_parameter_lists = 0;
 
   /* Not declaring an implicit function template.  */
+  parser->auto_is_implicit_function_template_parm_p = false;
   parser->fully_implicit_function_template_p = false;
+  parser->implicit_template_parms = 0;
+  parser->implicit_template_scope = 0;
 
   return parser;
 }
@@ -8617,12 +8620,17 @@ cp_parser_lambda_expression (cp_parser* parser)
         = parser->num_template_parameter_lists;
     unsigned char in_statement = parser->in_statement;
     bool in_switch_statement_p = parser->in_switch_statement_p;
-    bool fully_implicit_function_template_p = parser->fully_implicit_function_template_p;
+    bool fully_implicit_function_template_p
+        = parser->fully_implicit_function_template_p;
+    tree implicit_template_parms = parser->implicit_template_parms;
+    cp_binding_level* implicit_template_scope = parser->implicit_template_scope;
 
     parser->num_template_parameter_lists = 0;
     parser->in_statement = 0;
     parser->in_switch_statement_p = false;
     parser->fully_implicit_function_template_p = false;
+    parser->implicit_template_parms = 0;
+    parser->implicit_template_scope = 0;
 
     /* By virtue of defining a local class, a lambda expression has access to
        the private variables of enclosing classes.  */
@@ -8646,7 +8654,10 @@ cp_parser_lambda_expression (cp_parser* parser)
     parser->num_template_parameter_lists = saved_num_template_parameter_lists;
     parser->in_statement = in_statement;
     parser->in_switch_statement_p = in_switch_statement_p;
-    parser->fully_implicit_function_template_p = fully_implicit_function_template_p;
+    parser->fully_implicit_function_template_p
+	= fully_implicit_function_template_p;
+    parser->implicit_template_parms = implicit_template_parms;
+    parser->implicit_template_scope = implicit_template_scope;
   }
 
   pop_deferring_access_checks ();
@@ -14053,7 +14064,7 @@ cp_parser_explicit_specialization (cp_parser* parser)
     cp_parser_single_declaration (parser,
 				  /*checks=*/NULL,
 				  /*member_p=*/false,
-                                  /*explicit_specialization_p=*/true,
+				  /*explicit_specialization_p=*/true,
 				  /*friend_p=*/NULL);
   /* We're done with the specialization.  */
   end_specialization ();
@@ -14355,10 +14366,33 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     case RID_VOID:
       type = void_type_node;
       break;
-      
+
     case RID_AUTO:
       maybe_warn_cpp0x (CPP0X_AUTO);
-      type = make_auto ();
+      if (parser->auto_is_implicit_function_template_parm_p)
+	{
+	  type = synthesize_implicit_template_parm (parser);
+
+	  if (current_class_type && LAMBDA_TYPE_P (current_class_type))
+	    {
+	      if (cxx_dialect < cxx1y)
+		pedwarn (location_of (type), 0,
+			 "use of %<auto%> in lambda parameter declaration "
+			 "only available with "
+			 "-std=c++1y or -std=gnu++1y");
+	    }
+	  else if (cxx_dialect < cxx1y)
+	    pedwarn (location_of (type), 0,
+		     "use of %<auto%> in parameter declaration "
+		     "only available with "
+		     "-std=c++1y or -std=gnu++1y");
+	  else
+	    pedwarn (location_of (type), OPT_Wpedantic,
+		     "ISO C++ forbids use of %<auto%> in parameter "
+		     "declaration");
+	}
+      else
+	type = make_auto ();
       break;
 
     case RID_DECLTYPE:
@@ -17937,6 +17971,20 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
   bool ellipsis_p;
   bool is_error;
 
+  struct cleanup {
+    cp_parser* parser;
+    int auto_is_implicit_function_template_parm_p;
+    ~cleanup() {
+      parser->auto_is_implicit_function_template_parm_p
+	= auto_is_implicit_function_template_parm_p;
+    }
+  } cleanup = { parser, parser->auto_is_implicit_function_template_parm_p };
+
+  (void) cleanup;
+
+  if (!processing_specialization)
+    parser->auto_is_implicit_function_template_parm_p = true;
+
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   /* Check for trivial parameter-declaration-clauses.  */
@@ -18024,7 +18072,6 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
   tree *tail = &parameters; 
   bool saved_in_unbraced_linkage_specification_p;
   int index = 0;
-  int implicit_template_parms = 0;
 
   /* Assume all will go well.  */
   *is_error = false;
@@ -18052,18 +18099,11 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
-	{
-	  decl = grokdeclarator (parameter->declarator,
-				 &parameter->decl_specifiers,
-				 PARM,
-				 parameter->default_argument != NULL_TREE,
-				 &parameter->decl_specifiers.attributes);
-
-	  if (TREE_TYPE (decl) != error_mark_node
-	      && parameter->decl_specifiers.type
-	      && is_auto_or_concept (parameter->decl_specifiers.type))
-	      ++implicit_template_parms;
-	}
+	decl = grokdeclarator (parameter->declarator,
+			       &parameter->decl_specifiers,
+			       PARM,
+			       parameter->default_argument != NULL_TREE,
+			       &parameter->decl_specifiers.attributes);
 
       deprecated_state = DEPRECATED_NORMAL;
 
@@ -18151,10 +18191,12 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
   parser->in_unbraced_linkage_specification_p
     = saved_in_unbraced_linkage_specification_p;
 
-  if (parameters != error_mark_node && implicit_template_parms)
-    parameters = add_implicit_template_parms (parser,
-					      implicit_template_parms,
-					      parameters);
+  if (cp_binding_level *its = parser->implicit_template_scope)
+    if (current_binding_level->level_chain == its)
+      {
+	parser->implicit_template_parms = 0;
+	parser->implicit_template_scope = 0;
+      }
 
   return parameters;
 }
@@ -22406,6 +22448,15 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
   bool saved_in_function_body;
   unsigned saved_num_template_parameter_lists;
   cp_token *token;
+  bool fully_implicit_function_template_p
+    = parser->fully_implicit_function_template_p;
+  parser->fully_implicit_function_template_p = false;
+  tree implicit_template_parms
+    = parser->implicit_template_parms;
+  parser->implicit_template_parms = 0;
+  cp_binding_level* implicit_template_scope
+    = parser->implicit_template_scope;
+  parser->implicit_template_scope = 0;
 
   saved_in_function_body = parser->in_function_body;
   parser->in_function_body = true;
@@ -22478,6 +22529,13 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
     = saved_num_template_parameter_lists;
   parser->in_function_body = saved_in_function_body;
 
+  parser->fully_implicit_function_template_p
+    = fully_implicit_function_template_p;
+  parser->implicit_template_parms
+    = implicit_template_parms;
+  parser->implicit_template_scope
+    = implicit_template_scope;
+
   if (parser->fully_implicit_function_template_p)
     finish_fully_implicit_template (parser, /*member_decl_opt=*/0);
 
@@ -31011,7 +31069,7 @@ static tree
 make_generic_type_name ()
 {
   char buf[32];
-  sprintf (buf, "<auto%d>", ++generic_parm_count);
+  sprintf (buf, "auto:%d", ++generic_parm_count);
   return get_identifier (buf);
 }
 
@@ -31025,110 +31083,140 @@ tree_type_is_auto_or_concept (const_tree t)
   return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
 }
 
-/* Add EXPECT_COUNT implicit template parameters gleaned from the generic
-   type parameters in PARAMETERS to the CURRENT_TEMPLATE_PARMS (creating a new
-   template parameter list if necessary).  Returns PARAMETERS suitably rewritten
-   to reference the newly created types or ERROR_MARK_NODE on failure.  */
+/* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
+   (creating a new template parameter list if necessary).  Returns the newly
+   created template type parm.  */
 
 tree
-add_implicit_template_parms (cp_parser *parser, size_t expect_count,
-			     tree parameters)
+synthesize_implicit_template_parm  (cp_parser *parser)
 {
   gcc_assert (current_binding_level->kind == sk_function_parms);
 
-  cp_binding_level *fn_parms_scope = current_binding_level;
-
-  bool become_template =
-    fn_parms_scope->level_chain->kind != sk_template_parms;
-
-  size_t synth_count = 0;
+  /* We are either continuing a function template that already contains implicit
+     template parameters, creating a new fully-implicit function template, or
+     extending an existing explicit function template with implicit template
+     parameters.  */
 
-  /* Roll back a scope level and either introduce a new template parameter list
-     or update an existing one.  The function scope is added back after template
-     parameter synthesis below.  */
-  current_binding_level = fn_parms_scope->level_chain;
+  cp_binding_level *const entry_scope = current_binding_level;
 
-  /* TPARMS tracks the function's template parameter list.  This is either a new
-     chain in the case of a fully implicit function template or an extension of
-     the function's explicitly specified template parameter list.  */
-  tree tparms = NULL_TREE;
+  bool become_template = false;
+  cp_binding_level *parent_scope = 0;
 
-  if (become_template)
+  if (parser->implicit_template_scope)
     {
-      push_deferring_access_checks (dk_deferred);
-      begin_template_parm_list ();
+      gcc_assert (parser->implicit_template_parms);
 
-      parser->fully_implicit_function_template_p = true;
-      ++parser->num_template_parameter_lists;
+      current_binding_level = parser->implicit_template_scope;
     }
   else
     {
-      /* Roll back the innermost template parameter list such that it may be
-	 extended in the loop below as if it were being explicitly declared.  */
-
-      gcc_assert (current_template_parms);
+      /* Roll back to the existing template parameter scope (in the case of
+	 extending an explicit function template) or introduce a new template
+	 parameter scope ahead of the function parameter scope (or class scope
+	 in the case of out-of-line member definitions).  The function scope is
+	 added back after template parameter synthesis below.  */
 
-      /* Pop the innermost template parms into TPARMS.  */
-      tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
-      current_template_parms = TREE_CHAIN (current_template_parms);
+      cp_binding_level *scope = entry_scope;
 
-      size_t inner_vec_len = TREE_VEC_LENGTH (inner_vec);
-      if (inner_vec_len != 0)
+      while (scope->kind == sk_function_parms)
 	{
-	  tree t = tparms = TREE_VEC_ELT (inner_vec, 0);
-	  for (size_t n = 1; n < inner_vec_len; ++n)
-	    t = TREE_CHAIN (t) = TREE_VEC_ELT (inner_vec, n);
+	  parent_scope = scope;
+	  scope = scope->level_chain;
 	}
+      if (current_class_type && !LAMBDA_TYPE_P (current_class_type)
+	  && parser->num_classes_being_defined == 0)
+	while (scope->kind == sk_class)
+	  {
+	    parent_scope = scope;
+	    scope = scope->level_chain;
+	  }
 
-      ++processing_template_parmlist;
-    }
+      current_binding_level = scope;
 
-  for (tree p = parameters; p && synth_count < expect_count; p = TREE_CHAIN (p))
-    {
-      tree generic_type_ptr
-	= find_type_usage (TREE_VALUE (p), tree_type_is_auto_or_concept);
-
-      if (!generic_type_ptr)
-	continue;
+      if (scope->kind != sk_template_parms)
+	{
+	  /* Introduce a new template parameter list for implicit template
+	     parameters.  */
 
-      ++synth_count;
+	  become_template = true;
 
-      tree synth_id = make_generic_type_name ();
-      tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
-							synth_id);
-      tparms = process_template_parm (tparms, DECL_SOURCE_LOCATION (TREE_VALUE
-								    (p)),
-				      build_tree_list (NULL_TREE,
-						       synth_tmpl_parm),
-				      /*non_type=*/false,
-				      /*param_pack=*/false);
+	  push_deferring_access_checks (dk_deferred);
 
-      /* Rewrite the type of P to be the template_parm added above (getdecls is
-         used to retrieve it since it is the most recent declaration in this
-         scope).  Qualifiers need to be preserved also.  */
+	  parser->implicit_template_scope
+	      = begin_scope (sk_template_parms, NULL);
 
-      tree& cur_type = TREE_TYPE (generic_type_ptr);
-      tree new_type = TREE_TYPE (getdecls ());
+	  ++processing_template_decl;
 
-      if (TYPE_QUALS (cur_type))
-	cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type));
+	  parser->fully_implicit_function_template_p = true;
+	  ++parser->num_template_parameter_lists;
+	}
       else
-	cur_type = new_type;
+	{
+	  /* Synthesize implicit template parameters at the end of the explicit
+	     template parameter list.  */
+
+	  gcc_assert (current_template_parms);
+
+	  parser->implicit_template_scope = scope;
+
+	  tree v = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+	  parser->implicit_template_parms
+	    = TREE_VEC_ELT (v, TREE_VEC_LENGTH (v) - 1);
+	}
     }
 
-  gcc_assert (synth_count == expect_count);
+  /* Synthesize a new template parameter and track the current template
+     parameter chain with implicit_template_parms.  */
 
-  push_binding_level (fn_parms_scope);
+  tree synth_id = make_generic_type_name ();
+  tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
+						    synth_id);
+  tree new_parm
+    = process_template_parm (parser->implicit_template_parms,
+			     input_location,
+			     build_tree_list (NULL_TREE, synth_tmpl_parm),
+			     /*non_type=*/false,
+			     /*param_pack=*/false);
 
-  end_template_parm_list (tparms);
 
-  return parameters;
+  if (parser->implicit_template_parms)
+    parser->implicit_template_parms
+      = TREE_CHAIN (parser->implicit_template_parms);
+  else
+    parser->implicit_template_parms = new_parm;
+
+  tree new_type = TREE_TYPE (getdecls ());
+
+  /* If creating a fully implicit function template, start the new implicit
+     template parameter list with this synthesized type, otherwise grow the
+     current template parameter list.  */
+
+  if (become_template)
+    {
+      parent_scope->level_chain = current_binding_level;
+
+      tree new_parms = make_tree_vec (1);
+      TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
+      current_template_parms = tree_cons (size_int (processing_template_decl),
+					  new_parms, current_template_parms);
+    }
+  else
+    {
+      tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+      int new_parm_idx = TREE_VEC_LENGTH (new_parms);
+      new_parms = grow_tree_vec_stat (new_parms, new_parm_idx + 1);
+      TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
+    }
+
+  current_binding_level = entry_scope;
+
+  return new_type;
 }
 
 /* Finish the declaration of a fully implicit function template.  Such a
    template has no explicit template parameter list so has not been through the
-   normal template head and tail processing.  add_implicit_template_parms tries
-   to do the head; this tries to do the tail.  MEMBER_DECL_OPT should be
+   normal template head and tail processing.  synthesize_implicit_template_parm
+   tries to do the head; this tries to do the tail.  MEMBER_DECL_OPT should be
    provided if the declaration is a class member such that its template
    declaration can be completed.  If MEMBER_DECL_OPT is provided the finished
    form is returned.  Otherwise NULL_TREE is returned. */
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 75f327b..1024024 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -360,11 +360,30 @@ typedef struct GTY(()) cp_parser {
      data structure with everything needed for parsing the clauses.  */
   cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd;
 
+  /* Nonzero if parsing a parameter list where 'auto' should trigger an implicit
+     template parameter.  */
+  bool auto_is_implicit_function_template_parm_p;
+
   /* TRUE if the function being declared was made a template due to its
      parameter list containing generic type specifiers (`auto' or concept
      identifiers) rather than an explicit template parameter list.  */
   bool fully_implicit_function_template_p;
 
+  /* Tracks the function's template parameter list when declaring a function
+     using generic type parameters.  This is either a new chain in the case of a
+     fully implicit function template or an extension of the function's existing
+     template parameter list.  This is tracked to optimize calls subsequent
+     calls to synthesize_implicit_template_parm during
+     cp_parser_parameter_declaration.  */
+  tree implicit_template_parms;
+
+  /* The scope into which an implicit template parameter list has been
+     introduced or an existing template parameter list is being extended with
+     implicit template paramaters.  In most cases this is the sk_function_parms
+     scope containing the use of a generic type.  In the case of an out-of-line
+     member definition using a generic type, it is the sk_class scope.  */
+  cp_binding_level* implicit_template_scope;
+
 } cp_parser;
 
 /* In parser.c  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58534.C b/gcc/testsuite/g++.dg/cpp1y/pr58534.C
new file mode 100644
index 0000000..4aa4f43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58534.C
@@ -0,0 +1,9 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58534
+
+template<typename> void foo(const auto&) {}
+
+template<typename, typename...T> void foo(const auto&, T...) {}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58536.C b/gcc/testsuite/g++.dg/cpp1y/pr58536.C
new file mode 100644
index 0000000..8050c19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58536.C
@@ -0,0 +1,12 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58536
+
+struct A
+{
+  A(auto);
+};
+
+A::A(auto) {}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58548.C b/gcc/testsuite/g++.dg/cpp1y/pr58548.C
new file mode 100644
index 0000000..0ac2e1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58548.C
@@ -0,0 +1,10 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58548
+
+void foo(auto)
+{
+  struct A { int i; };
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58549.C b/gcc/testsuite/g++.dg/cpp1y/pr58549.C
new file mode 100644
index 0000000..b71bac9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58549.C
@@ -0,0 +1,10 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58549
+
+void foo(auto)
+{
+  void bar();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58637.C b/gcc/testsuite/g++.dg/cpp1y/pr58637.C
new file mode 100644
index 0000000..46200ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58637.C
@@ -0,0 +1,7 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58637
+
+template<> void foo(auto); // { dg-error "auto|not a template" }
+
diff --git a/gcc/tree.c b/gcc/tree.c
index 332751a..28cbba8 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1940,6 +1940,28 @@ make_tree_vec_stat (int len MEM_STAT_DECL)
 
   return t;
 }
+
+/* Grow a TREE_VEC node to new length LEN.  */
+
+tree
+grow_tree_vec_stat (tree v, int len MEM_STAT_DECL)
+{
+  gcc_assert (TREE_CODE (v) == TREE_VEC);
+
+  int oldlen = TREE_VEC_LENGTH (v);
+  gcc_assert (len > oldlen);
+
+  int oldlength = (oldlen - 1) * sizeof (tree) + sizeof (struct tree_vec);
+  int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
+
+  record_node_allocation_statistics (TREE_VEC, length - oldlength);
+
+  v = (tree) ggc_realloc_stat (v, length PASS_MEM_STAT);
+
+  TREE_VEC_LENGTH (v) = len;
+
+  return v;
+}
 \f
 /* Return 1 if EXPR is the integer constant zero or a complex constant
    of zero.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index 920ad07..8ca89d9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3412,6 +3412,11 @@ extern tree make_tree_binfo_stat (unsigned MEM_STAT_DECL);
 extern tree make_tree_vec_stat (int MEM_STAT_DECL);
 #define make_tree_vec(t) make_tree_vec_stat (t MEM_STAT_INFO)
 
+/* Grow a TREE_VEC.  */
+
+extern tree grow_tree_vec_stat (tree v, int MEM_STAT_DECL);
+#define grow_tree_vec(v, t) grow_tree_vec_stat (v, t MEM_STAT_INFO)
+
 /* Return the (unique) IDENTIFIER_NODE node for a given name.
    The name is supplied as a char *.  */
 
-- 
1.8.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [C++ PATCH 2/3] Support implicit parameter packs.
  2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 1/3] " Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 3/3] Add some generic lambda test cases Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
  2 siblings, 0 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher

	* parser.c (convert_generic_types_to_packs): New function to transform
	a range of implicitly introduced non-pack template parms to be parameter
	packs.
	(cp_parser_parameter_declaration_list): If a function parameter pack
	contains generic types, convert them to packs prior to grokdeclarator.
---
 gcc/cp/parser.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 74 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b699ac4..10b9f72 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2109,6 +2109,8 @@ static tree cp_parser_late_parsing_omp_declare_simd
 
 static tree synthesize_implicit_template_parm
   (cp_parser *);
+static tree convert_generic_types_to_packs
+  (tree, tree, int, int);
 static tree finish_fully_implicit_template
   (cp_parser *, tree);
 
@@ -18069,7 +18071,7 @@ static tree
 cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 {
   tree parameters = NULL_TREE;
-  tree *tail = &parameters; 
+  tree *tail = &parameters;
   bool saved_in_unbraced_linkage_specification_p;
   int index = 0;
 
@@ -18078,7 +18080,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
   /* The special considerations that apply to a function within an
      unbraced linkage specifications do not apply to the parameters
      to the function.  */
-  saved_in_unbraced_linkage_specification_p 
+  saved_in_unbraced_linkage_specification_p
     = parser->in_unbraced_linkage_specification_p;
   parser->in_unbraced_linkage_specification_p = false;
 
@@ -18088,6 +18090,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       cp_parameter_declarator *parameter;
       tree decl = error_mark_node;
       bool parenthesized_p = false;
+      int template_parm_idx = (parser->num_template_parameter_lists?
+			       TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
+						(current_template_parms)) : 0);
+
       /* Parse the parameter.  */
       parameter
 	= cp_parser_parameter_declaration (parser,
@@ -18099,11 +18105,30 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
-	decl = grokdeclarator (parameter->declarator,
-			       &parameter->decl_specifiers,
-			       PARM,
-			       parameter->default_argument != NULL_TREE,
-			       &parameter->decl_specifiers.attributes);
+	{
+	  /* If a function parameter pack was specified and an implicit template
+	     parameter was introduced during cp_parser_parameter_declaration,
+	     change any implicit parameters introduced into packs.  */
+	  if (parser->implicit_template_parms
+	      && parameter->declarator
+	      && parameter->declarator->parameter_pack_p)
+	    {
+	      int latest_template_parm_idx = TREE_VEC_LENGTH
+		(INNERMOST_TEMPLATE_PARMS (current_template_parms));
+
+	      if (latest_template_parm_idx != template_parm_idx)
+		parameter->decl_specifiers.type = convert_generic_types_to_packs
+		  (parameter->decl_specifiers.type,
+		   current_template_parms,
+		   template_parm_idx, latest_template_parm_idx);
+	    }
+
+	  decl = grokdeclarator (parameter->declarator,
+				 &parameter->decl_specifiers,
+				 PARM,
+				 parameter->default_argument != NULL_TREE,
+				 &parameter->decl_specifiers.attributes);
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
@@ -31213,6 +31238,48 @@ synthesize_implicit_template_parm  (cp_parser *parser)
   return new_type;
 }
 
+/* Convert the generic type parameters in PARM that match the types given in the
+   range [START_IDX, END_IDX) from the template parameters CURRENT into generic
+   type packs.  */
+
+tree
+convert_generic_types_to_packs (tree parm,
+				tree current, int start_idx, int end_idx)
+{
+  int depth = TMPL_PARMS_DEPTH (current);
+  current = INNERMOST_TEMPLATE_PARMS (current);
+  tree replacement = make_tree_vec (TREE_VEC_LENGTH (current));
+
+  for (int i = start_idx; i < end_idx; ++i)
+    {
+      /* Create a distinct parameter pack type from the current parm and add it
+	 to the replacement args to tsubst below into the generic function
+	 parameter.  */
+
+      tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))));
+      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
+      TYPE_MAIN_VARIANT (t) = t;
+      TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
+      SET_TYPE_STRUCTURAL_EQUALITY (t);
+      TREE_VEC_ELT (replacement, i) = t;
+    }
+
+  if (depth > 1)
+    {
+      /* Build up a tree vec of empty tree vecs up to the inner substitution
+	 args built above.  */
+
+      tree inner = replacement;
+      replacement = make_tree_vec (depth);
+      int last = depth - 1;
+      for (int i = 0; i < last; ++i)
+	TREE_VEC_ELT (replacement, i) = make_tree_vec (0);
+      TREE_VEC_ELT (replacement, last) = inner;
+    }
+
+  return tsubst (parm, replacement, tf_none, NULL_TREE);
+}
+
 /* Finish the declaration of a fully implicit function template.  Such a
    template has no explicit template parameter list so has not been through the
    normal template head and tail processing.  synthesize_implicit_template_parm
-- 
1.8.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [C++ PATCH 3/3] Add some generic lambda test cases.
  2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 1/3] " Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
  2013-11-02 10:03 ` [C++ PATCH 2/3] Support implicit parameter packs Adam Butcher
  2 siblings, 0 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher

gcc/testsuite/g++.dg/cpp1y/
		 * lambda-generic.C: New test case.
		 * lambda-generic-cfun.C: New test case.
		 * lambda-generic-dep.C: New test case.
		 * lambda-generic-udt.C: New test case.
		 * lambda-generic-variadic.C: New test case.
		 * lambda-generic-x.C: New test case.
		 * lambda-generic-xcfun.C: New test case.
		 * lambda-generic-xudt.C: New test case.
		 * lambda-generic-mixed.C: New test case.
---
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C   | 25 +++++++++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C    | 42 ++++++++++++++++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C  | 10 +++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C    | 51 ++++++++++++++++++++++
 .../g++.dg/cpp1y/lambda-generic-variadic.C         | 15 +++++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C      | 25 +++++++++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C  | 25 +++++++++++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C   |  4 ++
 gcc/testsuite/g++.dg/cpp1y/lambda-generic.C        | 23 ++++++++++
 9 files changed, 220 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic.C

diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
new file mode 100644
index 0000000..5e51526
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
@@ -0,0 +1,25 @@
+// Generic lambda conversion to function ptr test from N3690 5.1.2.6
+// { dg-options "-std=c++1y" }
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { }
+void g(int (*)(int)) { } // #1
+void g(char (*)(char)) { } // #2
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int main()
+{
+  auto glambda = [](auto a) { return a; };
+  int (*fp)(int) = glambda;
+  f1(glambda); // OK
+  f2(glambda); // { dg-error "invalid user-defined conversion" }
+  g(glambda); // { dg-error "ambiguous" }
+  h(glambda); // OK: calls #3 since it is convertible from ID
+  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+
+  auto GL = [](auto a) { return a; };
+  int (*GL_int)(int) = GL; // OK: through conversion function template
+  GL_int(3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
new file mode 100644
index 0000000..bb68738
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
@@ -0,0 +1,42 @@
+// Generic lambda type dependence test part from N3690 5.1.2.12
+// { dg-options "-std=c++1y" }
+
+void f(int, const int (&)[2] = {}) { } // #1
+void f(const int&, const int (&)[1]) { } // #2
+
+void test()
+{
+  const int x = 17;
+  auto g = [](auto a) {
+    f(x); // OK: calls #1, does not capture x
+  };
+  auto g2 = [=](auto a) {
+    int selector[sizeof(a) == 1 ? 1 : 2]{};
+    f(x, selector); // OK: is a dependent expression, so captures x
+  };
+}
+
+struct S {
+  struct N {
+    auto test () { return 7.f; }
+  };
+};
+
+#include <utility>
+
+int main()
+{
+  auto f = [] <typename T> (T const& s) mutable {
+    typename T::N x;
+    return x.test ();
+  };
+  auto g = [] (auto const& s) {
+    typename std::decay<decltype (s)>::type::N x;
+    return x.test ();
+  };
+
+  S i;
+  f(i);
+  g(i);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
new file mode 100644
index 0000000..4e26fc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
@@ -0,0 +1,10 @@
+// Mixed explicit and implicit generic lambda test.
+// { dg-options "-std=c++1y" }
+
+int main()
+{
+  auto f = [] <typename T> (T a, auto b) { return a + b; };
+  auto g = [] <typename T> (auto a, T b) { return a + b; };
+
+  return f (1.0, 3) + g (1.0, 3);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
new file mode 100644
index 0000000..9f6d45a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
@@ -0,0 +1,51 @@
+// Ensure that generic lambdas properly construct and destroy user types.
+// { dg-options "-std=c++1y -DUSE_AUTO_SYNTAX" }
+// { dg-do run }
+
+int i = 3;
+
+struct S
+{
+  S () { ++i; }
+  S (S const&) { ++i; }
+  S (S&& old) { old.shadow = true; i += 2; }
+  ~S () { if (shadow) i -= 2; else --i; }
+
+  bool shadow = false;
+};
+
+extern "C" void printf(...);
+#define assert(e) if (e); else \
+		 printf ("%s:%d: !(%s)\n", __FILE__, __LINE__, #e), __builtin_abort ();
+
+int main ()
+{
+  assert (i == 3);
+  {
+    S s; assert (i == 4);
+
+    #if USE_AUTO_SYNTAX
+    auto byref = [] (auto& r)                   { (void) r; };
+    auto bycref = [] (auto const& r)            { (void) r; };
+    auto byval = [] (auto v, auto const x)      { assert (i == x); (void) v; };
+    auto byrval = [] (auto&& r, auto const x)   { S steal (static_cast<S&&>(r));
+		 		 		 		 		           assert (i == x); };
+
+    #elif USE_EXPLICIT_TEMPLATE_SYNTAX
+    auto byref = [] <typename T> (T& r)         { (void) r; };
+    auto bycref = [] <typename T> (T const& r)  { (void) r; };
+    auto byval = [] <typename T, typename I>
+		 		     (T v, I const x)		 		 { assert (i == x); (void) v; };
+    auto byrval = [] <typename T, typename I>
+		 		      (T&& r, I const x)		 		 { S steal (static_cast<S&&>(r));
+		 		 		 		 		           assert (i == x); };
+    #endif
+
+    byref (s); assert (i == 4);
+    bycref (s); assert (i == 4);
+    byval (s, 5); assert (i == 4);
+    byrval (static_cast<S&&>(s), 6); assert (i == 5);
+  }
+  assert (i == 3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
new file mode 100644
index 0000000..bd41b35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
@@ -0,0 +1,15 @@
+// Basic generic lambda test
+// { dg-options "-std=c++1y" }
+// { dg-do run }
+
+template <typename T, typename U> struct pair {};
+template <typename... T> struct tuple {};
+
+int main()
+{
+  auto a = [] (auto, pair<auto,auto> v) { return sizeof (v); };
+  auto b = [] (auto, pair<pair<auto,auto>,auto>... v) { return sizeof... (v); };
+
+  a(1, pair<int, float>());
+  b(2, pair<pair<short,char>, double>(), pair<pair<float,long>, int>());
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
new file mode 100644
index 0000000..48a6268
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
@@ -0,0 +1,25 @@
+// Explicit generic lambda test from N3690 5.1.2.5
+// { dg-options "-std=gnu++1y" }
+
+#include <iostream>
+
+int main()
+{
+   auto glambda = [] <typename A, typename B> (A a, B&& b) { return a < b; };
+   bool b = glambda(3, 3.14); // OK
+   auto vglambda = [] <typename P> (P printer) {
+     return [=] <typename... T> (T&& ... ts) { // OK: ts is a function parameter pack
+       printer(std::forward<decltype(ts)>(ts)...);
+       return [=]() {
+         printer(ts ...);
+       };
+     };
+   };
+   auto p = vglambda( [] <typename A,
+                          typename B,
+                          typename C> (A v1, B v2, C v3)
+     { std::cout << v1 << v2 << v3; } );
+   auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
+   q(); // OK: outputs 1a3.14
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
new file mode 100644
index 0000000..d44b796
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
@@ -0,0 +1,25 @@
+// Explicit generic lambda conversion to function ptr test from N3690 5.1.2.6
+// { dg-options "-std=gnu++1y" }
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { }
+void g(int (*)(int)) { } // #1
+void g(char (*)(char)) { } // #2
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int main()
+{
+  auto glambda = [] <typename T> (T a) { return a; };
+  int (*fp)(int) = glambda;
+  f1(glambda); // OK
+  f2(glambda); // { dg-error "invalid user-defined conversion" }
+  g(glambda); // { dg-error "ambiguous" }
+  h(glambda); // OK: calls #3 since it is convertible from ID
+  int& (*fpi)(int*) = [] <typename T> (T* a) -> auto& { return *a; }; // OK
+
+  auto GL = [] <typename T> (T a) { return a; };
+  int (*GL_int)(int) = GL; // OK: through conversion function template
+  GL_int(3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
new file mode 100644
index 0000000..fba864b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
@@ -0,0 +1,4 @@
+// Ensure that generic lambdas properly construct and destroy user types.
+// { dg-options "-std=gnu++1y -DUSE_EXPLICIT_TEMPLATE_SYNTAX" }
+
+#include "lambda-generic-udt.C"
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
new file mode 100644
index 0000000..1f66475
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
@@ -0,0 +1,23 @@
+// Generic lambda test from N3690 5.1.2.5
+// { dg-options "-std=c++1y" }
+
+#include <iostream>
+
+int main()
+{
+  auto glambda = [](auto a, auto&& b) { return a < b; };
+  bool b = glambda(3, 3.14); // OK
+  auto vglambda = [](auto printer) {
+    return [=](auto&& ... ts) { // OK: ts is a function parameter pack
+      printer(std::forward<decltype(ts)>(ts)...);
+      return [=]() {
+        printer(ts ...);
+      };
+    };
+  };
+  auto p = vglambda( [](auto v1, auto v2, auto v3)
+    { std::cout << v1 << v2 << v3; } );
+  auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
+  q(); // OK: outputs 1a3.14
+}
+
-- 
1.8.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-02 10:03 ` [C++ PATCH 1/3] " Adam Butcher
@ 2013-11-08 19:10   ` Jason Merrill
  2013-11-09 13:56     ` Adam Butcher
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2013-11-08 19:10 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Volker Reichelt

On 10/31/2013 05:47 AM, Adam Butcher wrote:
> +         become_template = true;

> +         push_deferring_access_checks (dk_deferred);

Why is this call here?  I don't see anything in the rest of the function 
that would trigger an access check, or a matching pop.

> +      /* Create a distinct parameter pack type from the current parm and add it
> +        to the replacement args to tsubst below into the generic function
> +        parameter.  */
> +
> +      tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))));
> +      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);

Is this changing anything?  I'm not sure if we need to copy the decl or 
if we can just reuse it, but either way we need to set the type of 
TEMPLATE_TYPE_DECL (t) to t.

> +      SET_TYPE_STRUCTURAL_EQUALITY (t);

Why not

       TYPE_CANONICAL (t) = canonical_type_parameter (t);

?

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-08 19:10   ` [C++ PATCH] " Jason Merrill
@ 2013-11-09 13:56     ` Adam Butcher
  2013-11-09 20:16       ` Adam Butcher
  2013-11-10 10:34       ` Jason Merrill
  0 siblings, 2 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-09 13:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

On 2013-11-08 18:50, Jason Merrill wrote:
> On 10/31/2013 05:47 AM, Adam Butcher wrote:
>> +         become_template = true;
>>
>> +         push_deferring_access_checks (dk_deferred);
>
> Why is this call here?  I don't see anything in the rest of the
> function that would trigger an access check, or a matching pop.
>
This is only in the 'fully implicit function template' case; and the 
matching pop is in finish_fully_implicit_template.  It was in the 
original impl which was trying to do all the things that beginning and 
ending an explicit template parameter list did.  Maybe this is 
unnecessary.  I'll see if anything breaks if I remove it.

>> +      /* Create a distinct parameter pack type from the current 
>> parm and add it
>> +        to the replacement args to tsubst below into the generic 
>> function
>> +        parameter.  */
>> +
>> +      tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT 
>> (current, i))));
>> +      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
>
> Is this changing anything?  I'm not sure if we need to copy the decl
> or if we can just reuse it, but either way we need to set the type of
> TEMPLATE_TYPE_DECL (t) to t.
>
I think it (or at least one of the assignments) is necessary.  It is 
derived from some similar code in tsubst.  I'll have another look into 
it and add TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t also.  What problem 
will be caused by not setting the latter; is it a consistency issue?  I 
have not seen any probs in testing so far.

>> +      SET_TYPE_STRUCTURAL_EQUALITY (t);
>
> Why not
>
>       TYPE_CANONICAL (t) = canonical_type_parameter (t);
>
> ?
>
Only for the sake of not exposing this (currently static) function from 
pt.c (or moving the pack convert function into pt.c).  My original impl 
did extern canonical_type_parameter and use that and I think it worked 
as expected.  Would that be preferred?

Cheers,
Adam

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-09 13:56     ` Adam Butcher
@ 2013-11-09 20:16       ` Adam Butcher
  2013-11-10 10:34       ` Jason Merrill
  1 sibling, 0 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-09 20:16 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

[-- Attachment #1: Type: text/plain, Size: 2059 bytes --]

On 2013-11-09 13:21, Adam Butcher wrote:
> On 2013-11-08 18:50, Jason Merrill wrote:
>> On 10/31/2013 05:47 AM, Adam Butcher wrote:
>>> +         become_template = true;
>>>
>>> +         push_deferring_access_checks (dk_deferred);
>>
>> Why is this call here?  I don't see anything in the rest of the
>> function that would trigger an access check, or a matching pop.
>>
> This is only in the 'fully implicit function template' case; and the
> matching pop is in finish_fully_implicit_template.  It was in the
> original impl which was trying to do all the things that beginning 
> and
> ending an explicit template parameter list did.  Maybe this is
> unnecessary.  I'll see if anything breaks if I remove it.
>
>>> +      /* Create a distinct parameter pack type from the current 
>>> parm and add it
>>> +        to the replacement args to tsubst below into the generic 
>>> function
>>> +        parameter.  */
>>> +
>>> +      tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT 
>>> (current, i))));
>>> +      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
>>
>> Is this changing anything?  I'm not sure if we need to copy the decl
>> or if we can just reuse it, but either way we need to set the type 
>> of
>> TEMPLATE_TYPE_DECL (t) to t.
>>
> I think it (or at least one of the assignments) is necessary.  It is
> derived from some similar code in tsubst.  I'll have another look 
> into
> it and add TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t also.  What problem
> will be caused by not setting the latter; is it a consistency issue?
> I have not seen any probs in testing so far.
>
>>> +      SET_TYPE_STRUCTURAL_EQUALITY (t);
>>
>> Why not
>>
>>       TYPE_CANONICAL (t) = canonical_type_parameter (t);
>>
>> ?
>>
> Only for the sake of not exposing this (currently static) function
> from pt.c (or moving the pack convert function into pt.c).  My
> original impl did extern canonical_type_parameter and use that and I
> think it worked as expected.  Would that be preferred?
>
The following update appears to work.

Cheers,
Adam


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mods.diff --]
[-- Type: text/x-c; name=mods.diff, Size: 1597 bytes --]

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index be799a0..aba4a09 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -31270,8 +31270,6 @@ synthesize_implicit_template_parm  (cp_parser *parser)
 
 	  become_template = true;
 
-	  push_deferring_access_checks (dk_deferred);
-
 	  parser->implicit_template_scope
 	      = begin_scope (sk_template_parms, NULL);
 
@@ -31362,10 +31360,12 @@ convert_generic_types_to_packs (tree parm,
 	 parameter.  */
 
       tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))));
+      TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t;
       TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
       TYPE_MAIN_VARIANT (t) = t;
       TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
-      SET_TYPE_STRUCTURAL_EQUALITY (t);
+      extern tree canonical_type_parameter (tree);
+      TYPE_CANONICAL (t) = canonical_type_parameter (t);
       TREE_VEC_ELT (replacement, i) = t;
     }
 
@@ -31406,7 +31406,6 @@ finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt)
       DECL_VIRTUAL_P (member_decl_opt) = false;
     }
 
-  pop_deferring_access_checks ();
   if (member_decl_opt)
     member_decl_opt = finish_member_template_decl (member_decl_opt);
   end_template_decl ();
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8c1553f..d3047cb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3546,7 +3546,7 @@ build_template_parm_index (int index,
    parameter.  Returns the canonical type parameter, which may be TYPE
    if no such parameter existed.  */
 
-static tree
+tree
 canonical_type_parameter (tree type)
 {
   tree list;

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-09 13:56     ` Adam Butcher
  2013-11-09 20:16       ` Adam Butcher
@ 2013-11-10 10:34       ` Jason Merrill
  2013-11-10 12:08         ` Adam Butcher
  1 sibling, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2013-11-10 10:34 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Volker Reichelt

On 11/09/2013 08:21 AM, Adam Butcher wrote:
>>> +      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
>>
>> Is this changing anything?  I'm not sure if we need to copy the decl
>> or if we can just reuse it, but either way we need to set the type of
>> TEMPLATE_TYPE_DECL (t) to t.
>>
> I think it (or at least one of the assignments) is necessary.  It is
> derived from some similar code in tsubst.

The code in tsubst is updating the type because the 
TEMPLATE_TYPE_PARM_INDEX has changed; in this case, it hasn't, so 
neither has the TEMPLATE_TYPE_DECL.  But see below...

> I'll have another look into
> it and add TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t also.  What problem
> will be caused by not setting the latter; is it a consistency issue?  I
> have not seen any probs in testing so far.

Just that without this assignment anything wanting to get from the 
TYPE_DECL to its type will get the non-pack, but we want it to get the pack.

Hmm, actually I think messing with the non-pack's decl is dangerous, and 
we should come up with a new decl for the pack instead.  I think you can 
use reduce_template_parm_level with a "levels" argument of 0 to build a 
new decl and parm index.

And if we're doing that, setting TYPE_STUB_DECL and TYPE_NAME is indeed 
necessary.

> Only for the sake of not exposing this (currently static) function from
> pt.c (or moving the pack convert function into pt.c).  My original impl
> did extern canonical_type_parameter and use that and I think it worked
> as expected.  Would that be preferred?

Yes.  Please declare it in cp-tree.h rather than within the function.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-10 10:34       ` Jason Merrill
@ 2013-11-10 12:08         ` Adam Butcher
  2013-11-10 16:14           ` Adam Butcher
  0 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-10 12:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

On 2013-11-10 6:10, Jason Merrill wrote:
>
> Hmm, actually I think messing with the non-pack's decl is dangerous,
> and we should come up with a new decl for the pack instead.  I think
> you can use reduce_template_parm_level with a "levels" argument of 0
> to build a new decl and parm index.
>
I actually did this in one of my experiments and it worked fine.
Although I also had to update the template parm list with new decl:

   TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);

At that point I had the convert function in pt.c an operating directly
on current_template_parms (also having direct access to the two statics
required; reduce_template_parm_level and canonical_type_parameter).

I can't think of a case where we'd want to make this substitution in
anything but the current_template_parms so maybe moving the convert
function back into to pt.c and removing the 'current' parm from it
might be best?

> And if we're doing that, setting TYPE_STUB_DECL and TYPE_NAME is
> indeed necessary.
>
>> Only for the sake of not exposing this (currently static) function 
>> from
>> pt.c (or moving the pack convert function into pt.c).  My original 
>> impl
>> did extern canonical_type_parameter and use that and I think it 
>> worked
>> as expected.  Would that be preferred?
>
> Yes.  Please declare it in cp-tree.h rather than within the function.
>
Will do.  Unless, as suggested above, we go for moving
convert_generic_types_to_packs into pt.c in which case exposing these
internals won't be necessary.

Cheers,
Adam

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-10 12:08         ` Adam Butcher
@ 2013-11-10 16:14           ` Adam Butcher
  2013-11-10 19:54             ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-10 16:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

[-- Attachment #1: Type: text/plain, Size: 1694 bytes --]

On 2013-11-10 10:38, Adam Butcher wrote:
> On 2013-11-10 6:10, Jason Merrill wrote:
>>
>> Hmm, actually I think messing with the non-pack's decl is dangerous,
>> and we should come up with a new decl for the pack instead.  I think
>> you can use reduce_template_parm_level with a "levels" argument of 0
>> to build a new decl and parm index.
>>
> I actually did this in one of my experiments and it worked fine.
> Although I also had to update the template parm list with new decl:
>
>   TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);
>
> At that point I had the convert function in pt.c an operating 
> directly
> on current_template_parms (also having direct access to the two 
> statics
> required; reduce_template_parm_level and canonical_type_parameter).
>
> I can't think of a case where we'd want to make this substitution in
> anything but the current_template_parms so maybe moving the convert
> function back into to pt.c and removing the 'current' parm from it
> might be best?
>
>> And if we're doing that, setting TYPE_STUB_DECL and TYPE_NAME is
>> indeed necessary.
>>
>>> Only for the sake of not exposing this (currently static) function 
>>> from
>>> pt.c (or moving the pack convert function into pt.c).  My original 
>>> impl
>>> did extern canonical_type_parameter and use that and I think it 
>>> worked
>>> as expected.  Would that be preferred?
>>
>> Yes.  Please declare it in cp-tree.h rather than within the 
>> function.
>>
> Will do.  Unless, as suggested above, we go for moving
> convert_generic_types_to_packs into pt.c in which case exposing these
> internals won't be necessary.
>

With the convert function in pt.c, PATCH 2/3 now looks as follows:



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mods2.diff --]
[-- Type: text/x-c++; name=mods2.diff, Size: 4688 bytes --]

    Support implicit parameter packs.
    
    	* pt.c (convert_generic_types_to_packs): New function to transform
    	a range of implicitly introduced non-pack template parms to be parameter
    	packs.
    	* cp-tree.h (convert_generic_types_to_packs): Declare.
    	* parser.c (cp_parser_parameter_declaration_list): If a function
    	parameter pack contains generic types, convert them to packs prior to
    	grokdeclarator.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fd79adb..e30922a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5469,6 +5469,7 @@ extern tree type_uses_auto			(tree);
 extern tree type_uses_auto_or_concept		(tree);
 extern void append_type_to_template_for_access_check (tree, tree, tree,
 						      location_t);
+extern tree convert_generic_types_to_packs	(tree, int, int);
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern bool is_auto_or_concept			(const_tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c48952a..eaad8e4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18131,6 +18131,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       cp_parameter_declarator *parameter;
       tree decl = error_mark_node;
       bool parenthesized_p = false;
+      int template_parm_idx = (parser->num_template_parameter_lists?
+			       TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
+						(current_template_parms)) : 0);
+
       /* Parse the parameter.  */
       parameter
 	= cp_parser_parameter_declaration (parser,
@@ -18142,11 +18146,29 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
+	{
+	  /* If a function parameter pack was specified and an implicit template
+	     parameter was introduced during cp_parser_parameter_declaration,
+	     change any implicit parameters introduced into packs.  */
+	  if (parser->implicit_template_parms
+	      && parameter->declarator
+	      && parameter->declarator->parameter_pack_p)
+	    {
+	      int latest_template_parm_idx = TREE_VEC_LENGTH
+		(INNERMOST_TEMPLATE_PARMS (current_template_parms));
+
+	      if (latest_template_parm_idx != template_parm_idx)
+		parameter->decl_specifiers.type = convert_generic_types_to_packs
+		  (parameter->decl_specifiers.type,
+		   template_parm_idx, latest_template_parm_idx);
+	    }
+
 	  decl = grokdeclarator (parameter->declarator,
 				 &parameter->decl_specifiers,
 				 PARM,
 				 parameter->default_argument != NULL_TREE,
 				 &parameter->decl_specifiers.attributes);
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8c1553f..360d8a3 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21629,6 +21629,56 @@ append_type_to_template_for_access_check (tree templ,
 					      scope, location);
 }
 
+/* Convert the generic type parameters in PARM that match the types given in the
+   range [START_IDX, END_IDX) from the current_template_parms into generic type
+   packs.  */
+
+tree
+convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
+{
+  tree current = current_template_parms;
+  int depth = TMPL_PARMS_DEPTH (current);
+  current = INNERMOST_TEMPLATE_PARMS (current);
+  tree replacement = make_tree_vec (TREE_VEC_LENGTH (current));
+
+  for (int i = start_idx; i < end_idx; ++i)
+    {
+      /* Create a distinct parameter pack type from the current parm and add it
+	 to the replacement args to tsubst below into the generic function
+	 parameter.  */
+
+      tree o = TREE_TYPE (TREE_VALUE
+			  (TREE_VEC_ELT (current, i)));
+      tree t = copy_type (o);
+      TEMPLATE_TYPE_PARM_INDEX (t)
+	= reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (o),
+				      o, 0, 0, tf_none);
+      TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t;
+      TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
+      TYPE_MAIN_VARIANT (t) = t;
+      TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
+      TYPE_CANONICAL (t) = canonical_type_parameter (t);
+      TREE_VEC_ELT (replacement, i) = t;
+      TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);
+    }
+
+  if (depth > 1)
+    {
+      /* Build up a tree vec of empty tree vecs up to the inner substitution
+	 args built above.  */
+
+      tree inner = replacement;
+      replacement = make_tree_vec (depth);
+      int last = depth - 1;
+      for (int i = 0; i < last; ++i)
+	TREE_VEC_ELT (replacement, i) = make_tree_vec (0);
+      TREE_VEC_ELT (replacement, last) = inner;
+    }
+
+  return tsubst (parm, replacement, tf_none, NULL_TREE);
+}
+
+
 /* Set up the hash tables for template instantiations.  */
 
 void

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-10 16:14           ` Adam Butcher
@ 2013-11-10 19:54             ` Jason Merrill
  2013-11-10 20:28               ` Adam Butcher
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2013-11-10 19:54 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Volker Reichelt

On 11/10/2013 08:10 AM, Adam Butcher wrote:
> With the convert function in pt.c, PATCH 2/3 now looks as follows:

I like this direction.

> +      /* Build up a tree vec of empty tree vecs up to the inner substitution
> +	 args built above.  */

I think we want to copy the enclosing args; see existing uses of 
add_outermost_template_args.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-10 19:54             ` Jason Merrill
@ 2013-11-10 20:28               ` Adam Butcher
  2013-11-11  2:41                 ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-10 20:28 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

On 2013-11-10 18:49, Jason Merrill wrote:
> On 11/10/2013 08:10 AM, Adam Butcher wrote:
>>
>> +      /* Build up a tree vec of empty tree vecs up to the inner 
>> substitution
>> +	 args built above.  */
>
> I think we want to copy the enclosing args; see existing uses of
> add_outermost_template_args.
>
OK.  I had that originally but I was concerned that it was wasteful 
which is why I ended up using nullptrs for non-subst'd types in the 
inner level and empty tree vecs for the prior levels.  It seemed to work 
as expected; I assumed that tsubst simply doesn't do anything with a 
null tree substitution (i.e. it is an identity op).  There will be an 
additional, seemingly unnecessary, cost of copying these and the loop 
above will presumably be required to set the non-subst'd types rather 
than leave them as nullptr also.

Since we are tsubsting the declaration here and we only want to adjust 
the template parameter types themselves at their declaration is this 
really necessary?  I've no problem with implementing this if it truly is 
necessary but I don't want to add unnecessary cycles if not.

One other thing, by 'copy' I take it you mean copy the tree vecs of the 
enclosing levels only, not also the types within them.  And I also 
assume that I'll need to set the currently unset types in the inner 
level also?

Cheers
Adam

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-10 20:28               ` Adam Butcher
@ 2013-11-11  2:41                 ` Jason Merrill
  2013-11-11 21:45                   ` Adam Butcher
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2013-11-11  2:41 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Volker Reichelt

On 11/10/2013 02:39 PM, Adam Butcher wrote:
> I assumed that tsubst simply doesn't do anything with a
> null tree substitution (i.e. it is an identity op).

Substituting NULL_TREE for a template parameter gives a template 
parameter with a reduced level; this happens during partial instantiation.

> Since we are tsubsting the declaration here and we only want to adjust
> the template parameter types themselves at their declaration is this
> really necessary?  I've no problem with implementing this if it truly is
> necessary but I don't want to add unnecessary cycles if not.

The difference between setting copying a pointer to a vec versus setting 
it to null seems completely negligible to me.

I think it is necessary in case the function parameter type involves 
template parameters from the enclosing context as well as implicit 
template parameters.

> One other thing, by 'copy' I take it you mean copy the tree vecs of the
> enclosing levels only, not also the types within them.

Yes, using add_outermost_template_args.

> And I also assume that I'll need to set the currently unset types in the inner
> level also?

Can you have explicit template parameters at the same level as the 
implicit ones?  If so, then their places in the vec will need to be set 
appropriately in case they are used in the function parameter type.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-11  2:41                 ` Jason Merrill
@ 2013-11-11 21:45                   ` Adam Butcher
  2013-11-12  7:25                     ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-11 21:45 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt

[-- Attachment #1: Type: text/plain, Size: 2421 bytes --]

On 2013-11-10 23:21, Jason Merrill wrote:
> On 11/10/2013 02:39 PM, Adam Butcher wrote:
>> I assumed that tsubst simply doesn't do anything with a
>> null tree substitution (i.e. it is an identity op).
>
> Substituting NULL_TREE for a template parameter gives a template
> parameter with a reduced level; this happens during partial
> instantiation.
>
Ah, OK.

>> Since we are tsubsting the declaration here and we only want to 
>> adjust
>> the template parameter types themselves at their declaration is this
>> really necessary?  I've no problem with implementing this if it 
>> truly is
>> necessary but I don't want to add unnecessary cycles if not.
>
> The difference between setting copying a pointer to a vec versus
> setting it to null seems completely negligible to me.
>
Sure.  I was more concerned with allocating vecs for each outer list 
and copying the parms over versus allocating a 'null' placeholder list 
for each level which we're not concerned about.  No worries though, I've 
proceeded with your suggestion below.

> I think it is necessary in case the function parameter type involves
> template parameters from the enclosing context as well as implicit
> template parameters.
>
>> One other thing, by 'copy' I take it you mean copy the tree vecs of 
>> the
>> enclosing levels only, not also the types within them.
>
> Yes, using add_outermost_template_args.
>
I have done this (diff -w -b follows).  The route to this seems even 
more costly though; current_template_parms needs to first be converted 
to a vec by current_template_args() then the last nesting level is 
thrown away and replaced with the one we're working on.  It's all 
working but I'm wondering whether a custom loop here would be better.

>> And I also assume that I'll need to set the currently unset types in 
>> the inner
>> level also?
>
> Can you have explicit template parameters at the same level as the
> implicit ones?
>
Yes.

> If so, then their places in the vec will need to be
> set appropriately in case they are used in the function parameter
> type.
>
OK.  I had testcases that appeared to pass OK with the previous 
NULL_TREE tsubst but maybe I wasn't checking something (perhaps a 
combination of an explicit template parm type and an auto in a single 
parm).

End result is that everything looks OK though so we might be able to 
get the C++14 lambda support marked as "in 4.9" soon hopefully.

Cheers,
Adam

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mods3.diff --]
[-- Type: text/x-c; name=mods3.diff, Size: 1473 bytes --]

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 360d8a3..69c7688 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21641,6 +21641,10 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
   current = INNERMOST_TEMPLATE_PARMS (current);
   tree replacement = make_tree_vec (TREE_VEC_LENGTH (current));
 
+  for (int i = 0; i < start_idx; ++i)
+    TREE_VEC_ELT (replacement, i)
+      = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i)));
+
   for (int i = start_idx; i < end_idx; ++i)
     {
       /* Create a distinct parameter pack type from the current parm and add it
@@ -21662,18 +21666,15 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
       TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t);
     }
 
+  for (int i = end_idx, e = TREE_VEC_LENGTH (current); i < e; ++i)
+    TREE_VEC_ELT (replacement, i)
+      = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i)));
+
   if (depth > 1)
-    {
     /* Build up a tree vec of empty tree vecs up to the inner substitution
        args built above.  */
-
-      tree inner = replacement;
-      replacement = make_tree_vec (depth);
-      int last = depth - 1;
-      for (int i = 0; i < last; ++i)
-	TREE_VEC_ELT (replacement, i) = make_tree_vec (0);
-      TREE_VEC_ELT (replacement, last) = inner;
-    }
+    replacement = add_outermost_template_args (current_template_args (),
+					       replacement);
 
   return tsubst (parm, replacement, tf_none, NULL_TREE);
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
  2013-11-11 21:45                   ` Adam Butcher
@ 2013-11-12  7:25                     ` Jason Merrill
  0 siblings, 0 replies; 15+ messages in thread
From: Jason Merrill @ 2013-11-12  7:25 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Volker Reichelt

On 11/11/2013 02:44 PM, Adam Butcher wrote:
>> Yes, using add_outermost_template_args.
>>
> I have done this (diff -w -b follows).  The route to this seems even
> more costly though; current_template_parms needs to first be converted
> to a vec by current_template_args() then the last nesting level is
> thrown away and replaced with the one we're working on.

True.  It looks like you could avoid the wasted conversion of the 
innermost level by doing

template_parms_to_args (TREE_CHAIN (current_template_parms))

rather than

current_template_args.

The patch is OK with or without that change.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2013-11-12  1:57 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 1/3] " Adam Butcher
2013-11-08 19:10   ` [C++ PATCH] " Jason Merrill
2013-11-09 13:56     ` Adam Butcher
2013-11-09 20:16       ` Adam Butcher
2013-11-10 10:34       ` Jason Merrill
2013-11-10 12:08         ` Adam Butcher
2013-11-10 16:14           ` Adam Butcher
2013-11-10 19:54             ` Jason Merrill
2013-11-10 20:28               ` Adam Butcher
2013-11-11  2:41                 ` Jason Merrill
2013-11-11 21:45                   ` Adam Butcher
2013-11-12  7:25                     ` Jason Merrill
2013-11-02 10:03 ` [C++ PATCH 3/3] Add some generic lambda test cases Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 2/3] Support implicit parameter packs Adam Butcher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).