public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack.
  2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
  2013-08-27 19:43 ` [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
  2013-08-27 19:43 ` [PATCH 1/4] Support lambda templates Adam Butcher
@ 2013-08-27 19:43 ` Adam Butcher
  2013-09-01 20:28   ` Jason Merrill
  2013-08-27 20:03 ` [PATCH 3/4] Support dumping type bindings in lambda diagnostics Adam Butcher
  2013-09-01 20:05 ` Lambda templates and implicit function templates Jason Merrill
  4 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-08-27 19:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

	* lambda.c (maybe_add_lambda_conv_op): Optimize argvec building and
	early out if CALLOP contains a function parameter pack.
---
 gcc/cp/lambda.c | 60 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index e9bc7c5..4d76f82 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -770,8 +770,51 @@ maybe_add_lambda_conv_op (tree type)
       return;
     }
 
+  argvec = make_tree_vector ();
+
+  /* Non-template conversion operators are defined directly.  Templates are
+     deferred.  In the non-template case, the nullptr instance of the stateless
+     lambda type is added to ARGVEC for build_call_a.  In the template case it
+     is bound via build_min.  */
+  if (!generic_lambda_p)
+    {
+      arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
+		    null_pointer_node);
+      argvec->quick_push (arg);
+    }
+
+  /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to
+     declare the static member function "_FUN" below.  For each arg append to
+     ARGVEC (converting from reference in the template call op case).  Early out
+     if a parameter pack is found; conversion to function pointer is not
+     supported in this case.  */
+  tree fn_args = NULL_TREE;
+  {
+    tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
+    tree tgt;
+
+    while (src)
+      {
+	if (FUNCTION_PARAMETER_PACK_P (src))
+	  return;
+
+	if (!fn_args)
+	  fn_args = tgt = copy_node (src);
+	else
+	  {
+	    TREE_CHAIN (tgt) = copy_node (src);
+	    tgt = TREE_CHAIN (tgt);
+	  }
+
+	mark_exp_read (tgt);
+	vec_safe_push (argvec,
+		       generic_lambda_p ? convert_from_reference (tgt) : tgt);
+
+	src = TREE_CHAIN (src);
+      }
+  }
+
   tree fn_result = TREE_TYPE (TREE_TYPE (callop));
-  tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
 
   if (generic_lambda_p)
     {
@@ -780,12 +823,6 @@ maybe_add_lambda_conv_op (tree type)
 	 implementation of the conversion operator.  */
 
       tree instance = build_nop (type, null_pointer_node);
-      argvec = make_tree_vector ();
-      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
-	{
-	  mark_exp_read (arg);
-	  vec_safe_push (argvec, convert_from_reference (arg));
-	}
 
       tree objfn = build_min (COMPONENT_REF, NULL_TREE,
 			      instance, DECL_NAME (callop), NULL_TREE);
@@ -802,15 +839,6 @@ maybe_add_lambda_conv_op (tree type)
     }
   else
     {
-      arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
-		    null_pointer_node);
-      argvec = make_tree_vector ();
-      argvec->quick_push (arg);
-      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
-	{
-	  mark_exp_read (arg);
-	  vec_safe_push (argvec, arg);
-	}
       call = build_call_a (callop, argvec->length (), argvec->address ());
       CALL_FROM_THUNK_P (call) = 1;
       if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
-- 
1.8.4

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

* Re: Lambda templates and implicit function templates.
@ 2013-08-27 19:43 Adam Butcher
  2013-08-27 19:43 ` [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
                   ` (4 more replies)
  0 siblings, 5 replies; 22+ messages in thread
From: Adam Butcher @ 2013-08-27 19:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

Hi Jason,

Here's an updated patch set.  The fully_implicit_function_template_p
field has been moved into cp_parser and the other comments addressed.

I've done some testing with parameter packs also.  They work okay with
the explicit template parameter syntax for lambdas.

Unfortunately, due to errors being thrown 'early' in grokdeclarator, I
haven't been able to get 'auto...' (or reference/qualified variants)
working yet.  I think I need to defer processing the parameter pack
internals of grokdeclarator until I have the synthesized template
parameter (or generate one on the fly in-place --- but that's
returning to the old 'on-demand' implementation which we moved away
from).

I don't know if it's the correct thing to do but the implementation
currently omits the conversion to function pointer operator if the
argument list contains a parameter pack.

One other thing, assuming the 'auto...' syntax can be made to work,
bug 41933 needs to be resolved for the expansion returned by the
generic lambda in N3690 5.1.2.5 to compile.  Currently (transforming
the 'auto&&...' to an explicit '<typename T...> T&&...') appears to
yield the bug.

In particular I get:
  error: expansion pattern ‘ts’ contains no argument packs
  sorry, unimplemented: use of ‘type_pack_expansion’ in template

   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933#c8

You look to have done some work on it.  Any direction as to where to
go from there?  If the solution requires reworking variadics somehow
might that perhaps alleviate my problems implementing 'auto...'?
Wishful thinking probably!

Cheers,
Adam


Patch summary (4):
  Support lambda templates.
  Don't generate lambda conversion op if arglist has parameter pack.
  Support dumping type bindings in lambda diagnostics.
  Support using 'auto' in a function parameter list to introduce an
    implicit template parameter.

 gcc/cp/cp-tree.h    |   2 +
 gcc/cp/decl.c       |   7 +-
 gcc/cp/decl2.c      |   5 +-
 gcc/cp/error.c      |  22 +++---
 gcc/cp/lambda.c     | 115 ++++++++++++++++++++++-----
 gcc/cp/parser.c     | 222 +++++++++++++++++++++++++++++++++++++++++++++++++---
 gcc/cp/parser.h     |   6 ++
 gcc/cp/pt.c         |  39 +++++----
 gcc/cp/type-utils.h |  56 +++++++++++++
 9 files changed, 413 insertions(+), 61 deletions(-)
 create mode 100644 gcc/cp/type-utils.h

-- 
1.8.4

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

