public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Lambda templates and implicit function templates.
@ 2013-08-11 19:50 Adam Butcher
  2013-08-11 19:50 ` [PATCH 3/3] Support dumping type bindings in lambda diagnostics Adam Butcher
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Adam Butcher @ 2013-08-11 19:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

Hi Jason,

I decided to go ahead and submit the latest cleaned up version of the generic
lambda and implicit function template patches.  I think all review comments have
been addressed.  As well as the cleanup there are a few enhancements; generic
lambda instantiations in diagnostics now show template argument bindings and the
appropriate -std=xxx guards have been put in place.  I've also fixed a couple of
cases where invalid user code caused an ICE.

I am yet to write some tests for individual features to be included in the
source tree but intend to when I get some more time.  In the meantime I've
included the two main tests I've used for trials.

Cheers,
Adam

--------------------------------
Patch summary (3):

  Support lambda templates.
  Support using 'auto' in a function parameter list to introduce an
    implicit template parameter.
  Support dumping type bindings in lambda diagnostics.

 gcc/cp/cp-tree.h |  11 ++++
 gcc/cp/decl.c    |  19 +++++-
 gcc/cp/decl2.c   |   5 +-
 gcc/cp/error.c   |  22 +++----
 gcc/cp/lambda.c  |  87 +++++++++++++++++++------
 gcc/cp/parser.c  |  98 +++++++++++++++++++++++++---
 gcc/cp/pt.c      | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 7 files changed, 375 insertions(+), 60 deletions(-)

--------------------------------
Basic compile and runtime check:

   /* Implicit function templates at namespace scope.  */
   
   auto f1 (auto& a, auto const& b) { return a += b; }
   
   template <typename A>
   auto f2 (A& a, auto const& b) { return a += b; }
   
   template <typename B>
   auto f3 (auto& a, B const& b) { return a += b; }
   
   template <typename A, typename B>
   auto f4 (A& a, B const& b) { return a += b; }
   
   
   struct S
   {
     /* Implicit non-static member function templates.  */
   
     auto mf1 (auto& a, auto const& b) { return a += b; }
   
     template <typename A>
     auto mf2 (A& a, auto const& b) { return a += b; }
   
     template <typename B>
     auto mf3 (auto& a, B const& b) { return a += b; }
   
     template <typename A, typename B>
     auto mf4 (A& a, B const& b) { return a += b; }
   
     /* Implicit static member function templates.  */
   
     static auto smf1 (auto& a, auto const& b) { return a += b; }
   
     template <typename A>
     static auto smf2 (A& a, auto const& b) { return a += b; }
   
     template <typename B>
     static auto smf3 (auto& a, B const& b) { return a += b; }
   
     template <typename A, typename B>
     static auto smf4 (A& a, B const& b) { return a += b; }
   };
   
   
   #undef NDEBUG
   #include <cassert>
   
   
   #define CHECK(A, b, f) do {      \
      A a1 = 5, a2 = 12;            \
      auto r1 = f (a1, b);          \
      auto r2 = f (a2, b);          \
      assert ((#f, a1 == 5 + b));   \
      assert ((#f, a2 == 12 + b));  \
      assert ((#f, r1 == a1));      \
      assert ((#f, r2 == a2));      \
   } while (0)
   
   #define INVOKEi(f, A, b, i) do { CHECK (A, b, f ## i); } while (0)
   #define INVOKE4(f, A, b) do { INVOKEi (f, A, b, 1); \
   			         INVOKEi (f, A, b, 2); \
   			         INVOKEi (f, A, b, 3); \
   			         INVOKEi (f, A, b, 4); } while (0)
   
   #define AS_FUNi(f, A, b, i) do { CHECK (A, b, f ## i._FUN); } while (0)
   #define AS_FUN4(f, A, b) do { AS_FUNi (f, A, b, 1); \
   			         AS_FUNi (f, A, b, 2); \
   			         AS_FUNi (f, A, b, 3); \
   			         AS_FUNi (f, A, b, 4); } while (0)
   
   #define AS_PTRi(f, A, B, b, i) do { A (*pfn) (A&, B const&) = f ## i; \
   				    CHECK (A, b, pfn); } while (0)
   #define AS_PTR4(f, A, B, b) do { AS_PTRi (f, A, B, b, 1); \
   				    AS_PTRi (f, A, B, b, 2); \
   				    AS_PTRi (f, A, B, b, 3); \
   				    AS_PTRi (f, A, B, b, 4); } while (0)
   
   
   int main()
   {
     /* Check namespace templates.  */
   
     INVOKE4 (f, float, 7);
     AS_PTR4 (f, float, int, 7);
   
     /* Check member templates.  */
   
     S s;
     INVOKE4 (s.mf, float, 7);
     INVOKE4 (s.smf, float, 7);
     INVOKE4 (S::smf, float, 7);
     AS_PTR4 (s.smf, float, int, 7);
     AS_PTR4 (S::smf, float, int, 7);
   
     /* Regression check non-template stateless lambda and its conversion
        to function pointer.  */
   
     auto lf0 = [] (float& a, int const& b) { return a += b; };
   
     INVOKEi (lf, float, 7, 0);
     AS_FUNi (lf, float, 7, 0);
     AS_PTRi (lf, float, int, 7, 0);
   
     /* Check stateless lambda templates.  */
   
     auto lf1 = [] (auto& a, auto const& b) { return a += b; };
     auto lf2 = [] <typename A> (A& a, auto const& b) { return a += b; };
     auto lf3 = [] <typename B> (auto& a, B const& b) { return a += b; };
     auto lf4 = [] <typename A, typename B> (A& a, B const& b) { return a += b; };
   
     INVOKE4 (lf, float, 7);
     AS_FUN4 (lf, float, 7);
     AS_PTR4 (lf, float, int, 7);
   
     /* Check capturing lambda templates.  */
   
     int i;
   
     auto lc1 = [i] (auto& a, auto const& b) { return a += b; };
     auto lc2 = [i] <typename A> (A& a, auto const& b) { return a += b; };
     auto lc3 = [i] <typename B> (auto& a, B const& b) { return a += b; };
     auto lc4 = [i] <typename A, typename B> (A& a, B const& b) { return a += b; };
   
     INVOKE4 (lc, float, 7);
   }

--------------------------------
Dependent type check:

   struct S
   {
      struct N
      {
         float test () {}
      };
   };
   
   int main()
   {
      auto f = [] <typename T> (T const& s) {
         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);
   
      float (*pfn) (S const&) = f;
   
      pfn(i);
   
      pfn = g;
   
      return pfn(i);
   }

-- 
1.8.3

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

* [PATCH 3/3] Support dumping type bindings in lambda diagnostics.
  2013-08-11 19:50 Lambda templates and implicit function templates Adam Butcher
@ 2013-08-11 19:50 ` Adam Butcher
  2013-08-27 16:57   ` Jason Merrill
  2013-08-11 19:50 ` [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
  2013-08-11 19:50 ` [PATCH 1/3] Support lambda templates Adam Butcher
  2 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-11 19:50 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 440169a..bd5f8cc 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1374,14 +1374,7 @@ dump_function_decl (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 (DECL_CONTEXT (t), flags);
-      return;
-    }
+  bool lambda_p = false;
 
   flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
   if (TREE_CODE (t) == TEMPLATE_DECL)
@@ -1443,16 +1436,23 @@ dump_function_decl (tree t, int flags)
   else if (cname)
     {
       dump_type (cname, flags);
-      pp_cxx_colon_colon (cxx_pp);
+      if (LAMBDA_TYPE_P (cname))
+	lambda_p = true;
+      else
+	pp_cxx_colon_colon (cxx_pp);
     }
   else
     dump_scope (CP_DECL_CONTEXT (t), flags);
 
-  dump_function_name (t, flags);
+  /* A lambda's signature is essentially its "type", which has already been
+     dumped.  */
+  if (!lambda_p)
+    dump_function_name (t, flags);
 
   if (!(flags & TFF_NO_FUNCTION_ARGUMENTS))
     {
-      dump_parameters (parmtypes, flags);
+      if (!lambda_p)
+	dump_parameters (parmtypes, flags);
 
       if (TREE_CODE (fntype) == METHOD_TYPE)
 	{
-- 
1.8.3

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

* [PATCH 1/3] Support lambda templates.
  2013-08-11 19:50 Lambda templates and implicit function templates Adam Butcher
  2013-08-11 19:50 ` [PATCH 3/3] Support dumping type bindings in lambda diagnostics Adam Butcher
  2013-08-11 19:50 ` [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
@ 2013-08-11 19:50 ` Adam Butcher
  2013-08-12 15:47   ` Jason Merrill
  2 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-11 19:50 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=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 c5d398a..d32608c 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8790,6 +8790,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]
@@ -8809,10 +8810,31 @@ 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;
   tree t;
 
-  /* 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))
+    {
+      cp_lexer_consume_token (parser->lexer);
+
+      if (cxx_dialect < cxx1y || flag_iso)
+	cp_parser_error (parser,
+			 "lambda templates are only available with "
+			 "-std=gnu++1y");
+
+      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);
@@ -8858,6 +8880,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       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.
 
@@ -8901,6 +8925,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);
@@ -9023,7 +9053,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 d03c1cf..6345e7e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9101,7 +9101,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.3

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

* [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-11 19:50 Lambda templates and implicit function templates Adam Butcher
  2013-08-11 19:50 ` [PATCH 3/3] Support dumping type bindings in lambda diagnostics Adam Butcher
@ 2013-08-11 19:50 ` Adam Butcher
  2013-08-12 16:52   ` Jason Merrill
  2013-08-11 19:50 ` [PATCH 1/3] Support lambda templates Adam Butcher
  2 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-11 19:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton, Adam Butcher

	* cp-tree.h (struct saved_scope): Add x_fully_implicit_template bit ...
	(fully_implicit_template): ... and provide conventional access to it.
	(type_uses_auto_or_concept): Declare.
	(is_auto_or_concept): Declare.
	(add_implicit_template_parms): Declare.
	(finish_fully_implicit_template): Declare.
	* decl.c (grokdeclarator): Allow 'auto' parameters with -std=gnu++1y,
	or, in lambda parameter lists, with at least -std=c++1y.
	* parser.c (cp_parser_parameter_declaration_list): Count generic
	parameters and call add_implicit_template_parms to synthesize them.
	(cp_parser_direct_declarator): Account for implicit template parameters.
	(cp_parser_lambda_declarator_opt): Finish fully implicit template if
	necessary.
	(cp_parser_member_declaration): Likewise.
	(cp_parser_function_definition_after_declarator): Likewise.
	* pt.c (type_uses_auto): Reimplement with ...
	(find_type_usage): ... this new static function.
	(is_auto_or_concept): New function.
	(type_uses_auto_or_concept): New function.
	(make_generic_type_name): New static function.
	(tree_type_is_auto_or_concept): New static function.
	(add_implicit_template_parms): New function.
	(finish_fully_implicit_template): New function.
---
 gcc/cp/cp-tree.h |  11 ++++
 gcc/cp/decl.c    |  19 +++++-
 gcc/cp/parser.c  |  58 ++++++++++++++---
 gcc/cp/pt.c      | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 254 insertions(+), 23 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8672739..8e5247c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1034,6 +1034,7 @@ struct GTY(()) saved_scope {
   int x_processing_template_decl;
   int x_processing_specialization;
   BOOL_BITFIELD x_processing_explicit_instantiation : 1;
+  BOOL_BITFIELD x_fully_implicit_template : 1;
   BOOL_BITFIELD need_pop_function_context : 1;
 
   int unevaluated_operand;
@@ -1088,6 +1089,12 @@ struct GTY(()) saved_scope {
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
 
+/* Nonzero 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.  */
+
+#define fully_implicit_template scope_chain->x_fully_implicit_template
+
 /* The cached class binding level, from the most recently exited
    class, or NULL if none.  */
 
@@ -5454,12 +5461,16 @@ 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 add_implicit_template_parms		(size_t, tree);
+extern tree finish_fully_implicit_template	(tree);
 extern tree end_template_parm_list		(tree);
 extern void end_template_decl			(void);
 extern tree maybe_update_decl_type		(tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d49ed29..223bfd5 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10331,8 +10331,23 @@ grokdeclarator (const cp_declarator *declarator,
 
       if (type_uses_auto (type))
 	{
-	  error ("parameter declared %<auto%>");
-	  type = error_mark_node;
+	  bool lambda_p = (current_class_type
+	    && LAMBDA_TYPE_P (current_class_type));
+
+	  static const char * const lambda_error
+	    = "use of %<auto%> in lambda parameter declaration "
+	      "only available with "
+	      "-std=c++1y or -std=gnu++1y";
+	  static const char * const nonlambda_error
+	    = "use of %<auto%> in parameter declaration "
+	      "only available with "
+	      "-std=gnu++1y";
+
+	  if (!(cxx_dialect >= cxx1y && (!flag_iso || lambda_p)))
+	    {
+	      error (lambda_p ? lambda_error : nonlambda_error);
+	      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 d32608c..19182bd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8931,6 +8931,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	    finish_template_decl (template_param_list);
 	    --parser->num_template_parameter_lists;
 	  }
+	else if (fully_implicit_template)
+	  {
+	    fco = finish_fully_implicit_template (fco);
+	    --parser->num_template_parameter_lists;
+	  }
       }
 
     finish_member_declaration (fco);
@@ -16807,8 +16812,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);
@@ -17908,6 +17915,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;
@@ -17935,11 +17943,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;
 
@@ -18027,6 +18042,17 @@ 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 (implicit_template_parms,
+						parameters);
+
+      // Let the parser know that there's an extra parameter list active if this
+      // function has become a template.
+      if (fully_implicit_template)
+	++parser->num_template_parameter_lists;
+    }
+
   return parameters;
 }
 
@@ -20033,7 +20059,14 @@ 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 (fully_implicit_template)
+			{
+			  decl = finish_fully_implicit_template (decl);
+			  --parser->num_template_parameter_lists;
+			}
+		      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.  */
@@ -20049,6 +20082,11 @@ cp_parser_member_declaration (cp_parser* parser)
 				  initializer, /*init_const_expr_p=*/true,
 				  asm_specification,
 				  attributes);
+		if (fully_implicit_template)
+		  {
+		    decl = finish_fully_implicit_template (decl);
+		    --parser->num_template_parameter_lists;
+		  }
 	    }
 
 	  /* Reset PREFIX_ATTRIBUTES.  */
@@ -22316,6 +22354,12 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
     = saved_num_template_parameter_lists;
   parser->in_function_body = saved_in_function_body;
 
+  if (fully_implicit_template)
+    {
+      finish_fully_implicit_template (/*member_decl_opt=*/0);
+      --parser->num_template_parameter_lists;
+    }
+
   return fn;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6345e7e..ce899ef 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21097,31 +21097,65 @@ 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 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.
 
-tree
-type_uses_auto (tree type)
+   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.  */
+
+static inline tree
+find_type_usage (tree t, bool (*pred) (const_tree))
 {
   enum tree_code code;
-  if (is_auto (type))
-    return type;
+  if (pred (t))
+    return t;
 
-  code = TREE_CODE (type);
+  code = TREE_CODE (t);
 
   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));
+      || 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 (type))
-    return type_uses_auto (TREE_TYPE (TREE_TYPE
-				   (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+  if (TYPE_PTRMEMFUNC_P (t))
+    return find_type_usage
+      (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred);
 
   return NULL_TREE;
 }
 
+/* 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)
+{
+  return find_type_usage (type, is_auto);
+}
+
+/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto',
+   'decltype(auto)' or a concept.  */
+
+bool
+is_auto_or_concept (const_tree type)
+{
+  return is_auto (type); // or concept
+}
+
+/* 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.  */
+
+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.
@@ -21272,4 +21306,131 @@ print_template_statistics (void)
 	   htab_collisions (type_specializations));
 }
 
+/* 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 (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)
+    {
+      ++fully_implicit_template;
+      push_deferring_access_checks (dk_deferred);
+      begin_template_parm_list ();
+    }
+  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 (tree member_decl_opt)
+{
+  gcc_assert (fully_implicit_template > 0);
+
+  pop_deferring_access_checks ();
+  if (member_decl_opt)
+    member_decl_opt = finish_member_template_decl (member_decl_opt);
+  end_template_decl ();
+
+  --fully_implicit_template;
+
+  return member_decl_opt;
+}
+
 #include "gt-cp-pt.h"
-- 
1.8.3

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

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

On 08/11/2013 03:49 PM, Adam Butcher wrote:
> +      if (cxx_dialect < cxx1y || flag_iso)
> +	cp_parser_error (parser,
> +			 "lambda templates are only available with "
> +			 "-std=gnu++1y");

Normally we only use flag_iso to disable extensions that can change the 
meaning of conforming code, which I don't think is the case here.  For 
pure extensions, we prefer to use a pedwarn.

> +	  if (!DECL_TEMPLATE_INFO (decl) || DECL_TEMPLATE_RESULT
> +	      (DECL_TI_TEMPLATE (decl)) != decl)

This needs reformatting so that the arguments to a macro aren't to the 
left of the macro name.

Jason

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

* Re: [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-11 19:50 ` [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
@ 2013-08-12 16:52   ` Jason Merrill
  2013-08-13  0:34     ` Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2013-08-12 16:52 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/11/2013 03:49 PM, Adam Butcher wrote:
> +	  if (!(cxx_dialect >= cxx1y && (!flag_iso || lambda_p)))

Again, better to use a pedwarn.

> +#define fully_implicit_template scope_chain->x_fully_implicit_template

Why did you choose to add this to saved_scope rather than cp_parser?  It 
seems like state that could be local to the parser rather than shared 
with the rest of the compiler.

> +tree type_uses_auto (tree type)
> +tree type_uses_auto_or_concept (tree type)

Function name at the beginning of the line.

Jason

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

* Re: [PATCH 1/3] Support lambda templates.
  2013-08-12 15:47   ` Jason Merrill
@ 2013-08-12 23:52     ` Adam Butcher
  2013-08-13 12:29       ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-12 23:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 12.08.2013 16:47, Jason Merrill wrote:
> On 08/11/2013 03:49 PM, Adam Butcher wrote:
>> +      if (cxx_dialect < cxx1y || flag_iso)
>> +	cp_parser_error (parser,
>> +			 "lambda templates are only available with "
>> +			 "-std=gnu++1y");
>
> Normally we only use flag_iso to disable extensions that can change
> the meaning of conforming code, which I don't think is the case here.
> For pure extensions, we prefer to use a pedwarn.
>

Okay.  Though I'm not sure how to implement exactly what we discussed
before with pedwarn.  Namely:

On 07.08.2013 16:59, Jason Merrill wrote:
> On 08/07/2013 03:52 AM, Adam Butcher wrote:
>> I'm not sure which dialect guards to put these features behind 
>> though.
>> Strictly:
>>
>>   a) Generic lambdas created fully implicitly via 'auto params' 
>> should be
>>      accepted with -std=c++1y and -std=gnu++1y since it is actually 
>> spec'd by
>>      the draft.
>>
>>   b) Generic lambdas created with an explicit template parameter 
>> list should be
>>      accepted with -std=gnu++1y only.
>>
>>   c) Generalized implicit function templates should be accepted by 
>> -std=gnu++1y
>>      only.
>
> This makes sense to me.  Or perhaps add (c) to the concepts lite
> flag, when there is one.
>

