Index: gcc/testsuite/g++.dg/template/variadic69.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic69.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic69.C (revision 425) @@ -0,0 +1,33 @@ +template +struct stored_value +{ + explicit stored_value() : value() { } + + explicit stored_value(const T& value) : value(value) { } + + stored_value(int, const T& value) : value(value) { } + + T value; +}; + +template +struct myclass : public stored_value... +{ + myclass() { } + + explicit myclass(const Values&... values) + : stored_value(values)... { } + + explicit myclass(int x, const Values&... values) + : stored_value(x, values)... { } + +}; + +void f() +{ + int i; + float f; + myclass ifp1; + myclass ifp2(&i, &f); + myclass ifp3(1, &i, &f); +} Index: gcc/testsuite/g++.dg/template/variadic60.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic60.C (revision 414) +++ gcc/testsuite/g++.dg/template/variadic60.C (revision 425) @@ -7,7 +7,7 @@ template struct _Build_index_tuple<_Num, _Index_tuple<_Indexes...> > : _Build_index_tuple<_Num - 1, - _Index_tuple<_Indexes..., sizeof(_Indexes...)> > + _Index_tuple<_Indexes..., sizeof...(_Indexes)> > { }; Index: gcc/testsuite/g++.dg/template/variadic37.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic37.C (revision 414) +++ gcc/testsuite/g++.dg/template/variadic37.C (revision 425) @@ -1,7 +1,7 @@ template struct tuple { - static const __SIZE_TYPE__ length = sizeof(Values...); + static const __SIZE_TYPE__ length = sizeof...(Values); }; int a0[tuple<>::length == 0? 1 : -1]; Index: gcc/testsuite/g++.dg/template/variadic64.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic64.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic64.C (revision 425) @@ -0,0 +1,21 @@ +// { dg-do "run" } +template struct bomb; + +template +struct bomb { + static const T value = 0; +}; + +template +struct bomb { + static const T value = v + bomb::value; +}; + +extern "C" void abort(); + +int main() { + bomb b; + if (b.value != 10) + abort(); + return 0; +} Index: gcc/testsuite/g++.dg/template/variadic65.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic65.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic65.C (revision 425) @@ -0,0 +1,11 @@ +template struct list {}; + +template +struct push_front; + +template +struct push_front, Head> { + typedef list type; // { dg-error "parameter packs not unpacked" } +}; + +// { dg-error "Elements" "" { target *-*-* } 8 } Index: gcc/testsuite/g++.dg/template/variadic66.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic66.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic66.C (revision 425) @@ -0,0 +1,20 @@ +struct A {}; +struct B {}; +struct C {}; + +template +struct mixed_up : public Mixins... +{ +}; + +void fA(A); +void fB(B); +void fC(C); + +void g() +{ + mixed_up m; + fA(m); + fB(m); + fC(m); +} Index: gcc/testsuite/g++.dg/template/variadic67.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic67.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic67.C (revision 425) @@ -0,0 +1,32 @@ +// { dg-do "run" } +struct A {}; +struct B {}; +struct C {}; + +template void f(int idx) throw(Exceptions...) { + if (idx == 0) throw A(); + else if (idx == 1) throw B(); + else if (idx == 2) throw C(); +} + +extern "C" void abort(); + +int main() +{ + try { + f(0); + abort(); + } catch (A) { + } + try { + f(1); + abort(); + } catch (B) { + } + try { + f(2); + abort(); + } catch (C) { + } + return 0; +} Index: gcc/testsuite/g++.dg/template/variadic68.C =================================================================== --- gcc/testsuite/g++.dg/template/variadic68.C (revision 0) +++ gcc/testsuite/g++.dg/template/variadic68.C (revision 425) @@ -0,0 +1,23 @@ +// { dg-do "run" } + +extern "C" void abort(); + +template +void f(T* expected_values, int n) +{ + if (sizeof...(Values) != n) + abort (); + + T values[] = { Values... }; + for (int i = 0; i < n; ++i) + if (values[i] != expected_values[i]) + abort(); +} + +int main() +{ + int test_arr1[3] = { 1, 2, 3 }; + f(test_arr1, 3); + + return 0; +} Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 414) +++ gcc/cp/decl.c (revision 425) @@ -9617,6 +9617,8 @@ if (access == access_default_node) access = default_access; + if (PACK_UNPACK_P (basetype)) + basetype = PACK_UNPACK_PATTERN (basetype); if (TREE_CODE (basetype) == TYPE_DECL) basetype = TREE_TYPE (basetype); if (TREE_CODE (basetype) != RECORD_TYPE @@ -9662,6 +9664,11 @@ error ("duplicate base type %qT invalid", basetype); continue; } + + if (PACK_UNPACK_P (TREE_VALUE (base_list))) + /* Regenerate the pack/unpack type for the bases. */ + basetype = make_argument_pack_unpack (basetype); + TYPE_MARKED_P (basetype) = 1; base_binfo = copy_binfo (base_binfo, basetype, ref, Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 414) +++ gcc/cp/pt.c (revision 425) @@ -166,6 +166,7 @@ static tree tsubst (tree, tree, tsubst_flags_t, tree); static tree tsubst_expr (tree, tree, tsubst_flags_t, tree); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); +static tree tsubst_argument_pack (tree, tree, tsubst_flags_t, tree); static tree make_ith_pack_parameter_name (tree, int); /* Make the current scope suitable for access checking when we are @@ -2438,6 +2439,48 @@ 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. */ + 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 = ¶meter_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; + } + + /* 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/unpack type for the base type. */ + purpose = make_node (PACK_UNPACK_TYPE); + SET_PACK_UNPACK_PATTERN (purpose, TREE_PURPOSE (arg)); + PACK_UNPACK_PARAMETER_PACKS (purpose) = parameter_packs; + + return tree_cons (purpose, TREE_VALUE (arg), NULL_TREE); + } + if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL) for_types = true; @@ -3459,11 +3502,9 @@ check_default_tmpl_args (decl, current_template_parms, primary, is_partial); - /* If this is a function template, ensure that there are no - parameter packs in the types of the parameters (or the return - type) that have not been unpacked. */ - if (TREE_CODE (decl) == FUNCTION_DECL) - check_for_bare_parameter_packs (TREE_TYPE (decl)); + /* Ensure that there are no parameter packs in the type of this + declaration that have not been unpacked. */ + check_for_bare_parameter_packs (TREE_TYPE (decl)); if (is_partial) return process_partial_specialization (decl); @@ -6215,15 +6256,36 @@ { tree base; tree access = BINFO_BASE_ACCESS (pbinfo, i); + tree expanded_bases = NULL_TREE; + int idx, len = 1; - /* Substitute to figure out the base class. */ - base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error, NULL_TREE); - if (base == error_mark_node) - continue; + if (PACK_UNPACK_P (BINFO_TYPE (pbase_binfo))) + { + expanded_bases = tsubst_argument_pack (BINFO_TYPE (pbase_binfo), + args, tf_error, NULL_TREE); + if (expanded_bases == 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; + 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. */ @@ -6567,7 +6629,7 @@ with the substituted arguments, a PACK_UNPACK_* node (if only a partial substitution could be performed) or ERROR_MARK_NODE if there was an error. */ -static tree +tree tsubst_argument_pack (tree t, tree args, tsubst_flags_t complain, tree in_decl) { tree pattern; @@ -6728,7 +6790,7 @@ } /* Substitute into the PATTERN with the altered arguments. */ - if (EXPR_P (pattern)) + if (TREE_CODE (t) == PACK_UNPACK_EXPR) TREE_VEC_ELT (result, i) = tsubst_expr (pattern, args, complain, in_decl); else TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl); @@ -7929,11 +7991,31 @@ 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 unpacked_specs = NULL_TREE; + + if (PACK_UNPACK_P (TREE_VALUE (specs))) + { + /* Expand the pack/unpack type. */ + unpacked_specs = tsubst_argument_pack (TREE_VALUE (specs), + args, complain, + in_decl); + len = TREE_VEC_LENGTH (unpacked_specs); + } + + for (i = 0; i < len; ++i) + { + if (unpacked_specs) + spec = TREE_VEC_ELT (unpacked_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; @@ -10064,6 +10146,8 @@ tree r; tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); bool process_index_p; + int newlen; + bool need_copy_p = false; /* digest_init will do the wrong thing if we let it. */ if (type && TYPE_PTRMEMFUNC_P (type)) @@ -10075,13 +10159,54 @@ 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_UNPACK_P (ce->value)) + { + /* Substitute into the pack/unpack expression. */ + ce->value = tsubst_argument_pack (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); + } + } + r = build_constructor (NULL_TREE, n); TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t); @@ -13294,8 +13419,8 @@ if (TREE_CODE (gen) == FUNCTION_DECL) { tsubst (DECL_ARGUMENTS (gen), gen_args, tf_error | tf_warning, d); - tsubst (TYPE_RAISES_EXCEPTIONS (type), gen_args, - tf_error | tf_warning, d); + tsubst_exception_specification (type, gen_args, + tf_error | tf_warning, 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 @@ -13651,23 +13776,98 @@ { 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_error | tf_warning, - NULL_TREE); - decl = expand_member_init (decl); - if (decl && !DECL_P (decl)) - in_base_initializer = 1; + if (TREE_CODE (TREE_PURPOSE (t)) == PACK_UNPACK_TYPE) + { + tree expr; + tree arg; - init = tsubst_expr (TREE_VALUE (t), argvec, tf_error | tf_warning, - NULL_TREE); - in_base_initializer = 0; + /* Expand the base class unpack type into separate base + classes. */ + expanded_bases = tsubst_argument_pack (TREE_PURPOSE (t), argvec, + tf_error | tf_warning, + 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; - if (decl) - { - init = build_tree_list (decl, init); - TREE_CHAIN (init) = inits; - inits = init; - } + /* Build a dummy PACK_UNPACK_EXPR that will be used to + unpack each argument in the TREE_VALUE of t. */ + expr = make_node (PACK_UNPACK_EXPR); + PACK_UNPACK_PARAMETER_PACKS (expr) = + PACK_UNPACK_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_UNPACK_PATTERN (expr, TREE_VALUE (arg)); + expanded_exprs = tsubst_argument_pack (expr, argvec, + tf_error | tf_warning, + 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)); + } + } + + 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_error | tf_warning, NULL_TREE); + + decl = expand_member_init (decl); + if (decl && !DECL_P (decl)) + in_base_initializer = 1; + + init = tsubst_expr (TREE_VALUE (t), argvec, tf_error | tf_warning, + NULL_TREE); + in_base_initializer = 0; + } + + if (decl) + { + init = build_tree_list (decl, init); + TREE_CHAIN (init) = inits; + inits = init; + } + } } return inits; } @@ -14328,6 +14528,18 @@ 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 Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 414) +++ gcc/cp/semantics.c (revision 425) @@ -1339,7 +1339,14 @@ tree mem; for (mem = mem_inits; mem; mem = TREE_CHAIN (mem)) - check_for_bare_parameter_packs (TREE_VALUE (mem)); + { + /* If the TREE_PURPOSE is a PACK_UNPACK_TYPE, skip the check + for bare parameter packs in the TREE_VALUE because it may + contain parameter packs that are stated in the + TREE_PURPOSE. */ + if (TREE_CODE (TREE_PURPOSE (mem)) != PACK_UNPACK_TYPE) + check_for_bare_parameter_packs (TREE_VALUE (mem)); + } add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits)); } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 414) +++ gcc/cp/parser.c (revision 425) @@ -7895,8 +7895,8 @@ /* 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) @@ -7915,6 +7915,27 @@ /* Parse the mem-initializer. */ mem_initializer = cp_parser_mem_initializer (parser); + /* If the next token is a `...', we're expanding member initializers. */ + if (flag_variadic_templates + && 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/unpack type. */ + if (mem_initializer != error_mark_node) + mem_initializer = make_argument_pack_unpack (mem_initializer); + } /* Add it to the list, unless it was erroneous. */ if (mem_initializer != error_mark_node) { @@ -12742,8 +12763,8 @@ /* Parse an initializer-list. initializer-list: - initializer-clause - initializer-list , initializer-clause + initializer-clause ... [opt] + initializer-list , initializer-clause ... [opt] GNU Extension: @@ -12794,6 +12815,17 @@ if (clause_non_constant_p) *non_constant_p = true; + /* If we have an ellipsis, this is an initialize pack/unpack. */ + if (flag_variadic_templates + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + + /* Turn the initializer into an initializer unpack expression. */ + initializer = make_argument_pack_unpack (initializer); + } + /* Add it to the vector. */ CONSTRUCTOR_APPEND_ELT(v, identifier, initializer); @@ -14054,8 +14086,8 @@ : 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 @@ -14077,12 +14109,29 @@ { cp_token *token; tree base; + bool variadic_unpack_p = false; /* Look for the base-specifier. */ base = cp_parser_base_specifier (parser); + /* Look for the (optional) ellipsis. */ + if (flag_variadic_templates + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + + variadic_unpack_p = true; + } + /* Add BASE to the front of the list. */ if (base != error_mark_node) { + if (variadic_unpack_p) + /* Make this a pack/unpack type. */ + TREE_VALUE (base) = make_argument_pack_unpack (TREE_VALUE (base)); + else + check_for_bare_parameter_packs (TREE_VALUE (base)); + TREE_CHAIN (base) = bases; bases = base; } @@ -14229,8 +14278,6 @@ if (type == error_mark_node) return error_mark_node; - check_for_bare_parameter_packs (type); - return finish_base_specifier (TREE_TYPE (type), access, virtual_p); } @@ -14290,8 +14337,8 @@ /* 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. */ @@ -14308,6 +14355,16 @@ /* Get the next type-id. */ type = cp_parser_type_id (parser); + /* Parse the optional ellipsis. */ + if (flag_variadic_templates + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + + /* Turn the type into a pack/unpack expression. */ + type = make_argument_pack_unpack (type); + } /* Add it to the list. */ types = add_exception_specifier (types, type, /*complain=*/1); /* Peek at the next token. */ @@ -16154,6 +16211,7 @@ bool saved_integral_constant_expression_p; bool saved_non_integral_constant_expression_p; bool variadic_unpack_p = false; + bool deprecated_unpack_syntax_p = false; /* Initialize FORMAT the first time we get here. */ if (!format) @@ -16178,6 +16236,18 @@ = 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 (flag_variadic_templates && keyword == RID_SIZEOF + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + + /* Note that we'll be unpacking. */ + variadic_unpack_p = true; + } + /* Do not actually evaluate the expression. */ ++skip_evaluation; /* If it's a `(', then we might be looking at the type-id @@ -16205,7 +16275,9 @@ /* Consume the `...' */ cp_lexer_consume_token (parser->lexer); + /* This is unpacking using the deprecated syntax. */ variadic_unpack_p = true; + deprecated_unpack_syntax_p = true; } /* Now, look for the trailing `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, "%<)%>"); @@ -16224,10 +16296,6 @@ TYPENAME, /*initialized=*/0, /*attrlist=*/NULL); - - if (variadic_unpack_p) - /* Build a pack/unpack expression. */ - expr = make_argument_pack_unpack (expr); } } @@ -16257,8 +16325,9 @@ /* Consume the `...' */ cp_lexer_consume_token (parser->lexer); - /* Build a pack/unpack expression. */ - expr = make_argument_pack_unpack (expr); + /* This is unpacking using the deprecated syntax. */ + variadic_unpack_p = true; + deprecated_unpack_syntax_p = true; } /* Now, look for the trailing `)'. */ @@ -16270,9 +16339,24 @@ if (!expr) expr = cp_parser_unary_expression (parser, /*address_p=*/false, /*cast_p=*/false); + + if (variadic_unpack_p) + /* Build a pack/unpack expression. */ + expr = make_argument_pack_unpack (expr); + /* Go back to evaluating expressions. */ --skip_evaluation; + if (deprecated_unpack_syntax_p) + { + if (TYPE_P (expr)) + warning (0, "the syntax % is deprecated; please use % is deprecated; please use %type_definition_forbidden_message); /* And restore the old one. */