* [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
@ 2013-08-27 19:43 ` Adam Butcher
  2013-09-01 21:20   ` Jason Merrill
  2013-08-27 19:43 ` [PATCH 1/4] Support lambda templates Adam Butcher
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-08-27 19:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

	* cp-tree.h (type_uses_auto_or_concept): Declare.
	(is_auto_or_concept): Declare.
	* decl.c (grokdeclarator): Allow 'auto' parameters with -std=gnu++1y or
	-std=c++1y.
	* type-utils.h: New header defining ...
	(find_type_usage): ... this new template based on pt.c (type_uses_auto)
	for searching a type tree given a predicate.
	* pt.c (type_uses_auto): Reimplement via type-utils.h (find_type_usage).
	(is_auto_or_concept): New function.
	(type_uses_auto_or_concept): New function.
	* parser.h (struct cp_parser): Add fully_implicit_function_template_p.
	* parser.c (cp_parser_new): Initialize fully_implicit_function_template_p.
	(cp_parser_lambda_expression): Copy and restore value of
	fully_implicit_function_template_p as per other parser fields.
	(cp_parser_parameter_declaration_list): Count generic
	parameters and call ...
	(add_implicit_template_parms): ... this new function to synthesize them
	with help from type-utils.h (find_type_usage), ...
	(tree_type_is_auto_or_concept): ... this new static function and ...
	(make_generic_type_name): ... this new static function.
	(cp_parser_direct_declarator): Account for implicit template parameters.
	(cp_parser_lambda_declarator_opt): Finish fully implicit template if
	necessary by calling ...
	(finish_fully_implicit_template): ... this new function.
	(cp_parser_member_declaration): Likewise.
	(cp_parser_function_definition_after_declarator): Likewise.
---
 gcc/cp/cp-tree.h    |   2 +
 gcc/cp/decl.c       |   7 +-
 gcc/cp/parser.c     | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/parser.h     |   6 ++
 gcc/cp/pt.c         |  35 +++++-----
 gcc/cp/type-utils.h |  56 ++++++++++++++++
 6 files changed, 264 insertions(+), 24 deletions(-)
 create mode 100644 gcc/cp/type-utils.h

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 876a72a..8d4ac94 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5453,10 +5453,12 @@ extern tree make_auto				(void);
 extern tree make_decltype_auto			(void);
 extern tree do_auto_deduction			(tree, tree, tree);
 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 splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
+extern bool is_auto_or_concept			(const_tree);
 extern tree process_template_parm		(tree, location_t, tree, 
 						 bool, bool);
 extern tree end_template_parm_list		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4076a24..df44a6e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10325,9 +10325,12 @@ grokdeclarator (const cp_declarator *declarator,
       if (ctype || in_namespace)
 	error ("cannot use %<::%> in parameter declaration");
 
-      if (type_uses_auto (type))
+      if (type_uses_auto (type) && cxx_dialect < cxx1y)
 	{
-	  error ("parameter declared %<auto%>");
+	  pedwarn (location_of (type), 0,
+		   "use of %<auto%> in parameter declaration "
+		   "only available with "
+		   "-std=c++1y or -std=gnu++1y");
 	  type = error_mark_node;
 	}
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 1f0c2c2..7147bfa 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "plugin.h"
 #include "tree-pretty-print.h"
 #include "parser.h"
+#include "type-utils.h"
 
 \f
 /* The lexer.  */
@@ -2063,6 +2064,11 @@ static vec<constructor_elt, va_gc> *cp_parser_initializer_list
 static bool cp_parser_ctor_initializer_opt_and_function_body
   (cp_parser *, bool);
 
+static tree add_implicit_template_parms
+  (cp_parser *, size_t, tree);
+static tree finish_fully_implicit_template
+  (cp_parser *, tree);
+
 /* Classes [gram.class] */
 
 static tree cp_parser_class_name
@@ -3385,6 +3391,9 @@ cp_parser_new (void)
   /* No template parameters apply.  */
   parser->num_template_parameter_lists = 0;
 
+  /* Not declaring an implicit function template.  */
+  parser->fully_implicit_function_template_p = false;
+
   return parser;
 }
 
@@ -8549,10 +8558,12 @@ 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;
 
     parser->num_template_parameter_lists = 0;
     parser->in_statement = 0;
     parser->in_switch_statement_p = false;
+    parser->fully_implicit_function_template_p = false;
 
     /* By virtue of defining a local class, a lambda expression has access to
        the private variables of enclosing classes.  */
@@ -8576,6 +8587,7 @@ 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;
   }
 
   pop_deferring_access_checks ();
@@ -8920,6 +8932,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	    finish_template_decl (template_param_list);
 	    --parser->num_template_parameter_lists;
 	  }
+	else if (parser->fully_implicit_function_template_p)
+	  fco = finish_fully_implicit_template (parser, fco);
       }
 
     finish_member_declaration (fco);
@@ -16790,8 +16804,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 	      /* Parse the parameter-declaration-clause.  */
 	      params = cp_parser_parameter_declaration_clause (parser);
 
+	      /* Restore saved template parameter lists accounting for implicit
+		 template parameters.  */
 	      parser->num_template_parameter_lists
-		= saved_num_template_parameter_lists;
+		+= saved_num_template_parameter_lists;
 
 	      /* Consume the `)'.  */
 	      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -17889,6 +17905,7 @@ 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;
@@ -17916,11 +17933,18 @@ 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);
+	{
+	  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;
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
@@ -18008,6 +18032,11 @@ 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);
+
   return parameters;
 }
 
@@ -20014,7 +20043,11 @@ cp_parser_member_declaration (cp_parser* parser)
 							      attributes);
 		  /* If the member was not a friend, declare it here.  */
 		  if (!friend_p)
-		    finish_member_declaration (decl);
+		    {
+		      if (parser->fully_implicit_function_template_p)
+			decl = finish_fully_implicit_template (parser, decl);
+		      finish_member_declaration (decl);
+		    }
 		  /* Peek at the next token.  */
 		  token = cp_lexer_peek_token (parser->lexer);
 		  /* If the next token is a semicolon, consume it.  */
@@ -20030,6 +20063,8 @@ cp_parser_member_declaration (cp_parser* parser)
 				  initializer, /*init_const_expr_p=*/true,
 				  asm_specification,
 				  attributes);
+		if (parser->fully_implicit_function_template_p)
+		  decl = finish_fully_implicit_template (parser, decl);
 	    }
 
 	  /* Reset PREFIX_ATTRIBUTES.  */
@@ -22297,6 +22332,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
     = saved_num_template_parameter_lists;
   parser->in_function_body = saved_in_function_body;
 
+  if (parser->fully_implicit_function_template_p)
+    finish_fully_implicit_template (parser, /*member_decl_opt=*/0);
+
   return fn;
 }
 
@@ -28842,4 +28880,134 @@ c_parse_file (void)
   the_parser = NULL;
 }
 