Presumably with pedwarn it would need to be relaxed to simply
    "accepted with -std=c++1y or -std=gnu++1y"
for all?  flag_iso was the only thing I could find to discriminate 
between gnu++1y
and c++1y?

>> +	  if (!DECL_TEMPLATE_INFO (decl) || DECL_TEMPLATE_RESULT
>> +	      (DECL_TI_TEMPLATE (decl)) != decl)
>
> This needs reformatting so that the arguments to a macro aren't to
> the left of the macro name.
>
Done.

Adam

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

* Re: [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-12 16:52   ` Jason Merrill
@ 2013-08-13  0:34     ` Adam Butcher
  2013-08-14 14:07       ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-13  0:34 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 12.08.2013 17:00, Jason Merrill wrote:
> On 08/11/2013 03:49 PM, Adam Butcher wrote:
>> +#define fully_implicit_template 
>> scope_chain->x_fully_implicit_template
>
> Why did you choose to add this to saved_scope rather than cp_parser?
> It seems like state that could be local to the parser rather than
> shared with the rest of the compiler.
>
Currently it is the implicit function template code in pt.c that 
updates this; specifically add_implicit_template_parms and 
finish_fully_implicit_template.

It is queried by the parser (both in parser.c and lambda.c) to decide 
whether a new [implicit] template parameter list as been started and to 
decide how to finish up.

I had a look into this; it should be possible to move these out of pt.c 
and into parser.c (or some new file generic-parms.c, implicit-pt.c or 
some such) and possibly add a plain global counter for this state, 
rather than attribute it to each scope.

>> +tree type_uses_auto (tree type)
>> +tree type_uses_auto_or_concept (tree type)
>
> Function name at the beginning of the line.
>
Fixed.

Adam

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

* Re: [PATCH 1/3] Support lambda templates.
  2013-08-12 23:52     ` Adam Butcher
@ 2013-08-13 12:29       ` Jason Merrill
  0 siblings, 0 replies; 21+ messages in thread
From: Jason Merrill @ 2013-08-13 12:29 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/12/2013 07:52 PM, Adam Butcher wrote:
> Presumably with pedwarn it would need to be relaxed to simply
>     "accepted with -std=c++1y or -std=gnu++1y"
> for all?

Yes.

> flag_iso was the only thing I could find to discriminate
> between gnu++1y and c++1y?

Right, we don't make that distinction for most extensions.

Jason

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

* Re: [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-13  0:34     ` Adam Butcher
@ 2013-08-14 14:07       ` Jason Merrill
  2013-08-14 14:29         ` Gabriel Dos Reis
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2013-08-14 14:07 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/12/2013 08:34 PM, Adam Butcher wrote:
> Currently it is the implicit function template code in pt.c that updates
> this; specifically add_implicit_template_parms and
> finish_fully_implicit_template.
>
> It is queried by the parser (both in parser.c and lambda.c) to decide
> whether a new [implicit] template parameter list as been started and to
> decide how to finish up.
>
> I had a look into this; it should be possible to move these out of pt.c
> and into parser.c (or some new file generic-parms.c, implicit-pt.c or
> some such) and possibly add a plain global counter for this state,
> rather than attribute it to each scope.

Right, I was thinking it would make sense as a field of cp_parser, since 
it doesn't affect template instantiation context.

Jason

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

* Re: [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
  2013-08-14 14:07       ` Jason Merrill
@ 2013-08-14 14:29         ` Gabriel Dos Reis
  0 siblings, 0 replies; 21+ messages in thread
From: Gabriel Dos Reis @ 2013-08-14 14:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Adam Butcher, gcc-patches, Andrew Sutton

On Wed, Aug 14, 2013 at 9:07 AM, Jason Merrill <jason@redhat.com> wrote:
> On 08/12/2013 08:34 PM, Adam Butcher wrote:
>>
>> Currently it is the implicit function template code in pt.c that updates
>> this; specifically add_implicit_template_parms and
>> finish_fully_implicit_template.
>>
>> It is queried by the parser (both in parser.c and lambda.c) to decide
>> whether a new [implicit] template parameter list as been started and to
>> decide how to finish up.
>>
>> I had a look into this; it should be possible to move these out of pt.c
>> and into parser.c (or some new file generic-parms.c, implicit-pt.c or
>> some such) and possibly add a plain global counter for this state,
>> rather than attribute it to each scope.
>
>
> Right, I was thinking it would make sense as a field of cp_parser, since it
> doesn't affect template instantiation context.

Agreed.  I think we should reduce the number of such object macro states.

-- Gaby

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

* Re: [PATCH 3/3] Support dumping type bindings in lambda diagnostics.
  2013-08-11 19:50 ` [PATCH 3/3] Support dumping type bindings in lambda diagnostics Adam Butcher
@ 2013-08-27 16:57   ` Jason Merrill
  2013-08-27 19:43     ` Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2013-08-27 16:57 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

This patch doesn't seem to depend on the others; go ahead and apply it.

Jason

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

* Re: [PATCH 3/3] Support dumping type bindings in lambda diagnostics.
  2013-08-27 16:57   ` Jason Merrill
@ 2013-08-27 19:43     ` Adam Butcher
  2013-08-28  3:02       ` Jason Merrill
  0 siblings, 1 reply; 21+ 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

Hi Jason,

Was just about to compose a mail to gcc-patches...  Been busy, then 
ill, now just about ready to submit a new set of diffs.

On 27.08.2013 17:47, Jason Merrill wrote:
>
> This patch doesn't seem to depend on the others; go ahead and apply 
> it.
>
Okay.  As it stands, it means that you get an additional 'const' in 
diagnostics for lambda's not declared 'mutable'.  I didn't think this to 
be necessarily a bad thing (distinguishing between 'mutable' and 'plain' 
lambdas and pointing at the cause for possible user error attempting to 
write to by-value captures) but it's probably contentious.  Do you want 
me to ditch the 'const' output prior to pushing?

Cheers,
Adam

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

* Re: [PATCH 3/3] Support dumping type bindings in lambda diagnostics.
  2013-08-27 19:43     ` Adam Butcher
@ 2013-08-28  3:02       ` Jason Merrill
  2013-08-28  9:08         ` [PATCH] Support dumping type bindings and 'mutable' qualifier " Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2013-08-28  3:02 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Gabriel Dos Reis, Andrew Sutton

On 08/27/2013 02:46 PM, Adam Butcher wrote:
> Okay.  As it stands, it means that you get an additional 'const' in
> diagnostics for lambda's not declared 'mutable'.

Hmm, I guess it would be preferable to use 'mutable' or nothing when 
printing the lambda just like when declaring one.

Jason

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

* [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-28  3:02       ` Jason Merrill
@ 2013-08-28  9:08         ` Adam Butcher
  2013-08-28 12:57           ` Gabriel Dos Reis
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-28  9:08 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).
	Rather than qualifying the diagnostic with 'const' for plain lambdas,
	qualify with 'mutable' if non-const.
---
Okay to commit?
---
 gcc/cp/error.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c82a0ce..a8ca269 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,21 +1442,31 @@ 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)
 	{
 	  pp->padding = pp_before;
-	  pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype));
+	  if (!lambda_p)
+	    pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype));
+	  else if (!(TYPE_QUALS (class_of_this_parm (fntype)) & TYPE_QUAL_CONST))
+	    pp_c_ws_string (pp, "mutable");
 	  dump_ref_qualifier (pp, fntype, flags);
 	}
 
-- 
1.8.4

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

* Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-28  9:08         ` [PATCH] Support dumping type bindings and 'mutable' qualifier " Adam Butcher
@ 2013-08-28 12:57           ` Gabriel Dos Reis
  2013-08-29 15:15             ` Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Gabriel Dos Reis @ 2013-08-28 12:57 UTC (permalink / raw)
  To: Adam Butcher; +Cc: Jason Merrill, gcc-patches, Andrew Sutton

On Tue, Aug 27, 2013 at 7:54 PM, Adam Butcher <adam@jessamine.co.uk> wrote:
>         * 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).
>         Rather than qualifying the diagnostic with 'const' for plain lambdas,
>         qualify with 'mutable' if non-const.
> ---
> Okay to commit?

This looks good to me.  I have one suggestion.  See below.

> ---
>  gcc/cp/error.c | 27 +++++++++++++++------------
>  1 file changed, 15 insertions(+), 12 deletions(-)
>
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index c82a0ce..a8ca269 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,21 +1442,31 @@ 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;

Instead of introducing the local variable lambda_p and then
weave your way through the existing maze, do this instead:
    (1)  Introduce a new function, call it dump_lambda_expr
          (or something like that) that does only the formatting
          of a lambda expression, and nothing else.

   (2) when you arrive here where you test LAMBDA_TYPE_P
        then do a
            return dump_lambda_expr (pp, flags);

The result is much simpler and cleaner that way.
Thanks,

> +      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)
>         {
>           pp->padding = pp_before;
> -         pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype));
> +         if (!lambda_p)
> +           pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype));
> +         else if (!(TYPE_QUALS (class_of_this_parm (fntype)) & TYPE_QUAL_CONST))
> +           pp_c_ws_string (pp, "mutable");
>           dump_ref_qualifier (pp, fntype, flags);
>         }
>
> --
> 1.8.4
>

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

