Patchwork [3/4,lambda,polymorphic] Infer template parameter from auto used in function parameter list.

login
register
mail settings
Submitter Adam Butcher
Date July 1, 2013, 11:27 p.m.
Message ID <1372721221-6201-4-git-send-email-adam@jessamine.co.uk>
Download mbox | patch
Permalink /patch/256244/
State New
Headers show

Comments

Adam Butcher - July 1, 2013, 11:27 p.m.
---
 gcc/cp/decl.c   |   1 +
 gcc/cp/parser.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/cp/pt.c     |   7 ++
 3 files changed, 206 insertions(+), 5 deletions(-)

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 047fd77..00bcc35 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10331,6 +10331,7 @@  grokdeclarator (const cp_declarator *declarator,
 	{
 	  error ("parameter declared %<auto%>");
 	  type = error_mark_node;
+	  dump_backtrace ();
 	}
 
       /* 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 d0867c7..3bab09e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8780,6 +8780,178 @@  cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
   cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 }
 
+/* The struct auto_parm_handler_t defines an interface for customizing
+   the behaviour when a C++11 `auto' type is found as the primary type
+   specifier of a function parameter declaration.
+   If auto_parm_handler is set whilst parsing a function parameter
+   list, the function auto_parm_handler->hook will be called for each
+   parameter having `auto' as its primary type; in each case the
+   result of the hook will be used to replace `auto' as the primary
+   type.  */
+typedef struct auto_parm_handler_t auto_parm_handler_t;
+typedef tree (*auto_parm_hook_t) (auto_parm_handler_t*);
+struct auto_parm_handler_t
+{
+   auto_parm_hook_t hook;
+};
+/* Set to a structure that provides the above interface to be called
+   if a type containing `auto' is found during
+   cp_parser_parameter_declaration_list.  */
+auto_parm_handler_t* auto_parm_handler = 0;
+
+/* Handler state for processing `auto' found in lambda function call
+   parameter list.  Supports implicit polymorphic lambdas.  */
+typedef struct lambda_auto_handler_t
+{
+  auto_parm_hook_t hook;
+  tree* template_param_list;
+  vec<deferred_access_check, va_gc> *checks;
+  cp_parser* parser;
+  int i;
+}
+lambda_auto_handler_t;
+
+/* FIXME: Much of this would appear to fit better in pt.c.  */
+
+/* FIXME: It would also mean the copied function
+          build_template_parm_index and rudely extern'd
+          x_canonical_type_parameter would be unnecessary.  */
+
+tree lambda_parameter_make_auto_type_name
+  (lambda_auto_handler_t*);
+tree lambda_auto_handler
+  (lambda_auto_handler_t*);
+
+tree
+lambda_parameter_make_auto_type_name (lambda_auto_handler_t* handler)
+{
+  char buf[32];
+  sprintf (buf, "__AutoT%d", ++handler->i);
+  return get_identifier (buf);
+}
+
+/* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
+   ORIG_LEVEL, DECL, and TYPE.
+   FIXME: Remove this copy from here; i.e. probably move rest into
+          pt.c.  */
+
+static tree
+build_template_parm_index (int index,
+			   int level,
+			   int orig_level,
+			   tree decl,
+			   tree type)
+{
+  tree t = make_node (TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_IDX (t) = index;
+  TEMPLATE_PARM_LEVEL (t) = level;
+  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
+  TEMPLATE_PARM_DECL (t) = decl;
+  TREE_TYPE (t) = type;
+  TREE_CONSTANT (t) = TREE_CONSTANT (decl);
+  TREE_READONLY (t) = TREE_READONLY (decl);
+
+  return t;
+}
+
+tree
+lambda_auto_handler (lambda_auto_handler_t* handler)
+{
+  struct cp_binding_level* scope = current_binding_level;
+
+  /* FIXME: should use location of this 'auto' token. (maybe store on HANDLER?) */
+  location_t param_loc = cp_lexer_peek_token (handler->parser->lexer)->location;
+
+  /* First auto parameter may need to start a template parameter list.  */
+  bool become_template = *handler->template_param_list == NULL_TREE;
+
+  tree synth_id = lambda_parameter_make_auto_type_name (handler);
+  tree synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
+  synth_tmpl_parm = build_tree_list (NULL_TREE, synth_tmpl_parm);
+
+  if (become_template)
+    {
+      /* do something rude and pretend that the template parameter
+	 scope surrounds the function definition.  */
+      current_binding_level = current_binding_level->level_chain;
+
+      /*if (ENABLE_SCOPE_CHECKING)
+	--binding_depth;*/
+
+      push_deferring_access_checks (dk_deferred);
+      begin_template_parm_list ();
+    }
+
+  synth_tmpl_parm = process_template_parm (0,
+				       param_loc,
+				       synth_tmpl_parm,
+				       /*non_type=*/false,
+				       /*param_pack=*/false);
+
+  /* Re-index based on last existing parameter.  */
+  if (!become_template)
+    {
+      tree old = *handler->template_param_list;
+      size_t len = TREE_VEC_LENGTH (old);
+      size_t idx;
+      extern tree x_canonical_type_parameter (tree);
+
+      tree p = TREE_VALUE (TREE_VEC_ELT (old, --len));
+      if (TREE_CODE (p) == TYPE_DECL || TREE_CODE (p) == TEMPLATE_DECL)
+	idx = TEMPLATE_TYPE_IDX (TREE_TYPE (p));
+      else
+	idx = TEMPLATE_PARM_IDX (DECL_INITIAL (p));
+
+      ++idx;
+
+      TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (synth_id))
+	= build_template_parm_index (idx, processing_template_decl,
+				     processing_template_decl,
+				     TYPE_NAME (TREE_TYPE (synth_id)),
+				     TREE_TYPE (synth_id));
+      TYPE_CANONICAL (TREE_TYPE (synth_id)) = x_canonical_type_parameter (TREE_TYPE (synth_id));
+    }
+
+  if (become_template)
+    {
+      /* Initial template parameter, create new list.  */
+      *handler->template_param_list = end_template_parm_list (synth_tmpl_parm);
+      ++handler->parser->num_template_parameter_lists;
+      push_deferring_access_checks (dk_no_check);
+      push_binding_level (scope);
+    }
+  else /* Add to existing template parameter list.  */
+    {
+      tree old = *handler->template_param_list;
+      tree new_vec;
+      size_t len;
+
+      gcc_assert (TREE_CODE (old) == TREE_VEC);
+
+      len = TREE_VEC_LENGTH (old);
+
+      // FIXME: TODO: Store up 'auto' template parameters in HANDLER
+      // FIXME: TODO: and realloc actual template list once.  For now
+      // FIXME: TODO: just grow list by one each time.
+      new_vec = make_tree_vec (len+1);
+      {
+	size_t n;
+	for (n = 0; n != len; ++n)
+	  TREE_VEC_ELT (new_vec, n) = TREE_VEC_ELT (old, n);
+      }
+      TREE_VEC_ELT (new_vec, len) = synth_tmpl_parm;
+
+      ggc_free (old);
+
+      *handler->template_param_list = new_vec;
+
+      TREE_VALUE (current_template_parms) = new_vec;
+    }
+
+  /* Return synthesized type as a substitute for `auto'. */
+  return TREE_TYPE (synth_id);
+}
+
 /* Parse the (optional) middle of a lambda expression.
 
    lambda-declarator:
@@ -8829,6 +9001,15 @@  cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
       begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
 
+      /* Set up handler for auto being used in function parameter list.  */
+      lambda_auto_handler_t auto_handler;
+      auto_handler.hook = (auto_parm_hook_t) lambda_auto_handler;
+      auto_handler.template_param_list = &template_param_list;
+      auto_handler.checks = 0;
+      auto_handler.parser = parser;
+      auto_handler.i = 0;
+      auto_parm_handler = (auto_parm_handler_t*) &auto_handler;
+
       /* Parse parameters.  */
       param_list = cp_parser_parameter_declaration_clause (parser);
 
@@ -8839,6 +9020,9 @@  cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	  pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic,
 		   "default argument specified for lambda parameter");
 
