summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>2007-03-10 01:58:58 +0000
committerdgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>2007-03-10 01:58:58 +0000
commitd95d815de1c80955a3028fd71de78c4fe2325215 (patch)
tree5b5cbae80b3f073895daff4c00dc387a5f31c3bb
parenteb9161e7da456f72399e98b0f7a688bd6a6879fc (diff)
downloadgcc-d95d815de1c80955a3028fd71de78c4fe2325215.tar.gz
2007-03-09 Douglas Gregor <doug.gregor@gmail.com>
PR c++/20599 * typeck.c (check_return_expr): Check for bare parameter packs. (comptypes): Compare template parameter packs and type pack expansions. * decl.c (grokdeclarator): Deal with the declaration of function parameter packs. (grokparms): Verify that the (optional) function parameter pack is at the end of the parameter list. (xref_basetypes): Handle pack expansions in the base class. (cp_tree_node_structure): Handle ARGUMENT_PACK_SELECT. * cp-tree.def (TYPE_ARGUMENT_PACK): New. (NONTYPE_ARGUMENT_PACK): New. (TYPE_PACK_EXPANSION): New. (EXPR_PACK_EXPANSION): New. (ARGUMENT_PACK_SELECT): New. * cp-objcp-common.c (cp_tree_size): Compute size of (NON)TYPE_ARGUMENT_PACK, (TYPE|EXPR)_PACK_EXPANSION, and ARGUMENT_PACK_SELECT. * error.c (dump_template_argument): Print template argument packs. (dump_template_argument_list): Ditto. (dump_template_parameter): Dump `...' for template type parameter packs. (dump_type): Dump TYPE_PACK_EXPANSION nodes. (dump_parameters): Print function parameter packs. (dump_template_parms): Print template argument packs. (dump_expr): Dump EXPR_PACK_EXPANSION nodes. (maybe_warn_variadic_templates): New. * operators.def: Add ellipsis operator for EXPR_PACK_EXPANSION. * tree.c (cp_walk_subtrees): Walk BASELINK, TYPE_ARGUMENT_PACK, NONTYPE_ARGUMENT_PACK, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION, CAST_EXPR. * mangle.c (write_type): Mangle TYPE_PACK_EXPANSION. (write_template_arg): Write argument packs as separate arguments. * cp-tree.h (struct template_parm_index_s): Add flag that indicates that the template parameter is actually a parameter pack. (struct tree_argument_pack_select): New. (enum cp_tree_node_structure_enum): Add TS_CP_ARGUMENT_PACK_SELECT. (union lang_tree_node): Add argument_pack_select. (FUNCTION_PARAMETER_PACK_P): New. (PACK_EXPANSION_P): New. (PACK_EXPANSION_PATTERN): New. (SET_PACK_EXPANSION_PATTERN): New. (PACK_EXPANSION_PARAMETER_PACKS): New. (ARGUMENT_PACK_P): New. (ARGUMENT_PACK_ARGS): New. (SET_ARGUMENT_PACK_ARGS): New. (ARGUMENT_PACK_INCOMPLETE_P): New. (ARGUMENT_PACK_EXPLICIT_ARGS): New. (TEMPLATE_PARM_PARAMETER_PACK): New. (TEMPLATE_TYPE_PARAMETER_PACK): New. (ARGUMENT_PACK_SELECT_FROM_PACK): New. (ARGUMENT_PACK_SELECT_INDEX): New. (ARGUMENT_PACK_SELECT_ARG): New. (struct cp_declarator): Add parameter_pack_p flag. (maybe_warn_variadic_templates): Declare. (process_template_parm): Add bool parameter IS_PARAMETER_PACK, to indicate a template parameter pack. (uses_parameter_packs): Declare. (template_parameter_pack_p): Declare. (template_parms_variadic_p): Declare. (make_pack_expansion): Declare. (check_for_bare_parameter_packs): Declare. * cxx-pretty-print.c (pp_cxx_unary_expression): Print sizeof... expressions. (pp_cxx_expression): Print pack expansions and non-type argument packs. (pp_cxx_exception_specification): Print pack expansions. (pp_cxx_direct_declarator): Print ellipsis for parameter packs. (pp_cxx_ctor_initializer): Print pack expansions. (pp_cxx_type_id): Print pack expansions. (pp_cxx_template_argument_list): Print argument packs. (pp_cxx_template_parameter): Print ellipsis for template parameter packs. * pt.c (comp_template_parms): Compare template parameter packs. (template_parameter_pack_p): New. (template_parms_variadic_p): New. (template_args_variadic_p): New. (make_ith_pack_parameter_name): New. (struct find_parameter_pack_data): New. (find_parameter_packs_r): New. (uses_parameter_packs): New. (make_pack_expansion): New. (check_for_bare_parameter_packs): New. (expand_template_argument_pack): New. (reduce_template_parm_level): Propagate parameter pack flag. (process_template_parm): Add is_parameter_pack parameter to state when the parameter is actually a parameter pack. Create template parameter packs when is_parameter_pack is true. (current_template_args): The argument for a template parameter pack is an argument pack containing a single pack expansion. (process_partial_specialization): When checking that non-type argument expressions do not involve template parameters, loop over the arguments in argument packs separately. (push_template_decl_real): Check that the type of the declaration does not have any bare parameter packs. Check that primary templates have no more than one parameter pack, and that it comes at the end of the template parameter list. (convert_template_argument): Handle coercions for pack expansion expressions by coercing the pattern then rebuilding the expansion. (coerce_template_parms): When coercing the arguments for a variadic template, pack "extra" arguments into an argument pack. (coerce_template_template_parms): Cannot coerce between parameter packs and non-pack parameters. (template_args_equal): Compare PACK_EXPANSION_P expressions. (comp_template_args): Expand all template arguments packs before comparing template argument lists. (mangle_class_name_for_template): Make argument packs as separate template arguments. (for_each_template_parm_r): No need to handle BASELINK. (instantiate_class_template): Handle pack expansions in the base class list. (tsubst_pack_expansion): New. (tsubst_template_args): Handle substitutions of argument packs and pack expansion into template argument lists. (tsubst_decl): Expand function parameter packs into separate function parameters. (tsubst_arg_types): Expand a type pack expansion into separate argument types. (tsubst_exception_specification): Handle pack expansions in exception specifiers. (tsubst): See through ARGUMENT_PACK_SELECT arguments when replacing a template parameter with its argument. If we encounter a substitution for an argument pack, just return the parameter itself. (tsubst_copy): sizeof(X...) returns the number of elements in parameter pack X. See through ARGUMENT_PACK_SELECT when the PARM_DECL is a parameter pack. (tsubst_expr): Expression pack expansions and argument packs cannot show up here; they will all be handled through function calls, sizeof, and template argument lists. (tsubst_copy_and_build): sizeof(X...) returns the number of elements in parameter pack X. Handle pack expansions in TREE_LIST and CONSTRUCTOR nodes. (fn_type_unification): Handle "incomplete" explicit template argument lists that specify some of the arguments for a template parameter pack. (type_unification_real): Unify arguments against pack expansions. (template_parm_level_and_index): New, helper function. (unify_pack_expansion): New. (unify): Unify argument packs on an argument-by-argument basis, handling variadic argument packs as well. (more_specialized_fn): Handle unification of function parameter packs. All things being equal, prefer non-variadic function templates to variadic function templates. (more_specialized_class): Prefer the variadic class template partial specialization that binds fewer arguments to a parameter pack. (regenerate_decl_from_template): Expand function parameter packs into separate parameters. (instantiate_decl): Ditto. (tsubst_initializer_list): Handle pack expansions for base-class initializers. (dependent_type_p_r): Determine dependent types in argument packs and pack expansions. (value_dependent_expression_p): Determine value-dependence of non-type argument packs. (dependent_template_arg_p): Handle argument packs. * semantics.c (finish_cond): Check for bare parameter packs. (finish_expr_stmt): Ditto. (finish_for_expr): Ditto. (finish_switch_cond): Ditto. (finish_mem_initializers): Ditto. * name-lookup.c (arg_assoc_type): Handle pack expansions and argument packs. * decl2.c (cp_build_parm_decl): Mark function parameter packs. * parser.c (make_declarator): Declarator is not an expansion. (make_pointer_declarator): Transfer parameter pack flag to outer declarator. (make_reference_declarator): Ditto. (make_ptrmem_declarator): Ditto. (make_call_declarator): Ditto. (make_array_declarator): Ditto. (cp_parser_postfix_expression): Allow pack expansion expressions in the argument list for a call expression. (cp_parser_parenthesized_expression_list): Add new parameter ALLOW_EXPANSION_P. When true, parse the ellipsis to mean "expand into separate arguments." (cp_parser_new_placement): Allow pack expansion expressions. (cp_parser_new_initializer): Ditto. (cp_parser_mem_initializer_list): Allow ellipsis to create a base-class initializer expansion. (cp_parser_mem_initializer): Ditto. (cp_parser_template_parameter_list): Keep track of whether the template parameter is a template parameter pack. (cp_parser_template_parameter): Parse the ellipsis to indicate a template parameter pack. (cp_parser_type_parameter): Ditto. (cp_parser_template_argument_list): Parse the ellipsis to indicate a pack expansion. (cp_parser_direct_declarator): Parse the ellipsis to indicate that this declarator is a parameter pack. (cp_parser_parameter_declaration): The ellipsis does not end the parameter declaration, because it might be a parameter pack. Parse the ellipsis to indicate a parameter pack. (cp_parser_initializer): Allow pack expansions. (cp_parser_initializer_list): Allow ellipsis to create an initializer expansion. (cp_parser_base_clause): Allow ellipsis to create a base specifier expansion. (cp_parser_type_id_list): Allow ellipsis to create an exception specifier expansion. (cp_parser_attribute_list): Don't allow pack expansions. (cp_parser_functional_cast): Allow pack expansions. (cp_parser_sizeof_operand): Allow ellipsis following "sizeof" to compute the length of a parameter pack. (cp_parser_next_token_ends_template_argument_p): An ellipsis can end a template argument. * tree.c (cp_walk_subtrees): Walk BASELINK, TYPE_ARGUMENT_PACK, NONTYPE_ARGUMENT_PACK, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION, CAST_EXPR. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122788 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog214
-rw-r--r--gcc/cp/cp-objcp-common.c11
-rw-r--r--gcc/cp/cp-tree.def70
-rw-r--r--gcc/cp/cp-tree.h109
-rw-r--r--gcc/cp/cxx-pretty-print.c132
-rw-r--r--gcc/cp/decl.c24
-rw-r--r--gcc/cp/decl2.c6
-rw-r--r--gcc/cp/error.c80
-rw-r--r--gcc/cp/mangle.c15
-rw-r--r--gcc/cp/name-lookup.c12
-rw-r--r--gcc/cp/operators.def3
-rw-r--r--gcc/cp/parser.c370
-rw-r--r--gcc/cp/pt.c2393
-rw-r--r--gcc/cp/semantics.c23
-rw-r--r--gcc/cp/tree.c38
-rw-r--r--gcc/cp/typeck.c13
16 files changed, 3226 insertions, 287 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8d0ba18a79c..886b305c4a8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,217 @@
+2007-03-09 Douglas Gregor <doug.gregor@gmail.com>
+
+ PR c++/20599
+ * typeck.c (check_return_expr): Check for bare parameter packs.
+ (comptypes): Compare template parameter packs and
+ type pack expansions.
+ * decl.c (grokdeclarator): Deal with the declaration of function
+ parameter packs.
+ (grokparms): Verify that the (optional) function parameter pack is
+ at the end of the parameter list.
+ (xref_basetypes): Handle pack expansions in the base class.
+ (cp_tree_node_structure): Handle ARGUMENT_PACK_SELECT.
+ * cp-tree.def (TYPE_ARGUMENT_PACK): New.
+ (NONTYPE_ARGUMENT_PACK): New.
+ (TYPE_PACK_EXPANSION): New.
+ (EXPR_PACK_EXPANSION): New.
+ (ARGUMENT_PACK_SELECT): New.
+ * cp-objcp-common.c (cp_tree_size): Compute size of
+ (NON)TYPE_ARGUMENT_PACK, (TYPE|EXPR)_PACK_EXPANSION, and
+ ARGUMENT_PACK_SELECT.
+ * error.c (dump_template_argument): Print template argument packs.
+ (dump_template_argument_list): Ditto.
+ (dump_template_parameter): Dump `...' for template type parameter
+ packs.
+ (dump_type): Dump TYPE_PACK_EXPANSION nodes.
+ (dump_parameters): Print function parameter packs.
+ (dump_template_parms): Print template argument packs.
+ (dump_expr): Dump EXPR_PACK_EXPANSION nodes.
+ (maybe_warn_variadic_templates): New.
+ * operators.def: Add ellipsis operator for EXPR_PACK_EXPANSION.
+ * tree.c (cp_walk_subtrees): Walk BASELINK, TYPE_ARGUMENT_PACK,
+ NONTYPE_ARGUMENT_PACK, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION,
+ CAST_EXPR.
+ * mangle.c (write_type): Mangle TYPE_PACK_EXPANSION.
+ (write_template_arg): Write argument packs as separate arguments.
+ * cp-tree.h (struct template_parm_index_s): Add flag that
+ indicates that the template parameter is actually a parameter
+ pack.
+ (struct tree_argument_pack_select): New.
+ (enum cp_tree_node_structure_enum): Add TS_CP_ARGUMENT_PACK_SELECT.
+ (union lang_tree_node): Add argument_pack_select.
+ (FUNCTION_PARAMETER_PACK_P): New.
+ (PACK_EXPANSION_P): New.
+ (PACK_EXPANSION_PATTERN): New.
+ (SET_PACK_EXPANSION_PATTERN): New.
+ (PACK_EXPANSION_PARAMETER_PACKS): New.
+ (ARGUMENT_PACK_P): New.
+ (ARGUMENT_PACK_ARGS): New.
+ (SET_ARGUMENT_PACK_ARGS): New.
+ (ARGUMENT_PACK_INCOMPLETE_P): New.
+ (ARGUMENT_PACK_EXPLICIT_ARGS): New.
+ (TEMPLATE_PARM_PARAMETER_PACK): New.
+ (TEMPLATE_TYPE_PARAMETER_PACK): New.
+ (ARGUMENT_PACK_SELECT_FROM_PACK): New.
+ (ARGUMENT_PACK_SELECT_INDEX): New.
+ (ARGUMENT_PACK_SELECT_ARG): New.
+ (struct cp_declarator): Add parameter_pack_p flag.
+ (maybe_warn_variadic_templates): Declare.
+ (process_template_parm): Add bool parameter IS_PARAMETER_PACK, to
+ indicate a template parameter pack.
+ (uses_parameter_packs): Declare.
+ (template_parameter_pack_p): Declare.
+ (template_parms_variadic_p): Declare.
+ (make_pack_expansion): Declare.
+ (check_for_bare_parameter_packs): Declare.
+ * cxx-pretty-print.c (pp_cxx_unary_expression): Print
+ sizeof... expressions.
+ (pp_cxx_expression): Print pack expansions and non-type argument
+ packs.
+ (pp_cxx_exception_specification): Print pack expansions.
+ (pp_cxx_direct_declarator): Print ellipsis for parameter packs.
+ (pp_cxx_ctor_initializer): Print pack expansions.
+ (pp_cxx_type_id): Print pack expansions.
+ (pp_cxx_template_argument_list): Print argument packs.
+ (pp_cxx_template_parameter): Print ellipsis for template parameter
+ packs.
+ * pt.c (comp_template_parms): Compare template parameter packs.
+ (template_parameter_pack_p): New.
+ (template_parms_variadic_p): New.
+ (template_args_variadic_p): New.
+ (make_ith_pack_parameter_name): New.
+ (struct find_parameter_pack_data): New.
+ (find_parameter_packs_r): New.
+ (uses_parameter_packs): New.
+ (make_pack_expansion): New.
+ (check_for_bare_parameter_packs): New.
+ (expand_template_argument_pack): New.
+ (reduce_template_parm_level): Propagate parameter pack flag.
+ (process_template_parm): Add is_parameter_pack parameter to state
+ when the parameter is actually a parameter pack. Create template
+ parameter packs when is_parameter_pack is true.
+ (current_template_args): The argument for a template parameter
+ pack is an argument pack containing a single pack expansion.
+ (process_partial_specialization): When checking that non-type
+ argument expressions do not involve template parameters, loop over
+ the arguments in argument packs separately.
+ (push_template_decl_real): Check that the type of the declaration
+ does not have any bare parameter packs. Check that primary
+ templates have no more than one parameter pack, and that it comes
+ at the end of the template parameter list.
+ (convert_template_argument): Handle coercions for pack expansion
+ expressions by coercing the pattern then rebuilding the expansion.
+ (coerce_template_parms): When coercing the arguments for a
+ variadic template, pack "extra" arguments into an argument pack.
+ (coerce_template_template_parms): Cannot coerce between parameter
+ packs and non-pack parameters.
+ (template_args_equal): Compare PACK_EXPANSION_P expressions.
+ (comp_template_args): Expand all template arguments packs before
+ comparing template argument lists.
+ (mangle_class_name_for_template): Make argument packs as separate
+ template arguments.
+ (for_each_template_parm_r): No need to handle BASELINK.
+ (instantiate_class_template): Handle pack expansions in the base
+ class list.
+ (tsubst_pack_expansion): New.
+ (tsubst_template_args): Handle substitutions of argument packs and
+ pack expansion into template argument lists.
+ (tsubst_decl): Expand function parameter packs into separate
+ function parameters.
+ (tsubst_arg_types): Expand a type pack expansion into separate
+ argument types.
+ (tsubst_exception_specification): Handle pack expansions in
+ exception specifiers.
+ (tsubst): See through ARGUMENT_PACK_SELECT arguments when
+ replacing a template parameter with its argument. If we encounter
+ a substitution for an argument pack, just return the parameter
+ itself.
+ (tsubst_copy): sizeof(X...) returns the number of elements in
+ parameter pack X. See through ARGUMENT_PACK_SELECT when the
+ PARM_DECL is a parameter pack.
+ (tsubst_expr): Expression pack expansions and argument packs
+ cannot show up here; they will all be handled through function
+ calls, sizeof, and template argument lists.
+ (tsubst_copy_and_build): sizeof(X...) returns the number of
+ elements in parameter pack X. Handle pack expansions in TREE_LIST
+ and CONSTRUCTOR nodes.
+ (fn_type_unification): Handle "incomplete" explicit template
+ argument lists that specify some of the arguments for a template
+ parameter pack.
+ (type_unification_real): Unify arguments against pack expansions.
+ (template_parm_level_and_index): New, helper function.
+ (unify_pack_expansion): New.
+ (unify): Unify argument packs on an argument-by-argument basis,
+ handling variadic argument packs as well.
+ (more_specialized_fn): Handle unification of function parameter
+ packs. All things being equal, prefer non-variadic function
+ templates to variadic function templates.
+ (more_specialized_class): Prefer the variadic class template
+ partial specialization that binds fewer arguments to a parameter
+ pack.
+ (regenerate_decl_from_template): Expand function parameter packs
+ into separate parameters.
+ (instantiate_decl): Ditto.
+ (tsubst_initializer_list): Handle pack expansions for base-class
+ initializers.
+ (dependent_type_p_r): Determine dependent types in argument packs
+ and pack expansions.
+ (value_dependent_expression_p): Determine value-dependence of
+ non-type argument packs.
+ (dependent_template_arg_p): Handle argument packs.
+ * semantics.c (finish_cond): Check for bare parameter packs.
+ (finish_expr_stmt): Ditto.
+ (finish_for_expr): Ditto.
+ (finish_switch_cond): Ditto.
+ (finish_mem_initializers): Ditto.
+ * name-lookup.c (arg_assoc_type): Handle pack expansions and
+ argument packs.
+ * decl2.c (cp_build_parm_decl): Mark function parameter packs.
+ * parser.c (make_declarator): Declarator is not an expansion.
+ (make_pointer_declarator): Transfer parameter pack flag to outer
+ declarator.
+ (make_reference_declarator): Ditto.
+ (make_ptrmem_declarator): Ditto.
+ (make_call_declarator): Ditto.
+ (make_array_declarator): Ditto.
+ (cp_parser_postfix_expression): Allow pack expansion expressions
+ in the argument list for a call expression.
+ (cp_parser_parenthesized_expression_list): Add new parameter
+ ALLOW_EXPANSION_P. When true, parse the ellipsis to mean "expand
+ into separate arguments."
+ (cp_parser_new_placement): Allow pack expansion expressions.
+ (cp_parser_new_initializer): Ditto.
+ (cp_parser_mem_initializer_list): Allow ellipsis to create a
+ base-class initializer expansion.
+ (cp_parser_mem_initializer): Ditto.
+ (cp_parser_template_parameter_list): Keep track of whether the
+ template parameter is a template parameter pack.
+ (cp_parser_template_parameter): Parse the ellipsis to indicate a
+ template parameter pack.
+ (cp_parser_type_parameter): Ditto.
+ (cp_parser_template_argument_list): Parse the ellipsis to indicate
+ a pack expansion.
+ (cp_parser_direct_declarator): Parse the ellipsis to indicate that
+ this declarator is a parameter pack.
+ (cp_parser_parameter_declaration): The ellipsis does not end the
+ parameter declaration, because it might be a parameter pack. Parse
+ the ellipsis to indicate a parameter pack.
+ (cp_parser_initializer): Allow pack expansions.
+ (cp_parser_initializer_list): Allow ellipsis to create an
+ initializer expansion.
+ (cp_parser_base_clause): Allow ellipsis to create a base specifier
+ expansion.
+ (cp_parser_type_id_list): Allow ellipsis to create an exception
+ specifier expansion.
+ (cp_parser_attribute_list): Don't allow pack expansions.
+ (cp_parser_functional_cast): Allow pack expansions.
+ (cp_parser_sizeof_operand): Allow ellipsis following "sizeof" to
+ compute the length of a parameter pack.
+ (cp_parser_next_token_ends_template_argument_p): An ellipsis can
+ end a template argument.
+ * tree.c (cp_walk_subtrees): Walk BASELINK, TYPE_ARGUMENT_PACK,
+ NONTYPE_ARGUMENT_PACK, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION,
+ CAST_EXPR.
+
2007-03-09 Dirk Mueller <dmueller@suse.de>
* cp/call.c (build_new_op): Call warn_logical_operator.
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 372e8e5ac3e..7b1841e3fa7 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -124,6 +124,17 @@ cp_tree_size (enum tree_code code)
case DEFAULT_ARG: return sizeof (struct tree_default_arg);
case OVERLOAD: return sizeof (struct tree_overload);
case STATIC_ASSERT: return sizeof (struct tree_static_assert);
+ case TYPE_ARGUMENT_PACK:
+ case TYPE_PACK_EXPANSION:
+ return sizeof (struct tree_common);
+
+ case NONTYPE_ARGUMENT_PACK:
+ case EXPR_PACK_EXPANSION:
+ return sizeof (struct tree_exp);
+
+ case ARGUMENT_PACK_SELECT:
+ return sizeof (struct tree_argument_pack_select);
+
default:
gcc_unreachable ();
}
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index bcc6b54223c..83e1e53cbc7 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -352,6 +352,76 @@ DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1)
literal) to be displayed if the condition fails to hold. */
DEFTREECODE (STATIC_ASSERT, "static_assert", tcc_exceptional, 0)
+/* Represents an argument pack of types (or templates). An argument
+ pack stores zero or more arguments that will be used to instantiate
+ a parameter pack.
+
+ ARGUMENT_PACK_ARGS retrieves the arguments stored in the argument
+ pack.
+
+ Example:
+ template<typename... Values>
+ class tuple { ... };
+
+ tuple<int, float, double> t;
+
+ Values is a (template) parameter pack. When tuple<int, float,
+ double> is instantiated, the Values parameter pack is instantiated
+ with the argment pack <int, float, double>. ARGUMENT_PACK_ARGS will
+ be a TREE_VEC containing int, float, and double. */
+DEFTREECODE (TYPE_ARGUMENT_PACK, "type_argument_pack", tcc_type, 0)
+
+/* Represents an argument pack of values, which can be used either for
+ non-type template arguments or function call arguments.
+
+ NONTYPE_ARGUMENT_PACK plays precisely the same role as
+ TYPE_ARGUMENT_PACK, but will be used for packing non-type template
+ arguments (e.g., "int... Dimensions") or function arguments ("const
+ Args&... args"). */
+DEFTREECODE (NONTYPE_ARGUMENT_PACK, "nontype_argument_pack", tcc_expression, 1)
+
+/* Represents a type expression that will be expanded into a list of
+ types when instantiated with one or more argument packs.
+
+ PACK_EXPANSION_PATTERN retrieves the expansion pattern. This is
+ the type or expression that we will substitute into with each
+ argument in an argument pack.
+
+ SET_PACK_EXPANSION_PATTERN sets the expansion pattern.
+
+ PACK_EXPANSION_PARAMETER_PACKS contains a TREE_LIST of the parameter
+ packs that are used in this pack expansion.
+
+ Example:
+ template<typename... Values>
+ struct tied : tuple<Values&...> {
+ // ...
+ };
+
+ The derivation from tuple contains a TYPE_PACK_EXPANSION for the
+ template arguments. Its EXPR_PACK_EXPANSION is "Values&" and its
+ PACK_EXPANSION_PARAMETER_PACKS will contain "Values". */
+DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0)
+
+/* Represents an expression that will be expanded into a list of
+ expressions when instantiated with one or more argument packs.
+
+ EXPR_PACK_EXPANSION plays precisely the same role as TYPE_PACK_EXPANSION,
+ but will be used for expressions. */
+DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 1)
+
+/* Selects the Ith parameter out of an argument pack. This node will
+ be used when instantiating pack expansions; see
+ tsubst_pack_expansion.
+
+ ARGUMENT_PACK_SELECT_FROM_PACK contains the *_ARGUMENT_PACK node
+ from which the argument will be selected.
+
+ ARGUMENT_PACK_SELECT_INDEX contains the index into the argument
+ pack that will be returned by this ARGUMENT_PACK_SELECT node. The
+ index is a machine integer. */
+DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0)
+
/*
Local variables:
mode:c
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 95e278ce654..c90d5290eb3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -103,6 +103,7 @@ struct diagnostic_context;
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
+ FUNCTION_PARAMETER_PACK_P (in PARM_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
3: DECL_IN_AGGR_P.
@@ -222,6 +223,10 @@ struct template_parm_index_s GTY(())
HOST_WIDE_INT level;
HOST_WIDE_INT orig_level;
tree decl;
+
+ /* When true, indicates that this parameter is actually a parameter
+ pack, for variadic templates. */
+ BOOL_BITFIELD parameter_pack;
};
typedef struct template_parm_index_s template_parm_index;
@@ -469,6 +474,13 @@ struct tree_static_assert GTY (())
location_t location;
};
+struct tree_argument_pack_select GTY (())
+{
+ struct tree_common common;
+ tree argument_pack;
+ int index;
+};
+
enum cp_tree_node_structure_enum {
TS_CP_GENERIC,
TS_CP_IDENTIFIER,
@@ -481,6 +493,7 @@ enum cp_tree_node_structure_enum {
TS_CP_WRAPPER,
TS_CP_DEFAULT_ARG,
TS_CP_STATIC_ASSERT,
+ TS_CP_ARGUMENT_PACK_SELECT,
LAST_TS_CP_ENUM
};
@@ -499,6 +512,8 @@ union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"),
struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT")))
static_assertion;
+ struct tree_argument_pack_select GTY ((tag ("TS_CP_ARGUMENT_PACK_SELECT")))
+ argument_pack_select;
};
@@ -2188,7 +2203,7 @@ extern void decl_shadowed_for_var_insert (tree, tree);
/* Nonzero if the template arguments is actually a vector of vectors,
rather than just a vector. */
#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \
- (NODE && TREE_VEC_ELT (NODE, 0) \
+ (NODE && TREE_VEC_ELT (NODE, 0) \
&& TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
/* The depth of a template argument vector. When called directly by
@@ -2295,6 +2310,84 @@ extern void decl_shadowed_for_var_insert (tree, tree);
the class definition is complete. */
#define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
+/* Determine if a parameter (i.e., a PARM_DECL) is a function
+ parameter pack. */
+#define FUNCTION_PARAMETER_PACK_P(NODE) \
+ (DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE)))
+
+/* Determines if NODE is an expansion of one or more parameter packs,
+ e.g., a TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION. */
+#define PACK_EXPANSION_P(NODE) \
+ (TREE_CODE (NODE) == TYPE_PACK_EXPANSION \
+ || TREE_CODE (NODE) == EXPR_PACK_EXPANSION)
+
+/* Extracts the type or expression pattern from a TYPE_PACK_EXPANSION or
+ EXPR_PACK_EXPANSION. */
+#define PACK_EXPANSION_PATTERN(NODE) \
+ (TREE_CODE (NODE) == TYPE_PACK_EXPANSION? TREE_TYPE (NODE) \
+ : TREE_OPERAND (NODE, 0))
+
+/* Sets the type or expression pattern for a TYPE_PACK_EXPANSION or
+ EXPR_PACK_EXPANSION. */
+#define SET_PACK_EXPANSION_PATTERN(NODE,VALUE) \
+ if (TREE_CODE (NODE) == TYPE_PACK_EXPANSION) \
+ TREE_TYPE (NODE) = VALUE; \
+ else \
+ TREE_OPERAND (NODE, 0) = VALUE
+
+/* The list of parameter packs used in the PACK_EXPANSION_* node. The
+ TREE_VALUE of each TREE_LIST contains the parameter packs. */
+#define PACK_EXPANSION_PARAMETER_PACKS(NODE) TREE_CHAIN (NODE)
+
+/* Determine if this is an argument pack. */
+#define ARGUMENT_PACK_P(NODE) \
+ (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \
+ || TREE_CODE (NODE) == NONTYPE_ARGUMENT_PACK)
+
+/* The arguments stored in an argument pack. Arguments are stored in a
+ TREE_VEC, which may have length zero. */
+#define ARGUMENT_PACK_ARGS(NODE) \
+ (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK? TREE_TYPE (NODE) \
+ : TREE_OPERAND (NODE, 0))
+
+/* Set the arguments stored in an argument pack. VALUE must be a
+ TREE_VEC. */
+#define SET_ARGUMENT_PACK_ARGS(NODE,VALUE) \
+ if (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK) \
+ TREE_TYPE (NODE) = VALUE; \
+ else \
+ TREE_OPERAND (NODE, 0) = VALUE
+
+/* Whether the argument pack is "incomplete", meaning that more
+ arguments can still be deduced. Incomplete argument packs are only
+ used when the user has provided an explicit template argument list
+ for a variadic function template. Some of the explicit template
+ arguments will be placed into the beginning of the argument pack,
+ but additional arguments might still be deduced. */
+#define ARGUMENT_PACK_INCOMPLETE_P(NODE) \
+ TREE_LANG_FLAG_0 (ARGUMENT_PACK_ARGS (NODE))
+
+/* When ARGUMENT_PACK_INCOMPLETE_P, stores the explicit template
+ arguments used to fill this pack. */
+#define ARGUMENT_PACK_EXPLICIT_ARGS(NODE) \
+ TREE_TYPE (ARGUMENT_PACK_ARGS (NODE))
+
+/* In an ARGUMENT_PACK_SELECT, the argument pack from which an
+ argument will be selected. */
+#define ARGUMENT_PACK_SELECT_FROM_PACK(NODE) \
+ (((struct tree_argument_pack_select *)ARGUMENT_PACK_SELECT_CHECK (NODE))->argument_pack)
+
+/* In an ARGUMENT_PACK_SELECT, the index of the argument we want to
+ select. */
+#define ARGUMENT_PACK_SELECT_INDEX(NODE) \
+ (((struct tree_argument_pack_select *)ARGUMENT_PACK_SELECT_CHECK (NODE))->index)
+
+/* In an ARGUMENT_PACK_SELECT, the actual underlying argument that the
+ ARGUMENT_PACK_SELECT represents. */
+#define ARGUMENT_PACK_SELECT_ARG(NODE) \
+ TREE_VEC_ELT (ARGUMENT_PACK_ARGS (ARGUMENT_PACK_SELECT_FROM_PACK (NODE)), \
+ ARGUMENT_PACK_SELECT_INDEX (NODE));
+
/* In a FUNCTION_DECL, the saved language-specific per-function data. */
#define DECL_SAVED_FUNCTION_DATA(NODE) \
(DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE)) \
@@ -3612,6 +3705,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
#define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
+#define TEMPLATE_PARM_PARAMETER_PACK(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->parameter_pack)
/* These macros are for accessing the fields of TEMPLATE_TYPE_PARM,
TEMPLATE_TEMPLATE_PARM and BOUND_TEMPLATE_TEMPLATE_PARM nodes. */
@@ -3626,6 +3720,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
(TEMPLATE_PARM_ORIG_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
#define TEMPLATE_TYPE_DECL(NODE) \
(TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
+ (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
/* These constants can used as bit flags in the process of tree formatting.
@@ -3812,6 +3908,9 @@ struct cp_declarator {
cdk_id and cdk_error, guaranteed to be NULL. */
cp_declarator *declarator;
location_t id_loc; /* Currently only set for cdk_id. */
+ /* Whether we parsed an ellipsis (`...') just before the declarator,
+ to indicate this is a parameter pack. */
+ bool parameter_pack_p;
union {
/* For identifiers. */
struct {
@@ -4104,6 +4203,7 @@ extern const char *lang_decl_name (tree, int);
extern const char *language_to_string (enum languages);
extern const char *class_key_or_enum_as_string (tree);
extern void print_instantiation_context (void);
+extern void maybe_warn_variadic_templates (void);
/* in except.c */
extern void init_exception_processing (void);
@@ -4194,7 +4294,7 @@ extern void end_specialization (void);
extern void begin_explicit_instantiation (void);
extern void end_explicit_instantiation (void);
extern tree check_explicit_specialization (tree, tree, int, int);
-extern tree process_template_parm (tree, tree, bool);
+extern tree process_template_parm (tree, tree, bool, bool);
extern tree end_template_parm_list (tree);
extern void end_template_decl (void);
extern tree push_template_decl (tree);
@@ -4215,6 +4315,11 @@ extern void do_decl_instantiation (tree, tree);
extern void do_type_instantiation (tree, tree, tsubst_flags_t);
extern tree instantiate_decl (tree, int, bool);
extern int comp_template_parms (tree, tree);
+extern bool uses_parameter_packs (tree);
+extern bool template_parameter_pack_p (tree);
+extern bool template_parms_variadic_p (tree);
+extern tree make_pack_expansion (tree);
+extern void check_for_bare_parameter_packs (tree);
extern int template_class_depth (tree);
extern int is_specialization_of (tree, tree);
extern bool is_specialization_of_friend (tree, tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 5c13362df95..e250bf78a2f 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -659,6 +659,7 @@ pp_cxx_delete_expression (cxx_pretty_printer *pp, tree t)
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
+ sizeof ... ( identifier )
new-expression
delete-expression
@@ -686,6 +687,21 @@ pp_cxx_unary_expression (cxx_pretty_printer *pp, tree t)
break;
case SIZEOF_EXPR:
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ {
+ pp_cxx_identifier (pp, "sizeof");
+ pp_cxx_identifier (pp, "...");
+ pp_cxx_whitespace (pp);
+ pp_cxx_left_paren (pp);
+ if (TYPE_P (TREE_OPERAND (t, 0)))
+ pp_cxx_type_id (pp, TREE_OPERAND (t, 0));
+ else
+ pp_unary_expression (pp, TREE_OPERAND (t, 0));
+ pp_cxx_right_paren (pp);
+ break;
+ }
+ /* Fall through */
+
case ALIGNOF_EXPR:
pp_cxx_identifier (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__");
pp_cxx_whitespace (pp);
@@ -1000,6 +1016,24 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t)
pp_cxx_expression (pp, t);
break;
+ case EXPR_PACK_EXPANSION:
+ pp_cxx_expression (pp, PACK_EXPANSION_PATTERN (t));
+ pp_cxx_identifier (pp, "...");
+ break;
+
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree args = ARGUMENT_PACK_ARGS (t);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; ++i)
+ {
+ if (i > 0)
+ pp_cxx_separate_with (pp, ',');
+ pp_cxx_expression (pp, TREE_VEC_ELT (args, i));
+ }
+ }
+ break;
+
default:
pp_c_expression (pp_c_base (pp), t);
break;
@@ -1290,6 +1324,7 @@ static void
pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
{
tree ex_spec = TYPE_RAISES_EXCEPTIONS (t);
+ bool need_comma = false;
if (!TYPE_NOTHROW_P (t) && ex_spec == NULL)
return;
@@ -1297,9 +1332,28 @@ pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
pp_cxx_left_paren (pp);
for (; ex_spec && TREE_VALUE (ex_spec); ex_spec = TREE_CHAIN (ex_spec))
{
- pp_cxx_type_id (pp, TREE_VALUE (ex_spec));
- if (TREE_CHAIN (ex_spec))
- pp_cxx_separate_with (pp, ',');
+ tree type = TREE_VALUE (ex_spec);
+ tree argpack = NULL_TREE;
+ int i, len = 1;
+
+ if (ARGUMENT_PACK_P (type))
+ {
+ argpack = ARGUMENT_PACK_ARGS (type);
+ len = TREE_VEC_LENGTH (argpack);
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (argpack)
+ type = TREE_VEC_ELT (argpack, i);
+
+ if (need_comma)
+ pp_cxx_separate_with (pp, ',');
+ else
+ need_comma = true;
+
+ pp_cxx_type_id (pp, type);
+ }
}
pp_cxx_right_paren (pp);
}
@@ -1323,6 +1377,13 @@ pp_cxx_direct_declarator (cxx_pretty_printer *pp, tree t)
if (DECL_NAME (t))
{
pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (t));
+
+ if ((TREE_CODE (t) == PARM_DECL && FUNCTION_PARAMETER_PACK_P (t))
+ || template_parameter_pack_p (t))
+ /* A function parameter pack or non-type template
+ parameter pack. */
+ pp_cxx_identifier (pp, "...");
+
pp_cxx_id_expression (pp, DECL_NAME (t));
}
pp_cxx_abstract_declarator (pp, TREE_TYPE (t));
@@ -1388,8 +1449,16 @@ pp_cxx_ctor_initializer (cxx_pretty_printer *pp, tree t)
pp_cxx_whitespace (pp);
for (; t; t = TREE_CHAIN (t))
{
- pp_cxx_primary_expression (pp, TREE_PURPOSE (t));
+ tree purpose = TREE_PURPOSE (t);
+ bool is_pack = PACK_EXPANSION_P (purpose);
+
+ if (is_pack)
+ pp_cxx_primary_expression (pp, PACK_EXPANSION_PATTERN (purpose));
+ else
+ pp_cxx_primary_expression (pp, purpose);
pp_cxx_call_argument_list (pp, TREE_VALUE (t));
+ if (is_pack)
+ pp_cxx_identifier (pp, "...");
if (TREE_CHAIN (t))
pp_cxx_separate_with (pp, ',');
}
@@ -1510,6 +1579,11 @@ pp_cxx_type_id (cxx_pretty_printer *pp, tree t)
pp_cxx_type_specifier_seq (pp, t);
break;
+ case TYPE_PACK_EXPANSION:
+ pp_cxx_type_id (pp, PACK_EXPANSION_PATTERN (t));
+ pp_cxx_identifier (pp, "...");
+ break;
+
default:
pp_c_type_id (pp_c_base (pp), t);
break;
@@ -1519,30 +1593,50 @@ pp_cxx_type_id (cxx_pretty_printer *pp, tree t)
}
/* template-argument-list:
- template-argument
- template-argument-list, template-argument
+ template-argument ...(opt)
+ template-argument-list, template-argument ...(opt)
template-argument:
assignment-expression
type-id
- template-name */
+ template-name */
static void
pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t)
{
int i;
+ bool need_comma = false;
+
if (t == NULL)
return;
for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
{
tree arg = TREE_VEC_ELT (t, i);
- if (i != 0)
- pp_cxx_separate_with (pp, ',');
- if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL
- && TYPE_P (DECL_TEMPLATE_RESULT (arg))))
- pp_cxx_type_id (pp, arg);
- else
- pp_cxx_expression (pp, arg);
+ tree argpack = NULL_TREE;
+ int idx, len = 1;
+
+ if (ARGUMENT_PACK_P (arg))
+ {
+ argpack = ARGUMENT_PACK_ARGS (arg);
+ len = TREE_VEC_LENGTH (argpack);
+ }
+
+ for (idx = 0; idx < len; idx++)
+ {
+ if (argpack)
+ arg = TREE_VEC_ELT (argpack, idx);
+
+ if (need_comma)
+ pp_cxx_separate_with (pp, ',');
+ else
+ need_comma = true;
+
+ if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL
+ && TYPE_P (DECL_TEMPLATE_RESULT (arg))))
+ pp_cxx_type_id (pp, arg);
+ else
+ pp_cxx_expression (pp, arg);
+ }
}
}
@@ -1837,11 +1931,11 @@ pp_cxx_template_parameter_list (cxx_pretty_printer *pp, tree t)
parameter-declaration
type-parameter:
- class identifier(opt)
- class identifier(op) = type-id
+ class ...(opt) identifier(opt)
+ class identifier(opt) = type-id
typename identifier(opt)
- typename identifier(opt) = type-id
- template < template-parameter-list > class identifier(opt)
+ typename ...(opt) identifier(opt) = type-id
+ template < template-parameter-list > class ...(opt) identifier(opt)
template < template-parameter-list > class identifier(opt) = template-name */
static void
@@ -1852,6 +1946,8 @@ pp_cxx_template_parameter (cxx_pretty_printer *pp, tree t)
{
case TYPE_DECL:
pp_cxx_identifier (pp, "class");
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
+ pp_cxx_identifier (pp, "...");
if (DECL_NAME (parameter))
pp_cxx_tree_identifier (pp, DECL_NAME (parameter));
/* FIXME: Chech if we should print also default argument. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 62c1aafef8e..318085a02b4 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6967,6 +6967,7 @@ grokdeclarator (const cp_declarator *declarator,
cp_storage_class storage_class;
bool unsigned_p, signed_p, short_p, long_p, thread_p;
bool type_was_error_mark_node = false;
+ bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
bool set_no_warning = false;
signed_p = declspecs->specs[(int)ds_signed];
@@ -7938,6 +7939,16 @@ grokdeclarator (const cp_declarator *declarator,
attrlist = &returned_attrs;
}
+ /* Handle parameter packs. */
+ if (parameter_pack_p)
+ {
+ if (decl_context == PARM)
+ /* Turn the type into a pack expansion.*/
+ type = make_pack_expansion (type);
+ else
+ error ("non-parameter %qs cannot be a parameter pack", name);
+ }
+
/* Did array size calculations overflow? */
if (TREE_CODE (type) == ARRAY_TYPE
@@ -8940,6 +8951,11 @@ grokparms (cp_parameter_declarator *first_parm, tree *parms)
init = check_default_argument (decl, init);
}
+ if (TREE_CODE (decl) == PARM_DECL
+ && FUNCTION_PARAMETER_PACK_P (decl)
+ && parm->next)
+ error ("parameter packs must be at the end of the parameter list");
+
TREE_CHAIN (decl) = decls;
decls = decl;
result = tree_cons (init, type, result);
@@ -9941,6 +9957,8 @@ xref_basetypes (tree ref, tree base_list)
if (access == access_default_node)
access = default_access;
+ if (PACK_EXPANSION_P (basetype))
+ basetype = PACK_EXPANSION_PATTERN (basetype);
if (TREE_CODE (basetype) == TYPE_DECL)
basetype = TREE_TYPE (basetype);
if (TREE_CODE (basetype) != RECORD_TYPE
@@ -9986,6 +10004,11 @@ xref_basetypes (tree ref, tree base_list)
error ("duplicate base type %qT invalid", basetype);
return false;
}
+
+ if (PACK_EXPANSION_P (TREE_VALUE (base_list)))
+ /* Regenerate the pack expansion for the bases. */
+ basetype = make_pack_expansion (basetype);
+
TYPE_MARKED_P (basetype) = 1;
base_binfo = copy_binfo (base_binfo, basetype, ref,
@@ -11695,6 +11718,7 @@ cp_tree_node_structure (union lang_tree_node * t)
case PTRMEM_CST: return TS_CP_PTRMEM;
case BASELINK: return TS_CP_BASELINK;
case STATIC_ASSERT: return TS_CP_STATIC_ASSERT;
+ case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT;
default: return TS_CP_GENERIC;
}
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a1664b81bcd..bd078330b0a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -136,6 +136,12 @@ cp_build_parm_decl (tree name, tree type)
sees templates. */
if (!processing_template_decl)
DECL_ARG_TYPE (parm) = type_passed_as (type);
+
+ /* If the type is a pack expansion, then we have a function
+ parameter pack. */
+ if (type && TREE_CODE (type) == TYPE_PACK_EXPANSION)
+ FUNCTION_PARAMETER_PACK_P (parm) = 1;
+
return parm;
}
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 5779805d80c..41a7e1d0d20 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -138,7 +138,9 @@ dump_scope (tree scope, int flags)
static void
dump_template_argument (tree arg, int flags)
{
- if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
+ if (ARGUMENT_PACK_P (arg))
+ dump_template_argument_list (ARGUMENT_PACK_ARGS (arg), flags);
+ else if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
dump_type (arg, flags & ~TFF_CLASS_KEY_OR_ENUM);
else
dump_expr (arg, (flags | TFF_EXPR_IN_PARENS) & ~TFF_CLASS_KEY_OR_ENUM);
@@ -156,9 +158,17 @@ dump_template_argument_list (tree args, int flags)
for (i = 0; i< n; ++i)
{
- if (need_comma)
+ tree arg = TREE_VEC_ELT (args, i);
+
+ /* Only print a comma if we know there is an argument coming. In
+ the case of an empty template argument pack, no actual
+ argument will be printed. */
+ if (need_comma
+ && (!ARGUMENT_PACK_P (arg)
+ || TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
pp_separate_with_comma (cxx_pp);
- dump_template_argument (TREE_VEC_ELT (args, i), flags);
+
+ dump_template_argument (arg, flags);
need_comma = 1;
}
}
@@ -182,6 +192,8 @@ dump_template_parameter (tree parm, int flags)
if (flags & TFF_DECL_SPECIFIERS)
{
pp_cxx_identifier (cxx_pp, "class");
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (p)))
+ pp_cxx_identifier (cxx_pp, "...");
if (DECL_NAME (p))
pp_cxx_tree_identifier (cxx_pp, DECL_NAME (p));
}
@@ -378,6 +390,11 @@ dump_type (tree t, int flags)
pp_cxx_right_paren (cxx_pp);
break;
+ case TYPE_PACK_EXPANSION:
+ dump_type (PACK_EXPANSION_PATTERN (t), flags);
+ pp_cxx_identifier (cxx_pp, "...");
+ break;
+
default:
pp_unsupported_tree (cxx_pp, t);
/* Fall through to error. */
@@ -1102,8 +1119,7 @@ dump_function_decl (tree t, int flags)
static void
dump_parameters (tree parmtypes, int flags)
{
- int first;
-
+ int first = 1;
pp_cxx_left_paren (cxx_pp);
for (first = 1; parmtypes != void_list_node;
@@ -1117,7 +1133,22 @@ dump_parameters (tree parmtypes, int flags)
pp_cxx_identifier (cxx_pp, "...");
break;
}
- dump_type (TREE_VALUE (parmtypes), flags);
+ if (ARGUMENT_PACK_P (TREE_VALUE (parmtypes)))
+ {
+ tree types = ARGUMENT_PACK_ARGS (TREE_VALUE (parmtypes));
+ int i, len = TREE_VEC_LENGTH (types);
+ first = 1;
+ for (i = 0; i < len; ++i)
+ {
+ if (!first)
+ pp_separate_with_comma (cxx_pp);
+ first = 0;
+
+ dump_type (TREE_VEC_ELT (types, i), flags);
+ }
+ }
+ else
+ dump_type (TREE_VALUE (parmtypes), flags);
if ((flags & TFF_FUNCTION_DEFAULT_ARGUMENTS) && TREE_PURPOSE (parmtypes))
{
@@ -1240,14 +1271,19 @@ dump_template_parms (tree info, int primary, int flags)
{
tree arg = TREE_VEC_ELT (args, ix);
- if (ix)
- pp_separate_with_comma (cxx_pp);
-
- if (!arg)
- pp_identifier (cxx_pp, "<template parameter error>");
- else
- dump_template_argument (arg, flags);
- }
+ /* Only print a comma if we know there is an argument coming. In
+ the case of an empty template argument pack, no actual
+ argument will be printed. */
+ if (ix
+ && (!ARGUMENT_PACK_P (arg)
+ || TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
+ pp_separate_with_comma (cxx_pp);
+
+ if (!arg)
+ pp_identifier (cxx_pp, "<template parameter error>");
+ else
+ dump_template_argument (arg, flags);
+ }
}
else if (primary)
{
@@ -1946,6 +1982,11 @@ dump_expr (tree t, int flags)
dump_expr (TREE_OPERAND (t, 0), flags);
break;
+ case EXPR_PACK_EXPANSION:
+ dump_expr (PACK_EXPANSION_PATTERN (t), flags);
+ pp_cxx_identifier (cxx_pp, "...");
+ break;
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -2464,3 +2505,14 @@ cp_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level,
input_location, dlevel);
report_diagnostic (&diagnostic);
}
+
+/* Warn about the use of variadic templates when appropriate. */
+void
+maybe_warn_variadic_templates (void)
+{
+ if ((!flag_cpp0x || flag_iso) && !in_system_header)
+ /* We really want to surpress this warning in system headers,
+ because libstdc++ uses variadic templates even when we aren't
+ in C++0x mode. */
+ pedwarn ("ISO C++ does not include variadic templates");
+}
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 94d7ed5e92c..40c059ad63c 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1645,6 +1645,11 @@ write_type (tree type)
write_type (TREE_TYPE (type));
break;
+ case TYPE_PACK_EXPANSION:
+ write_string ("U10__variadic");
+ write_type (PACK_EXPANSION_PATTERN (type));
+ break;
+
default:
gcc_unreachable ();
}
@@ -2302,7 +2307,15 @@ write_template_arg (tree node)
G.need_abi_warning = 1;
}
- if (TYPE_P (node))
+ if (ARGUMENT_PACK_P (node))
+ {
+ /* Expand the template argument pack. */
+ tree args = ARGUMENT_PACK_ARGS (node);
+ int i, length = TREE_VEC_LENGTH (args);
+ for (i = 0; i < length; ++i)
+ write_template_arg (TREE_VEC_ELT (args, i));
+ }
+ else if (TYPE_P (node))
write_type (node);
else if (code == TEMPLATE_DECL)
/* A template appearing as a template arg is a template template arg. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 08f1c90f7a0..8efcfed28a4 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4563,6 +4563,18 @@ arg_assoc_type (struct arg_lookup *k, tree type)
case LANG_TYPE:
gcc_assert (type == unknown_type_node);
return false;
+ case TYPE_PACK_EXPANSION:
+ return arg_assoc_type (k, PACK_EXPANSION_PATTERN (type));
+ case TYPE_ARGUMENT_PACK:
+ {
+ tree args = ARGUMENT_PACK_ARGS (type);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; i++)
+ if (arg_assoc_type (k, TREE_VEC_ELT (args, i)))
+ return true;
+ }
+ break;
+
default:
gcc_unreachable ();
}
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index 4518843b38f..b8400cd33c3 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -150,3 +150,6 @@ DEF_SIMPLE_OPERATOR ("?:", COND_EXPR, "qu", 3)
/* Miscellaneous. */
DEF_SIMPLE_OPERATOR ("()", CALL_EXPR, "cl", -1)
+
+/* Variadic templates extension. */
+DEF_SIMPLE_OPERATOR ("...", EXPR_PACK_EXPANSION, "pu", 1)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f21ad7bcb5e..f81fbdf5904 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -891,6 +891,7 @@ make_declarator (cp_declarator_kind kind)
declarator->kind = kind;
declarator->attributes = NULL_TREE;
declarator->declarator = NULL;
+ declarator->parameter_pack_p = false;
return declarator;
}
@@ -928,7 +929,7 @@ make_id_declarator (tree qualifying_scope, tree unqualified_name,
declarator->u.id.qualifying_scope = qualifying_scope;
declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk;
-
+
return declarator;
}
@@ -945,6 +946,13 @@ make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
@@ -960,6 +968,13 @@ make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
@@ -978,6 +993,14 @@ make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = class_type;
+ if (pointee)
+ {
+ declarator->parameter_pack_p = pointee->parameter_pack_p;
+ pointee->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
+
return declarator;
}
@@ -999,6 +1022,13 @@ make_call_declarator (cp_declarator *target,
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
declarator->u.function.exception_specification = exception_specification;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
@@ -1014,6 +1044,13 @@ make_array_declarator (cp_declarator *element, tree bounds)
declarator = make_declarator (cdk_array);
declarator->declarator = element;
declarator->u.array.bounds = bounds;
+ if (element)
+ {
+ declarator->parameter_pack_p = element->parameter_pack_p;
+ element->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
@@ -1518,7 +1555,7 @@ static tree cp_parser_postfix_open_square_expression
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
static tree cp_parser_parenthesized_expression_list
- (cp_parser *, bool, bool, bool *);
+ (cp_parser *, bool, bool, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
@@ -1731,9 +1768,9 @@ static void cp_parser_template_declaration
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
- (cp_parser *, bool *);
+ (cp_parser *, bool *, bool *);
static tree cp_parser_type_parameter
- (cp_parser *);
+ (cp_parser *, bool *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
@@ -4368,7 +4405,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
}
args = (cp_parser_parenthesized_expression_list
(parser, /*is_attribute_list=*/false,
- /*cast_p=*/false,
+ /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
if (is_builtin_constant_p)
{
@@ -4764,6 +4801,9 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
CAST_P is true if this expression is the target of a cast.
+ ALLOW_EXPANSION_P is true if this expression allows expansion of an
+ argument pack.
+
Returns a TREE_LIST. The TREE_VALUE of each node is a
representation of an assignment-expression. Note that a TREE_LIST
is returned even if there is only a single expression in the list.
@@ -4778,6 +4818,7 @@ static tree
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
bool cast_p,
+ bool allow_expansion_p,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
@@ -4827,6 +4868,18 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
if (fold_expr_p)
expr = fold_non_dependent_expr (expr);
+ /* If we have an ellipsis, then this is an expression
+ expansion. */
+ if (allow_expansion_p
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Build the argument pack. */
+ expr = make_pack_expansion (expr);
+ }
+
/* Add it to the list. We add error_mark_node
expressions to the list, so that we can still tell if
the correct form for a parenthesized expression-list
@@ -5276,7 +5329,7 @@ cp_parser_new_placement (cp_parser* parser)
/* Parse the expression-list. */
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*cast_p=*/false,
+ (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
return expression_list;
@@ -5481,7 +5534,7 @@ cp_parser_new_initializer (cp_parser* parser)
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*cast_p=*/false,
+ (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
@@ -8189,8 +8242,8 @@ cp_parser_ctor_initializer_opt (cp_parser* parser)
/* Parse a mem-initializer-list.
mem-initializer-list:
- mem-initializer
- mem-initializer , mem-initializer-list */
+ mem-initializer ... [opt]
+ mem-initializer ... [opt] , mem-initializer-list */
static void
cp_parser_mem_initializer_list (cp_parser* parser)
@@ -8209,6 +8262,26 @@ cp_parser_mem_initializer_list (cp_parser* parser)
/* Parse the mem-initializer. */
mem_initializer = cp_parser_mem_initializer (parser);
+ /* If the next token is a `...', we're expanding member initializers. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* The TREE_PURPOSE must be a _TYPE, because base-specifiers
+ can be expanded but members cannot. */
+ if (mem_initializer != error_mark_node
+ && !TYPE_P (TREE_PURPOSE (mem_initializer)))
+ {
+ error ("cannot expand initializer for member %<%D%>",
+ TREE_PURPOSE (mem_initializer));
+ mem_initializer = error_mark_node;
+ }
+
+ /* Construct the pack expansion type. */
+ if (mem_initializer != error_mark_node)
+ mem_initializer = make_pack_expansion (mem_initializer);
+ }
/* Add it to the list, unless it was erroneous. */
if (mem_initializer != error_mark_node)
{
@@ -8264,6 +8337,7 @@ cp_parser_mem_initializer (cp_parser* parser)
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
+ /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL);
if (expression_list == error_mark_node)
return error_mark_node;
@@ -8667,14 +8741,18 @@ cp_parser_template_parameter_list (cp_parser* parser)
tree parameter;
cp_token *token;
bool is_non_type;
+ bool is_parameter_pack;
/* Parse the template-parameter. */
- parameter = cp_parser_template_parameter (parser, &is_non_type);
+ parameter = cp_parser_template_parameter (parser,
+ &is_non_type,
+ &is_parameter_pack);
/* Add it to the list. */
if (parameter != error_mark_node)
parameter_list = process_template_parm (parameter_list,
parameter,
- is_non_type);
+ is_non_type,
+ is_parameter_pack);
else
{
tree err_parm = build_tree_list (parameter, parameter);
@@ -8703,10 +8781,12 @@ cp_parser_template_parameter_list (cp_parser* parser)
If all goes well, returns a TREE_LIST. The TREE_VALUE represents
the parameter. The TREE_PURPOSE is the default value, if any.
Returns ERROR_MARK_NODE on failure. *IS_NON_TYPE is set to true
- iff this parameter is a non-type parameter. */
+ iff this parameter is a non-type parameter. *IS_PARAMETER_PACK is
+ set to true iff this parameter is a parameter pack. */
static tree
-cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
+cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
+ bool *is_parameter_pack)
{
cp_token *token;
cp_parameter_declarator *parameter_declarator;
@@ -8714,11 +8794,13 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
/* Assume it is a type parameter or a template parameter. */
*is_non_type = false;
+ /* Assume it not a parameter pack. */
+ *is_parameter_pack = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it is `class' or `template', we have a type-parameter. */
if (token->keyword == RID_TEMPLATE)
- return cp_parser_type_parameter (parser);
+ return cp_parser_type_parameter (parser, is_parameter_pack);
/* If it is `class' or `typename' we do not know yet whether it is a
type parameter or a non-type parameter. Consider:
@@ -8736,6 +8818,10 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
{
/* Peek at the token after `class' or `typename'. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
+ /* If it's an ellipsis, we have a template type parameter
+ pack. */
+ if (token->type == CPP_ELLIPSIS)
+ return cp_parser_type_parameter (parser, is_parameter_pack);
/* If it's an identifier, skip it. */
if (token->type == CPP_NAME)
token = cp_lexer_peek_nth_token (parser->lexer, 3);
@@ -8744,7 +8830,7 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
if (token->type == CPP_COMMA
|| token->type == CPP_EQ
|| token->type == CPP_GREATER)
- return cp_parser_type_parameter (parser);
+ return cp_parser_type_parameter (parser, is_parameter_pack);
}
/* Otherwise, it is a non-type parameter.
@@ -8759,12 +8845,40 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
parameter_declarator
= cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
+
+ /* If the parameter declaration is marked as a parameter pack, set
+ *IS_PARAMETER_PACK to notify the caller. Also, unmark the
+ declarator's PACK_EXPANSION_P, otherwise we'll get errors from
+ grokdeclarator. */
+ if (parameter_declarator
+ && parameter_declarator->declarator
+ && parameter_declarator->declarator->parameter_pack_p)
+ {
+ *is_parameter_pack = true;
+ parameter_declarator->declarator->parameter_pack_p = false;
+ }
+
+ /* If the next token is an ellipsis, and we don't already have it
+ marked as a parameter pack, then we have a parameter pack (that
+ has no declarator); */
+ if (!*is_parameter_pack
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
+
parm = grokdeclarator (parameter_declarator->declarator,
&parameter_declarator->decl_specifiers,
PARM, /*initialized=*/0,
/*attrlist=*/NULL);
if (parm == error_mark_node)
return error_mark_node;
+
return build_tree_list (parameter_declarator->default_argument, parm);
}
@@ -8779,12 +8893,20 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
template < template-parameter-list > class identifier [opt]
= id-expression
+ GNU Extension (variadic templates):
+
+ type-parameter:
+ class ... identifier [opt]
+ typename ... identifier [opt]
+
Returns a TREE_LIST. The TREE_VALUE is itself a TREE_LIST. The
TREE_PURPOSE is the default-argument, if any. The TREE_VALUE is
- the declaration of the parameter. */
+ the declaration of the parameter.
+
+ Sets *IS_PARAMETER_PACK if this is a template parameter pack. */
static tree
-cp_parser_type_parameter (cp_parser* parser)
+cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
{
cp_token *token;
tree parameter;
@@ -8803,6 +8925,17 @@ cp_parser_type_parameter (cp_parser* parser)
tree identifier;
tree default_argument;
+ /* If the next token is an ellipsis, we have a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
+
/* If the next token is an identifier, then it names the
parameter. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
@@ -8821,6 +8954,18 @@ cp_parser_type_parameter (cp_parser* parser)
/* Parse the default-argument. */
push_deferring_access_checks (dk_no_deferred);
default_argument = cp_parser_type_id (parser);
+
+ /* Template parameter packs cannot have default
+ arguments. */
+ if (*is_parameter_pack)
+ {
+ if (identifier)
+ error ("template parameter pack %qD cannot have a default argument",
+ identifier);
+ else
+ error ("template parameter packs cannot have default arguments");
+ default_argument = NULL_TREE;
+ }
pop_deferring_access_checks ();
}
else
@@ -8846,6 +8991,16 @@ cp_parser_type_parameter (cp_parser* parser)
cp_parser_require (parser, CPP_GREATER, "`>'");
/* Look for the `class' keyword. */
cp_parser_require_keyword (parser, RID_CLASS, "`class'");
+ /* If the next token is an ellipsis, we have a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
/* If the next token is an `=', then there is a
default-argument. If the next token is a `>', we are at
the end of the parameter-list. If the next token is a `,',
@@ -8900,6 +9055,18 @@ cp_parser_type_parameter (cp_parser* parser)
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
+
+ /* Template parameter packs cannot have default
+ arguments. */
+ if (*is_parameter_pack)
+ {
+ if (identifier)
+ error ("template parameter pack %qD cannot have a default argument",
+ identifier);
+ else
+ error ("template parameter packs cannot have default arguments");
+ default_argument = NULL_TREE;
+ }
pop_deferring_access_checks ();
}
else
@@ -9316,8 +9483,8 @@ cp_parser_template_name (cp_parser* parser,
/* Parse a template-argument-list.
template-argument-list:
- template-argument
- template-argument-list , template-argument
+ template-argument ... [opt]
+ template-argument-list , template-argument ... [opt]
Returns a TREE_VEC containing the arguments. */
@@ -9353,6 +9520,19 @@ cp_parser_template_argument_list (cp_parser* parser)
/* Parse the template-argument. */
argument = cp_parser_template_argument (parser);
+
+ /* If the next token is an ellipsis, we're expanding a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Make the argument into a TYPE_PACK_EXPANSION or
+ EXPR_PACK_EXPANSION. */
+ argument = make_pack_expansion (argument);
+ }
+
if (n_args == alloced)
{
alloced *= 2;
@@ -11878,17 +12058,47 @@ cp_parser_direct_declarator (cp_parser* parser,
tree unqualified_name;
special_function_kind sfk;
bool abstract_ok;
+ bool pack_expansion_p = false;
/* Parse a declarator-id */
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
if (abstract_ok)
- cp_parser_parse_tentatively (parser);
+ {
+ cp_parser_parse_tentatively (parser);
+
+ /* If we see an ellipsis, we should be looking at a
+ parameter pack. */
+ if (token->type == CPP_ELLIPSIS)
+ {
+ /* Consume the `...' */
+ cp_lexer_consume_token (parser->lexer);
+
+ pack_expansion_p = true;
+ }
+ }
+
unqualified_name
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
if (abstract_ok)
{
- if (!cp_parser_parse_definitely (parser))
+ bool okay = false;
+
+ if (!unqualified_name && pack_expansion_p)
+ {
+ /* Check whether an error occurred. */
+ okay = !cp_parser_error_occurred (parser);
+
+ /* We already consumed the ellipsis to mark a
+ parameter pack, but we have no way to report it,
+ so abort the tentative parse. We will be exiting
+ immediately anyway. */
+ cp_parser_abort_tentative_parse (parser);
+ }
+ else
+ okay = cp_parser_parse_definitely (parser);
+
+ if (!okay)
unqualified_name = error_mark_node;
else if (unqualified_name
&& (qualifying_scope
@@ -11905,6 +12115,8 @@ cp_parser_direct_declarator (cp_parser* parser,
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
+ pack_expansion_p = false;
+ declarator->parameter_pack_p = false;
break;
}
@@ -11941,6 +12153,7 @@ cp_parser_direct_declarator (cp_parser* parser,
}
sfk = sfk_none;
+
if (unqualified_name)
{
tree class_type;
@@ -12008,6 +12221,10 @@ cp_parser_direct_declarator (cp_parser* parser,
unqualified_name,
sfk);
declarator->id_loc = token->location;
+ declarator->parameter_pack_p = pack_expansion_p;
+
+ if (pack_expansion_p)
+ maybe_warn_variadic_templates ();
handle_declarator:;
scope = get_scope_of_declarator (declarator);
@@ -12569,9 +12786,9 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
/* Parse a parameter declaration.
parameter-declaration:
- decl-specifier-seq declarator
+ decl-specifier-seq ... [opt] declarator
decl-specifier-seq declarator = assignment-expression
- decl-specifier-seq abstract-declarator [opt]
+ decl-specifier-seq ... [opt] abstract-declarator [opt]
decl-specifier-seq abstract-declarator [opt] = assignment-expression
If TEMPLATE_PARM_P is TRUE, then this parameter-declaration
@@ -12626,12 +12843,13 @@ cp_parser_parameter_declaration (cp_parser *parser,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
+
/* If the next token is a `)', `,', `=', `>', or `...', then there
- is no declarator. */
+ is no declarator. However, when variadic templates are enabled,
+ there may be a declarator following `...'. */
if (token->type == CPP_CLOSE_PAREN
|| token->type == CPP_COMMA
|| token->type == CPP_EQ
- || token->type == CPP_ELLIPSIS
|| token->type == CPP_GREATER)
{
declarator = NULL;
@@ -12673,6 +12891,34 @@ cp_parser_parameter_declaration (cp_parser *parser,
cp_parser_attributes_opt (parser));
}
+ /* If the next token is an ellipsis, and the type of the declarator
+ contains parameter packs but it is not a TYPE_PACK_EXPANSION, then
+ we actually have a parameter pack expansion expression. Otherwise,
+ leave the ellipsis for a C-style variadic function. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ tree type = decl_specifiers.type;
+
+ if (DECL_P (type))
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) != TYPE_PACK_EXPANSION
+ && (!declarator || !declarator->parameter_pack_p)
+ && uses_parameter_packs (type))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ /* Build a pack expansion type */
+ if (declarator)
+ declarator->parameter_pack_p = true;
+ else
+ decl_specifiers.type = make_pack_expansion (type);
+ }
+ }
+
/* The restriction on defining new types applies only to the type
of the parameter, not to the default argument. */
parser->type_definition_forbidden_message = saved_message;
@@ -12904,6 +13150,7 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init,
else if (token->type == CPP_OPEN_PAREN)
init = cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
+ /*allow_expansion_p=*/true,
non_constant_p);
else
{
@@ -12979,8 +13226,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
/* Parse an initializer-list.
initializer-list:
- initializer-clause
- initializer-list , initializer-clause
+ initializer-clause ... [opt]
+ initializer-list , initializer-clause ... [opt]
GNU Extension:
@@ -13034,6 +13281,17 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
if (clause_non_constant_p)
*non_constant_p = true;
+ /* If we have an ellipsis, this is an initializer pack
+ expansion. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Turn the initializer into an initializer expansion. */
+ initializer = make_pack_expansion (initializer);
+ }
+
/* Add it to the vector. */
CONSTRUCTOR_APPEND_ELT(v, identifier, initializer);
@@ -14335,8 +14593,8 @@ cp_parser_constant_initializer (cp_parser* parser)
: base-specifier-list
base-specifier-list:
- base-specifier
- base-specifier-list , base-specifier
+ base-specifier ... [opt]
+ base-specifier-list , base-specifier ... [opt]
Returns a TREE_LIST representing the base-classes, in the order in
which they were declared. The representation of each node is as
@@ -14358,12 +14616,28 @@ cp_parser_base_clause (cp_parser* parser)
{
cp_token *token;
tree base;
+ bool pack_expansion_p = false;
/* Look for the base-specifier. */
base = cp_parser_base_specifier (parser);
+ /* Look for the (optional) ellipsis. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ pack_expansion_p = true;
+ }
+
/* Add BASE to the front of the list. */
if (base != error_mark_node)
{
+ if (pack_expansion_p)
+ /* Make this a pack expansion type. */
+ TREE_VALUE (base) = make_pack_expansion (TREE_VALUE (base));
+ else
+ check_for_bare_parameter_packs (TREE_VALUE (base));
+
TREE_CHAIN (base) = bases;
bases = base;
}
@@ -14569,8 +14843,8 @@ cp_parser_exception_specification_opt (cp_parser* parser)
/* Parse an (optional) type-id-list.
type-id-list:
- type-id
- type-id-list , type-id
+ type-id ... [opt]
+ type-id-list , type-id ... [opt]
Returns a TREE_LIST. The TREE_VALUE of each node is a TYPE,
in the order that the types were presented. */
@@ -14587,6 +14861,15 @@ cp_parser_type_id_list (cp_parser* parser)
/* Get the next type-id. */
type = cp_parser_type_id (parser);
+ /* Parse the optional ellipsis. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Turn the type into a pack expansion expression. */
+ type = make_pack_expansion (type);
+ }
/* Add it to the list. */
types = add_exception_specifier (types, type, /*complain=*/1);
/* Peek at the next token. */
@@ -15020,6 +15303,7 @@ cp_parser_attribute_list (cp_parser* parser)
{
arguments = cp_parser_parenthesized_expression_list
(parser, true, /*cast_p=*/false,
+ /*allow_expansion_p=*/false,
/*non_constant_p=*/NULL);
/* Save the arguments away. */
TREE_VALUE (attribute) = arguments;
@@ -16102,6 +16386,7 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/true,
+ /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL);
cast = build_functional_cast (type, expression_list);
@@ -16451,6 +16736,7 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
const char *saved_message;
bool saved_integral_constant_expression_p;
bool saved_non_integral_constant_expression_p;
+ bool pack_expansion_p = false;
/* Initialize FORMAT the first time we get here. */
if (!format)
@@ -16475,6 +16761,19 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
= parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
+ /* If it's a `...', then we are computing the length of a parameter
+ pack. */
+ if (keyword == RID_SIZEOF
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ /* Note that this is an expansion. */
+ pack_expansion_p = true;
+ }
+
/* Do not actually evaluate the expression. */
++skip_evaluation;
/* If it's a `(', then we might be looking at the type-id
@@ -16519,6 +16818,11 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
if (!expr)
expr = cp_parser_unary_expression (parser, /*address_p=*/false,
/*cast_p=*/false);
+
+ if (pack_expansion_p)
+ /* Build a pack expansion. */
+ expr = make_pack_expansion (expr);
+
/* Go back to evaluating expressions. */
--skip_evaluation;
@@ -16811,7 +17115,9 @@ cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_COMMA || token->type == CPP_GREATER);
+ return (token->type == CPP_COMMA
+ || token->type == CPP_GREATER
+ || token->type == CPP_ELLIPSIS);
}
/* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 84ff4219ee3..bf82f8c5330 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -124,6 +124,7 @@ static tree convert_template_argument (tree, tree, tree,
tsubst_flags_t, int, tree);
static int for_each_template_parm (tree, tree_fn_t, void*,
struct pointer_set_t*);
+static tree expand_template_argument_pack (tree);
static tree build_template_parm_index (int, int, int, tree, tree);
static int inline_needs_template_parms (tree);
static void push_inline_template_parms_recursive (tree, int);
@@ -138,6 +139,8 @@ static int can_complete_type_without_circularity (tree);
static tree get_bindings (tree, tree, tree, bool);
static int template_decl_level (tree);
static int check_cv_quals_for_unify (int, tree, tree);
+static void template_parm_level_and_index (tree, int*, int*);
+static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -161,11 +164,13 @@ static tree copy_default_args_to_explicit_spec_1 (tree, tree);
static void copy_default_args_to_explicit_spec (tree);
static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
static int eq_local_specializations (const void *, const void *);
+static bool dependent_template_arg_p (tree);
static bool any_template_arguments_need_structural_equality_p (tree);
static bool dependent_type_p_r (tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree);
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
+static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@@ -2262,7 +2267,9 @@ comp_template_parms (tree parms1, tree parms2)
if (TREE_CODE (parm1) != TREE_CODE (parm2))
return 0;
- if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+ if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+ && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+ == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
continue;
else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
return 0;
@@ -2277,6 +2284,402 @@ comp_template_parms (tree parms1, tree parms2)
return 1;
}
+/* Determine whether PARM is a parameter pack. */
+bool
+template_parameter_pack_p (tree parm)
+{
+ /* Determine if we have a non-type template parameter pack. */
+ if (TREE_CODE (parm) == PARM_DECL)
+ return (DECL_TEMPLATE_PARM_P (parm)
+ && TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)));
+
+ /* If this is a list of template parameters, we could get a
+ TYPE_DECL or a TEMPLATE_DECL. */
+ if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL)
+ parm = TREE_TYPE (parm);
+
+ return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
+ && TEMPLATE_TYPE_PARAMETER_PACK (parm));
+}
+
+/* Determine whether PARMS describes a variadic template parameter
+ list, i.e., one that is terminated by a template parameter pack. */
+bool
+template_parms_variadic_p (tree parms)
+{
+ int nparms = TREE_VEC_LENGTH (parms);
+ tree last_parm = TREE_VALUE (TREE_VEC_ELT (parms, nparms - 1));
+
+ return template_parameter_pack_p (last_parm);
+}
+
+/* Determine whether ARGS describes a variadic template args list,
+ i.e., one that is terminated by a template argument pack. */
+static bool
+template_args_variadic_p (tree args)
+{
+ int nargs;
+ tree last_parm;
+
+ if (args == NULL_TREE)
+ return false;
+
+ args = INNERMOST_TEMPLATE_ARGS (args);
+ nargs = TREE_VEC_LENGTH (args);
+
+ if (nargs == 0)
+ return false;
+
+ last_parm = TREE_VEC_ELT (args, nargs - 1);
+
+ return ARGUMENT_PACK_P (last_parm);
+}
+
+/* Generate a new name for the parameter pack name NAME (an
+ IDENTIFIER_NODE) that incorporates its */
+static tree
+make_ith_pack_parameter_name (tree name, int i)
+{
+ /* Munge the name to include the parameter index. */
+ char numbuf[128];
+ char* newname;
+
+ sprintf(numbuf, "%i", i);
+ newname = (char*)alloca (IDENTIFIER_LENGTH (name) + strlen(numbuf) + 2);
+ sprintf(newname, "%s#%i", IDENTIFIER_POINTER (name), i);
+ return get_identifier (newname);
+}
+
+/* Structure used to track the progress of find_parameter_pack_r. */
+struct find_parameter_pack_data
+{
+ tree* parameter_packs;
+ struct pointer_set_t *visited;
+};
+
+/* Identifiers all of the argument packs that occur in a template
+ argument and appends them to the TREE_LIST inside DATA, which is a
+ find_parameter_pack_Data structure. This is a subroutine of
+ make_pack_expansion and uses_parameter_packs. */
+static tree
+find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
+{
+ tree t = *tp;
+ struct find_parameter_pack_data* ppd =
+ (struct find_parameter_pack_data*)data;
+
+ if (TYPE_P (t))
+ {
+ tree context = TYPE_CONTEXT (t);
+ walk_tree (&context, &find_parameter_packs_r, ppd, ppd->visited);
+ }
+
+ /* This switch statement will return immediately if we don't find a
+ parameter pack. */
+ switch (TREE_CODE (t))
+ {
+ case TEMPLATE_PARM_INDEX:
+ if (TEMPLATE_PARM_PARAMETER_PACK (t))
+ break;
+ return NULL_TREE;
+
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ /* Check the template arguments. */
+ walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+
+ /* Dig out the underlying TEMPLATE_TEMPLATE_PARM. */
+ t = TYPE_TI_TEMPLATE (t);
+ if (DECL_P (t) && TREE_TYPE (t))
+ t = TREE_TYPE (t);
+ *walk_subtrees = 0;
+
+ /* Fall through. */
+
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+ break;
+ return NULL_TREE;
+
+ case PARM_DECL:
+ if (FUNCTION_PARAMETER_PACK_P (t))
+ {
+ /* We don't want to walk into the type of a PARM_DECL,
+ because we don't want to see the type parameter pack.*/
+ *walk_subtrees = 0;
+ break;
+ }
+ return NULL_TREE;
+
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (t))
+ return NULL_TREE;
+ /* Fall through. */
+
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ if (TYPE_TEMPLATE_INFO (t))
+ {
+ tree args = TREE_VALUE (TYPE_TEMPLATE_INFO (t));
+ walk_tree (&args, &find_parameter_packs_r, ppd, ppd->visited);
+ }
+
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case TEMPLATE_DECL:
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
+ && TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
+ break;
+
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case TYPE_PACK_EXPANSION:
+ case EXPR_PACK_EXPANSION:
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ default:
+ return NULL_TREE;
+ }
+
+ /* Add this parameter pack to the list. */
+ *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
+
+ return NULL_TREE;
+}
+
+/* Determines if the expression or type T uses any parameter packs. */
+bool
+uses_parameter_packs (tree t)
+{
+ tree parameter_packs = NULL_TREE;
+ struct find_parameter_pack_data ppd;
+ ppd.parameter_packs = &parameter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+ return parameter_packs != NULL_TREE;
+}
+
+/* Turn ARG, which may be an expression, type, or a TREE_LIST
+ representation a base-class initializer into a parameter pack
+ expansion. If all goes well, the resulting node will be an
+ EXPR_PACK_EXPANSION, TYPE_PACK_EXPANSION, or TREE_LIST,
+ respectively. */
+tree
+make_pack_expansion (tree arg)
+{
+ tree result;
+ tree parameter_packs = NULL_TREE;
+ bool for_types = false;
+ struct find_parameter_pack_data ppd;
+
+ if (!arg || arg == error_mark_node)
+ return arg;
+
+ if (TREE_CODE (arg) == TREE_LIST)
+ {
+ /* The only time we will see a TREE_LIST here is for a base
+ class initializer. In this case, the TREE_PURPOSE will be a
+ _TYPE node (representing the base class expansion we're
+ initializing) and the TREE_VALUE will be a TREE_LIST
+ containing the initialization arguments.
+
+ The resulting expansion looks somewhat different from most
+ expansions. Rather than returning just one _EXPANSION, we
+ return a TREE_LIST whose TREE_PURPOSE is a
+ TYPE_PACK_EXPANSION containing the bases that will be
+ initialized. The TREE_VALUE will be identical to the
+ original TREE_VALUE, which is a list of arguments that will
+ be passed to each base. We do not introduce any new pack
+ expansion nodes into the TREE_VALUE (although it is possible
+ that some already exist), because the TREE_PURPOSE and
+ TREE_VALUE all need to be expanded together with the same
+ _EXPANSION node. Note that the TYPE_PACK_EXPANSION in the
+ resulting TREE_PURPOSE will mention the parameter packs in
+ both the bases and the arguments to the bases. */
+ tree purpose;
+ tree value;
+ tree parameter_packs = NULL_TREE;
+
+ /* Determine which parameter packs will be used by the base
+ class expansion. */
+ ppd.visited = pointer_set_create ();
+ ppd.parameter_packs = &parameter_packs;
+ walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r,
+ &ppd, ppd.visited);
+
+ if (parameter_packs == NULL_TREE)
+ {
+ error ("base initializer expansion %<%T%> contains no parameter packs", arg);
+ return error_mark_node;
+ }
+
+ if (TREE_VALUE (arg) != void_type_node)
+ {
+ /* Collect the sets of parameter packs used in each of the
+ initialization arguments. */
+ for (value = TREE_VALUE (arg); value; value = TREE_CHAIN (value))
+ {
+ /* Determine which parameter packs will be expanded in this
+ argument. */
+ walk_tree (&TREE_VALUE (value), &find_parameter_packs_r,
+ &ppd, ppd.visited);
+ }
+ }
+
+ /* Create the pack expansion type for the base type. */
+ purpose = make_node (TYPE_PACK_EXPANSION);
+ SET_PACK_EXPANSION_PATTERN (purpose, TREE_PURPOSE (arg));
+ PACK_EXPANSION_PARAMETER_PACKS (purpose) = parameter_packs;
+
+ /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+ they will rarely be compared to anything. */
+ SET_TYPE_STRUCTURAL_EQUALITY (purpose);
+
+ return tree_cons (purpose, TREE_VALUE (arg), NULL_TREE);
+ }
+
+ if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
+ for_types = true;
+
+ /* Build the PACK_EXPANSION_* node. */
+ result = make_node (for_types ? TYPE_PACK_EXPANSION : EXPR_PACK_EXPANSION);
+ SET_PACK_EXPANSION_PATTERN (result, arg);
+ if (TREE_CODE (result) == EXPR_PACK_EXPANSION)
+ {
+ /* Propagate type and const-expression information. */
+ TREE_TYPE (result) = TREE_TYPE (arg);
+ TREE_CONSTANT (result) = TREE_CONSTANT (arg);
+ }
+ else
+ /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+ they will rarely be compared to anything. */
+ SET_TYPE_STRUCTURAL_EQUALITY (result);
+
+ /* Determine which parameter packs will be expanded. */
+ ppd.parameter_packs = &parameter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&arg, &find_parameter_packs_r, &ppd, ppd.visited);
+
+ /* Make sure we found some parameter packs. */
+ if (parameter_packs == NULL_TREE)
+ {
+ if (TYPE_P (arg))
+ error ("expansion pattern %<%T%> contains no argument packs", arg);
+ else
+ error ("expansion pattern %<%E%> contains no argument packs", arg);
+ return error_mark_node;
+ }
+ PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs;
+
+ return result;
+}
+
+/* Checks T for any "bare" parameter packs, which have not yet been
+ expanded, and issues an error if any are found. This operation can
+ only be done on full expressions or types (e.g., an expression
+ statement, "if" condition, etc.), because we could have expressions like:
+
+ foo(f(g(h(args)))...)
+
+ where "args" is a parameter pack. check_for_bare_parameter_packs
+ should not be called for the subexpressions args, h(args),
+ g(h(args)), or f(g(h(args))), because we would produce erroneous
+ error messages. */
+void
+check_for_bare_parameter_packs (tree t)
+{
+ tree parameter_packs = NULL_TREE;
+ struct find_parameter_pack_data ppd;
+
+ if (!processing_template_decl || !t || t == error_mark_node)
+ return;
+
+ if (TREE_CODE (t) == TYPE_DECL)
+ t = TREE_TYPE (t);
+
+ ppd.parameter_packs = &parameter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+
+ if (parameter_packs) {
+ error ("parameter packs not expanded with `...':");
+ while (parameter_packs)
+ {
+ tree pack = TREE_VALUE (parameter_packs);
+ tree name = NULL_TREE;
+
+ if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM)
+ name = TYPE_NAME (pack);
+ else
+ name = DECL_NAME (pack);
+ inform (" %qD", name);
+
+ parameter_packs = TREE_CHAIN (parameter_packs);
+ }
+ }
+}
+
+/* Expand any parameter packs that occur in the template arguments in
+ ARGS. */
+tree
+expand_template_argument_pack (tree args)
+{
+ tree result_args = NULL_TREE;
+ int in_arg, out_arg = 0, nargs = args ? TREE_VEC_LENGTH (args) : 0;
+ int num_result_args = -1;
+
+ /* First, determine if we need to expand anything, and the number of
+ slots we'll need. */
+ for (in_arg = 0; in_arg < nargs; ++in_arg)
+ {
+ tree arg = TREE_VEC_ELT (args, in_arg);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ int num_packed = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg));
+ if (num_result_args < 0)
+ num_result_args = in_arg + num_packed;
+ else
+ num_result_args += num_packed;
+ }
+ else
+ {
+ if (num_result_args >= 0)
+ num_result_args++;
+ }
+ }
+
+ /* If no expansion is necessary, we're done. */
+ if (num_result_args < 0)
+ return args;
+
+ /* Expand arguments. */
+ result_args = make_tree_vec (num_result_args);
+ for (in_arg = 0; in_arg < nargs; ++in_arg)
+ {
+ tree arg = TREE_VEC_ELT (args, in_arg);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ tree packed = ARGUMENT_PACK_ARGS (arg);
+ int i, num_packed = TREE_VEC_LENGTH (packed);
+ for (i = 0; i < num_packed; ++i, ++out_arg)
+ TREE_VEC_ELT (result_args, out_arg) = TREE_VEC_ELT(packed, i);
+ }
+ else
+ {
+ TREE_VEC_ELT (result_args, out_arg) = arg;
+ ++out_arg;
+ }
+ }
+
+ return result_args;
+}
+
/* Complain if DECL shadows a template parameter.
[temp.local]: A template-parameter shall not be redeclared within its
@@ -2399,6 +2802,8 @@ reduce_template_parm_level (tree index, tree type, int levels)
TEMPLATE_PARM_ORIG_LEVEL (index),
decl, type);
TEMPLATE_PARM_DESCENDANTS (index) = t;
+ TEMPLATE_PARM_PARAMETER_PACK (t)
+ = TEMPLATE_PARM_PARAMETER_PACK (index);
/* Template template parameters need this. */
if (TREE_CODE (decl) != CONST_DECL)
@@ -2411,10 +2816,12 @@ reduce_template_parm_level (tree index, tree type, int levels)
/* Process information from new template parameter PARM and append it to the
LIST being built. This new parameter is a non-type parameter iff
- IS_NON_TYPE is true. */
+ IS_NON_TYPE is true. This new parameter is a parameter
+ pack iff IS_PARAMETER_PACK is true. */
tree
-process_template_parm (tree list, tree parm, bool is_non_type)
+process_template_parm (tree list, tree parm, bool is_non_type,
+ bool is_parameter_pack)
{
tree decl = 0;
tree defval;
@@ -2467,6 +2874,16 @@ process_template_parm (tree list, tree parm, bool is_non_type)
TREE_VALUE (err_parm_list) = error_mark_node;
return chainon (list, err_parm_list);
}
+
+ if (uses_parameter_packs (TREE_TYPE (parm)) && !is_parameter_pack)
+ {
+ /* This template parameter is not a parameter pack, but it
+ should be. Complain about "bare" parameter packs. */
+ check_for_bare_parameter_packs (TREE_TYPE (parm));
+
+ /* Recover by calling this a parameter pack. */
+ is_parameter_pack = true;
+ }
}
/* A template parameter is not modifiable. */
@@ -2481,6 +2898,9 @@ process_template_parm (tree list, tree parm, bool is_non_type)
= build_template_parm_index (idx, processing_template_decl,
processing_template_decl,
decl, TREE_TYPE (parm));
+
+ TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+ = is_parameter_pack;
}
else
{
@@ -2510,6 +2930,7 @@ process_template_parm (tree list, tree parm, bool is_non_type)
= build_template_parm_index (idx, processing_template_decl,
processing_template_decl,
decl, TREE_TYPE (parm));
+ TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
TYPE_CANONICAL (t) = canonical_type_parameter (t);
}
DECL_ARTIFICIAL (decl) = 1;
@@ -2602,11 +3023,38 @@ current_template_args (void)
{
if (TREE_CODE (t) == TYPE_DECL
|| TREE_CODE (t) == TEMPLATE_DECL)
- t = TREE_TYPE (t);
- else
- t = DECL_INITIAL (t);
- }
-
+ {
+ t = TREE_TYPE (t);
+
+ if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+ {
+ /* Turn this argument into a TYPE_ARGUMENT_PACK
+ with a single element, which expands T. */
+ tree vec = make_tree_vec (1);
+ TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+
+ t = make_node (TYPE_ARGUMENT_PACK);
+ SET_ARGUMENT_PACK_ARGS (t, vec);
+ }
+ }
+ else
+ {
+ t = DECL_INITIAL (t);
+
+ if (TEMPLATE_PARM_PARAMETER_PACK (t))
+ {
+ /* Turn this argument into a NONTYPE_ARGUMENT_PACK
+ with a single element, which expands T. */
+ tree vec = make_tree_vec (1);
+ tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t));
+ TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+
+ t = make_node (NONTYPE_ARGUMENT_PACK);
+ SET_ARGUMENT_PACK_ARGS (t, vec);
+ TREE_TYPE (t) = type;
+ }
+ }
+ }
TREE_VEC_ELT (a, i) = t;
}
}
@@ -2796,74 +3244,114 @@ process_partial_specialization (tree decl)
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
- specialization. */
+ specialization.
+
+ Also, we verify that pack expansions only occur at the
+ end of the argument list. */
gcc_assert (nargs == DECL_NTPARMS (maintmpl));
tpd2.parms = 0;
for (i = 0; i < nargs; ++i)
{
+ tree parm = TREE_VALUE (TREE_VEC_ELT (main_inner_parms, i));
tree arg = TREE_VEC_ELT (inner_args, i);
- if (/* These first two lines are the `non-type' bit. */
- !TYPE_P (arg)
- && TREE_CODE (arg) != TEMPLATE_DECL
- /* This next line is the `argument expression is not just a
- simple identifier' condition and also the `specialized
- non-type argument' bit. */
- && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
- {
- if (tpd.arg_uses_template_parms[i])
- error ("template argument %qE involves template parameter(s)", arg);
- else
- {
- /* Look at the corresponding template parameter,
- marking which template parameters its type depends
- upon. */
- tree type =
- TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (main_inner_parms,
- i)));
-
- if (!tpd2.parms)
- {
- /* We haven't yet initialized TPD2. Do so now. */
- tpd2.arg_uses_template_parms
- = (int *) alloca (sizeof (int) * nargs);
- /* The number of parameters here is the number in the
- main template, which, as checked in the assertion
- above, is NARGS. */
- tpd2.parms = (int *) alloca (sizeof (int) * nargs);
- tpd2.level =
- TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
- }
+ tree packed_args = NULL_TREE;
+ int j, len = 1;
- /* Mark the template parameters. But this time, we're
- looking for the template parameters of the main
- template, not in the specialization. */
- tpd2.current_arg = i;
- tpd2.arg_uses_template_parms[i] = 0;
- memset (tpd2.parms, 0, sizeof (int) * nargs);
- for_each_template_parm (type,
- &mark_template_parm,
- &tpd2,
- NULL);
-
- if (tpd2.arg_uses_template_parms [i])
- {
- /* The type depended on some template parameters.
- If they are fully specialized in the
- specialization, that's OK. */
- int j;
- for (j = 0; j < nargs; ++j)
- if (tpd2.parms[j] != 0
- && tpd.arg_uses_template_parms [j])
- {
- error ("type %qT of template argument %qE depends "
- "on template parameter(s)",
- type,
- arg);
- break;
- }
- }
- }
- }
+ if (ARGUMENT_PACK_P (arg))
+ {
+ /* Extract the arguments from the argument pack. We'll be
+ iterating over these in the following loop. */
+ packed_args = ARGUMENT_PACK_ARGS (arg);
+ len = TREE_VEC_LENGTH (packed_args);
+ }
+
+ for (j = 0; j < len; j++)
+ {
+ if (packed_args)
+ /* Get the Jth argument in the parameter pack. */
+ arg = TREE_VEC_ELT (packed_args, j);
+
+ if (PACK_EXPANSION_P (arg))
+ {
+ /* Pack expansions must come at the end of the
+ argument list. */
+ if ((packed_args && j < len - 1)
+ || (!packed_args && i < nargs - 1))
+ {
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ error ("parameter pack argument %qE must be at the end of the template argument list", arg);
+ else
+ error ("parameter pack argument %qT must be at the end of the template argument list", arg);
+ }
+ }
+
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ /* We only care about the pattern. */
+ arg = PACK_EXPANSION_PATTERN (arg);
+
+ if (/* These first two lines are the `non-type' bit. */
+ !TYPE_P (arg)
+ && TREE_CODE (arg) != TEMPLATE_DECL
+ /* This next line is the `argument expression is not just a
+ simple identifier' condition and also the `specialized
+ non-type argument' bit. */
+ && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
+ {
+ if ((!packed_args && tpd.arg_uses_template_parms[i])
+ || (packed_args && uses_template_parms (arg)))
+ error ("template argument %qE involves template parameter(s)",
+ arg);
+ else
+ {
+ /* Look at the corresponding template parameter,
+ marking which template parameters its type depends
+ upon. */
+ tree type = TREE_TYPE (parm);
+
+ if (!tpd2.parms)
+ {
+ /* We haven't yet initialized TPD2. Do so now. */
+ tpd2.arg_uses_template_parms
+ = (int *) alloca (sizeof (int) * nargs);
+ /* The number of parameters here is the number in the
+ main template, which, as checked in the assertion
+ above, is NARGS. */
+ tpd2.parms = (int *) alloca (sizeof (int) * nargs);
+ tpd2.level =
+ TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
+ }
+
+ /* Mark the template parameters. But this time, we're
+ looking for the template parameters of the main
+ template, not in the specialization. */
+ tpd2.current_arg = i;
+ tpd2.arg_uses_template_parms[i] = 0;
+ memset (tpd2.parms, 0, sizeof (int) * nargs);
+ for_each_template_parm (type,
+ &mark_template_parm,
+ &tpd2,
+ NULL);
+
+ if (tpd2.arg_uses_template_parms [i])
+ {
+ /* The type depended on some template parameters.
+ If they are fully specialized in the
+ specialization, that's OK. */
+ int j;
+ for (j = 0; j < nargs; ++j)
+ if (tpd2.parms[j] != 0
+ && tpd.arg_uses_template_parms [j])
+ {
+ error ("type %qT of template argument %qE depends "
+ "on template parameter(s)",
+ type,
+ arg);
+ break;
+ }
+ }
+ }
+ }
+ }
}
if (retrieve_specialization (maintmpl, specargs,
@@ -3158,9 +3646,36 @@ push_template_decl_real (tree decl, bool is_friend)
check_default_tmpl_args (decl, current_template_parms,
primary, is_partial);
+ /* Ensure that there are no parameter packs in the type of this
+ declaration that have not been expanded. */
+ check_for_bare_parameter_packs (TREE_TYPE (decl));
+
if (is_partial)
return process_partial_specialization (decl);
+ /* A primary class template can only have one parameter pack, at the
+ end of the template parameter list. */
+ if (primary && TREE_CODE (decl) == TYPE_DECL)
+ {
+ tree inner_parms
+ = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ int i, len = TREE_VEC_LENGTH (inner_parms);
+ for (i = 0; i < len - 1; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (inner_parms, i));
+
+ if (template_parameter_pack_p (parm))
+ {
+ if (TREE_CODE (parm) == PARM_DECL)
+ error ("parameter pack %qE must be at the end of the"
+ " template parameter list", parm);
+ else
+ error ("parameter pack %qT must be at the end of the"
+ " template parameter list", TREE_TYPE (parm));
+ }
+ }
+ }
+
args = current_template_args ();
if (!ctx
@@ -3935,9 +4450,6 @@ coerce_template_template_parms (tree parm_parms,
switch (TREE_CODE (parm))
{
- case TYPE_DECL:
- break;
-
case TEMPLATE_DECL:
/* We encounter instantiations of templates like
template <template <template <class> class> class TT>
@@ -3950,6 +4462,13 @@ coerce_template_template_parms (tree parm_parms,
(parmparm, argparm, complain, in_decl, outer_args))
return 0;
}
+ /* Fall through. */
+
+ case TYPE_DECL:
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))
+ != TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg)))
+ /* One is a parameter pack, the other is not. */
+ return 0;
break;
case PARM_DECL:
@@ -3965,6 +4484,11 @@ coerce_template_template_parms (tree parm_parms,
(tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
TREE_TYPE (arg)))
return 0;
+
+ if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+ != TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg)))
+ /* One is a parameter pack, the other is not. */
+ return 0;
break;
default:
@@ -3991,6 +4515,7 @@ convert_template_argument (tree parm,
{
tree val;
int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
+ tree check_arg = arg;
if (TREE_CODE (arg) == TREE_LIST
&& TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
@@ -4008,10 +4533,16 @@ convert_template_argument (tree parm,
requires_type = (TREE_CODE (parm) == TYPE_DECL
|| requires_tmpl_type);
- is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL
- && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
- || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
- || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
+ /* When determining whether a argument pack expansion is a template,
+ look at the pattern. */
+ if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+ check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+ is_tmpl_type =
+ ((TREE_CODE (check_arg) == TEMPLATE_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (check_arg)) == TYPE_DECL)
+ || TREE_CODE (check_arg) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (check_arg) == UNBOUND_CLASS_TEMPLATE);
if (is_tmpl_type
&& (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
@@ -4079,7 +4610,15 @@ convert_template_argument (tree parm,
else
{
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
- tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+ tree argparm;
+
+ check_arg = arg;
+ /* When determining whether a pack expansion is a template,
+ look at the pattern. */
+ if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+ check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+ argparm = DECL_INNERMOST_TEMPLATE_PARMS (check_arg);
if (coerce_template_template_parms (parmparm, argparm,
complain, in_decl,
@@ -4089,9 +4628,17 @@ convert_template_argument (tree parm,
/* TEMPLATE_TEMPLATE_PARM node is preferred over
TEMPLATE_DECL. */
- if (val != error_mark_node
- && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
- val = TREE_TYPE (val);
+ if (val != error_mark_node)
+ {
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+ val = TREE_TYPE (val);
+ else if (TREE_CODE (val) == TYPE_PACK_EXPANSION
+ && DECL_TEMPLATE_TEMPLATE_PARM_P (check_arg))
+ {
+ val = TREE_TYPE (check_arg);
+ val = make_pack_expansion (val);
+ }
+ }
}
else
{
@@ -4175,12 +4722,20 @@ coerce_template_parms (tree parms,
tree new_inner_args;
bool saved_skip_evaluation;
- inner_args = INNERMOST_TEMPLATE_ARGS (args);
+ /* When used as a boolean value, indicates whether this is a
+ variadic template parameter list. Since it's an int, we can also
+ subtract it from nparms to get the number of non-variadic
+ parameters. */
+ int variadic_p = template_parms_variadic_p (parms) ? 1 : 0;
+
+ inner_args
+ = expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args));
+
nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
nparms = TREE_VEC_LENGTH (parms);
- if (nargs > nparms
- || (nargs < nparms
+ if ((nargs > nparms - variadic_p && !variadic_p)
+ || (nargs < nparms - variadic_p
&& require_all_args
&& (!use_default_args
|| (TREE_VEC_ELT (parms, nargs) != error_mark_node
@@ -4188,8 +4743,15 @@ coerce_template_parms (tree parms,
{
if (complain & tf_error)
{
- error ("wrong number of template arguments (%d, should be %d)",
- nargs, nparms);
+ const char *or_more = "";
+ if (variadic_p)
+ {
+ or_more = " or more";
+ --nparms;
+ }
+
+ error ("wrong number of template arguments (%d, should be %d%s)",
+ nargs, nparms, or_more);
if (in_decl)
error ("provided for %q+D", in_decl);
@@ -4204,7 +4766,7 @@ coerce_template_parms (tree parms,
skip_evaluation = false;
new_inner_args = make_tree_vec (nparms);
new_args = add_outermost_template_args (args, new_inner_args);
- for (i = 0; i < nparms; i++)
+ for (i = 0; i < nparms - variadic_p; i++)
{
tree arg;
tree parm;
@@ -4220,7 +4782,29 @@ coerce_template_parms (tree parms,
/* Calculate the Ith argument. */
if (i < nargs)
- arg = TREE_VEC_ELT (inner_args, i);
+ {
+ arg = TREE_VEC_ELT (inner_args, i);
+
+ if (PACK_EXPANSION_P (arg))
+ {
+ /* If ARG is a pack expansion, then PARM must be
+ a template parameter pack. We can't expand into a
+ fixed-length argument list. */
+ tree actual_parm = TREE_VALUE (parm);
+ bool parm_is_parameter_pack
+ = template_parameter_pack_p (actual_parm);
+
+ if (!parm_is_parameter_pack)
+ {
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ error ("cannot expand %<%E%> into a fixed-length "
+ "argument list", arg);
+ else
+ error ("cannot expand %<%T%> into a fixed-length "
+ "argument list", arg);
+ }
+ }
+ }
else if (require_all_args)
/* There must be a default arg in this case. */
arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
@@ -4245,6 +4829,101 @@ coerce_template_parms (tree parms,
}
skip_evaluation = saved_skip_evaluation;
+ if (variadic_p)
+ {
+ int expected_len = nargs - nparms + 1;
+ tree parm = TREE_VEC_ELT (parms, nparms - 1);
+ tree packed_args;
+ tree argument_pack;
+ tree packed_types = NULL_TREE;
+
+ packed_args = make_tree_vec (expected_len >= 0 ? expected_len : 0);
+
+ if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
+ && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
+ {
+ /* When the template parameter is a non-type template
+ parameter pack whose type uses parameter packs, we need
+ to look at each of the template arguments
+ separately. Build a vector of the types for these
+ non-type template parameters in PACKED_TYPES. */
+ tree expansion
+ = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm)));
+ packed_types = tsubst_pack_expansion (expansion, args,
+ complain, in_decl);
+
+ if (packed_types == error_mark_node)
+ return error_mark_node;
+
+ /* Check that we have the right number of arguments. */
+ if (i < nargs
+ && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i))
+ && nargs - i != TREE_VEC_LENGTH (packed_types))
+ {
+ error ("wrong number of template arguments (%d, should be %d)",
+ nargs, nparms - 1 + TREE_VEC_LENGTH (packed_types));
+ return error_mark_node;
+ }
+
+ /* If we aren't able to check the actual arguments now
+ (because they haven't been expanded yet), we can at least
+ verify that all of the types used for the non-type
+ template parameter pack are, in fact, valid for non-type
+ template parameters. */
+ if (i < nargs && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i)))
+ {
+ int j, len = TREE_VEC_LENGTH (packed_types);
+ for (j = 0; j < len; ++j)
+ {
+ tree t = TREE_VEC_ELT (packed_types, j);
+ if (invalid_nontype_parm_type_p (t, complain))
+ return error_mark_node;
+ }
+ }
+ }
+
+ /* Convert the remaining arguments, which will be a part of the
+ parameter pack "parm". */
+ for (; i < nargs; ++i)
+ {
+ tree arg = TREE_VEC_ELT (inner_args, i);
+ tree actual_parm = TREE_VALUE (parm);
+
+ if (packed_types && !PACK_EXPANSION_P (arg))
+ {
+ /* When we have a vector of types (corresponding to the
+ non-type template parameter pack that uses parameter
+ packs in its type, as mention above), and the
+ argument is not an expansion (which expands to a
+ currently unknown number of arguments), clone the
+ parm and give it the next type in PACKED_TYPES. */
+ actual_parm = copy_node (actual_parm);
+ TREE_TYPE (actual_parm) =
+ TREE_VEC_ELT (packed_types, i - nparms + 1);
+ }
+
+ arg = convert_template_argument (actual_parm,
+ arg, new_args, complain, i,
+ in_decl);
+ if (arg == error_mark_node)
+ lost++;
+ TREE_VEC_ELT (packed_args, i - nparms + 1) = arg;
+ }
+
+ if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
+ || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
+ argument_pack = make_node (TYPE_ARGUMENT_PACK);
+ else
+ {
+ argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
+ TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+ TREE_CONSTANT (argument_pack) = 1;
+ }
+
+ SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
+ TREE_VEC_ELT (new_inner_args, nparms - 1) = argument_pack;
+ }
+
if (lost)
return error_mark_node;
@@ -4262,6 +4941,10 @@ template_args_equal (tree ot, tree nt)
if (TREE_CODE (nt) == TREE_VEC)
/* For member templates */
return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+ else if (PACK_EXPANSION_P (ot))
+ return PACK_EXPANSION_P (nt)
+ && template_args_equal (PACK_EXPANSION_PATTERN (ot),
+ PACK_EXPANSION_PATTERN (nt));
else if (TYPE_P (nt))
return TYPE_P (ot) && same_type_p (ot, nt);
else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
@@ -4278,6 +4961,9 @@ comp_template_args (tree oldargs, tree newargs)
{
int i;
+ oldargs = expand_template_argument_pack (oldargs);
+ newargs = expand_template_argument_pack (newargs);
+
if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
return 0;
@@ -5018,16 +5704,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
return error_mark_node;
break;
- case BASELINK:
- /* If we do not handle this case specially, we end up walking
- the BINFO hierarchy, which is circular, and therefore
- confuses walk_tree. */
- *walk_subtrees = 0;
- if (for_each_template_parm (BASELINK_FUNCTIONS (*tp), fn, data,
- pfd->visited))
- return error_mark_node;
- break;
-
default:
break;
}
@@ -5720,15 +6396,37 @@ instantiate_class_template (tree type)
{
tree base;
tree access = BINFO_BASE_ACCESS (pbinfo, i);
-
- /* Substitute to figure out the base class. */
- base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error, NULL_TREE);
- if (base == error_mark_node)
- continue;
-
- base_list = tree_cons (access, base, base_list);
- if (BINFO_VIRTUAL_P (pbase_binfo))
- TREE_TYPE (base_list) = integer_type_node;
+ tree expanded_bases = NULL_TREE;
+ int idx, len = 1;
+
+ if (PACK_EXPANSION_P (BINFO_TYPE (pbase_binfo)))
+ {
+ expanded_bases =
+ tsubst_pack_expansion (BINFO_TYPE (pbase_binfo),
+ args, tf_error, NULL_TREE);
+ if (expanded_bases == error_mark_node)
+ continue;
+
+ len = TREE_VEC_LENGTH (expanded_bases);
+ }
+
+ for (idx = 0; idx < len; idx++)
+ {
+ if (expanded_bases)
+ /* Extract the already-expanded base class. */
+ base = TREE_VEC_ELT (expanded_bases, idx);
+ else
+ /* Substitute to figure out the base class. */
+ base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error,
+ NULL_TREE);
+
+ if (base == error_mark_node)
+ continue;
+
+ base_list = tree_cons (access, base, base_list);
+ if (BINFO_VIRTUAL_P (pbase_binfo))
+ TREE_TYPE (base_list) = integer_type_node;
+ }
}
/* The list is now in reverse order; correct that. */
@@ -6077,13 +6775,203 @@ tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return r;
}
+/* Substitute ARGS into T, which is an pack expansion
+ (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
+ TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
+ (if only a partial substitution could be performed) or
+ ERROR_MARK_NODE if there was an error. */
+tree
+tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pattern;
+ tree pack, packs = NULL_TREE, unsubstituted_packs = NULL_TREE;
+ tree first_arg_pack; int i, len = -1;
+ tree result;
+ int incomplete = 0;
+
+ gcc_assert (PACK_EXPANSION_P (t));
+ pattern = PACK_EXPANSION_PATTERN (t);
+
+ /* Determine the argument packs that will instantiate the parameter
+ packs used in the expansion expression. While we're at it,
+ compute the number of arguments to be expanded and make sure it
+ is consistent. */
+ for (pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack;
+ pack = TREE_CHAIN (pack))
+ {
+ tree parm_pack = TREE_VALUE (pack);
+ tree arg_pack = NULL_TREE;
+ tree orig_arg = NULL_TREE;
+
+ if (TREE_CODE (parm_pack) == PARM_DECL)
+ {
+ if (local_specializations)
+ arg_pack = retrieve_local_specialization (parm_pack);
+ }
+ else
+ {
+ int level, idx, levels;
+ template_parm_level_and_index (parm_pack, &level, &idx);
+
+ levels = TMPL_ARGS_DEPTH (args);
+ if (level <= levels)
+ arg_pack = TMPL_ARG (args, level, idx);
+ }
+
+ orig_arg = arg_pack;
+ if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
+ arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
+
+ if (arg_pack)
+ {
+ int my_len =
+ TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack));
+
+ /* It's all-or-nothing with incomplete argument packs. */
+ if (incomplete && !ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+ return error_mark_node;
+
+ if (ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+ incomplete = 1;
+
+ if (len < 0)
+ {
+ len = my_len;
+ first_arg_pack = arg_pack;
+ }
+ else if (len != my_len)
+ {
+ if (TREE_CODE (t) == TYPE_PACK_EXPANSION)
+ error ("mismatched argument pack lengths while expanding "
+ "%<%T%>",
+ pattern);
+ else
+ error ("mismatched argument pack lengths while expanding "
+ "%<%E%>",
+ pattern);
+ return error_mark_node;
+ }
+
+ /* Keep track of the parameter packs and their corresponding
+ argument packs. */
+ packs = tree_cons (parm_pack, arg_pack, packs);
+ TREE_TYPE (packs) = orig_arg;
+ }
+ else
+ /* We can't substitute for this parameter pack. */
+ unsubstituted_packs = tree_cons (TREE_PURPOSE (pack),
+ TREE_VALUE (pack),
+ unsubstituted_packs);
+ }
+
+ /* We cannot expand this expansion expression, because we don't have
+ all of the argument packs we need. Substitute into the pattern
+ and return a PACK_EXPANSION_*. The caller will need to deal with
+ that. */
+ if (unsubstituted_packs)
+ return make_pack_expansion (tsubst (pattern, args, complain,
+ in_decl));
+
+ /* We could not find any argument packs that work. */
+ if (len < 0)
+ return error_mark_node;
+
+ /* For each argument in each argument pack, substitute into the
+ pattern. */
+ result = make_tree_vec (len + incomplete);
+ for (i = 0; i < len + incomplete; ++i)
+ {
+ /* For parameter pack, change the substitution of the parameter
+ pack to the ith argument in its argument pack, then expand
+ the pattern. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm = TREE_PURPOSE (pack);
+
+ if (TREE_CODE (parm) == PARM_DECL)
+ {
+ /* Select the Ith argument from the pack. */
+ tree arg = make_node (ARGUMENT_PACK_SELECT);
+ ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
+ ARGUMENT_PACK_SELECT_INDEX (arg) = i;
+ mark_used (parm);
+ register_local_specialization (arg, parm);
+ }
+ else
+ {
+ tree value = parm;
+ int idx, level;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ if (i < len)
+ {
+ /* Select the Ith argument from the pack. */
+ value = make_node (ARGUMENT_PACK_SELECT);
+ ARGUMENT_PACK_SELECT_FROM_PACK (value) = TREE_VALUE (pack);
+ ARGUMENT_PACK_SELECT_INDEX (value) = i;
+ }
+
+ /* Update the corresponding argument. */
+ TMPL_ARG (args, level, idx) = value;
+ }
+ }
+
+ /* Substitute into the PATTERN with the altered arguments. */
+ if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
+ TREE_VEC_ELT (result, i) =
+ tsubst_expr (pattern, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ else
+ TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl);
+
+ if (i == len)
+ /* When we have incomplete argument packs, the last "expanded"
+ result is itself a pack expansion, which allows us
+ to deduce more arguments. */
+ TREE_VEC_ELT (result, i) =
+ make_pack_expansion (TREE_VEC_ELT (result, i));
+
+ if (TREE_VEC_ELT (result, i) == error_mark_node)
+ {
+ result = error_mark_node;
+ break;
+ }
+ }
+
+ /* Update ARGS to restore the substitution from parameter packs to
+ their argument packs. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm = TREE_PURPOSE (pack);
+
+ if (TREE_CODE (parm) == PARM_DECL)
+ register_local_specialization (TREE_TYPE (pack), parm);
+ else
+ {
+ int idx, level;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ /* Update the corresponding argument. */
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+ TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) =
+ TREE_TYPE (pack);
+ else
+ TREE_VEC_ELT (args, idx) = TREE_TYPE (pack);
+ }
+ }
+
+ return result;
+}
+
/* Substitute ARGS into the vector or list of template arguments T. */
static tree
tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
+ tree orig_t = t;
int len = TREE_VEC_LENGTH (t);
- int need_new = 0, i;
+ int need_new = 0, i, expanded_len_adjust = 0, out;
tree *elts = (tree *) alloca (len * sizeof (tree));
for (i = 0; i < len; i++)
@@ -6093,6 +6981,42 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (TREE_CODE (orig_arg) == TREE_VEC)
new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
+ else if (PACK_EXPANSION_P (orig_arg))
+ {
+ /* Substitute into an expansion expression. */
+ new_arg = tsubst_pack_expansion (orig_arg, args, complain, in_decl);
+
+ if (TREE_CODE (new_arg) == TREE_VEC)
+ /* Add to the expanded length adjustment the number of
+ expanded arguments. We subtract one from this
+ measurement, because the argument pack expression
+ itself is already counted as 1 in
+ LEN. EXPANDED_LEN_ADJUST can actually be negative, if
+ the argument pack is empty. */
+ expanded_len_adjust += TREE_VEC_LENGTH (new_arg) - 1;
+ }
+ else if (ARGUMENT_PACK_P (orig_arg))
+ {
+ /* Substitute into each of the arguments. */
+ new_arg = make_node (TREE_CODE (orig_arg));
+
+ SET_ARGUMENT_PACK_ARGS (
+ new_arg,
+ tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
+ args, complain, in_decl));
+
+ if (ARGUMENT_PACK_ARGS (new_arg) == error_mark_node)
+ new_arg = error_mark_node;
+
+ if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK) {
+ TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
+ complain, in_decl);
+ TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
+
+ if (TREE_TYPE (new_arg) == error_mark_node)
+ new_arg = error_mark_node;
+ }
+ }
else
new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
@@ -6107,9 +7031,27 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (!need_new)
return t;
- t = make_tree_vec (len);
- for (i = 0; i < len; i++)
- TREE_VEC_ELT (t, i) = elts[i];
+ /* Make space for the expanded arguments coming from template
+ argument packs. */
+ t = make_tree_vec (len + expanded_len_adjust);
+ for (i = 0, out = 0; i < len; i++)
+ {
+ if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i))
+ || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i)))
+ && TREE_CODE (elts[i]) == TREE_VEC)
+ {
+ int idx;
+
+ /* Now expand the template argument pack "in place". */
+ for (idx = 0; idx < TREE_VEC_LENGTH (elts[i]); idx++, out++)
+ TREE_VEC_ELT (t, out) = TREE_VEC_ELT (elts[i], idx);
+ }
+ else
+ {
+ TREE_VEC_ELT (t, out) = elts[i];
+ out++;
+ }
+ }
return t;
}
@@ -6718,33 +7660,112 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
case PARM_DECL:
{
- tree type;
-
- r = copy_node (t);
- if (DECL_TEMPLATE_PARM_P (t))
- SET_DECL_TEMPLATE_PARM_P (r);
-
- type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- type = type_decays_to (type);
- TREE_TYPE (r) = type;
- cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+ tree type = NULL_TREE;
+ int i, len = 1;
+ tree expanded_types = NULL_TREE;
+ tree prev_r = NULL_TREE;
+ tree first_r = NULL_TREE;
- if (DECL_INITIAL (r))
- {
- if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
- DECL_INITIAL (r) = TREE_TYPE (r);
- else
- DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
- complain, in_decl);
- }
+ if (FUNCTION_PARAMETER_PACK_P (t))
+ {
+ /* If there is a local specialization that isn't a
+ parameter pack, it means that we're doing a "simple"
+ substitution from inside tsubst_pack_expansion. Just
+ return the local specialiation (which will be a single
+ parm). */
+ tree spec = NULL_TREE;
+ if (local_specializations)
+ spec = retrieve_local_specialization (t);
+ if (spec
+ && TREE_CODE (spec) == PARM_DECL
+ && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION)
+ return spec;
+
+ /* Expand the TYPE_PACK_EXPANSION that provides the types for
+ the parameters in this function parameter pack. */
+ expanded_types = tsubst_pack_expansion (TREE_TYPE (t), args,
+ complain, in_decl);
+ if (TREE_CODE (expanded_types) == TREE_VEC)
+ {
+ len = TREE_VEC_LENGTH (expanded_types);
+
+ /* Zero-length parameter packs are boring. Just substitute
+ into the chain. */
+ if (len == 0)
+ return tsubst (TREE_CHAIN (t), args, complain,
+ TREE_CHAIN (t));
+ }
+ else
+ {
+ /* All we did was update the type. Make a note of that. */
+ type = expanded_types;
+ expanded_types = NULL_TREE;
+ }
+ }
- DECL_CONTEXT (r) = NULL_TREE;
+ /* Loop through all of the parameter's we'll build. When T is
+ a function parameter pack, LEN is the number of expanded
+ types in EXPANDED_TYPES; otherwise, LEN is 1. */
+ r = NULL_TREE;
+ for (i = 0; i < len; ++i)
+ {
+ prev_r = r;
+ r = copy_node (t);
+ if (DECL_TEMPLATE_PARM_P (t))
+ SET_DECL_TEMPLATE_PARM_P (r);
+
+ if (expanded_types)
+ /* We're on the Ith parameter of the function parameter
+ pack. */
+ {
+ /* Get the Ith type. */
+ type = TREE_VEC_ELT (expanded_types, i);
+
+ if (DECL_NAME (r))
+ /* Rename the parameter to include the index. */
+ DECL_NAME (r) =
+ make_ith_pack_parameter_name (DECL_NAME (r), i);
+ }
+ else if (!type)
+ /* We're dealing with a normal parameter. */
+ type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+ type = type_decays_to (type);
+ TREE_TYPE (r) = type;
+ cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+
+ if (DECL_INITIAL (r))
+ {
+ if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
+ DECL_INITIAL (r) = TREE_TYPE (r);
+ else
+ DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
+ complain, in_decl);
+ }
+
+ DECL_CONTEXT (r) = NULL_TREE;
+
+ if (!DECL_TEMPLATE_PARM_P (r))
+ DECL_ARG_TYPE (r) = type_passed_as (type);
+
+ /* Keep track of the first new parameter we
+ generate. That's what will be returned to the
+ caller. */
+ if (!first_r)
+ first_r = r;
+
+ /* Build a proper chain of parameters when substituting
+ into a function parameter pack. */
+ if (prev_r)
+ TREE_CHAIN (prev_r) = r;
+ }
- if (!DECL_TEMPLATE_PARM_P (r))
- DECL_ARG_TYPE (r) = type_passed_as (type);
if (TREE_CHAIN (t))
TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args,
complain, TREE_CHAIN (t));
+
+ /* FIRST_R contains the start of the chain we've built. */
+ r = first_r;
}
break;
@@ -6986,9 +8007,10 @@ tsubst_arg_types (tree arg_types,
tree in_decl)
{
tree remaining_arg_types;
- tree type;
+ tree type = NULL_TREE;
+ int i = 1;
+ tree expanded_args = NULL_TREE;
tree default_arg;
- tree result = NULL_TREE;
if (!arg_types || arg_types == void_list_node)
return arg_types;
@@ -6998,42 +8020,73 @@ tsubst_arg_types (tree arg_types,
if (remaining_arg_types == error_mark_node)
return error_mark_node;
- type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
- if (type == error_mark_node)
- return error_mark_node;
- if (VOID_TYPE_P (type))
+ if (PACK_EXPANSION_P (TREE_VALUE (arg_types)))
{
- if (complain & tf_error)
- {
- error ("invalid parameter type %qT", type);
- if (in_decl)
- error ("in declaration %q+D", in_decl);
- }
- return error_mark_node;
- }
+ /* For a pack expansion, perform substitution on the
+ entire expression. Later on, we'll handle the arguments
+ one-by-one. */
+ expanded_args = tsubst_pack_expansion (TREE_VALUE (arg_types),
+ args, complain, in_decl);
- /* Do array-to-pointer, function-to-pointer conversion, and ignore
- top-level qualifiers as required. */
- type = TYPE_MAIN_VARIANT (type_decays_to (type));
+ if (TREE_CODE (expanded_args) == TREE_VEC)
+ /* So that we'll spin through the parameters, one by one. */
+ i = TREE_VEC_LENGTH (expanded_args);
+ else
+ {
+ /* We only partially substituted into the parameter
+ pack. Our type is TYPE_PACK_EXPANSION. */
+ type = expanded_args;
+ expanded_args = NULL_TREE;
+ }
+ }
- /* We do not substitute into default arguments here. The standard
- mandates that they be instantiated only when needed, which is
- done in build_over_call. */
- default_arg = TREE_PURPOSE (arg_types);
+ while (i > 0) {
+ --i;
+
+ if (expanded_args)
+ type = TREE_VEC_ELT (expanded_args, i);
+ else if (!type)
+ type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
- if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
- {
- /* We've instantiated a template before its default arguments
- have been parsed. This can happen for a nested template
- class, and is not an error unless we require the default
- argument in a call of this function. */
- result = tree_cons (default_arg, type, remaining_arg_types);
- VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg), result);
+ if (type == error_mark_node)
+ return error_mark_node;
+ if (VOID_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ {
+ error ("invalid parameter type %qT", type);
+ if (in_decl)
+ error ("in declaration %q+D", in_decl);
+ }
+ return error_mark_node;
}
- else
- result = hash_tree_cons (default_arg, type, remaining_arg_types);
+
+ /* Do array-to-pointer, function-to-pointer conversion, and ignore
+ top-level qualifiers as required. */
+ type = TYPE_MAIN_VARIANT (type_decays_to (type));
- return result;
+ /* We do not substitute into default arguments here. The standard
+ mandates that they be instantiated only when needed, which is
+ done in build_over_call. */
+ default_arg = TREE_PURPOSE (arg_types);
+
+ if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
+ {
+ /* We've instantiated a template before its default arguments
+ have been parsed. This can happen for a nested template
+ class, and is not an error unless we require the default
+ argument in a call of this function. */
+ remaining_arg_types =
+ tree_cons (default_arg, type, remaining_arg_types);
+ VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg),
+ remaining_arg_types);
+ }
+ else
+ remaining_arg_types =
+ hash_tree_cons (default_arg, type, remaining_arg_types);
+ }
+
+ return remaining_arg_types;
}
/* Substitute into a FUNCTION_TYPE or METHOD_TYPE. This routine does
@@ -7153,11 +8206,31 @@ tsubst_exception_specification (tree fntype,
while (specs)
{
tree spec;
- spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
- if (spec == error_mark_node)
- return spec;
- new_specs = add_exception_specifier (new_specs, spec, complain);
- specs = TREE_CHAIN (specs);
+ int i, len = 1;
+ tree expanded_specs = NULL_TREE;
+
+ if (PACK_EXPANSION_P (TREE_VALUE (specs)))
+ {
+ /* Expand the pack expansion type. */
+ expanded_specs = tsubst_pack_expansion (TREE_VALUE (specs),
+ args, complain,
+ in_decl);
+ len = TREE_VEC_LENGTH (expanded_specs);
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (expanded_specs)
+ spec = TREE_VEC_ELT (expanded_specs, i);
+ else
+ spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
+ if (spec == error_mark_node)
+ return spec;
+ new_specs = add_exception_specifier (new_specs, spec,
+ complain);
+ }
+
+ specs = TREE_CHAIN (specs);
}
}
return new_specs;
@@ -7307,12 +8380,32 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
levels = TMPL_ARGS_DEPTH (args);
if (level <= levels)
- arg = TMPL_ARG (args, level, idx);
+ {
+ arg = TMPL_ARG (args, level, idx);
+
+ if (arg && TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
+ /* See through ARGUMENT_PACK_SELECT arguments. */
+ arg = ARGUMENT_PACK_SELECT_ARG (arg);
+ }
if (arg == error_mark_node)
return error_mark_node;
else if (arg != NULL_TREE)
{
+ if (ARGUMENT_PACK_P (arg))
+ /* If ARG is an argument pack, we don't actually want to
+ perform a substitution here, because substitutions
+ for argument packs are only done
+ element-by-element. We can get to this point when
+ substituting the type of a non-type template
+ parameter pack, when that type actually contains
+ template parameter packs from an outer template, e.g.,
+
+ template<typename... Types> struct A {
+ template<Types... Values> struct B { };
+ }; */
+ return t;
+
if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
{
int quals;
@@ -7782,6 +8875,26 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
complain);
}
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree r = make_node (TREE_CODE (t));
+ tree packed_out =
+ tsubst_template_args (ARGUMENT_PACK_ARGS (t),
+ args,
+ complain,
+ in_decl);
+ SET_ARGUMENT_PACK_ARGS (r, packed_out);
+
+ /* For template nontype argument packs, also substitute into
+ the type. */
+ if (TREE_CODE (t) == NONTYPE_ARGUMENT_PACK)
+ TREE_TYPE (r) = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+ return r;
+ }
+ break;
+
default:
sorry ("use of %qs in template",
tree_code_name [(int) TREE_CODE (t)]);
@@ -7991,6 +9104,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case PARM_DECL:
r = retrieve_local_specialization (t);
gcc_assert (r != NULL);
+ if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
+ r = ARGUMENT_PACK_SELECT_ARG (r);
mark_used (r);
return r;
@@ -8110,13 +9225,22 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
(code, tsubst (TREE_TYPE (t), args, complain, in_decl),
tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
+ case SIZEOF_EXPR:
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ {
+ /* We only want to compute the number of arguments. */
+ tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+ complain, in_decl);
+ return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+ }
+ /* Fall through */
+
case INDIRECT_REF:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
case BIT_NOT_EXPR:
case ADDR_EXPR:
case UNARY_PLUS_EXPR: /* Unary + */
- case SIZEOF_EXPR:
case ALIGNOF_EXPR:
case ARROW_EXPR:
case THROW_EXPR:
@@ -8345,6 +9469,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
mark_used (TREE_OPERAND (t, 1));
return t;
+ case EXPR_PACK_EXPANSION:
+ error ("invalid use of pack expansion expression");
+ return error_mark_node;
+
+ case NONTYPE_ARGUMENT_PACK:
+ error ("use %<...%> to expand argument pack");
+ return error_mark_node;
+
default:
return t;
}
@@ -8801,6 +9933,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
}
break;
+ case EXPR_PACK_EXPANSION:
+ error ("invalid use of pack expansion expression");
+ return error_mark_node;
+
+ case NONTYPE_ARGUMENT_PACK:
+ error ("use %<...%> to expand argument pack");
+ return error_mark_node;
+
default:
gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
@@ -9069,6 +10209,15 @@ tsubst_copy_and_build (tree t,
/*overloaded_p=*/NULL);
case SIZEOF_EXPR:
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ {
+ /* We only want to compute the number of arguments. */
+ tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+ complain, in_decl);
+ return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+ }
+ /* Fall through */
+
case ALIGNOF_EXPR:
op1 = TREE_OPERAND (t, 0);
if (!args)
@@ -9241,6 +10390,69 @@ tsubst_copy_and_build (tree t,
if (t == void_list_node)
return t;
+ if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
+ || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
+ {
+ /* We have pack expansions, so expand those and
+ create a new list out of it. */
+ tree purposevec = NULL_TREE;
+ tree valuevec = NULL_TREE;
+ tree chain;
+ int i, len = -1;
+
+ /* Expand the argument expressions. */
+ if (TREE_PURPOSE (t))
+ purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
+ complain, in_decl);
+ if (TREE_VALUE (t))
+ valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
+ complain, in_decl);
+
+ /* Build the rest of the list. */
+ chain = TREE_CHAIN (t);
+ if (chain && chain != void_type_node)
+ chain = RECUR (chain);
+
+ /* Determine the number of arguments. */
+ if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
+ {
+ len = TREE_VEC_LENGTH (purposevec);
+ gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
+ }
+ else if (TREE_CODE (valuevec) == TREE_VEC)
+ len = TREE_VEC_LENGTH (valuevec);
+ else
+ {
+ /* Since we only performed a partial substitution into
+ the argument pack, we only return a single list
+ node. */
+ if (purposevec == TREE_PURPOSE (t)
+ && valuevec == TREE_VALUE (t)
+ && chain == TREE_CHAIN (t))
+ return t;
+
+ return tree_cons (purposevec, valuevec, chain);
+ }
+
+ /* Convert the argument vectors into a TREE_LIST */
+ i = len;
+ while (i > 0)
+ {
+ /* Grab the Ith values. */
+ i--;
+ purpose = purposevec ? TREE_VEC_ELT (purposevec, i)
+ : NULL_TREE;
+ value
+ = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, i))
+ : NULL_TREE;
+
+ /* Build the list (backwards). */
+ chain = tree_cons (purpose, value, chain);
+ }
+
+ return chain;
+ }
+
purpose = TREE_PURPOSE (t);
if (purpose)
purpose = RECUR (purpose);
@@ -9353,6 +10565,8 @@ tsubst_copy_and_build (tree t,
unsigned HOST_WIDE_INT idx;
tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
bool process_index_p;
+ int newlen;
+ bool need_copy_p = false;
if (type == error_mark_node)
return error_mark_node;
@@ -9367,13 +10581,54 @@ tsubst_copy_and_build (tree t,
process_index_p = !(type && IS_AGGR_TYPE (type));
n = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t));
+ newlen = VEC_length (constructor_elt, n);
for (idx = 0; VEC_iterate (constructor_elt, n, idx, ce); idx++)
{
if (ce->index && process_index_p)
ce->index = RECUR (ce->index);
- ce->value = RECUR (ce->value);
+
+ if (PACK_EXPANSION_P (ce->value))
+ {
+ /* Substitute into the pack expansion. */
+ ce->value = tsubst_pack_expansion (ce->value, args, complain,
+ in_decl);
+
+ if (TREE_VEC_LENGTH (ce->value) == 1)
+ /* Just move the argument into place. */
+ ce->value = TREE_VEC_ELT (ce->value, 0);
+ else
+ {
+ /* Update the length of the final CONSTRUCTOR
+ arguments vector, and note that we will need to
+ copy.*/
+ newlen = newlen + TREE_VEC_LENGTH (ce->value) - 1;
+ need_copy_p = true;
+ }
+ }
+ else
+ ce->value = RECUR (ce->value);
}
+ if (need_copy_p)
+ {
+ VEC(constructor_elt,gc) *old_n = n;
+
+ n = VEC_alloc (constructor_elt, gc, newlen);
+ for (idx = 0; VEC_iterate (constructor_elt, old_n, idx, ce);
+ idx++)
+ {
+ if (TREE_CODE (ce->value) == TREE_VEC)
+ {
+ int i, len = TREE_VEC_LENGTH (ce->value);
+ for (i = 0; i < len; ++i)
+ CONSTRUCTOR_APPEND_ELT (n, 0,
+ TREE_VEC_ELT (ce->value, i));
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (n, 0, ce->value);
+ }
+ }
+
if (TREE_HAS_CONSTRUCTOR (t))
return finish_compound_literal (type, n);
@@ -9662,6 +10917,7 @@ fn_type_unification (tree fn,
tree parms;
tree fntype;
int result;
+ bool incomplete_argument_packs_p = false;
gcc_assert (TREE_CODE (fn) == TEMPLATE_DECL);
@@ -9685,16 +10941,16 @@ fn_type_unification (tree fn,
specified template argument values. If a substitution in a
template parameter or in the function type of the function
template results in an invalid type, type deduction fails. */
- int i;
+ tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
+ int i, len = TREE_VEC_LENGTH (tparms);
tree converted_args;
- bool incomplete;
+ bool incomplete = false;
if (explicit_targs == error_mark_node)
return 1;
converted_args
- = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (fn),
- explicit_targs, NULL_TREE, tf_none,
+ = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
/*require_all_args=*/false,
/*use_default_args=*/false));
if (converted_args == error_mark_node)
@@ -9706,7 +10962,49 @@ fn_type_unification (tree fn,
an incomplete set of explicit args, we must not do semantic
processing during substitution as we could create partial
instantiations. */
- incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+ for (i = 0; i < len; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
+ bool parameter_pack = false;
+
+ /* Dig out the actual parm. */
+ if (TREE_CODE (parm) == TYPE_DECL
+ || TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ parm = TREE_TYPE (parm);
+ parameter_pack = TEMPLATE_TYPE_PARAMETER_PACK (parm);
+ }
+ else if (TREE_CODE (parm) == PARM_DECL)
+ {
+ parm = DECL_INITIAL (parm);
+ parameter_pack = TEMPLATE_PARM_PARAMETER_PACK (parm);
+ }
+
+ if (parameter_pack)
+ {
+ int level, idx;
+ tree targ;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ /* Mark the argument pack as "incomplete". We could
+ still deduce more arguments during unification. */
+ targ = TMPL_ARG (converted_args, level, idx);
+ ARGUMENT_PACK_INCOMPLETE_P(targ) = 1;
+ ARGUMENT_PACK_EXPLICIT_ARGS (targ) = ARGUMENT_PACK_ARGS (targ);
+
+ /* We have some incomplete argument packs. */
+ incomplete_argument_packs_p = true;
+ }
+ }
+
+ if (incomplete_argument_packs_p)
+ /* Any substitution is guaranteed to be incomplete if there
+ are incomplete argument packs, because we can still deduce
+ more arguments. */
+ incomplete = 1;
+ else
+ incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+
processing_template_decl += incomplete;
fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
processing_template_decl -= incomplete;
@@ -9736,6 +11034,22 @@ fn_type_unification (tree fn,
targs, parms, args, /*subr=*/0,
strict, flags);
+ if (result == 0 && incomplete_argument_packs_p)
+ {
+ int i, len = NUM_TMPL_ARGS (targs);
+
+ /* Clear the "incomplete" flags on all argument packs. */
+ for (i = 0; i < len; i++)
+ {
+ tree arg = TREE_VEC_ELT (targs, i);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ ARGUMENT_PACK_INCOMPLETE_P (arg) = 0;
+ ARGUMENT_PACK_EXPLICIT_ARGS (arg) = NULL_TREE;
+ }
+ }
+ }
+
if (result == 0)
/* All is well so far. Now, check:
@@ -9891,6 +11205,9 @@ type_unification_real (tree tparms,
while (parms && parms != void_list_node
&& args && args != void_list_node)
{
+ if (TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+ break;
+
parm = TREE_VALUE (parms);
parms = TREE_CHAIN (parms);
arg = TREE_VALUE (args);
@@ -9959,6 +11276,39 @@ type_unification_real (tree tparms,
}
}
+
+ if (parms
+ && parms != void_list_node
+ && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+ {
+ /* Unify the remaining arguments with the pack expansion type. */
+ tree argvec;
+ tree parmvec = make_tree_vec (1);
+ int len = 0;
+ tree t;
+
+ /* Count the number of arguments that remain. */
+ for (t = args; t && t != void_list_node; t = TREE_CHAIN (t))
+ len++;
+
+ /* Allocate a TREE_VEC and copy in all of the arguments */
+ argvec = make_tree_vec (len);
+ for (i = 0; args && args != void_list_node; args = TREE_CHAIN (args))
+ {
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (args);
+ ++i;
+ }
+
+ /* Copy the parameter into parmvec. */
+ TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
+ if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
+ /*call_args_p=*/true, /*subr=*/subr))
+ return 1;
+
+ /* Advance to the end of the list of parameters. */
+ parms = TREE_CHAIN (parms);
+ }
+
/* Fail if we've reached the end of the parm list, and more args
are present, and the parm list isn't variadic. */
if (args && args != void_list_node && parms == void_list_node)
@@ -10330,6 +11680,246 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
return 1;
}
+/* Determines the LEVEL and INDEX for the template parameter PARM. */
+void
+template_parm_level_and_index (tree parm, int* level, int* index)
+{
+ if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ {
+ *index = TEMPLATE_TYPE_IDX (parm);
+ *level = TEMPLATE_TYPE_LEVEL (parm);
+ }
+ else
+ {
+ *index = TEMPLATE_PARM_IDX (parm);
+ *level = TEMPLATE_PARM_LEVEL (parm);
+ }
+}
+
+/* Unifies the remaining arguments in PACKED_ARGS with the pack
+ expansion at the end of PACKED_PARMS. Returns 0 if the type
+ deduction succeeds, 1 otherwise. STRICT is the same as in
+ unify. CALL_ARGS_P is true iff PACKED_ARGS is actually a function
+ call argument list. We'll need to adjust the arguments to make them
+ types. SUBR tells us if this is from a recursive call to
+ type_unification_real. */
+int
+unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
+ tree packed_args, int strict, bool call_args_p,
+ bool subr)
+{
+ tree parm
+ = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
+ tree pattern = PACK_EXPANSION_PATTERN (parm);
+ tree pack, packs = NULL_TREE;
+ int i, start = TREE_VEC_LENGTH (packed_parms) - 1;
+ int len = TREE_VEC_LENGTH (packed_args);
+
+ /* Determine the parameter packs we will be deducing from the
+ pattern, and record their current deductions. */
+ for (pack = PACK_EXPANSION_PARAMETER_PACKS (parm);
+ pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm_pack = TREE_VALUE (pack);
+ int idx, level;
+
+ /* Determine the index and level of this parameter pack. */
+ template_parm_level_and_index (parm_pack, &level, &idx);
+
+ /* Keep track of the parameter packs and their corresponding
+ argument packs. */
+ packs = tree_cons (parm_pack, TMPL_ARG (targs, level, idx), packs);
+ TREE_TYPE (packs) = make_tree_vec (len - start);
+ }
+
+ /* Loop through all of the arguments that have not yet been
+ unified and unify each with the pattern. */
+ for (i = start; i < len; i++)
+ {
+ tree parm = pattern;
+
+ /* For each parameter pack, clear out the deduced value so that
+ we can deduce it again. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ int idx, level;
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ TMPL_ARG (targs, level, idx) = NULL_TREE;
+ }
+
+ /* Unify the pattern with the current argument. */
+ {
+ tree arg = TREE_VEC_ELT (packed_args, i);
+ int arg_strict = strict;
+ bool skip_arg_p = false;
+
+ if (call_args_p)
+ {
+ int sub_strict;
+
+ /* This mirrors what we do in type_unification_real. */
+ switch (strict)
+ {
+ case DEDUCE_CALL:
+ sub_strict = (UNIFY_ALLOW_OUTER_LEVEL
+ | UNIFY_ALLOW_MORE_CV_QUAL
+ | UNIFY_ALLOW_DERIVED);
+ break;
+
+ case DEDUCE_CONV:
+ sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;
+ break;
+
+ case DEDUCE_EXACT:
+ sub_strict = UNIFY_ALLOW_NONE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!TYPE_P (arg))
+ {
+ gcc_assert (TREE_TYPE (arg) != NULL_TREE);
+ if (type_unknown_p (arg))
+ {
+ /* [temp.deduct.type] A template-argument can be
+ deduced from a pointer to function or pointer
+ to member function argument if the set of
+ overloaded functions does not contain function
+ templates and at most one of a set of
+ overloaded functions provides a unique
+ match. */
+
+ if (resolve_overloaded_unification
+ (tparms, targs, parm, arg, strict, sub_strict)
+ != 0)
+ return 1;
+ skip_arg_p = true;
+ }
+
+ if (!skip_arg_p)
+ {
+ arg = TREE_TYPE (arg);
+ if (arg == error_mark_node)
+ return 1;
+ }
+ }
+
+ arg_strict = sub_strict;
+
+ if (!subr)
+ arg_strict |=
+ maybe_adjust_types_for_deduction (strict, &parm, &arg);
+ }
+
+ if (!skip_arg_p)
+ {
+ if (unify (tparms, targs, parm, arg, arg_strict))
+ return 1;
+ }
+ }
+
+ /* For each parameter pack, collect the deduced value. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ int idx, level;
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ TREE_VEC_ELT (TREE_TYPE (pack), i - start) =
+ TMPL_ARG (targs, level, idx);
+ }
+ }
+
+ /* Verify that the results of unification with the parameter packs
+ produce results consistent with what we've seen before, and make
+ the deduced argument packs available. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree old_pack = TREE_VALUE (pack);
+ tree new_args = TREE_TYPE (pack);
+
+ if (old_pack && ARGUMENT_PACK_INCOMPLETE_P (old_pack))
+ {
+ /* Prepend the explicit arguments onto NEW_ARGS. */
+ tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+ tree old_args = new_args;
+ int i, explicit_len = TREE_VEC_LENGTH (explicit_args);
+ int len = explicit_len + TREE_VEC_LENGTH (old_args);
+
+ /* Copy the explicit arguments. */
+ new_args = make_tree_vec (len);
+ for (i = 0; i < explicit_len; i++)
+ TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (explicit_args, i);
+
+ /* Copy the deduced arguments. */
+ for (; i < len; i++)
+ TREE_VEC_ELT (new_args, i) =
+ TREE_VEC_ELT (old_args, i - explicit_len);
+ }
+
+ if (!old_pack)
+ {
+ tree result;
+ int idx, level;
+
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Build the deduced *_ARGUMENT_PACK. */
+ if (TREE_CODE (TREE_PURPOSE (pack)) == TEMPLATE_PARM_INDEX)
+ {
+ result = make_node (NONTYPE_ARGUMENT_PACK);
+ TREE_TYPE (result) =
+ TREE_TYPE (TEMPLATE_PARM_DECL (TREE_PURPOSE (pack)));
+ TREE_CONSTANT (result) = 1;
+ }
+ else
+ result = make_node (TYPE_ARGUMENT_PACK);
+
+ SET_ARGUMENT_PACK_ARGS (result, new_args);
+
+ /* Note the deduced argument packs for this parameter
+ pack. */
+ TMPL_ARG (targs, level, idx) = result;
+ }
+ else if (ARGUMENT_PACK_INCOMPLETE_P (old_pack)
+ && (ARGUMENT_PACK_ARGS (old_pack)
+ == ARGUMENT_PACK_EXPLICIT_ARGS (old_pack)))
+ {
+ /* We only had the explicitly-provided arguments before, but
+ now we have a complete set of arguments. */
+ int idx, level;
+ tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Keep the original deduced argument pack. */
+ TMPL_ARG (targs, level, idx) = old_pack;
+
+ SET_ARGUMENT_PACK_ARGS (old_pack, new_args);
+ ARGUMENT_PACK_INCOMPLETE_P (old_pack) = 1;
+ ARGUMENT_PACK_EXPLICIT_ARGS (old_pack) = explicit_args;
+ }
+ else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
+ new_args))
+ /* Inconsistent unification of this parameter pack. */
+ return 1;
+ else
+ {
+ int idx, level;
+
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Keep the original deduced argument pack. */
+ TMPL_ARG (targs, level, idx) = old_pack;
+ }
+ }
+
+ return 0;
+}
+
/* Deduce the value of template parameters. TPARMS is the (innermost)
set of template parameters to a template. TARGS is the bindings
for those template parameters, as determined thus far; TARGS may
@@ -10570,6 +12160,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return 1;
}
+ /* If ARG is a parameter pack or an expansion, we cannot unify
+ against it unless PARM is also a parameter pack. */
+ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+ && !template_parameter_pack_p (parm))
+ return 1;
+
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
@@ -10620,6 +12216,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
else
return 1;
+ /* If ARG is a parameter pack or an expansion, we cannot unify
+ against it unless PARM is also a parameter pack. */
+ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+ && !TEMPLATE_PARM_PARAMETER_PACK (parm))
+ return 1;
+
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
@@ -10920,6 +12522,47 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
/* Matched cases are handled by the ARG == PARM test above. */
return 1;
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree packed_parms = ARGUMENT_PACK_ARGS (parm);
+ tree packed_args = ARGUMENT_PACK_ARGS (arg);
+ int i, len = TREE_VEC_LENGTH (packed_parms);
+ int argslen = TREE_VEC_LENGTH (packed_args);
+ int parm_variadic_p = 0;
+
+ /* Check if the parameters end in a pack, making them variadic. */
+ if (len > 0
+ && PACK_EXPANSION_P (TREE_VEC_ELT (packed_parms, len - 1)))
+ parm_variadic_p = 1;
+
+ /* If we don't have enough arguments to satisfy the parameters
+ (not counting the pack expression at the end), or we have
+ too many arguments for a parameter list that doesn't end in
+ a pack expression, we can't unify. */
+ if (argslen < (len - parm_variadic_p)
+ || (argslen > len && !parm_variadic_p))
+ return 1;
+
+ /* Unify all of the parameters that precede the (optional)
+ pack expression. */
+ for (i = 0; i < len - parm_variadic_p; ++i)
+ {
+ if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
+ TREE_VEC_ELT (packed_args, i), strict))
+ return 1;
+ }
+
+ if (parm_variadic_p)
+ return unify_pack_expansion (tparms, targs,
+ packed_parms, packed_args,
+ strict, /*call_args_p=*/false,
+ /*subr=*/false);
+ return 0;
+ }
+
+ break;
+
default:
gcc_assert (EXPR_P (parm));
@@ -11090,6 +12733,18 @@ more_specialized_fn (tree pat1, tree pat2, int len)
int quals1 = -1;
int quals2 = -1;
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+ && TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ {
+ /* When both arguments are pack expansions, we need only
+ unify the patterns themselves. */
+ arg1 = PACK_EXPANSION_PATTERN (arg1);
+ arg2 = PACK_EXPANSION_PATTERN (arg2);
+
+ /* This is the last comparison we need to do. */
+ len = 0;
+ }
+
if (TREE_CODE (arg1) == REFERENCE_TYPE)
{
arg1 = TREE_TYPE (arg1);
@@ -11145,8 +12800,62 @@ more_specialized_fn (tree pat1, tree pat2, int len)
arg1 = TYPE_MAIN_VARIANT (arg1);
arg2 = TYPE_MAIN_VARIANT (arg2);
- deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
- deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION)
+ {
+ int i, len2 = len + 1;
+ tree parmvec = make_tree_vec (1);
+ tree argvec = make_tree_vec (len2);
+ tree ta = args2;
+
+ /* Setup the parameter vector, which contains only ARG1. */
+ TREE_VEC_ELT (parmvec, 0) = arg1;
+
+ /* Setup the argument vector, which contains the remaining
+ arguments. */
+ for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+ deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec,
+ argvec, UNIFY_ALLOW_NONE,
+ /*call_args_p=*/false,
+ /*subr=*/0);
+
+ /* We cannot deduce in the other direction, because ARG1 is
+ a pack expansion but ARG2 is not. */
+ deduce2 = 0;
+ }
+ else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ {
+ int i, len1 = len + 1;
+ tree parmvec = make_tree_vec (1);
+ tree argvec = make_tree_vec (len1);
+ tree ta = args1;
+
+ /* Setup the parameter vector, which contains only ARG1. */
+ TREE_VEC_ELT (parmvec, 0) = arg2;
+
+ /* Setup the argument vector, which contains the remaining
+ arguments. */
+ for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+ deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec,
+ argvec, UNIFY_ALLOW_NONE,
+ /*call_args_p=*/false,
+ /*subr=*/0);
+
+ /* We cannot deduce in the other direction, because ARG2 is
+ a pack expansion but ARG1 is not.*/
+ deduce1 = 0;
+ }
+
+ else
+ {
+ /* The normal case, where neither argument is a pack
+ expansion. */
+ deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
+ deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+ }
if (!deduce1)
better2 = -1;
@@ -11171,12 +12880,31 @@ more_specialized_fn (tree pat1, tree pat2, int len)
if (deduce2 && !deduce1 && !better1)
better1 = 1;
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+ || TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ /* We have already processed all of the arguments in our
+ handing of the pack expansion type. */
+ len = 0;
+
args1 = TREE_CHAIN (args1);
args2 = TREE_CHAIN (args2);
}
processing_template_decl--;
+ /* All things being equal, if the next argument is a pack expansion
+ for one function but not for the other, prefer the
+ non-variadic function. */
+ if ((better1 > 0) - (better2 > 0) == 0
+ && args1 && TREE_VALUE (args1)
+ && args2 && TREE_VALUE (args2))
+ {
+ if (TREE_CODE (TREE_VALUE (args1)) == TYPE_PACK_EXPANSION)
+ return TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION ? 0 : -1;
+ else if (TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION)
+ return 1;
+ }
+
return (better1 > 0) - (better2 > 0);
}
@@ -11200,6 +12928,7 @@ more_specialized_class (tree pat1, tree pat2)
tree targs;
tree tmpl1, tmpl2;
int winner = 0;
+ bool any_deductions = false;
tmpl1 = TREE_TYPE (pat1);
tmpl2 = TREE_TYPE (pat2);
@@ -11213,15 +12942,46 @@ more_specialized_class (tree pat1, tree pat2)
CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs)
- --winner;
+ {
+ --winner;
+ any_deductions = true;
+ }
targs = get_class_bindings (TREE_VALUE (pat2),
CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs)
- ++winner;
+ {
+ ++winner;
+ any_deductions = true;
+ }
--processing_template_decl;
+ /* In the case of a tie where at least one of the class templates
+ has a parameter pack at the end, the template with the most
+ non-packed parameters wins. */
+ if (winner == 0
+ && any_deductions
+ && (template_args_variadic_p (TREE_PURPOSE (pat1))
+ || template_args_variadic_p (TREE_PURPOSE (pat2))))
+ {
+ tree args1 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat1));
+ tree args2 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat2));
+ int len1 = TREE_VEC_LENGTH (args1);
+ int len2 = TREE_VEC_LENGTH (args2);
+
+ /* We don't count the pack expansion at the end. */
+ if (template_args_variadic_p (TREE_PURPOSE (pat1)))
+ --len1;
+ if (template_args_variadic_p (TREE_PURPOSE (pat2)))
+ --len2;
+
+ if (len1 > len2)
+ return 1;
+ else if (len1 < len2)
+ return -1;
+ }
+
return winner;
}
@@ -11910,11 +13670,11 @@ regenerate_decl_from_template (tree decl, tree tmpl)
pattern_parm
= skip_artificial_parms_for (code_pattern,
DECL_ARGUMENTS (code_pattern));
- while (decl_parm)
+ while (decl_parm && !FUNCTION_PARAMETER_PACK_P (pattern_parm))
{
tree parm_type;
tree attributes;
-
+
if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
DECL_NAME (decl_parm) = DECL_NAME (pattern_parm);
parm_type = tsubst (TREE_TYPE (pattern_parm), args, tf_error,
@@ -11931,7 +13691,39 @@ regenerate_decl_from_template (tree decl, tree tmpl)
decl_parm = TREE_CHAIN (decl_parm);
pattern_parm = TREE_CHAIN (pattern_parm);
}
-
+ /* Merge any parameters that match with the function parameter
+ pack. */
+ if (pattern_parm && FUNCTION_PARAMETER_PACK_P (pattern_parm))
+ {
+ int i, len;
+ tree expanded_types;
+ /* Expand the TYPE_PACK_EXPANSION that provides the types for
+ the parameters in this function parameter pack. */
+ expanded_types = tsubst_pack_expansion (TREE_TYPE (pattern_parm),
+ args, tf_error, NULL_TREE);
+ len = TREE_VEC_LENGTH (expanded_types);
+ for (i = 0; i < len; i++)
+ {
+ tree parm_type;
+ tree attributes;
+
+ if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
+ /* Rename the parameter to include the index. */
+ DECL_NAME (decl_parm) =
+ make_ith_pack_parameter_name (DECL_NAME (pattern_parm), i);
+ parm_type = TREE_VEC_ELT (expanded_types, i);
+ parm_type = type_decays_to (parm_type);
+ if (!same_type_p (TREE_TYPE (decl_parm), parm_type))
+ TREE_TYPE (decl_parm) = parm_type;
+ attributes = DECL_ATTRIBUTES (pattern_parm);
+ if (DECL_ATTRIBUTES (decl_parm) != attributes)
+ {
+ DECL_ATTRIBUTES (decl_parm) = attributes;
+ cplus_decl_attributes (&decl_parm, attributes, /*flags=*/0);
+ }
+ decl_parm = TREE_CHAIN (decl_parm);
+ }
+ }
/* Merge additional specifiers from the CODE_PATTERN. */
if (DECL_DECLARED_INLINE_P (code_pattern)
&& !DECL_DECLARED_INLINE_P (decl))
@@ -12138,8 +13930,8 @@ instantiate_decl (tree d, int defer_ok,
if (TREE_CODE (gen) == FUNCTION_DECL)
{
tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
- tsubst (TYPE_RAISES_EXCEPTIONS (type), gen_args,
- tf_warning_or_error, d);
+ tsubst_exception_specification (type, gen_args, tf_warning_or_error,
+ d);
/* Don't simply tsubst the function type, as that will give
duplicate warnings about poor parameter qualifications.
The function arguments are the same as the decl_arguments
@@ -12314,12 +14106,46 @@ instantiate_decl (tree d, int defer_ok,
spec_parm = skip_artificial_parms_for (d, spec_parm);
tmpl_parm = skip_artificial_parms_for (subst_decl, tmpl_parm);
}
- while (tmpl_parm)
+ while (tmpl_parm && !FUNCTION_PARAMETER_PACK_P (tmpl_parm))
{
register_local_specialization (spec_parm, tmpl_parm);
tmpl_parm = TREE_CHAIN (tmpl_parm);
spec_parm = TREE_CHAIN (spec_parm);
}
+ if (tmpl_parm && FUNCTION_PARAMETER_PACK_P (tmpl_parm))
+ {
+ /* Collect all of the extra "packed" parameters into an
+ argument pack. */
+ tree parmvec;
+ tree parmtypevec;
+ tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+ tree argtypepack = make_node (TYPE_ARGUMENT_PACK);
+ int i, len = 0;
+ tree t;
+
+ /* Count how many parameters remain. */
+ for (t = spec_parm; t; t = TREE_CHAIN (t))
+ len++;
+
+ /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters. */
+ parmvec = make_tree_vec (len);
+ parmtypevec = make_tree_vec (len);
+ for(i = 0; i < len; i++, spec_parm = TREE_CHAIN (spec_parm))
+ {
+ TREE_VEC_ELT (parmvec, i) = spec_parm;
+ TREE_VEC_ELT (parmtypevec, i) = TREE_TYPE (spec_parm);
+ }
+
+ /* Build the argument packs. */
+ SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+ SET_ARGUMENT_PACK_ARGS (argtypepack, parmtypevec);
+ TREE_TYPE (argpack) = argtypepack;
+
+ /* Register the (value) argument pack as a specialization of
+ TMPL_PARM, then move on. */
+ register_local_specialization (argpack, tmpl_parm);
+ tmpl_parm = TREE_CHAIN (tmpl_parm);
+ }
gcc_assert (!spec_parm);
/* Substitute into the body of the function. */
@@ -12471,24 +14297,99 @@ tsubst_initializer_list (tree t, tree argvec)
{
tree decl;
tree init;
+ tree expanded_bases = NULL_TREE;
+ tree expanded_arguments = NULL_TREE;
+ int i, len = 1;
- decl = tsubst_copy (TREE_PURPOSE (t), argvec, tf_warning_or_error,
- NULL_TREE);
- decl = expand_member_init (decl);
- if (decl && !DECL_P (decl))
- in_base_initializer = 1;
-
- init = tsubst_expr (TREE_VALUE (t), argvec, tf_warning_or_error,
- NULL_TREE,
- /*integral_constant_expression_p=*/false);
- in_base_initializer = 0;
+ if (TREE_CODE (TREE_PURPOSE (t)) == TYPE_PACK_EXPANSION)
+ {
+ tree expr;
+ tree arg;
+
+ /* Expand the base class expansion type into separate base
+ classes. */
+ expanded_bases = tsubst_pack_expansion (TREE_PURPOSE (t), argvec,
+ tf_warning_or_error,
+ NULL_TREE);
+ if (expanded_bases == error_mark_node)
+ continue;
+
+ /* We'll be building separate TREE_LISTs of arguments for
+ each base. */
+ len = TREE_VEC_LENGTH (expanded_bases);
+ expanded_arguments = make_tree_vec (len);
+ for (i = 0; i < len; i++)
+ TREE_VEC_ELT (expanded_arguments, i) = NULL_TREE;
+
+ /* Build a dummy EXPR_PACK_EXPANSION that will be used to
+ expand each argument in the TREE_VALUE of t. */
+ expr = make_node (EXPR_PACK_EXPANSION);
+ PACK_EXPANSION_PARAMETER_PACKS (expr) =
+ PACK_EXPANSION_PARAMETER_PACKS (TREE_PURPOSE (t));
+
+ /* Substitute parameter packs into each argument in the
+ TREE_LIST. */
+ in_base_initializer = 1;
+ for (arg = TREE_VALUE (t); arg; arg = TREE_CHAIN (arg))
+ {
+ tree expanded_exprs;
+
+ /* Expand the argument. */
+ SET_PACK_EXPANSION_PATTERN (expr, TREE_VALUE (arg));
+ expanded_exprs = tsubst_pack_expansion (expr, argvec,
+ tf_warning_or_error,
+ NULL_TREE);
+
+ /* Prepend each of the expanded expressions to the
+ corresponding TREE_LIST in EXPANDED_ARGUMENTS. */
+ for (i = 0; i < len; i++)
+ {
+ TREE_VEC_ELT (expanded_arguments, i) =
+ tree_cons (NULL_TREE, TREE_VEC_ELT (expanded_exprs, i),
+ TREE_VEC_ELT (expanded_arguments, i));
+ }
+ }
+ in_base_initializer = 0;
+
+ /* Reverse all of the TREE_LISTs in EXPANDED_ARGUMENTS,
+ since we built them backwards. */
+ for (i = 0; i < len; i++)
+ {
+ TREE_VEC_ELT (expanded_arguments, i) =
+ nreverse (TREE_VEC_ELT (expanded_arguments, i));
+ }
+ }
- if (decl)
- {
- init = build_tree_list (decl, init);
- TREE_CHAIN (init) = inits;
- inits = init;
- }
+ for (i = 0; i < len; ++i)
+ {
+ if (expanded_bases)
+ {
+ decl = TREE_VEC_ELT (expanded_bases, i);
+ decl = expand_member_init (decl);
+ init = TREE_VEC_ELT (expanded_arguments, i);
+ }
+ else
+ {
+ decl = tsubst_copy (TREE_PURPOSE (t), argvec,
+ tf_warning_or_error, NULL_TREE);
+
+ decl = expand_member_init (decl);
+ if (decl && !DECL_P (decl))
+ in_base_initializer = 1;
+
+ init = tsubst_expr (TREE_VALUE (t), argvec,
+ tf_warning_or_error, NULL_TREE,
+ /*integral_constant_expression_p=*/false);
+ in_base_initializer = 0;
+ }
+
+ if (decl)
+ {
+ init = build_tree_list (decl, init);
+ TREE_CHAIN (init) = inits;
+ inits = init;
+ }
+ }
}
return inits;
}
@@ -12729,6 +14630,22 @@ dependent_type_p_r (tree type)
if (TREE_CODE (type) == TYPEOF_TYPE)
return true;
+ /* A template argument pack is dependent if any of its packed
+ arguments are. */
+ if (TREE_CODE (type) == TYPE_ARGUMENT_PACK)
+ {
+ tree args = ARGUMENT_PACK_ARGS (type);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; ++i)
+ if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+ return true;
+ }
+
+ /* All TYPE_PACK_EXPANSIONs are dependent, because parameter packs must
+ be template parameters. */
+ if (TREE_CODE (type) == TYPE_PACK_EXPANSION)
+ return true;
+
/* The standard does not specifically mention types that are local
to template functions or local classes, but they should be
considered dependent too. For example:
@@ -12900,9 +14817,11 @@ value_dependent_expression_p (tree expression)
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
/* A `sizeof' expression is value-dependent if the operand is
- type-dependent. */
+ type-dependent or is a pack expansion. */
expression = TREE_OPERAND (expression, 0);
- if (TYPE_P (expression))
+ if (PACK_EXPANSION_P (expression))
+ return true;
+ else if (TYPE_P (expression))
return dependent_type_p (expression);
return type_dependent_expression_p (expression);
@@ -12919,6 +14838,20 @@ value_dependent_expression_p (tree expression)
such calls are value-dependent. */
return true;
+ case NONTYPE_ARGUMENT_PACK:
+ /* A NONTYPE_ARGUMENT_PACK is value-dependent if any packed argument
+ is value-dependent. */
+ {
+ tree values = ARGUMENT_PACK_ARGS (expression);
+ int i, len = TREE_VEC_LENGTH (values);
+
+ for (i = 0; i < len; ++i)
+ if (value_dependent_expression_p (TREE_VEC_ELT (values, i)))
+ return true;
+
+ return false;
+ }
+
default:
/* A constant expression is value-dependent if any subexpression is
value-dependent. */
@@ -13095,7 +15028,7 @@ any_type_dependent_arguments_p (tree args)
/* Returns TRUE if the ARG (a template argument) is dependent. */
-static bool
+bool
dependent_template_arg_p (tree arg)
{
if (!processing_template_decl)
@@ -13104,6 +15037,18 @@ dependent_template_arg_p (tree arg)
if (TREE_CODE (arg) == TEMPLATE_DECL
|| TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
return dependent_template_p (arg);
+ else if (ARGUMENT_PACK_P (arg))
+ {
+ tree args = ARGUMENT_PACK_ARGS (arg);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; ++i)
+ {
+ if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+ return true;
+ }
+
+ return false;
+ }
else if (TYPE_P (arg))
return dependent_type_p (arg);
else
@@ -13131,16 +15076,32 @@ any_template_arguments_need_structural_equality_p (tree args)
for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
{
tree arg = TREE_VEC_ELT (level, j);
- if (error_operand_p (arg))
- return true;
- else if (TREE_CODE (arg) == TEMPLATE_DECL
- || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
- continue;
- else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
- return true;
- else if (!TYPE_P (arg) && TREE_TYPE (arg)
- && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
- return true;
+ tree packed_args = NULL_TREE;
+ int k, len = 1;
+
+ if (ARGUMENT_PACK_P (arg))
+ {
+ /* Look inside the argument pack. */
+ packed_args = ARGUMENT_PACK_ARGS (arg);
+ len = TREE_VEC_LENGTH (packed_args);
+ }
+
+ for (k = 0; k < len; ++k)
+ {
+ if (packed_args)
+ arg = TREE_VEC_ELT (packed_args, k);
+
+ if (error_operand_p (arg))
+ return true;
+ else if (TREE_CODE (arg) == TEMPLATE_DECL
+ || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ continue;
+ else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
+ return true;
+ else if (!TYPE_P (arg) && TREE_TYPE (arg)
+ && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
+ return true;
+ }
}
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 30f4214e5db..f63ed2f47f7 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -509,6 +509,8 @@ finish_cond (tree *cond_p, tree expr)
tree cond = pop_stmt_list (*cond_p);
if (TREE_CODE (cond) == DECL_EXPR)
expr = cond;
+
+ check_for_bare_parameter_packs (expr);
}
*cond_p = expr;
}
@@ -618,6 +620,8 @@ finish_expr_stmt (tree expr)
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "statement");
+ check_for_bare_parameter_packs (expr);
+
/* Simplification of inner statement expressions, compound exprs,
etc can result in us already having an EXPR_STMT. */
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
@@ -866,6 +870,7 @@ finish_for_expr (tree expr, tree for_stmt)
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
expr = maybe_cleanup_point_expr_void (expr);
+ check_for_bare_parameter_packs (expr);
FOR_EXPR (for_stmt) = expr;
}
@@ -966,6 +971,7 @@ finish_switch_cond (tree cond, tree switch_stmt)
add_stmt (switch_stmt);
push_switch (switch_stmt);
SWITCH_STMT_BODY (switch_stmt) = push_stmt_list ();
+ check_for_bare_parameter_packs (cond);
}
/* Finish the body of a switch-statement, which may be given by
@@ -1362,7 +1368,22 @@ finish_mem_initializers (tree mem_inits)
mem_inits = nreverse (mem_inits);
if (processing_template_decl)
- add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+ {
+ tree mem;
+
+ for (mem = mem_inits; mem; mem = TREE_CHAIN (mem))
+ {
+ /* If the TREE_PURPOSE is a TYPE_PACK_EXPANSION, skip the
+ check for bare parameter packs in the TREE_VALUE, because
+ any parameter packs in the TREE_VALUE have already been
+ bound as part of the TREE_PURPOSE. See
+ make_pack_expansion for more information. */
+ if (TREE_CODE (TREE_PURPOSE (mem)) != TYPE_PACK_EXPANSION)
+ check_for_bare_parameter_packs (TREE_VALUE (mem));
+ }
+
+ add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+ }
else
emit_mem_initializers (mem_inits);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b7e1d0f7dcc..d334a689e29 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2233,12 +2233,16 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
case TEMPLATE_TYPE_PARM:
case TYPENAME_TYPE:
case TYPEOF_TYPE:
- case BASELINK:
/* None of these have subtrees other than those already walked
above. */
*walk_subtrees_p = 0;
break;
+ case BASELINK:
+ WALK_SUBTREE (BASELINK_FUNCTIONS (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
case TINST_LEVEL:
WALK_SUBTREE (TINST_DECL (*tp));
*walk_subtrees_p = 0;
@@ -2264,6 +2268,38 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree args = ARGUMENT_PACK_ARGS (*tp);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; i++)
+ WALK_SUBTREE (TREE_VEC_ELT (args, i));
+ }
+ break;
+
+ case TYPE_PACK_EXPANSION:
+ WALK_SUBTREE (TREE_TYPE (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
+ case EXPR_PACK_EXPANSION:
+ WALK_SUBTREE (TREE_OPERAND (*tp, 0));
+ *walk_subtrees_p = 0;
+ break;
+
+ case CAST_EXPR:
+ if (TREE_TYPE (*tp))
+ WALK_SUBTREE (TREE_TYPE (*tp));
+
+ {
+ int i;
+ for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (*tp)); ++i)
+ WALK_SUBTREE (TREE_OPERAND (*tp, i));
+ }
+ *walk_subtrees_p = 0;
+ break;
+
default:
input_location = save_locus;
return NULL_TREE;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 404117ce016..c774671ef0d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -991,7 +991,9 @@ structural_comptypes (tree t1, tree t2, int strict)
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
- || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+ || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+ || (TEMPLATE_TYPE_PARAMETER_PACK (t1)
+ != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
return false;
if (!comp_template_parms
(DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
@@ -1050,7 +1052,9 @@ structural_comptypes (tree t1, tree t2, int strict)
case TEMPLATE_TYPE_PARM:
if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
- || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+ || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+ || (TEMPLATE_TYPE_PARAMETER_PACK (t1)
+ != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
return false;
break;
@@ -1080,6 +1084,10 @@ structural_comptypes (tree t1, tree t2, int strict)
return false;
break;
+ case TYPE_PACK_EXPANSION:
+ return same_type_p (PACK_EXPANSION_PATTERN (t1),
+ PACK_EXPANSION_PATTERN (t2));
+
default:
return false;
}
@@ -6543,6 +6551,7 @@ check_return_expr (tree retval, bool *no_warning)
if (processing_template_decl)
{
current_function_returns_value = 1;
+ check_for_bare_parameter_packs (retval);
return retval;
}