* [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-28 12:57           ` Gabriel Dos Reis
@ 2013-08-29 15:15             ` Adam Butcher
  2013-08-29 15:57               ` Gabriel Dos Reis
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-29 15:15 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc-patches, Jason Merrill, Andrew Sutton, Adam Butcher

	* error.c (dump_lambda_function): New function, dependent on ...
	(maybe_dump_template_bindings): ... this new function, factored out of
	...
	(dump_function_decl): ... here.  Updated to early-out with call to
	dump_lambda_function after determining template bindings.
---
Reworked as requested.  Okay to commit?
---
 gcc/cp/error.c | 60 ++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c82a0ce..1edfa0b 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1363,6 +1363,39 @@ find_typenames (tree t)
   return ft.typenames;
 }
 
+static void
+maybe_dump_template_bindings (cxx_pretty_printer *pp,
+			      tree t, tree template_parms, tree template_args,
+			      int flags)
+{
+  if (template_parms != NULL_TREE && template_args != NULL_TREE
+      && !(flags & TFF_NO_TEMPLATE_BINDINGS))
+    {
+      vec<tree, va_gc> *typenames = find_typenames (t);
+      pp_cxx_whitespace (pp);
+      pp_cxx_left_bracket (pp);
+      pp_cxx_ws_string (pp, M_("with"));
+      pp_cxx_whitespace (pp);
+      dump_template_bindings (pp, template_parms, template_args, typenames);
+      pp_cxx_right_bracket (pp);
+    }
+}
+
+static void
+dump_lambda_function (cxx_pretty_printer *pp,
+		      tree fn, tree template_parms, tree template_args,
+		      int flags)
+{
+  /* A lambda's signature is essentially its "type".  */
+  dump_type (pp, DECL_CONTEXT (fn), flags);
+  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST))
+    {
+      pp->padding = pp_before;
+      pp_c_ws_string (pp, "mutable");
+    }
+  maybe_dump_template_bindings (pp, fn, template_parms, template_args, flags);
+}
+
 /* Pretty print a function decl. There are several ways we want to print a
    function declaration. The TFF_ bits in FLAGS tells us how to behave.
    As error can only apply the '#' flag once to give 0 and 1 for V, there
@@ -1379,15 +1412,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
   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;
-    }
 
   flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
   if (TREE_CODE (t) == TEMPLATE_DECL)
@@ -1409,10 +1433,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 	{
 	  template_parms = DECL_TEMPLATE_PARMS (tmpl);
 	  t = tmpl;
-	  typenames = find_typenames (t);
 	}
     }
 
+  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
+    return dump_lambda_function (pp, t, template_parms, template_args,
+				 flags);
+
   fntype = TREE_TYPE (t);
   parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
 
@@ -1476,17 +1503,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
       if (show_return)
 	dump_type_suffix (pp, TREE_TYPE (fntype), flags);
 
-      /* If T is a template instantiation, dump the parameter binding.  */
-      if (template_parms != NULL_TREE && template_args != NULL_TREE
-	  && !(flags & TFF_NO_TEMPLATE_BINDINGS))
-	{
-	  pp_cxx_whitespace (pp);
-	  pp_cxx_left_bracket (pp);
-	  pp_cxx_ws_string (pp, M_("with"));
-	  pp_cxx_whitespace (pp);
-	  dump_template_bindings (pp, template_parms, template_args, typenames);
-	  pp_cxx_right_bracket (pp);
-	}
+      maybe_dump_template_bindings (pp, t, template_parms, template_args,
+				    flags);
     }
   else if (template_args)
     {
-- 
1.8.4

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

* Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-29 15:15             ` Adam Butcher
@ 2013-08-29 15:57               ` Gabriel Dos Reis
  2013-08-29 18:24                 ` Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Gabriel Dos Reis @ 2013-08-29 15:57 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Jason Merrill, Andrew Sutton

On Thu, Aug 29, 2013 at 9:20 AM, Adam Butcher <adam@jessamine.co.uk> wrote:
>         * error.c (dump_lambda_function): New function, dependent on ...
>         (maybe_dump_template_bindings): ... this new function, factored out of
>         ...
>         (dump_function_decl): ... here.  Updated to early-out with call to
>         dump_lambda_function after determining template bindings.
> ---
> Reworked as requested.  Okay to commit?

Document the new functions.
Use pp->translate_string ("with") instead of
pp_cxx_ws_string (pp, M_("with")).

 OK to commit with those changes.

Thanks,
-- Gaby

>
> +static void
> +maybe_dump_template_bindings (cxx_pretty_printer *pp,
> +                             tree t, tree template_parms, tree template_args,
> +                             int flags)
> +{
> +  if (template_parms != NULL_TREE && template_args != NULL_TREE
> +      && !(flags & TFF_NO_TEMPLATE_BINDINGS))
> +    {
> +      vec<tree, va_gc> *typenames = find_typenames (t);
> +      pp_cxx_whitespace (pp);
> +      pp_cxx_left_bracket (pp);
> +      pp_cxx_ws_string (pp, M_("with"));
> +      pp_cxx_whitespace (pp);
> +      dump_template_bindings (pp, template_parms, template_args, typenames);
> +      pp_cxx_right_bracket (pp);
> +    }
> +}
> +
> +static void
> +dump_lambda_function (cxx_pretty_printer *pp,
> +                     tree fn, tree template_parms, tree template_args,
> +                     int flags)
> +{
> +  /* A lambda's signature is essentially its "type".  */
> +  dump_type (pp, DECL_CONTEXT (fn), flags);
> +  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST))
> +    {
> +      pp->padding = pp_before;
> +      pp_c_ws_string (pp, "mutable");
> +    }
> +  maybe_dump_template_bindings (pp, fn, template_parms, template_args, flags);
> +}
> +
>  /* Pretty print a function decl. There are several ways we want to print a
>     function declaration. The TFF_ bits in FLAGS tells us how to behave.
>     As error can only apply the '#' flag once to give 0 and 1 for V, there
> @@ -1379,15 +1412,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>    int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
>    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;
> -    }
>
>    flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
>    if (TREE_CODE (t) == TEMPLATE_DECL)
> @@ -1409,10 +1433,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>         {
>           template_parms = DECL_TEMPLATE_PARMS (tmpl);
>           t = tmpl;
> -         typenames = find_typenames (t);
>         }
>      }
>
> +  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
> +    return dump_lambda_function (pp, t, template_parms, template_args,
> +                                flags);
> +
>    fntype = TREE_TYPE (t);
>    parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
>
> @@ -1476,17 +1503,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>        if (show_return)
>         dump_type_suffix (pp, TREE_TYPE (fntype), flags);
>
> -      /* If T is a template instantiation, dump the parameter binding.  */
> -      if (template_parms != NULL_TREE && template_args != NULL_TREE
> -         && !(flags & TFF_NO_TEMPLATE_BINDINGS))
> -       {
> -         pp_cxx_whitespace (pp);
> -         pp_cxx_left_bracket (pp);
> -         pp_cxx_ws_string (pp, M_("with"));
> -         pp_cxx_whitespace (pp);
> -         dump_template_bindings (pp, template_parms, template_args, typenames);
> -         pp_cxx_right_bracket (pp);
> -       }
> +      maybe_dump_template_bindings (pp, t, template_parms, template_args,
> +                                   flags);
>      }
>    else if (template_args)
>      {
> --
> 1.8.4
>

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

* Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-29 15:57               ` Gabriel Dos Reis
@ 2013-08-29 18:24                 ` Adam Butcher
  2013-08-29 18:51                   ` Adam Butcher
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-29 18:24 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc-patches, Jason Merrill, Andrew Sutton

On 29.08.2013 16:25, Gabriel Dos Reis wrote:
> On Thu, Aug 29, 2013 at 9:20 AM, Adam Butcher <adam@jessamine.co.uk> 
> wrote:
>>         * error.c (dump_lambda_function): New function, dependent on 
>> ...
>>         (maybe_dump_template_bindings): ... this new function, 
>> factored out of
>>         ...
>>         (dump_function_decl): ... here.  Updated to early-out with 
>> call to
>>         dump_lambda_function after determining template bindings.
>> ---
>> Reworked as requested.  Okay to commit?
>
> Document the new functions.
> Use pp->translate_string ("with") instead of
> pp_cxx_ws_string (pp, M_("with")).
>
Done.  In documenting 'maybe_dump_template_bindings' and reviewing it 
again I'm not sure it's got the right name.  It wraps 
'dump_template_bindings' in "[with " and "]".  So it does more than just 
filter a call to 'dump_template_bindings'.

Any suggestions?  What do you think of 'maybe_dump_with_clause' or 
something similar?

Cheers,
Adam

>
> Thanks,
> -- Gaby
>
>>
>> +static void
>> +maybe_dump_template_bindings (cxx_pretty_printer *pp,
>> +                             tree t, tree template_parms, tree 
>> template_args,
>> +                             int flags)
>> +{
>> +  if (template_parms != NULL_TREE && template_args != NULL_TREE
>> +      && !(flags & TFF_NO_TEMPLATE_BINDINGS))
>> +    {
>> +      vec<tree, va_gc> *typenames = find_typenames (t);
>> +      pp_cxx_whitespace (pp);
>> +      pp_cxx_left_bracket (pp);
>> +      pp_cxx_ws_string (pp, M_("with"));
>> +      pp_cxx_whitespace (pp);
>> +      dump_template_bindings (pp, template_parms, template_args, 
>> typenames);
>> +      pp_cxx_right_bracket (pp);
>> +    }
>> +}
>> +
>> +static void
>> +dump_lambda_function (cxx_pretty_printer *pp,
>> +                     tree fn, tree template_parms, tree 
>> template_args,
>> +                     int flags)
>> +{
>> +  /* A lambda's signature is essentially its "type".  */
>> +  dump_type (pp, DECL_CONTEXT (fn), flags);
>> +  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & 
>> TYPE_QUAL_CONST))
>> +    {
>> +      pp->padding = pp_before;
>> +      pp_c_ws_string (pp, "mutable");
>> +    }
>> +  maybe_dump_template_bindings (pp, fn, template_parms, 
>> template_args, flags);
>> +}
>> +
>>  /* Pretty print a function decl. There are several ways we want to 
>> print a
>>     function declaration. The TFF_ bits in FLAGS tells us how to 
>> behave.
>>     As error can only apply the '#' flag once to give 0 and 1 for V, 
>> there
>> @@ -1379,15 +1412,6 @@ dump_function_decl (cxx_pretty_printer *pp, 
>> tree t, int flags)
>>    int show_return = flags & TFF_RETURN_TYPE || flags & 
>> TFF_DECL_SPECIFIERS;
>>    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;
>> -    }
>>
>>    flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
>>    if (TREE_CODE (t) == TEMPLATE_DECL)
>> @@ -1409,10 +1433,13 @@ dump_function_decl (cxx_pretty_printer *pp, 
>> tree t, int flags)
>>         {
>>           template_parms = DECL_TEMPLATE_PARMS (tmpl);
>>           t = tmpl;
>> -         typenames = find_typenames (t);
>>         }
>>      }
>>
>> +  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
>> +    return dump_lambda_function (pp, t, template_parms, 
>> template_args,
>> +                                flags);
>> +
>>    fntype = TREE_TYPE (t);
>>    parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
>>
>> @@ -1476,17 +1503,8 @@ dump_function_decl (cxx_pretty_printer *pp, 
>> tree t, int flags)
>>        if (show_return)
>>         dump_type_suffix (pp, TREE_TYPE (fntype), flags);
>>
>> -      /* If T is a template instantiation, dump the parameter 
>> binding.  */
>> -      if (template_parms != NULL_TREE && template_args != NULL_TREE
>> -         && !(flags & TFF_NO_TEMPLATE_BINDINGS))
>> -       {
>> -         pp_cxx_whitespace (pp);
>> -         pp_cxx_left_bracket (pp);
>> -         pp_cxx_ws_string (pp, M_("with"));
>> -         pp_cxx_whitespace (pp);
>> -         dump_template_bindings (pp, template_parms, template_args, 
>> typenames);
>> -         pp_cxx_right_bracket (pp);
>> -       }
>> +      maybe_dump_template_bindings (pp, t, template_parms, 
>> template_args,
>> +                                   flags);
>>      }
>>    else if (template_args)
>>      {
>> --
>> 1.8.4
>>

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

* Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-29 18:24                 ` Adam Butcher
@ 2013-08-29 18:51                   ` Adam Butcher
  2013-08-29 19:38                     ` Gabriel Dos Reis
  0 siblings, 1 reply; 21+ messages in thread
From: Adam Butcher @ 2013-08-29 18:51 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc-patches, Jason Merrill, Andrew Sutton, Adam Butcher

	* error.c (dump_lambda_function): New function, dependent on ...
	(maybe_dump_with_clause): ... this new function, factored out of ...
	(subst_to_string): ... here and ...
	(dump_function_decl): ... here.  Updated to early-out with call to
	dump_lambda_function after determining template bindings.
---
Hi Gaby,

On 29.08.2013 18:04, Adam Butcher wrote:
> On 29.08.2013 16:25, Gabriel Dos Reis wrote:
> >
> > Document the new functions.
> > Use pp->translate_string ("with") instead of
> > pp_cxx_ws_string (pp, M_("with")).
> >
> Done.  In documenting 'maybe_dump_template_bindings' and reviewing
> it again I'm not sure it's got the right name.  It wraps
> 'dump_template_bindings' in "[with " and "]".  So it does more than
> just filter a call to 'dump_template_bindings'.
>
> Any suggestions?  What do you think of 'maybe_dump_with_clause' or
> something similar?
>
Here's a diff with the name change (though I'm not all that happy with
it) and the docs.