+      /* TODO: copy auto_handler.checks out */
+      auto_parm_handler = 0;
+
       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
       attributes = cp_parser_attributes_opt (parser);
@@ -17915,11 +18099,20 @@  cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
       deprecated_state = DEPRECATED_SUPPRESS;
 
       if (parameter)
-	decl = grokdeclarator (parameter->declarator,
-			       &parameter->decl_specifiers,
-			       PARM,
-			       parameter->default_argument != NULL_TREE,
-			       &parameter->decl_specifiers.attributes);
+	{
+	  /* If there is a custom `auto' handler and the primary type
+	     of this parameter is `auto', then invoke the hook and
+	     replace `auto' with the result. */
+	  if (auto_parm_handler && is_auto (parameter->decl_specifiers.type))
+	    {
+	      parameter->decl_specifiers.type = auto_parm_handler->hook (auto_parm_handler);
+	    }
+	  decl = grokdeclarator (parameter->declarator,
+				 &parameter->decl_specifiers,
+				 PARM,
+				 parameter->default_argument != NULL_TREE,
+				 &parameter->decl_specifiers.attributes);
+	}
 
       deprecated_state = DEPRECATED_NORMAL;
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fbdd8ec6..8ed7aab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3545,6 +3545,13 @@  canonical_type_parameter (tree type)
     }
 }
 
+/* FIXME: Cleanup this mess */
+tree x_canonical_type_parameter (tree type);
+tree x_canonical_type_parameter (tree type)
+{
+  return canonical_type_parameter (type);
+}
+
 /* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
    TEMPLATE_PARM_LEVEL has been decreased by LEVELS.  If such a
    TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a