This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list.
- From: Adam Butcher <adam at jessamine dot co dot uk>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Jason Merrill <jason at redhat dot com>, Adam Butcher <adam at jessamine dot co dot uk>
- Date: Tue, 2 Jul 2013 00:27:00 +0100
- Subject: [PATCH 3/4] [lambda] [polymorphic] Infer template parameter from auto used in function parameter list.
- References: <1372721221-6201-1-git-send-email-adam at jessamine dot co dot uk>
---
gcc/cp/decl.c | 1 +
gcc/cp/parser.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
gcc/cp/pt.c | 7 ++
3 files changed, 206 insertions(+), 5 deletions(-)
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,
- ¶meter->decl_specifiers,
- PARM,
- parameter->default_argument != NULL_TREE,
- ¶meter->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,
+ ¶meter->decl_specifiers,
+ PARM,
+ parameter->default_argument != NULL_TREE,
+ ¶meter->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
--
1.8.3