I've also reimplemented subst_to_string in terms of the new function
as it was duplicating much of the code from dump_function_decl (the
only downside of this is some unnecessary tests in the subst_to_string
case but I think they should get optimized away if it were inlined --
we're dealing with diagnostics formatting here anyway so performance
is probably not a big factor).

Cheers,
Adam
---
 gcc/cp/error.c | 73 ++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 46 insertions(+), 27 deletions(-)

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c82a0ce..3d1e173 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1363,6 +1363,47 @@ find_typenames (tree t)
   return ft.typenames;
 }
 
+/* Output the "[with ...]" clause for a template instantiation T iff
+   TEMPLATE_PARMS, TEMPLATE_ARGS and FLAGS are suitable.  T may be NULL if
+   formatting a deduction/substitution diagnostic rather than an
+   instantiation.  */
+
+static void
+maybe_dump_with_clause (cxx_pretty_printer *pp,
+			tree t, tree template_parms, tree template_args,
+			int flags)
+{
+  if (template_parms != NULL_TREE && template_args != NULL_TREE
+      && !(flags & TFF_NO_TEMPLATE_BINDINGS))
+    {
+      vec<tree, va_gc> *typenames = t ? find_typenames (t) : NULL;
+      pp_cxx_whitespace (pp);
+      pp_cxx_left_bracket (pp);
+      pp->translate_string ("with");
+      pp_cxx_whitespace (pp);
+      dump_template_bindings (pp, template_parms, template_args, typenames);
+      pp_cxx_right_bracket (pp);
+    }
+}
+
+/* Dump the lambda function FN including its 'mutable' qualifier and any
+   template bindings.  */
+
+static void
+dump_lambda_function (cxx_pretty_printer *pp,
+		      tree fn, tree template_parms, tree template_args,
+		      int flags)
+{
+  /* A lambda's signature is essentially its "type".  */
+  dump_type (pp, DECL_CONTEXT (fn), flags);
+  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST))
+    {
+      pp->padding = pp_before;
+      pp_c_ws_string (pp, "mutable");
+    }
+  maybe_dump_with_clause (pp, fn, template_parms, template_args, flags);
+}
+
 /* Pretty print a function decl. There are several ways we want to print a
    function declaration. The TFF_ bits in FLAGS tells us how to behave.
    As error can only apply the '#' flag once to give 0 and 1 for V, there
@@ -1379,15 +1420,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
   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;
-    }
 
   flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
   if (TREE_CODE (t) == TEMPLATE_DECL)
@@ -1409,10 +1441,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 	{
 	  template_parms = DECL_TEMPLATE_PARMS (tmpl);
 	  t = tmpl;
-	  typenames = find_typenames (t);
 	}
     }
 
+  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
+    return dump_lambda_function (pp, t, template_parms, template_args, flags);
+
   fntype = TREE_TYPE (t);
   parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
 
@@ -1476,17 +1510,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
       if (show_return)
 	dump_type_suffix (pp, TREE_TYPE (fntype), flags);
 
-      /* If T is a template instantiation, dump the parameter binding.  */
-      if (template_parms != NULL_TREE && template_args != NULL_TREE
-	  && !(flags & TFF_NO_TEMPLATE_BINDINGS))
-	{
-	  pp_cxx_whitespace (pp);
-	  pp_cxx_left_bracket (pp);
-	  pp_cxx_ws_string (pp, M_("with"));
-	  pp_cxx_whitespace (pp);
-	  dump_template_bindings (pp, template_parms, template_args, typenames);
-	  pp_cxx_right_bracket (pp);
-	}
+      maybe_dump_with_clause (pp, t, template_parms, template_args, flags);
     }
   else if (template_args)
     {
@@ -2950,12 +2974,7 @@ subst_to_string (tree p)
 
   reinit_cxx_pp ();
   dump_template_decl (cxx_pp, TREE_PURPOSE (p), flags);
-  pp_cxx_whitespace (cxx_pp);
-  pp_cxx_left_bracket (cxx_pp);
-  pp_cxx_ws_string (cxx_pp, M_("with"));
-  pp_cxx_whitespace (cxx_pp);
-  dump_template_bindings (cxx_pp, tparms, targs, NULL);
-  pp_cxx_right_bracket (cxx_pp);
+  maybe_dump_with_clause (cxx_pp, NULL, tparms, targs, /*flags=*/0);
   return pp_ggc_formatted_text (cxx_pp);
 }
 