+/* Create an identifier for a generic parameter type (a synthesized
+   template parameter implied by `auto' or a concept identifier). */
+
+static tree
+make_generic_type_name (int i)
+{
+  char buf[32];
+  sprintf (buf, "__GenT%d", i);
+  return get_identifier (buf);
+}
+
+/* Predicate that behaves as is_auto_or_concept but matches the parent
+   node of the generic type rather than the generic type itself.  This
+   allows for type transformation in add_implicit_template_parms.  */
+
+static inline bool
+tree_type_is_auto_or_concept (const_tree t)
+{
+  return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
+}
+
+/* Add 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.  */
+
+tree
+add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters)
+{
+  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_idx = 0;
+  tree tparms = NULL_TREE;
+
+  // 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;
+
+  if (become_template)
+    {
+      push_deferring_access_checks (dk_deferred);
+      begin_template_parm_list ();
+
+      parser->fully_implicit_function_template_p = true;
+      ++parser->num_template_parameter_lists;
+    }
+  else // extend current template parameter list
+    {
+      gcc_assert (current_template_parms);
+
+      // pop the innermost template parms into tparms
+      tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+      current_template_parms = TREE_CHAIN (current_template_parms);
+      for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < end; ++n)
+	tparms = chainon (tparms, TREE_VEC_ELT (inner_vec, n));
+
+      ++processing_template_parmlist;
+    }
+
+  for (tree p = parameters; p && synth_idx < 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;
+
+      tree synth_id = make_generic_type_name (synth_idx++);
+      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);
+
+      // 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.
+
+      tree& cur_type = TREE_TYPE (generic_type_ptr);
+      tree new_type = TREE_TYPE (getdecls ());
+
+      if (TYPE_QUALS (cur_type))
+	cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type));
+      else
+	cur_type = new_type;
+    }
+
+  gcc_assert (synth_idx == count);
+
+  push_binding_level (fn_parms_scope);
+
+  end_template_parm_list (tparms);
+
+  return parameters;
+}
+
+/* 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
+   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. */
+
+tree
+finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt)
+{
+  gcc_assert (parser->fully_implicit_function_template_p);
+
+  pop_deferring_access_checks ();
+  if (member_decl_opt)
+    member_decl_opt = finish_member_template_decl (member_decl_opt);
+  end_template_decl ();
+
+  parser->fully_implicit_function_template_p = false;
+  --parser->num_template_parameter_lists;
+
+  return member_decl_opt;
+}
+
 #include "gt-cp-parser.h"
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 3d8bb74..ffdddaf 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -341,6 +341,12 @@ typedef struct GTY(()) cp_parser {
   /* The number of template parameter lists that apply directly to the
      current declaration.  */
   unsigned num_template_parameter_lists;
+
+  /* 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;
+
 } cp_parser;
 
 /* In parser.c  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ba841ca..22087fb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "timevar.h"
 #include "tree-iterator.h"
+#include "type-utils.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
@@ -21098,31 +21099,35 @@ is_auto (const_tree type)
     return false;
 }
 
-/* Returns true iff TYPE contains a use of 'auto'.  Since auto can only
-   appear as a type-specifier for the declaration in question, we don't
-   have to look through the whole type.  */
+/* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains
+   a use of `auto'.  Returns NULL_TREE otherwise.  */
 
 tree
 type_uses_auto (tree type)
 {
-  enum tree_code code;
-  if (is_auto (type))
-    return type;
+  return find_type_usage (type, is_auto);
+}
 
-  code = TREE_CODE (type);
+/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto',
+   'decltype(auto)' or a concept.  */
 
-  if (code == POINTER_TYPE || code == REFERENCE_TYPE
-      || code == OFFSET_TYPE || code == FUNCTION_TYPE
-      || code == METHOD_TYPE || code == ARRAY_TYPE)
-    return type_uses_auto (TREE_TYPE (type));
+bool
+is_auto_or_concept (const_tree type)
+{
+  return is_auto (type); // or concept
+}
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    return type_uses_auto (TREE_TYPE (TREE_TYPE
-				   (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+/* Returns the TEMPLATE_TYPE_PARM in TYPE representing a generic type (`auto' or
+   a concept identifier) iff TYPE contains a use of a generic type.  Returns
+   NULL_TREE otherwise.  */
 
-  return NULL_TREE;
+tree
+type_uses_auto_or_concept (tree type)
+{
+  return find_type_usage (type, is_auto_or_concept);
 }
 
+
 /* For a given template T, return the vector of typedefs referenced
    in T for which access check is needed at T instantiation time.
    T is either  a FUNCTION_DECL or a RECORD_TYPE.
diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h
new file mode 100644
index 0000000..db5b1e2
--- /dev/null
+++ b/gcc/cp/type-utils.h
@@ -0,0 +1,56 @@
+/* Utilities for querying and manipulating type trees.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_TYPE_UTILS_H
+#define GCC_CP_TYPE_UTILS_H
+
+/* Returns the first tree within T that is directly matched by PRED.  T may be a
+   type or PARM_DECL and is incrementally decomposed toward its type-specifier
+   until a match is found.  NULL_TREE is returned if PRED does not match any
+   part of T.
+
+   This is primarily intended for detecting whether T uses `auto' or a concept
+   identifier.  Since either of these can only appear as a type-specifier for
+   the declaration in question, only top-level qualifications are traversed;
+   find_type_usage does not look through the whole type.  */
+
+template <typename TreePredicate>
+inline tree
+find_type_usage (tree t, TreePredicate pred)
+{
+  enum tree_code code;
+  if (pred (t))
+    return t;
+
+  code = TREE_CODE (t);
+
+  if (code == POINTER_TYPE || code == REFERENCE_TYPE
+      || code == PARM_DECL || code == OFFSET_TYPE
+      || code == FUNCTION_TYPE || code == METHOD_TYPE
+      || code == ARRAY_TYPE)
+    return find_type_usage (TREE_TYPE (t), pred);
+
+  if (TYPE_PTRMEMFUNC_P (t))
+    return find_type_usage
+      (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred);
+
+  return NULL_TREE;
+}
+
+#endif // GCC_CP_TYPE_UTILS_H
-- 
1.8.4

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

* [PATCH 1/4] Support lambda templates.
  2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
  2013-08-27 19:43 ` [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
@ 2013-08-27 19:43 ` Adam Butcher
  2013-09-01 20:22   ` Jason Merrill
  2013-08-27 19:43 ` [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack Adam Butcher
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-08-27 19:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

	* parser.c (cp_parser_lambda_declarator_opt): Accept template parameter
	list with std=c++1y or std=gnu++1y.
	(cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call
	operator template to avoid adding template result to symbol table.
	* lambda.c (lambda_function): Return template result if call operator is
	a template.
	(maybe_add_lambda_conv_op): Support conversion of a non-capturing lambda
	template to a function pointer.
	* decl2.c (check_member_template): Don't reject lambda call operator
	template in local [lambda] class.
	* pt.c (instantiate_class_template_1): Don't instantiate lambda call
	operator template when instantiating lambda class.
---
 gcc/cp/decl2.c  |  5 ++--
 gcc/cp/lambda.c | 87 ++++++++++++++++++++++++++++++++++++++++++++-------------
 gcc/cp/parser.c | 40 ++++++++++++++++++++++++--
 gcc/cp/pt.c     |  4 ++-
 4 files changed, 110 insertions(+), 26 deletions(-)

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index d5d2912..ac9dbd7 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -507,8 +507,9 @@ check_member_template (tree tmpl)
       || (TREE_CODE (decl) == TYPE_DECL
 	  && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))))
     {
-      /* The parser rejects template declarations in local classes.  */
-      gcc_assert (!current_function_decl);
+      /* The parser rejects template declarations in local classes
+	 (with the exception of generic lambdas).  */
+      gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl));
       /* The parser rejects any use of virtual in a function template.  */
       gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL
 		    && DECL_VIRTUAL_P (decl)));
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index a53e692..e9bc7c5 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -196,7 +196,7 @@ lambda_function (tree lambda)
 			  /*protect=*/0, /*want_type=*/false,
 			  tf_warning_or_error);
   if (lambda)
-    lambda = BASELINK_FUNCTIONS (lambda);
+    lambda = STRIP_TEMPLATE (get_first_fn (lambda));
   return lambda;
 }
 
@@ -759,6 +759,10 @@ maybe_add_lambda_conv_op (tree type)
   if (processing_template_decl)
     return;
 
+  bool generic_lambda_p
+    = (DECL_TEMPLATE_INFO (callop)
+    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
+
   if (DECL_INITIAL (callop) == NULL_TREE)
     {
       /* If the op() wasn't instantiated due to errors, give up.  */
@@ -766,7 +770,54 @@ maybe_add_lambda_conv_op (tree type)
       return;
     }
 
-  stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)),
+  tree fn_result = TREE_TYPE (TREE_TYPE (callop));
+  tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
+
+  if (generic_lambda_p)
+    {
+      /* Construct the dependent member call for the static member function
+	 '_FUN' and remove 'auto' from its return type to allow for simple
+	 implementation of the conversion operator.  */
+
+      tree instance = build_nop (type, null_pointer_node);
+      argvec = make_tree_vector ();
+      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+	{
+	  mark_exp_read (arg);
+	  vec_safe_push (argvec, convert_from_reference (arg));
+	}
+
+      tree objfn = build_min (COMPONENT_REF, NULL_TREE,
+			      instance, DECL_NAME (callop), NULL_TREE);
+      call = build_nt_call_vec (objfn, argvec);
+
+      if (type_uses_auto (fn_result))
+	{
+	  ++processing_template_decl;
+	  fn_result = finish_decltype_type
+	    (call, /*id_expression_or_member_access_p=*/false,
+	     tf_warning_or_error);
+	  --processing_template_decl;
+	}
+    }
+  else
+    {
+      arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
+		    null_pointer_node);
+      argvec = make_tree_vector ();
+      argvec->quick_push (arg);
+      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+	{
+	  mark_exp_read (arg);
+	  vec_safe_push (argvec, arg);
+	}
+      call = build_call_a (callop, argvec->length (), argvec->address ());
+      CALL_FROM_THUNK_P (call) = 1;
+      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
+	call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
+    }
+
+  stattype = build_function_type (fn_result,
 				  FUNCTION_ARG_CHAIN (callop));
 
   /* First build up the conversion op.  */
@@ -794,6 +845,9 @@ maybe_add_lambda_conv_op (tree type)
   if (nested)
     DECL_INTERFACE_KNOWN (fn) = 1;
 
+  if (generic_lambda_p)
+    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
   add_method (type, fn, NULL_TREE);
 
   /* Generic thunk code fails for varargs; we'll complain in mark_used if
@@ -820,8 +874,8 @@ maybe_add_lambda_conv_op (tree type)
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
-  DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
-  for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg))
+  DECL_ARGUMENTS (fn) = fn_args;
+  for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
       /* Avoid duplicate -Wshadow warnings.  */
       DECL_NAME (arg) = NULL_TREE;
@@ -830,6 +884,9 @@ maybe_add_lambda_conv_op (tree type)
   if (nested)
     DECL_INTERFACE_KNOWN (fn) = 1;
 
+  if (generic_lambda_p)
+    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
+
   add_method (type, fn, NULL_TREE);
 
   if (nested)
@@ -852,27 +909,15 @@ maybe_add_lambda_conv_op (tree type)
     }
   body = begin_function_body ();
   compound_stmt = begin_compound_stmt (0);
