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