-- 
1.8.4

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

* Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
  2013-08-29 18:51                   ` Adam Butcher
@ 2013-08-29 19:38                     ` Gabriel Dos Reis
  0 siblings, 0 replies; 21+ messages in thread
From: Gabriel Dos Reis @ 2013-08-29 19:38 UTC (permalink / raw)
  To: Adam Butcher; +Cc: gcc-patches, Jason Merrill, Andrew Sutton

On Thu, Aug 29, 2013 at 1:51 PM, Adam Butcher <adam@jessamine.co.uk> wrote:
>         * error.c (dump_lambda_function): New function, dependent on ...
>         (maybe_dump_with_clause): ... this new function, factored out of ...
>         (subst_to_string): ... here and ...
>         (dump_function_decl): ... here.  Updated to early-out with call to
>         dump_lambda_function after determining template bindings.
> ---
> Hi Gaby,
>
> On 29.08.2013 18:04, Adam Butcher wrote:
>> On 29.08.2013 16:25, Gabriel Dos Reis wrote:
>> >
>> > Document the new functions.
>> > Use pp->translate_string ("with") instead of
>> > pp_cxx_ws_string (pp, M_("with")).
>> >
>> Done.  In documenting 'maybe_dump_template_bindings' and reviewing
>> it again I'm not sure it's got the right name.  It wraps
>> 'dump_template_bindings' in "[with " and "]".  So it does more than
>> just filter a call to 'dump_template_bindings'.
>>
>> Any suggestions?  What do you think of 'maybe_dump_with_clause' or
>> something similar?
>>
> Here's a diff with the name change (though I'm not all that happy with
> it) and the docs.