-
-  arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
-		null_pointer_node);
-  argvec = make_tree_vector ();
-  argvec->quick_push (arg);
-  for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg))
-    {
-      mark_exp_read (arg);
-      vec_safe_push (argvec, arg);
-    }
-  call = build_call_a (callop, argvec->length (), argvec->address ());
-  CALL_FROM_THUNK_P (call) = 1;
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
-    call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
   call = convert_from_reference (call);
   finish_return_stmt (call);
 
   finish_compound_stmt (compound_stmt);
   finish_function_body (body);
 
-  expand_or_defer_fn (finish_function (2));
+  fn = finish_function (/*inline*/2);
+  if (!generic_lambda_p)
+    expand_or_defer_fn (fn);
 
   /* Generate the body of the conversion op.  */
 
@@ -888,7 +933,9 @@ maybe_add_lambda_conv_op (tree type)
   finish_compound_stmt (compound_stmt);
   finish_function_body (body);
 
-  expand_or_defer_fn (finish_function (2));
+  fn = finish_function (/*inline*/2);
+  if (!generic_lambda_p)
+    expand_or_defer_fn (fn);
 
   if (nested)
     pop_function_context ();
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 923277b..1f0c2c2 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8783,6 +8783,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
+     < template-parameter-list [opt] >
      ( parameter-declaration-clause [opt] )
        attribute-specifier [opt]
        mutable [opt]
@@ -8802,9 +8803,30 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
   tree param_list = void_list_node;
   tree attributes = NULL_TREE;
   tree exception_spec = NULL_TREE;
+  tree template_param_list = NULL_TREE;
 
-  /* The lambda-declarator is optional, but must begin with an opening
-     parenthesis if present.  */
+  /* The template-parameter-list is optional, but must begin with
+     an opening angle if present.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    {
+      if (cxx_dialect < cxx1y)
+	pedwarn (parser->lexer->next_token->location, 0,
+		 "lambda templates are only available with "
+		 "-std=c++1y or -std=gnu++1y");
+
+      cp_lexer_consume_token (parser->lexer);
+
+      template_param_list = cp_parser_template_parameter_list (parser);
+
+      cp_parser_skip_to_end_of_template_parameter_list (parser);
+
+      /* We just processed one more parameter list.  */
+      ++parser->num_template_parameter_lists;
+    }
+
+  /* The parameter-declaration-clause is optional (unless
+     template-parameter-list was given), but must begin with an
+     opening parenthesis if present.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
       cp_lexer_consume_token (parser->lexer);
@@ -8847,6 +8869,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
          trailing-return-type in case of decltype.  */
       pop_bindings_and_leave_scope ();
     }
+  else if (template_param_list != NULL_TREE) // generate diagnostic
+    cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
   /* Create the function call operator.
 
@@ -8890,6 +8914,12 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	DECL_ARTIFICIAL (fco) = 1;
 	/* Give the object parameter a different name.  */
 	DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
+	if (template_param_list)
+	  {
+	    fco = finish_member_template_decl (fco);
+	    finish_template_decl (template_param_list);
+	    --parser->num_template_parameter_lists;
+	  }
       }
 
     finish_member_declaration (fco);
@@ -9012,7 +9042,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     finish_lambda_scope ();
 
     /* Finish the function and generate code for it if necessary.  */
-    expand_or_defer_fn (finish_function (/*inline*/2));
+    tree fn = finish_function (/*inline*/2);
+
+    /* Only expand if the call op is not a template.  */
+    if (!DECL_TEMPLATE_INFO (fco))
+      expand_or_defer_fn (fn);
   }
 
   parser->local_variables_forbidden_p = local_variables_forbidden_p;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e937318..ba841ca 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9102,7 +9102,9 @@ instantiate_class_template_1 (tree type)
       tree decl = lambda_function (type);
       if (decl)
 	{
-	  instantiate_decl (decl, false, false);
+	  if (!DECL_TEMPLATE_INFO (decl)
+	      || DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) != decl)
+	    instantiate_decl (decl, false, false);
 
 	  /* We need to instantiate the capture list from the template
 	     after we've instantiated the closure members, but before we
-- 
1.8.4

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

* [PATCH 3/4] Support dumping type bindings in lambda diagnostics.
  2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
                   ` (2 preceding siblings ...)
  2013-08-27 19:43 ` [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack Adam Butcher
@ 2013-08-27 20:03 ` Adam Butcher
  2013-09-01 20:05 ` Lambda templates and implicit function templates Jason Merrill
  4 siblings, 0 replies; 22+ messages in thread
From: Adam Butcher @ 2013-08-27 20:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

	* error.c (dump_function_decl): Use standard diagnostic flow to dump a
	lambda diagnostic, albeit without stating the function name or
	duplicating the parameter spec (which is dumped as part of the type).
---
 gcc/cp/error.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c82a0ce..27ff962 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1380,14 +1380,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME);
   tree exceptions;
   vec<tree, va_gc> *typenames = NULL;
-
-  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
-    {
-      /* A lambda's signature is essentially its "type", so defer.  */
-      gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t)));
-      dump_type (pp, DECL_CONTEXT (t), flags);
-      return;
-    }
+  bool lambda_p = false;
 
   flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
   if (TREE_CODE (t) == TEMPLATE_DECL)
@@ -1449,16 +1442,23 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   else if (cname)
     {
       dump_type (pp, cname, flags);
-      pp_cxx_colon_colon (pp);
+      if (LAMBDA_TYPE_P (cname))
+	lambda_p = true;
+      else
+	pp_cxx_colon_colon (pp);
     }
   else
     dump_scope (pp, CP_DECL_CONTEXT (t), flags);
 
