diff options
author | Douglas Gregor <doug.gregor@gmail.com> | 2007-05-25 13:15:04 +0000 |
---|---|---|
committer | Doug Gregor <dgregor@gcc.gnu.org> | 2007-05-25 13:15:04 +0000 |
commit | b1d7b1c00e10e3550b2b1bfc91168679463e457f (patch) | |
tree | 626e35a9a9d851c0a1a037eb6349540dc9831f0e | |
parent | 77315816df628ed27788142071b54e0f31752313 (diff) | |
download | gcc-b1d7b1c00e10e3550b2b1bfc91168679463e457f.zip gcc-b1d7b1c00e10e3550b2b1bfc91168679463e457f.tar.gz gcc-b1d7b1c00e10e3550b2b1bfc91168679463e457f.tar.bz2 |
re PR c++/31431 (ICE with invalid parameter pack)
2007-05-25 Douglas Gregor <doug.gregor@gmail.com>
PR c++/31431
PR c++/31432
PR c++/31434
PR c++/31435
PR c++/31437
PR c++/31438
PR c++/31442
PR c++/31443
PR c++/31444
PR c++/31445
* error.c (dump_type): Dump TYPE_ARGUMENT_PACK nodes.
* cp-tree.h (check_for_bare_parameter_packs): Returns bool.
* pt.c (check_for_bare_parameter_packs): Return bool indicated
whether everything was okay. Fix indentation.
(push_template_decl_real): Check for bare parameter packs in
function parameters; where errors occur, mark the parameter types
with ERROR_MARK_NODEs to avert ICEs.
(coerce_template_parameter_pack): New.
(coerce_template_parms): Moved parameter pack coercion into
coerce_template_parameter_pack, and permit it anywhere in the
template parameter list (not just at the end). Parameter and
argument indices can vary (somewhat) separately now, so add
PARM_IDX and ARG_IDX.
(fn_type_unification): Don't set an argument pack as incomplete if
no argument pack was deduced.
(type_unification_real): If a type parameter is a parameter pack
and has not otherwise been deduced, it will be deduced to an empty
parameter pack.
(more_specialized_fn): Use the actual lengths of the argument
lists when comparing against expansions.
* semantics.c (finish_member_declaration): If a field's type has
bare parameter packs, error and set its type to ERROR_MARK_NODE.
2007-05-25 Douglas Gregor <doug.gregor@gmail.com>
PR c++/31431
PR c++/31432
PR c++/31434
PR c++/31435
PR c++/31437
PR c++/31438
PR c++/31442
PR c++/31443
PR c++/31444
PR c++/31445
* g++.dg/cpp0x/pr31431.C: New.
* g++.dg/cpp0x/pr31437.C: New.
* g++.dg/cpp0x/pr31442.C: New.
* g++.dg/cpp0x/pr31444.C: New.
* g++.dg/cpp0x/pr31431-2.C: New.
* g++.dg/cpp0x/pr31432.C: New.
* g++.dg/cpp0x/pr31434.C: New.
* g++.dg/cpp0x/pr31438.C: New.
* g++.dg/cpp0x/pr31443.C: New.
* g++.dg/cpp0x/pr31445.C: New.
* g++.dg/cpp0x/variadic-crash1.C: New.
From-SVN: r125062
-rw-r--r-- | gcc/cp/ChangeLog | 35 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/error.c | 13 | ||||
-rw-r--r-- | gcc/cp/pt.c | 428 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31431-2.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31431.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31432.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31434.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31437.C | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31438.C | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31442.C | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31443.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31444.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr31445.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C | 72 |
17 files changed, 510 insertions, 158 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7738d1f..f2c6b6a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +2007-05-25 Douglas Gregor <doug.gregor@gmail.com> + + PR c++/31431 + PR c++/31432 + PR c++/31434 + PR c++/31435 + PR c++/31437 + PR c++/31438 + PR c++/31442 + PR c++/31443 + PR c++/31444 + PR c++/31445 + * error.c (dump_type): Dump TYPE_ARGUMENT_PACK nodes. + * cp-tree.h (check_for_bare_parameter_packs): Returns bool. + * pt.c (check_for_bare_parameter_packs): Return bool indicated + whether everything was okay. Fix indentation. + (push_template_decl_real): Check for bare parameter packs in + function parameters; where errors occur, mark the parameter types + with ERROR_MARK_NODEs to avert ICEs. + (coerce_template_parameter_pack): New. + (coerce_template_parms): Moved parameter pack coercion into + coerce_template_parameter_pack, and permit it anywhere in the + template parameter list (not just at the end). Parameter and + argument indices can vary (somewhat) separately now, so add + PARM_IDX and ARG_IDX. + (fn_type_unification): Don't set an argument pack as incomplete if + no argument pack was deduced. + (type_unification_real): If a type parameter is a parameter pack + and has not otherwise been deduced, it will be deduced to an empty + parameter pack. + (more_specialized_fn): Use the actual lengths of the argument + lists when comparing against expansions. + * semantics.c (finish_member_declaration): If a field's type has + bare parameter packs, error and set its type to ERROR_MARK_NODE. + 2007-05-24 Danny Smith <dannysmith@users.sourceforge.net> PR target/27067 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index df067c9..413b224 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4393,7 +4393,7 @@ 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 bool 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/error.c b/gcc/cp/error.c index 7329109..fcc7b08 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -395,6 +395,19 @@ dump_type (tree t, int flags) pp_cxx_identifier (cxx_pp, "..."); break; + case TYPE_ARGUMENT_PACK: + { + tree args = ARGUMENT_PACK_ARGS (t); + int i; + for (i = 0; i < TREE_VEC_LENGTH (args); ++i) + { + if (i) + pp_separate_with_comma (cxx_pp); + dump_type (TREE_VEC_ELT (args, i), flags); + } + } + break; + default: pp_unsupported_tree (cxx_pp, t); /* Fall through to error. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 05d7752..584e6cf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2599,15 +2599,18 @@ make_pack_expansion (tree arg) 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 + error messages. + + Returns TRUE if there were no bare parameter packs, returns FALSE + (and emits an error) if there were bare parameter packs.*/ +bool 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; + return true; if (TREE_CODE (t) == TYPE_DECL) t = TREE_TYPE (t); @@ -2617,25 +2620,30 @@ check_for_bare_parameter_packs (tree t) walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited); pointer_set_destroy (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 if (TREE_CODE (pack) == TEMPLATE_PARM_INDEX) - name = DECL_NAME (TEMPLATE_PARM_DECL (pack)); - else - name = DECL_NAME (pack); - inform (" %qD", name); - - parameter_packs = TREE_CHAIN (parameter_packs); - } - } + 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 if (TREE_CODE (pack) == TEMPLATE_PARM_INDEX) + name = DECL_NAME (TEMPLATE_PARM_DECL (pack)); + else + name = DECL_NAME (pack); + inform (" %qD", name); + + parameter_packs = TREE_CHAIN (parameter_packs); + } + + return false; + } + + return true; } /* Expand any parameter packs that occur in the template arguments in @@ -3376,7 +3384,7 @@ process_partial_specialization (tree decl) DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = tree_cons (specargs, inner_parms, - DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)); + DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)); TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type; return decl; } @@ -3692,7 +3700,38 @@ push_template_decl_real (tree decl, bool is_friend) /* 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 (TREE_CODE (decl) == FUNCTION_DECL) + { + /* Check each of the arguments individually to see if there are + any bare parameter packs. */ + tree type = TREE_TYPE (decl); + tree arg = DECL_ARGUMENTS (decl); + tree argtype = TYPE_ARG_TYPES (type); + + while (arg && argtype) + { + if (!FUNCTION_PARAMETER_PACK_P (arg) + && !check_for_bare_parameter_packs (TREE_TYPE (arg))) + { + /* This is a PARM_DECL that contains unexpanded parameter + packs. We have already complained about this in the + check_for_bare_parameter_packs call, so just replace + these types with ERROR_MARK_NODE. */ + TREE_TYPE (arg) = error_mark_node; + TREE_VALUE (argtype) = error_mark_node; + } + + arg = TREE_CHAIN (arg); + argtype = TREE_CHAIN (argtype); + } + + /* Check for bare parameter packs in the return type and the + exception specifiers. */ + check_for_bare_parameter_packs (TREE_TYPE (type)); + check_for_bare_parameter_packs (TYPE_RAISES_EXCEPTIONS (type)); + } + else + check_for_bare_parameter_packs (TREE_TYPE (decl)); if (is_partial) return process_partial_specialization (decl); @@ -4740,6 +4779,121 @@ convert_template_argument (tree parm, return val; } +/* Coerces the remaining template arguments in INNER_ARGS (from + ARG_IDX to the end) into the parameter pack at PARM_IDX in PARMS. + Returns the coerced argument pack. PARM_IDX is the position of this + parameter in the template parameter list. ARGS is the original + template argument list. */ +static tree +coerce_template_parameter_pack (tree parms, + int parm_idx, + tree args, + tree inner_args, + int arg_idx, + tree new_args, + int* lost, + tree in_decl, + tsubst_flags_t complain) +{ + tree parm = TREE_VEC_ELT (parms, parm_idx); + int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0; + tree packed_args; + tree argument_pack; + tree packed_types = NULL_TREE; + + if (arg_idx > nargs) + arg_idx = nargs; + + packed_args = make_tree_vec (nargs - arg_idx); + + 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 (arg_idx < nargs + && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx)) + && nargs - arg_idx != TREE_VEC_LENGTH (packed_types)) + { + int needed_parms + = TREE_VEC_LENGTH (parms) - 1 + TREE_VEC_LENGTH (packed_types); + error ("wrong number of template arguments (%d, should be %d)", + nargs, needed_parms); + 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 (arg_idx < nargs + && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx))) + { + 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 (; arg_idx < nargs; ++arg_idx) + { + tree arg = TREE_VEC_ELT (inner_args, arg_idx); + 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, arg_idx - parm_idx); + } + + arg = convert_template_argument (actual_parm, + arg, new_args, complain, parm_idx, + in_decl); + if (arg == error_mark_node) + (*lost)++; + TREE_VEC_ELT (packed_args, arg_idx - parm_idx) = 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); + return argument_pack; +} + /* Convert all template arguments to their appropriate types, and return a vector containing the innermost resulting template arguments. If any error occurs, return error_mark_node. Error and @@ -4760,7 +4914,7 @@ coerce_template_parms (tree parms, bool require_all_args, bool use_default_args) { - int nparms, nargs, i, lost = 0; + int nparms, nargs, parm_idx, arg_idx, lost = 0; tree inner_args; tree new_args; tree new_inner_args; @@ -4770,7 +4924,7 @@ coerce_template_parms (tree parms, 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; + int variadic_p = 0; inner_args = expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args)); @@ -4778,6 +4932,17 @@ coerce_template_parms (tree parms, nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0; nparms = TREE_VEC_LENGTH (parms); + /* Determine if there are any parameter packs. */ + for (parm_idx = 0; parm_idx < nparms; ++parm_idx) + { + tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx)); + if (template_parameter_pack_p (tparm)) + { + variadic_p = 1; + break; + } + } + if ((nargs > nparms - variadic_p && !variadic_p) || (nargs < nparms - variadic_p && require_all_args @@ -4810,164 +4975,88 @@ 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 - variadic_p; i++) + for (parm_idx = 0, arg_idx = 0; parm_idx < nparms; parm_idx++, arg_idx++) { tree arg; tree parm; /* Get the Ith template parameter. */ - parm = TREE_VEC_ELT (parms, i); + parm = TREE_VEC_ELT (parms, parm_idx); if (parm == error_mark_node) { - TREE_VEC_ELT (new_inner_args, i) = error_mark_node; + TREE_VEC_ELT (new_inner_args, arg_idx) = error_mark_node; continue; } - /* Calculate the Ith argument. */ - if (i < nargs) + /* Calculate the next argument. */ + if (template_parameter_pack_p (TREE_VALUE (parm))) { - arg = TREE_VEC_ELT (inner_args, i); - - if (PACK_EXPANSION_P (arg)) + /* All remaining arguments will be placed in the + template parameter pack PARM. */ + arg = coerce_template_parameter_pack (parms, parm_idx, args, + inner_args, arg_idx, + new_args, &lost, + in_decl, complain); + + /* Store this argument. */ + if (arg == error_mark_node) + lost++; + TREE_VEC_ELT (new_inner_args, parm_idx) = arg; + + /* We are done with all of the arguments. */ + arg_idx = nargs; + + continue; + } + else if (arg_idx < nargs) + { + arg = TREE_VEC_ELT (inner_args, arg_idx); + + if (arg && PACK_EXPANSION_P (arg)) { - /* If ARG is a pack expansion, then PARM must be - a template parameter pack. We can't expand into a + /* If ARG is a pack expansion, but PARM is not a + template parameter pack (if it were, we would have + handled it above), we're trying to 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); - } + 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, - complain, in_decl); + /* There must be a default arg in this case. */ + arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args, + complain, in_decl); else break; - gcc_assert (arg); if (arg == error_mark_node) { if (complain & tf_error) - error ("template argument %d is invalid", i + 1); - } + error ("template argument %d is invalid", arg_idx + 1); + } + else if (!arg) + /* This only occurs if there was an error in the template + parameter list itself (which we would already have + reported) that we are trying to recover from, e.g., a class + template with a parameter list such as + template<typename..., typename>. */ + return error_mark_node; else arg = convert_template_argument (TREE_VALUE (parm), - arg, new_args, complain, i, - in_decl); + arg, new_args, complain, + parm_idx, in_decl); if (arg == error_mark_node) lost++; - TREE_VEC_ELT (new_inner_args, i) = arg; + TREE_VEC_ELT (new_inner_args, arg_idx) = arg; } 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; @@ -11055,8 +11144,12 @@ fn_type_unification (tree fn, /* 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); + if (targ) + { + 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; @@ -11425,6 +11518,27 @@ type_unification_real (tree tparms, } } + /* If the type parameter is a parameter pack, then it will + be deduced to an empty parameter pack. */ + if (template_parameter_pack_p (tparm)) + { + tree arg; + + if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX) + { + arg = make_node (NONTYPE_ARGUMENT_PACK); + TREE_TYPE (arg) = TREE_TYPE (TEMPLATE_PARM_DECL (tparm)); + TREE_CONSTANT (arg) = 1; + } + else + arg = make_node (TYPE_ARGUMENT_PACK); + + SET_ARGUMENT_PACK_ARGS (arg, make_tree_vec (0)); + + TREE_VEC_ELT (targs, i) = arg; + continue; + } + return 2; } @@ -12889,7 +13003,7 @@ more_specialized_fn (tree pat1, tree pat2, int len) if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION) { - int i, len2 = len + 1; + int i, len2 = list_length (args2); tree parmvec = make_tree_vec (1); tree argvec = make_tree_vec (len2); tree ta = args2; @@ -12913,7 +13027,7 @@ more_specialized_fn (tree pat1, tree pat2, int len) } else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION) { - int i, len1 = len + 1; + int i, len1 = list_length (args1); tree parmvec = make_tree_vec (1); tree argvec = make_tree_vec (len1); tree ta = args1; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a484c05..827f532 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2283,6 +2283,11 @@ finish_member_declaration (tree decl) /* Mark the DECL as a member of the current class. */ DECL_CONTEXT (decl) = current_class_type; + /* Check for bare parameter packs in the member variable declaration. */ + if (TREE_CODE (decl) == FIELD_DECL + && !check_for_bare_parameter_packs (TREE_TYPE (decl))) + TREE_TYPE (decl) == error_mark_node; + /* [dcl.link] A C language linkage is ignored for the names of class members diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 499acb2..474be38 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,27 @@ +2007-05-25 Douglas Gregor <doug.gregor@gmail.com> + + PR c++/31431 + PR c++/31432 + PR c++/31434 + PR c++/31435 + PR c++/31437 + PR c++/31438 + PR c++/31442 + PR c++/31443 + PR c++/31444 + PR c++/31445 + * g++.dg/cpp0x/pr31431.C: New. + * g++.dg/cpp0x/pr31437.C: New. + * g++.dg/cpp0x/pr31442.C: New. + * g++.dg/cpp0x/pr31444.C: New. + * g++.dg/cpp0x/pr31431-2.C: New. + * g++.dg/cpp0x/pr31432.C: New. + * g++.dg/cpp0x/pr31434.C: New. + * g++.dg/cpp0x/pr31438.C: New. + * g++.dg/cpp0x/pr31443.C: New. + * g++.dg/cpp0x/pr31445.C: New. + * g++.dg/cpp0x/variadic-crash1.C: New. + 2007-05-25 Richard Sandiford <richard@codesourcery.com> * gcc.target/arm/long-calls-1.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C new file mode 100644 index 0000000..2f74e38 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C @@ -0,0 +1,7 @@ +// { dg-options "-std=gnu++0x" } +template<typename, typename..., typename> void foo(); + +void bar() +{ + foo<int>(); // { dg-error "no matching function" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431.C b/gcc/testsuite/g++.dg/cpp0x/pr31431.C new file mode 100644 index 0000000..061dab0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31431.C @@ -0,0 +1,7 @@ +// { dg-options "-std=gnu++0x" } +template<typename..., typename> void foo(); + +void bar() +{ + foo<int>(); // { dg-error "no matching function" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31432.C b/gcc/testsuite/g++.dg/cpp0x/pr31432.C new file mode 100644 index 0000000..cb8826e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31432.C @@ -0,0 +1,8 @@ +// { dg-options "-std=gnu++0x" } +template<typename..., typename> struct A // { dg-error "parameter pack" } +{ + static int i; +}; + +A<int, int> a; // { dg-error "invalid type" } +A<char,int> b; // { dg-error "invalid type" } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C new file mode 100644 index 0000000..a785ae9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31434.C @@ -0,0 +1,11 @@ +// { dg-options "-std=gnu++0x" } +template<typename... T> int foo(const T&) // { dg-error "not expanded with|T" } +{ + union { T t; }; // { dg-error "not expanded with|T" } + return t; +} + +void bar() +{ + foo(0); // { dg-error "no matching" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31437.C b/gcc/testsuite/g++.dg/cpp0x/pr31437.C new file mode 100644 index 0000000..0e1a888 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31437.C @@ -0,0 +1,9 @@ +// { dg-options "-std=gnu++0x" } +template <typename... T> struct A +{ // { dg-error "candidates|A" } + A(T* p) { // { dg-error "parameter packs|T" } + (A<T...>*)(p); + } +}; + +A<int> a(0); // { dg-error "no matching" } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31438.C b/gcc/testsuite/g++.dg/cpp0x/pr31438.C new file mode 100644 index 0000000..3a12563 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31438.C @@ -0,0 +1,9 @@ +// { dg-options "-std=gnu++0x" } + +template<typename> struct A; // { dg-error "candidates" } +template<typename T, typename... U> struct A<T(U)> // { dg-error "parameter packs|U" } +{ // { dg-error "parameter packs|U" } + template<typename X> A(X); // { dg-error "parameter packs|U" } +}; + +A<void(int)> a(0); // { dg-error "no matching" } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31442.C b/gcc/testsuite/g++.dg/cpp0x/pr31442.C new file mode 100644 index 0000000..050e299 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31442.C @@ -0,0 +1,9 @@ +// { dg-options "-std=gnu++0x" } +template<typename... T, T = 0> struct A {}; // { dg-error "parameter packs|T|the end" } + +struct B +{ + template <template <typename...> class C> B(C<int>); +}; + +B b = A<int>(); diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31443.C b/gcc/testsuite/g++.dg/cpp0x/pr31443.C new file mode 100644 index 0000000..1eb9d31 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31443.C @@ -0,0 +1,11 @@ +// { dg-options "-std=gnu++0x" } + +template<int, typename... T> struct A +{ + template<int N> void foo(A<N,T>); // { dg-error "parameter packs|T" } +}; + +void bar() +{ + A<0,int>().foo(A<0,int>()); // { dg-error "no member named" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31444.C b/gcc/testsuite/g++.dg/cpp0x/pr31444.C new file mode 100644 index 0000000..b1f86fe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31444.C @@ -0,0 +1,10 @@ +// { dg-options "-std=gnu++0x" } +template<typename... T> struct A +{ + template<int> void foo(A<T>); // { dg-error "not expanded|T" } +}; + +void bar() +{ + A<int>().foo<0>(A<int>()); // { dg-error "no member named" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31445.C b/gcc/testsuite/g++.dg/cpp0x/pr31445.C new file mode 100644 index 0000000..025cb96 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr31445.C @@ -0,0 +1,8 @@ +// { dg-options "-std=gnu++0x" } +template <typename... T> struct A +{ + void foo(T...); // { dg-error "candidates" } + A(T... t) { foo(t); } // { dg-error "parameter packs|t|no matching" } +}; + +A<int> a(0); diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C new file mode 100644 index 0000000..f26aee2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C @@ -0,0 +1,72 @@ +// { dg-options "-std=gnu++0x" } + +#define ONE +#define TWO +#define THREE + +struct Something {}; +Something ___; + +template <class F> +struct Trial +{ + F f; +public: + Trial() : f() {} + Trial( const F& ff ) : f(ff) { } + template <typename... Args> + struct Sig { typedef int ResultType; }; + + template <typename... Args> + struct Sig<Something,Args...> { typedef int ResultType; }; + +#ifdef ONE + +template <typename... Args> +typename Sig<Something,Args...>::ResultType operator()(const Something& s, const Args&... args) const +{ + return f(args...); +} +#endif +#ifdef TWO +template <typename... Args> +typename Sig<Args...>::ResultType operator()(const Args&... args) const +{ + return f(args...); +} +#endif +}; + +struct Internal +{ + +template <typename... Args> +struct Sig { typedef int ResultType; }; + +template <typename... Args> +struct Sig<Something,Args...> { typedef int ResultType; }; + +template <typename... Args> +int operator()(const Args&... args) const +{ + int n = sizeof...(Args); + return n; +} + + static Trial<Internal>& full() { static Trial<Internal> f; return f; } +}; + +static Trial<Internal>& internal = Internal::full(); + +int main() +{ + int n = 0; +#ifdef ONE + n = internal(___,1,2); +#endif +#ifdef THREE + n = internal(___,1,2,3); + n = internal(___,1,2,3,4); +#endif + return 0; +} |