call it dump_substitution.  We don't need the 'maybe_' prefix since
an empty substitution is the identity transformation.

>
> I've also reimplemented subst_to_string in terms of the new function
> as it was duplicating much of the code from dump_function_decl (the
> only downside of this is some unnecessary tests in the subst_to_string
> case but I think they should get optimized away if it were inlined --
> we're dealing with diagnostics formatting here anyway so performance
> is probably not a big factor).

Patch OK with that change.  Thanks!

>
> Cheers,
> Adam
> ---
>  gcc/cp/error.c | 73 ++++++++++++++++++++++++++++++++++++----------------------
>  1 file changed, 46 insertions(+), 27 deletions(-)
>
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index c82a0ce..3d1e173 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -1363,6 +1363,47 @@ find_typenames (tree t)
>    return ft.typenames;
>  }
>
> +/* Output the "[with ...]" clause for a template instantiation T iff
> +   TEMPLATE_PARMS, TEMPLATE_ARGS and FLAGS are suitable.  T may be NULL if
> +   formatting a deduction/substitution diagnostic rather than an
> +   instantiation.  */
> +
> +static void
> +maybe_dump_with_clause (cxx_pretty_printer *pp,
> +                       tree t, tree template_parms, tree template_args,
> +                       int flags)
> +{
> +  if (template_parms != NULL_TREE && template_args != NULL_TREE
> +      && !(flags & TFF_NO_TEMPLATE_BINDINGS))
> +    {
> +      vec<tree, va_gc> *typenames = t ? find_typenames (t) : NULL;
> +      pp_cxx_whitespace (pp);
> +      pp_cxx_left_bracket (pp);
> +      pp->translate_string ("with");
> +      pp_cxx_whitespace (pp);
> +      dump_template_bindings (pp, template_parms, template_args, typenames);
> +      pp_cxx_right_bracket (pp);
> +    }
> +}
> +
> +/* Dump the lambda function FN including its 'mutable' qualifier and any
> +   template bindings.  */
> +
> +static void
> +dump_lambda_function (cxx_pretty_printer *pp,
> +                     tree fn, tree template_parms, tree template_args,
> +                     int flags)
> +{
> +  /* A lambda's signature is essentially its "type".  */
> +  dump_type (pp, DECL_CONTEXT (fn), flags);
> +  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST))
> +    {
> +      pp->padding = pp_before;
> +      pp_c_ws_string (pp, "mutable");
> +    }
> +  maybe_dump_with_clause (pp, fn, template_parms, template_args, flags);
> +}
> +
>  /* Pretty print a function decl. There are several ways we want to print a
>     function declaration. The TFF_ bits in FLAGS tells us how to behave.
>     As error can only apply the '#' flag once to give 0 and 1 for V, there
> @@ -1379,15 +1420,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>    int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
>    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;
> -    }
>
>    flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
>    if (TREE_CODE (t) == TEMPLATE_DECL)
> @@ -1409,10 +1441,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>         {
>           template_parms = DECL_TEMPLATE_PARMS (tmpl);
>           t = tmpl;
> -         typenames = find_typenames (t);
>         }
>      }
>
> +  if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t))
> +    return dump_lambda_function (pp, t, template_parms, template_args, flags);
> +
>    fntype = TREE_TYPE (t);
>    parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
>
> @@ -1476,17 +1510,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>        if (show_return)
>         dump_type_suffix (pp, TREE_TYPE (fntype), flags);
>
> -      /* If T is a template instantiation, dump the parameter binding.  */
> -      if (template_parms != NULL_TREE && template_args != NULL_TREE
> -         && !(flags & TFF_NO_TEMPLATE_BINDINGS))
> -       {
> -         pp_cxx_whitespace (pp);
> -         pp_cxx_left_bracket (pp);
> -         pp_cxx_ws_string (pp, M_("with"));
> -         pp_cxx_whitespace (pp);
> -         dump_template_bindings (pp, template_parms, template_args, typenames);
> -         pp_cxx_right_bracket (pp);
> -       }
> +      maybe_dump_with_clause (pp, t, template_parms, template_args, flags);
>      }
>    else if (template_args)
>      {
> @@ -2950,12 +2974,7 @@ subst_to_string (tree p)
>
>    reinit_cxx_pp ();
>    dump_template_decl (cxx_pp, TREE_PURPOSE (p), flags);
> -  pp_cxx_whitespace (cxx_pp);
> -  pp_cxx_left_bracket (cxx_pp);
> -  pp_cxx_ws_string (cxx_pp, M_("with"));
> -  pp_cxx_whitespace (cxx_pp);
> -  dump_template_bindings (cxx_pp, tparms, targs, NULL);
> -  pp_cxx_right_bracket (cxx_pp);
> +  maybe_dump_with_clause (cxx_pp, NULL, tparms, targs, /*flags=*/0);
>    return pp_ggc_formatted_text (cxx_pp);
>  }
>
> --
> 1.8.4
>

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