-  dump_function_name (pp, t, flags);
+  /* A lambda's signature is essentially its "type", which has already been
+     dumped.  */
+  if (!lambda_p)
+    dump_function_name (pp, t, flags);
 
   if (!(flags & TFF_NO_FUNCTION_ARGUMENTS))
     {
-      dump_parameters (pp, parmtypes, flags);
+      if (!lambda_p)
+	dump_parameters (pp, parmtypes, flags);
 
       if (TREE_CODE (fntype) == METHOD_TYPE)
 	{
-- 
1.8.4

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

* Re: Lambda templates and implicit function templates.
  2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
                   ` (3 preceding siblings ...)
  2013-08-27 20:03 ` [PATCH 3/4] Support dumping type bindings in lambda diagnostics Adam Butcher
@ 2013-09-01 20:05 ` Jason Merrill
  2013-09-02 18:27   ` Adam Butcher
  4 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-01 20:05 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/27/2013 03:42 PM, Adam Butcher wrote:
> Unfortunately, due to errors being thrown 'early' in grokdeclarator, I
> haven't been able to get 'auto...' (or reference/qualified variants)
> working yet.  I think I need to defer processing the parameter pack
> internals of grokdeclarator until I have the synthesized template
> parameter (or generate one on the fly in-place --- but that's
> returning to the old 'on-demand' implementation which we moved away
> from).

Hmm, yes.  I'm not sure which approach would be better.

> I don't know if it's the correct thing to do but the implementation
> currently omits the conversion to function pointer operator if the
> argument list contains a parameter pack.

I would expect that to work.  Does the specification not provide for 
deduction in that case?

> One other thing, assuming the 'auto...' syntax can be made to work,
> bug 41933 needs to be resolved for the expansion returned by the
> generic lambda in N3690 5.1.2.5 to compile.  Currently (transforming
> the 'auto&&...' to an explicit '<typename T...> T&&...') appears to
> yield the bug.

Bug 41933 is specifically about lambda capture; I think you're running 
into something else.

Jason

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-08-27 19:43 ` [PATCH 1/4] Support lambda templates Adam Butcher
@ 2013-09-01 20:22   ` Jason Merrill
  2013-09-02 18:30     ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-01 20:22 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/27/2013 03:42 PM, Adam Butcher wrote:
> +	  vec_safe_push (argvec, arg);

I bet we want convert_from_reference in the non-generic lambda case, too.

OK with that change.

Jason

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

* Re: [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack.
  2013-08-27 19:43 ` [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack Adam Butcher
@ 2013-09-01 20:28   ` Jason Merrill
  0 siblings, 0 replies; 22+ messages in thread
From: Jason Merrill @ 2013-09-01 20:28 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/27/2013 03:42 PM, Adam Butcher wrote:
> +	if (FUNCTION_PARAMETER_PACK_P (src))
> +	  return;

Yeah, in the case of a parameter pack we want to pass a pack expansion.

Jason

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

* Re: [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-27 19:43 ` [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
@ 2013-09-01 21:20   ` Jason Merrill
  2013-09-02 18:45     ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-01 21:20 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/27/2013 03:42 PM, Adam Butcher wrote:
> +  else // extend current template parameter list
> +      // pop the innermost template parms into tparms

Most comments should start with a capital letter and end with a period.

> +      for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < end; ++n)
> +	tparms = chainon (tparms, TREE_VEC_ELT (inner_vec, n));

Doing chainon in a loop has bad algorithmic complexity, as it walks 
through the whole tparms list each iteration.  Better to build up a list 
from inner_vec and then chainon that list as a whole.

> +template <typename TreePredicate>
> +inline tree
> +find_type_usage (tree t, TreePredicate pred)

I don't think this needs to be a template, since we know the predicates 
take a single tree and return bool.

I don't see any diagnostic for the implicit function template extension; 
my earlier comment about not controlling it with -std=c++1y vs gnu++1y 
didn't mean it should go away entirely.  :)

Maybe we should call it part of c++1z, or just control the diagnostic 
with -pedantic.

Jason

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

* Re: Lambda templates and implicit function templates.
  2013-09-01 20:05 ` Lambda templates and implicit function templates Jason Merrill
@ 2013-09-02 18:27   ` Adam Butcher
  2013-09-02 18:51     ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-02 18:27 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 01.09.2013 21:05, Jason Merrill wrote:
> On 08/27/2013 03:42 PM, Adam Butcher wrote:
>> I don't know if it's the correct thing to do but the implementation
>> currently omits the conversion to function pointer operator if the
>> argument list contains a parameter pack.
>
> I would expect that to work.  Does the specification not provide for
> deduction in that case?
>
It doesn't forbid it as far as I can see.  But it also gives no
example of a stateless lambda with a variadic parameter.  TBH I just
couldn't figure out the right implementation so thought it better
to omit the conversion operator on the assumption that it is not a
common use case rather than ICE .  I'll have a rethink based on your
follow up to 2/4 and try to get a pack expansion working there.

>> One other thing, assuming the 'auto...' syntax can be made to work,
>> bug 41933 needs to be resolved for the expansion returned by the
>> generic lambda in N3690 5.1.2.5 to compile.  Currently (transforming
>> the 'auto&&...' to an explicit '<typename T...> T&&...') appears to
>> yield the bug.
>
> Bug 41933 is specifically about lambda capture; I think you're
> running into something else.
>
The problem is in expanding the 'ts' capture from the 5.1.2.5.  It
looks like this:

   1 auto vglambda = [](auto printer) {
   2   return [=](auto&& ... ts) { // OK: ts is a function parameter 
pack
   3     printer(std::forward<decltype(ts)>(ts)...);
   4     return [=]() {
   5       printer(ts ...);
   6     };
   7   };
   8 };

It is the expansion of the captured 'ts' on line 5 that I think yields
the bug.  Might be slightly different to 41933 though due to not being
explicitly captured as "ts...".  Unsure.   My point was that in order 
to
conform this issue will need to be fixed as well as getting the
'auto...' syntax to work.

Cheers,
Adam

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-01 20:22   ` Jason Merrill
@ 2013-09-02 18:30     ` Adam Butcher
  2013-09-02 18:34       ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-02 18:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 01.09.2013 21:22, Jason Merrill wrote:
> On 08/27/2013 03:42 PM, Adam Butcher wrote:
>> +	  vec_safe_push (argvec, arg);
>
> I bet we want convert_from_reference in the non-generic lambda case, 
> too.
>
> OK with that change.
>
I think I had made that change originally to keep the two impls the 
same and I hit issues with non-generic lambdas.  But I can't remember 
the details.  I'll try again.  If it works with convert_from_reference 
in both cases should I push or should I sort out the parameter pack 
conversion op issue and roll that up into this?


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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-02 18:30     ` Adam Butcher
@ 2013-09-02 18:34       ` Jason Merrill
  2013-09-02 21:18         ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-02 18:34 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09/02/2013 02:30 PM, Adam Butcher wrote:
> I think I had made that change originally to keep the two impls the same
> and I hit issues with non-generic lambdas.  But I can't remember the
> details.  I'll try again.  If it works with convert_from_reference in
> both cases should I push or should I sort out the parameter pack
> conversion op issue and roll that up into this?

I think roll them together, since that patch rewrites parts of this one.

Jason


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

* Re: [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-09-01 21:20   ` Jason Merrill
@ 2013-09-02 18:45     ` Adam Butcher
  0 siblings, 0 replies; 22+ messages in thread
From: Adam Butcher @ 2013-09-02 18:45 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 01.09.2013 22:20, Jason Merrill wrote:
> On 08/27/2013 03:42 PM, Adam Butcher wrote:
>> +  else // extend current template parameter list
>> +      // pop the innermost template parms into tparms
>
> Most comments should start with a capital letter and end with a 
> period.
>
Will change.

>> +      for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < 
>> end; ++n)
>> +	tparms = chainon (tparms, TREE_VEC_ELT (inner_vec, n));
>
> Doing chainon in a loop has bad algorithmic complexity, as it walks
> through the whole tparms list each iteration.  Better to build up a
> list from inner_vec and then chainon that list as a whole.
>
Okay.

>> +template <typename TreePredicate>
>> +inline tree
>> +find_type_usage (tree t, TreePredicate pred)
>
> I don't think this needs to be a template, since we know the
> predicates take a single tree and return bool.
>
I didn't know whether to allow for someone passing in a stateful
lambda (or other functor) in future so I avoided the issue by
making the predicate a template type param.  If we're happy that
only c-style functions (or stateless lambdas) will be passed then
I'll put it back as 'bool (*) (const_tree)'.

> I don't see any diagnostic for the implicit function template
> extension; my earlier comment about not controlling it with 
> -std=c++1y
> vs gnu++1y didn't mean it should go away entirely.  :)
>
> Maybe we should call it part of c++1z, or just control the diagnostic
> with -pedantic.
>
I must confess I was a bit unclear about how to proceed there.  I'll
reinstate the two messages and go with a specific diagnostic if
-pedantic is set in the non-lambda case.

Cheers,
Adam

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

* Re: Lambda templates and implicit function templates.
  2013-09-02 18:27   ` Adam Butcher
@ 2013-09-02 18:51     ` Jason Merrill
  0 siblings, 0 replies; 22+ messages in thread
From: Jason Merrill @ 2013-09-02 18:51 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09/02/2013 02:27 PM, Adam Butcher wrote:
>> Bug 41933 is specifically about lambda capture; I think you're
>> running into something else.
>>
> The problem is in expanding the 'ts' capture from the 5.1.2.5.  It
> looks like this:
>
>    1 auto vglambda = [](auto printer) {
>    2   return [=](auto&& ... ts) { // OK: ts is a function parameter pack
>    3     printer(std::forward<decltype(ts)>(ts)...);
>    4     return [=]() {
>    5       printer(ts ...);
>    6     };
>    7   };
>    8 };
>
> It is the expansion of the captured 'ts' on line 5 that I think yields
> the bug.

Ah, yes, that is 41933.  I thought you were saying that a testcase 
without the innermost lambda would fail.

Jason

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-02 18:34       ` Jason Merrill
@ 2013-09-02 21:18         ` Adam Butcher
  2013-09-03  3:50           ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-02 21:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 02.09.2013 19:34, Jason Merrill wrote:
> On 09/02/2013 02:30 PM, Adam Butcher wrote:
>> On 01.09.2013 21:22, Jason Merrill wrote:
>>> I bet we want convert_from_reference in the non-generic lambda 
>>> case, too.
>>>
>> I think I had made that change originally to keep the two impls the 
>> same
>> and I hit issues with non-generic lambdas.  But I can't remember the
>> details.  I'll try again.
>>
Okay, finally got around to trying this again.  With 
convert_from_reference in the non-generic case, the code compiles okay 
but SEGVs on the attempt to branch to '_FUN'.

   │105       auto lf0 = [] (float& a, int const& b) { return a += b; };
   │106
   │107       INVOKEi (lf, float, 7, 0);
  >│108       AS_FUNi (lf, float, 7, 0);
   │109       AS_PTRi (lf, float, int, 7, 0);

   │0x404500 <main()+14687> mov    %eax,-0x4bc(%rbp)
   │0x404506 <main()+14693> mov    0x36f0(%rip),%eax        # 0x407bfc
   │0x40450c <main()+14699> mov    %eax,-0x4c0(%rbp)
   │0x404512 <main()+14705> movl   $0x7,-0x2a4(%rbp)
   │0x40451c <main()+14715> lea    -0x2a4(%rbp),%rdx
   │0x404523 <main()+14722> lea    -0x4bc(%rbp),%rax
   │0x40452a <main()+14729> mov    %rdx,%rsi
   │0x40452d <main()+14732> mov    %rax,%rdi
  >│0x404530 <main()+14735> callq  0x400934 <<lambda(float&, int 
const&)>::_FUN(float &, const int &)>


>> If it works with convert_from_reference in
>> both cases should I push or should I sort out the parameter pack
>> conversion op issue and roll that up into this?
>
> I think roll them together, since that patch rewrites parts of this 
> one.
>
Will assume, for now, that the convert_from_reference call is not 
wanted in the non-generic case (maybe something to do with using 
'build_call_a' instead of 'build_nt_call_vec' or the 
convert_from_reference on the call itself?) and will focus on the 
parameter pack stuff (when I get a chance).

Cheers,
Adam

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-02 21:18         ` Adam Butcher
@ 2013-09-03  3:50           ` Jason Merrill
  2013-09-03 19:50             ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-03  3:50 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09/02/2013 05:18 PM, Adam Butcher wrote:
> Will assume, for now, that the convert_from_reference call is not wanted
> in the non-generic case (maybe something to do with using 'build_call_a'
> instead of 'build_nt_call_vec' or the convert_from_reference on the call
> itself?)

Ah, yes; we are passing references through directly as pointers rather 
than doing the equivalent of &*.

> and will focus on the parameter pack stuff (when I get a chance).

Sounds good.

Jason

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-03  3:50           ` Jason Merrill
@ 2013-09-03 19:50             ` Adam Butcher
  2013-09-03 21:25               ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-03 19:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 03.09.2013 04:50, Jason Merrill wrote:
> On 09/02/2013 05:18 PM, Adam Butcher wrote:
> > will focus on the parameter pack stuff (when I get a chance).
> >
> Sounds good.
>
I had a quick hack at getting pack expansion working for the conversion 
op.
The syntactic side seems to be okay.  It gets all the way to finalizing 
the tu.
It generates suitable diagnostics if I force warnings in various places 
in my
testcase.

I've done what amounts to the following (diff hand edited to removing 
noisy
debug logging and temporaries):

------------------
@@ -795,20 +794,39 @@ maybe_add_lambda_conv_op (tree type)

      while (src)
        {
-       if (FUNCTION_PARAMETER_PACK_P (src))
-         return;
+       tree new_node = copy_node (src);

         if (!fn_args)
-         fn_args = tgt = copy_node (src);
+         fn_args = tgt = new_node;
         else
           {
-           TREE_CHAIN (tgt) = copy_node (src);
-           tgt = TREE_CHAIN (tgt);
+           TREE_CHAIN (tgt) = new_node;
+           tgt = new_node;
           }

         mark_exp_read (tgt);
+
+       if (FUNCTION_PARAMETER_PACK_P (tgt))
+           vec_safe_push (argvec, make_pack_expansion (tgt));
+       else
             vec_safe_push (argvec,
                            generic_lambda_p ? convert_from_reference 
(tgt) : tgt);

         src = TREE_CHAIN (src);
        }
------------------


Problem is that no RTL is set for the incoming parms in the 
instantiation of
the expansion.  It ICEs in gimple_expand_cfg because 'DECL_RTL_IF_SET 
(var)'
returns nullptr for the incoming parms resulting in a failed assertion 
that
SA.partition_to_pseudo[i] is non-null.

What follows below is basically a dump of various info that may help 
you to
point me in the right direction or may be completely useless or 
unnecessary to
you.

Any ideas appreciated.

Cheers,
Adam


The error diagnostic is:


/home/ajb/t7-variadic-ptr.cpp: In static member function ‘static 
decltype (((main()::<lambda(P 
...)>)0u).operator()(main::__lambda1::_FUN::<unnamed> ...)) 
main()::<lambda(P ...)>::_FUN(P ...) [with P = {double, double, double}; 
decltype (((main()::<lambda(P 
...)>)0u).operator()(main::__lambda1::_FUN::<unnamed> ...)) = float]’:

/home/ajb/t7-variadic-ptr.cpp:13:37: internal compiler error: in 
gimple_expand_cfg, at cfgexpand.c:4649
     auto g = [] <typename... P> (P...) { return 3.f; };
                                      ^

This only occurs if I instantiate the conversion op.


I added the following tracing to gimple_expand_cfg:

--------------
@@ -4635,9 +4635,17 @@ gimple_expand_cfg (void)
      {
        tree var = SSA_NAME_VAR (partition_to_var (SA.map, i));

+      debug_tree (var);
+
+      if (TREE_CODE (var) != VAR_DECL)
+        fprintf (stderr, "SA.partition_to_pseudo[%d] == %p\n", i, 
SA.partition_to_pseudo[i]);
+
        if (TREE_CODE (var) != VAR_DECL
           && !SA.partition_to_pseudo[i])
+       {
           SA.partition_to_pseudo[i] = DECL_RTL_IF_SET (var);
+         fprintf (stderr, "SA.partition_to_pseudo[%d] => %p\n", i, 
SA.partition_to_pseudo[i]);
+       }
        gcc_assert (SA.partition_to_pseudo[i]);

        /* If this decl was marked as living in multiple places, reset
--------------


I expected the instantiated parm_decl for the pack expansion parms to 
look
similar to this (from a 'normal' non-pack parm) ...

  <parm_decl 0x7f38340e1f80 D.2134
     type <real_type 0x7f3833f83f18 float type_6 SF
         size <integer_cst 0x7f3833f85340 constant 32>
         unit size <integer_cst 0x7f3833f85360 constant 4>
         align 32 symtab 0 alias set -1 canonical type 0x7f3833f83f18 
precision 32
         pointer_to_this <pointer_type 0x7f3833f8d150>>
     used SF file /home/ajb/t7-variadic-ptr.cpp line 12 col 30 size 
<integer_cst 0x7f3833f85340 32> unit size <integer_cst 0x7f3833f85360 4>
     align 32 context <function_decl 0x7f38340e0900 _FUN>

     (mem/c:SF (plus:DI (reg/f:DI 70 virtual-stack-vars)
         (const_int -20 [0xffffffffffffffec])) [0 D.2134+0 S4 A32]) 
arg-type <real_type 0x7f3833f83f18 float>
     incoming-rtl (reg:SF 21 xmm0 [ D.2134 ])>


... but instead it looks like this:


  <parm_decl 0x7f38340e4600 D.2145
     type <real_type 0x7f3833f8d000 double type_6 DF
         size <integer_cst 0x7f3833f67fc0 constant 64>
         unit size <integer_cst 0x7f3833f67fe0 constant 8>
         align 64 symtab 0 alias set -1 canonical type 0x7f3833f8d000 
precision 64
         pointer_to_this <pointer_type 0x7f3833f8d1f8>>
     used VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34
     align 8
     arg-type <real_type 0x7f3833f8d000 double> chain <parm_decl 
0x7f38340e4680 D.2146>>


  Everything under the tree type seems to be 'default' and I note that 
context
  has gone (it is there in the pack expansion expression prior to
  instantiation).  I'm not sure if this is relevant.

(note I was passing 3 doubles into the variadic template and a float 
into the 'plain' single arg template)


Here's some dumps of the expansion creation from 
maybe_add_lambda_conv_op:


SRC =>
   <parm_decl 0x7f0ae009e880 D.2062
     type <type_pack_expansion 0x7f0ae00a0498
         type <template_type_parm 0x7f0ae00a03f0 P VOID
             align 8 symtab 0 alias set -1 canonical type 0x7f0ae008c150
            index 0 level 1 orig_level 1
             chain <type_decl 0x7f0ae0098cf0 P>>
         type_0 type_6 VOID
         align 8 symtab 0 alias set -1 structural equality>
     decl_1 VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34
     align 8 context <function_decl 0x7f0ae009f800 operator()>
    >
NEW_NODE =>
   <parm_decl 0x7f0ae009ea00 D.2068
     type <type_pack_expansion 0x7f0ae00a0498
         type <template_type_parm 0x7f0ae00a03f0 P VOID
             align 8 symtab 0 alias set -1 canonical type 0x7f0ae008c150
            index 0 level 1 orig_level 1
             chain <type_decl 0x7f0ae0098cf0 P>>
         type_0 type_6 VOID
         align 8 symtab 0 alias set -1 structural equality>
     decl_1 VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34
     align 8 context <function_decl 0x7f0ae009f800 operator()>
    >
MAKE_PACK_EXPANSION =>
   <expr_pack_expansion 0x7f0ae009d270
     type <type_pack_expansion 0x7f0ae00a0498
         type <template_type_parm 0x7f0ae00a03f0 P VOID
             align 8 symtab 0 alias set -1 canonical type 0x7f0ae008c150
            index 0 level 1 orig_level 1
             chain <type_decl 0x7f0ae0098cf0 P>>
         type_0 type_6 VOID
         align 8 symtab 0 alias set -1 structural equality>

     arg 0 <parm_decl 0x7f0ae009ea00 D.2068 type <type_pack_expansion 
0x7f0ae00a0498>
         decl_1 VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34
         align 8 context <function_decl 0x7f0ae009f800 operator()>
        >
     arg 1 <tree_list 0x7f0ae00a12d0 value <parm_decl 0x7f0ae009ea00 
D.2068>>>


  (note the decl context is updated to _FUN instead of operator() after 
this was logged).

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-03 19:50             ` Adam Butcher
@ 2013-09-03 21:25               ` Jason Merrill
  2013-09-05 19:14                 ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Jason Merrill @ 2013-09-03 21:25 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09/03/2013 03:50 PM, Adam Butcher wrote:
> Problem is that no RTL is set for the incoming parms in the
> instantiation of the expansion.  It ICEs in gimple_expand_cfg because 'DECL_RTL_IF_SET
> (var)' returns nullptr for the incoming parms resulting in a failed assertion that
> SA.partition_to_pseudo[i] is non-null.

Sounds like a problem with how _FUN's parameters are instantiated.  I'm 
not sure why it would be special.

Does using a function parameter pack in the lambda body work currently? 
  If so, how are the expanded parameters different?

Jason

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-03 21:25               ` Jason Merrill
@ 2013-09-05 19:14                 ` Adam Butcher
  2013-09-05 20:53                   ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-05 19:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 03.09.2013 22:25, Jason Merrill wrote:
> On 09/03/2013 03:50 PM, Adam Butcher wrote:
>> Problem is that no RTL is set for the incoming parms in the
>> instantiation of the expansion.  It ICEs in gimple_expand_cfg 
>> because 'DECL_RTL_IF_SET
>> (var)' returns nullptr for the incoming parms resulting in a failed 
>> assertion that
>> SA.partition_to_pseudo[i] is non-null.
>
> Sounds like a problem with how _FUN's parameters are instantiated.
> I'm not sure why it would be special.
>
> Does using a function parameter pack in the lambda body work
> currently?  If so, how are the expanded parameters different?
>
Yes it does work.  And I think (hope) I've cracked it; 
make_pack_expansion needs to be called in the body of the thunk (i.e. 
after start_preparsed_function).

If I butcher the implementation so that I rewrite any parameter packs 
with their expansion prior to building the call in return statement, it 
seems to work.

Certainly the following does what I expect it to, the trees look right 
and, more importantly, it doesn't ICE!

    auto g = [] <typename... P> (P...) -> float { return 3.f; };

    float (*pg3) (double, double, double) = g;

    return pg3(1,2,3);

I'll try to clean up what I've got then submit a rolled up patch.

Cheers,
Adam

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-05 19:14                 ` Adam Butcher
@ 2013-09-05 20:53                   ` Adam Butcher
  2013-09-09  7:24                     ` Adam Butcher
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-05 20:53 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 05.09.2013 20:14, Adam Butcher wrote:
> On 03.09.2013 22:25, Jason Merrill wrote:
>> On 09/03/2013 03:50 PM, Adam Butcher wrote:
>>> Problem is that no RTL is set for the incoming parms in the
>>> instantiation of the expansion.  It ICEs in gimple_expand_cfg 
>>> because 'DECL_RTL_IF_SET
>>> (var)' returns nullptr for the incoming parms resulting in a failed 
>>> assertion that
>>> SA.partition_to_pseudo[i] is non-null.
>>
>> Sounds like a problem with how _FUN's parameters are instantiated.
>> I'm not sure why it would be special.
>>
>> Does using a function parameter pack in the lambda body work
>> currently?  If so, how are the expanded parameters different?
>>
> Yes it does work.  And I think (hope) I've cracked it;
> make_pack_expansion needs to be called in the body of the thunk (i.e.
> after start_preparsed_function).
>
Okay, this worked because it had the side effect of setting 
PACK_EXPANSION_LOCAL_P on the expansion.

Doing that at the top, in the existing code seems to have the same 
effect.

Cheers,
Adam

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-05 20:53                   ` Adam Butcher
@ 2013-09-09  7:24                     ` Adam Butcher
  2013-09-09 15:08                       ` Jason Merrill
  0 siblings, 1 reply; 22+ messages in thread
From: Adam Butcher @ 2013-09-09  7:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

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

Hi Jason,

I've attached a patch that handles parameter packs in the conversion 
op.  I thought it best to get this reviewed independently before rolling 
up into the 'Support lambda templates' patch.

Do you think it's the right idea?  It seems to work okay but I've 
reworked the way the template op call is built (and built a separate 
call for the decltype expression).

Cheers,
Adam

[-- Attachment #2: handle-parm-packs-in-lambda-call-op.patch --]
[-- Type: text/plain, Size: 8338 bytes --]

commit 29891189d498f5c6e3aabac72db14b94a200182c
Author: Adam Butcher <adam@jessamine.co.uk>
Date:   Thu Aug 15 20:21:38 2013 +0100

    [Intended for rollup into 1/4]: Handle parameter packs in lambda conversion op.
    
    	* lambda.c (maybe_add_lambda_conv_op): Move decls to point of use.
    	* TODO: parm pack changelog to be merged with PATCH 1/4.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index e9bc7c5..3d17948 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -741,6 +741,22 @@ nonlambda_method_basetype (void)
   return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
 }
 
+/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with
+   indicated FN, and NARGS, but do not initialize the return type or any of the
+   argument slots.  */
+
+static tree
+prepare_op_call (tree fn, int nargs)
+{
+  tree t;
+
+  t = build_vl_exp (CALL_EXPR, nargs + 3);
+  CALL_EXPR_FN (t) = fn;
+  CALL_EXPR_STATIC_CHAIN (t) = NULL;
+
+  return t;
+}
+
 /* If the closure TYPE has a static op(), also add a conversion to function
    pointer.  */
 
@@ -749,9 +765,6 @@ maybe_add_lambda_conv_op (tree type)
 {
   bool nested = (current_function_decl != NULL_TREE);
   tree callop = lambda_function (type);
-  tree rettype, name, fntype, fn, body, compound_stmt;
-  tree thistype, stattype, statfn, convfn, call, arg;
-  vec<tree, va_gc> *argvec;
 
   if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
     return;
@@ -759,7 +772,7 @@ maybe_add_lambda_conv_op (tree type)
   if (processing_template_decl)
     return;
 
-  bool generic_lambda_p
+  bool const generic_lambda_p
     = (DECL_TEMPLATE_INFO (callop)
     && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
 
@@ -770,63 +783,127 @@ maybe_add_lambda_conv_op (tree type)
       return;
     }
 
+  /* Non-template conversion operators are defined directly with build_call_a
+     and using DIRECT_ARGVEC for arguments (including 'this').  Templates are
+     deferred and the CALL is built in-place.  In the case of a deduced return
+     call op, the decltype expression used as a substitute for the return type,
+     DECLTYPE_CALL is also built in-place.  The arguments of DECLTYPE_CALL in
+     the return expression may differ in flags from those in body CALL.  In
+     particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in
+     the body CALL, but not in DECLTYPE_CALL.  */
+
+  vec<tree, va_gc> *direct_argvec;
+  tree decltype_call = 0, call;
   tree fn_result = TREE_TYPE (TREE_TYPE (callop));
-  tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop)));
 
   if (generic_lambda_p)
     {
-      /* Construct the dependent member call for the static member function
-	 '_FUN' and remove 'auto' from its return type to allow for simple
+      /* Prepare the dependent member call for the static member function
+	 '_FUN' and, potentially, prepare another call to be used in a decltype
+	 return expression for a deduced return call op to allow for simple
 	 implementation of the conversion operator.  */
 
       tree instance = build_nop (type, null_pointer_node);
-      argvec = make_tree_vector ();
-      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
-	{
-	  mark_exp_read (arg);
-	  vec_safe_push (argvec, convert_from_reference (arg));
-	}
-
       tree objfn = build_min (COMPONENT_REF, NULL_TREE,
 			      instance, DECL_NAME (callop), NULL_TREE);
-      call = build_nt_call_vec (objfn, argvec);
+      int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;
 
+      call = prepare_op_call (objfn, nargs);
       if (type_uses_auto (fn_result))
+	decltype_call = prepare_op_call (objfn, nargs);
+    }
+  else
+    {
+      direct_argvec = make_tree_vector ();
+      direct_argvec->quick_push (build1 (NOP_EXPR,
+					 TREE_TYPE (DECL_ARGUMENTS (callop)),
+					 null_pointer_node));
+    }
+
+  /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to
+     declare the static member function "_FUN" below.  For each arg append to
+     DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated
+     call args (for the template case).  If a parameter pack is found, expand
+     it, flagging it as PACK_EXPANSION_LOCAL_P for the body call.  */
+
+  tree fn_args = NULL_TREE;
+  {
+    int ix = 0;
+    tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
+    tree tgt;
+
+    while (src)
+      {
+	tree new_node = copy_node (src);
+
+	if (!fn_args)
+	  fn_args = tgt = new_node;
+	else
+	  {
+	    TREE_CHAIN (tgt) = new_node;
+	    tgt = new_node;
+	  }
+
+	mark_exp_read (tgt);
+
+	if (generic_lambda_p)
+	  {
+	    if (FUNCTION_PARAMETER_PACK_P (tgt))
+	      {
+		tree a = make_pack_expansion (tgt);
+		if (decltype_call)
+		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
+		PACK_EXPANSION_LOCAL_P (a) = true;
+		CALL_EXPR_ARG (call, ix) = a;
+	      }
+	    else
+	      {
+		tree a = convert_from_reference (tgt);
+		CALL_EXPR_ARG (call, ix) = a;
+		if (decltype_call)
+		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
+	      }
+	    ++ix;
+	  }
+	else
+	  vec_safe_push (direct_argvec, tgt);
+
+	src = TREE_CHAIN (src);
+      }
+  }
+
+
+  if (generic_lambda_p)
+    {
+      if (decltype_call)
 	{
 	  ++processing_template_decl;
 	  fn_result = finish_decltype_type
-	    (call, /*id_expression_or_member_access_p=*/false,
+	    (decltype_call, /*id_expression_or_member_access_p=*/false,
 	     tf_warning_or_error);
 	  --processing_template_decl;
 	}
     }
   else
     {
-      arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)),
-		    null_pointer_node);
-      argvec = make_tree_vector ();
-      argvec->quick_push (arg);
-      for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
-	{
-	  mark_exp_read (arg);
-	  vec_safe_push (argvec, arg);
-	}
-      call = build_call_a (callop, argvec->length (), argvec->address ());
+      call = build_call_a (callop,
+			   direct_argvec->length (),
+			   direct_argvec->address ());
       CALL_FROM_THUNK_P (call) = 1;
       if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
 	call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
     }
 
