diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3f7eb1aa9e2..c85345eb270 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2013-11-12 Adam Butcher + + * pt.c (convert_generic_types_to_packs): New function to transform + a range of implicitly introduced non-pack template parms to be parameter + packs. + * cp-tree.h (convert_generic_types_to_packs): Declare. + * parser.c (cp_parser_parameter_declaration_list): If a function + parameter pack contains generic types, convert them to packs prior to + grokdeclarator. + 2013-11-12 Adam Butcher PR c++/58534 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fd79adbd357..e30922ab43a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5469,6 +5469,7 @@ 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 convert_generic_types_to_packs (tree, int, int); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern bool is_auto_or_concept (const_tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c48952abbb2..eaad8e44aa7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18112,7 +18112,7 @@ static tree cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) { tree parameters = NULL_TREE; - tree *tail = ¶meters; + tree *tail = ¶meters; bool saved_in_unbraced_linkage_specification_p; int index = 0; @@ -18121,7 +18121,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) /* The special considerations that apply to a function within an unbraced linkage specifications do not apply to the parameters to the function. */ - saved_in_unbraced_linkage_specification_p + saved_in_unbraced_linkage_specification_p = parser->in_unbraced_linkage_specification_p; parser->in_unbraced_linkage_specification_p = false; @@ -18131,6 +18131,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) cp_parameter_declarator *parameter; tree decl = error_mark_node; bool parenthesized_p = false; + int template_parm_idx = (parser->num_template_parameter_lists? + TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS + (current_template_parms)) : 0); + /* Parse the parameter. */ parameter = cp_parser_parameter_declaration (parser, @@ -18142,11 +18146,29 @@ 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 a function parameter pack was specified and an implicit template + parameter was introduced during cp_parser_parameter_declaration, + change any implicit parameters introduced into packs. */ + if (parser->implicit_template_parms + && parameter->declarator + && parameter->declarator->parameter_pack_p) + { + int latest_template_parm_idx = TREE_VEC_LENGTH + (INNERMOST_TEMPLATE_PARMS (current_template_parms)); + + if (latest_template_parm_idx != template_parm_idx) + parameter->decl_specifiers.type = convert_generic_types_to_packs + (parameter->decl_specifiers.type, + template_parm_idx, latest_template_parm_idx); + } + + 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 d066c26dd88..57a9769aecc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21630,6 +21630,58 @@ append_type_to_template_for_access_check (tree templ, scope, location); } +/* Convert the generic type parameters in PARM that match the types given in the + range [START_IDX, END_IDX) from the current_template_parms into generic type + packs. */ + +tree +convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) +{ + tree current = current_template_parms; + int depth = TMPL_PARMS_DEPTH (current); + current = INNERMOST_TEMPLATE_PARMS (current); + tree replacement = make_tree_vec (TREE_VEC_LENGTH (current)); + + for (int i = 0; i < start_idx; ++i) + TREE_VEC_ELT (replacement, i) + = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))); + + for (int i = start_idx; i < end_idx; ++i) + { + /* Create a distinct parameter pack type from the current parm and add it + to the replacement args to tsubst below into the generic function + parameter. */ + + tree o = TREE_TYPE (TREE_VALUE + (TREE_VEC_ELT (current, i))); + tree t = copy_type (o); + TEMPLATE_TYPE_PARM_INDEX (t) + = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (o), + o, 0, 0, tf_none); + TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t; + TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t); + TYPE_MAIN_VARIANT (t) = t; + TEMPLATE_TYPE_PARAMETER_PACK (t) = true; + TYPE_CANONICAL (t) = canonical_type_parameter (t); + TREE_VEC_ELT (replacement, i) = t; + TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t); + } + + for (int i = end_idx, e = TREE_VEC_LENGTH (current); i < e; ++i) + TREE_VEC_ELT (replacement, i) + = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))); + + /* If there are more levels then build up the replacement with the outer + template parms. */ + if (depth > 1) + replacement = add_to_template_args (template_parms_to_args + (TREE_CHAIN (current_template_parms)), + replacement); + + return tsubst (parm, replacement, tf_none, NULL_TREE); +} + + /* Set up the hash tables for template instantiations. */ void