end of thread, other threads:[~2013-08-29 19:34 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-11 19:50 Lambda templates and implicit function templates Adam Butcher
2013-08-11 19:50 ` [PATCH 3/3] Support dumping type bindings in lambda diagnostics Adam Butcher
2013-08-27 16:57   ` Jason Merrill
2013-08-27 19:43     ` Adam Butcher
2013-08-28  3:02       ` Jason Merrill
2013-08-28  9:08         ` [PATCH] Support dumping type bindings and 'mutable' qualifier " Adam Butcher
2013-08-28 12:57           ` Gabriel Dos Reis
2013-08-29 15:15             ` Adam Butcher
2013-08-29 15:57               ` Gabriel Dos Reis
2013-08-29 18:24                 ` Adam Butcher
2013-08-29 18:51                   ` Adam Butcher
2013-08-29 19:38                     ` Gabriel Dos Reis
2013-08-11 19:50 ` [PATCH 2/3] Support using 'auto' in a function parameter list to introduce an implicit template parameter Adam Butcher
2013-08-12 16:52   ` Jason Merrill
2013-08-13  0:34     ` Adam Butcher
2013-08-14 14:07       ` Jason Merrill
2013-08-14 14:29         ` Gabriel Dos Reis
2013-08-11 19:50 ` [PATCH 1/3] Support lambda templates Adam Butcher
2013-08-12 15:47   ` Jason Merrill
2013-08-12 23:52     ` Adam Butcher
2013-08-13 12:29       ` 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).