-  stattype = build_function_type (fn_result,
-				  FUNCTION_ARG_CHAIN (callop));
+  tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
 
   /* First build up the conversion op.  */
 
-  rettype = build_pointer_type (stattype);
-  name = mangle_conv_op_name_for_type (rettype);
-  thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
-  fntype = build_method_type_directly (thistype, rettype, void_list_node);
-  fn = convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
+  tree rettype = build_pointer_type (stattype);
+  tree name = mangle_conv_op_name_for_type (rettype);
+  tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+  tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
+  tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
+  tree fn = convfn;
   DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
 
   if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
@@ -861,7 +938,8 @@ maybe_add_lambda_conv_op (tree type)
   /* Now build up the thunk to be returned.  */
 
   name = get_identifier ("_FUN");
-  fn = statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
+  tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
+  fn = statfn;
   DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
   if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
       && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
@@ -875,7 +953,7 @@ maybe_add_lambda_conv_op (tree type)
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
   DECL_ARGUMENTS (fn) = fn_args;
-  for (arg = fn_args; arg; arg = DECL_CHAIN (arg))
+  for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
       /* Avoid duplicate -Wshadow warnings.  */
       DECL_NAME (arg) = NULL_TREE;
@@ -907,8 +985,8 @@ maybe_add_lambda_conv_op (tree type)
 	 ((symtab_node) cgraph_get_create_node (statfn),
           (symtab_node) cgraph_get_create_node (callop));
     }
-  body = begin_function_body ();
-  compound_stmt = begin_compound_stmt (0);
+  tree body = begin_function_body ();
+  tree compound_stmt = begin_compound_stmt (0);
   call = convert_from_reference (call);
   finish_return_stmt (call);
 

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

* Re: [PATCH 1/4] Support lambda templates.
  2013-09-09  7:24                     ` Adam Butcher
@ 2013-09-09 15:08                       ` Jason Merrill
  0 siblings, 0 replies; 22+ messages in thread
From: Jason Merrill @ 2013-09-09 15:08 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 09/09/2013 03:22 AM, Adam Butcher wrote:
> I've attached a patch that handles parameter packs in the conversion
> op.  I thought it best to get this reviewed independently before rolling
> up into the 'Support lambda templates' patch.
>
> Do you think it's the right idea?  It seems to work okay but I've
> reworked the way the template op call is built (and built a separate
> call for the decltype expression).

Yes, that looks fine.

Jason


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

end of thread, other threads:[~2013-09-09 14:05 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-27 19:43 Lambda templates and implicit function templates Adam Butcher
2013-08-27 19:43 ` [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
2013-09-01 21:20   ` Jason Merrill
2013-09-02 18:45     ` Adam Butcher
2013-08-27 19:43 ` [PATCH 1/4] Support lambda templates Adam Butcher
2013-09-01 20:22   ` Jason Merrill
2013-09-02 18:30     ` Adam Butcher
2013-09-02 18:34       ` Jason Merrill
2013-09-02 21:18         ` Adam Butcher
2013-09-03  3:50           ` Jason Merrill
2013-09-03 19:50             ` Adam Butcher
2013-09-03 21:25               ` Jason Merrill
2013-09-05 19:14                 ` Adam Butcher
2013-09-05 20:53                   ` Adam Butcher
2013-09-09  7:24                     ` Adam Butcher
2013-09-09 15:08                       ` Jason Merrill
2013-08-27 19:43 ` [PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack Adam Butcher
2013-09-01 20:28   ` Jason Merrill
2013-08-27 20:03 ` [PATCH 3/4] Support dumping type bindings in lambda diagnostics Adam Butcher
2013-09-01 20:05 ` Lambda templates and implicit function templates Jason Merrill
2013-09-02 18:27   ` Adam Butcher
2013-09-02 18:51     ` Jason Merrill

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).