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
This commit is contained in:
parent
77315816df
commit
b1d7b1c00e
17 changed files with 508 additions and 156 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
424
gcc/cp/pt.c
424
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 (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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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))
|
||||
{
|
||||
/* 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);
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
/* 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, 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. */
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
7
gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-options "-std=gnu++0x" }
|
||||
template<typename, typename..., typename> void foo();
|
||||
|
||||
void bar()
|
||||
{
|
||||
foo<int>(); // { dg-error "no matching function" }
|
||||
}
|
7
gcc/testsuite/g++.dg/cpp0x/pr31431.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/pr31431.C
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-options "-std=gnu++0x" }
|
||||
template<typename..., typename> void foo();
|
||||
|
||||
void bar()
|
||||
{
|
||||
foo<int>(); // { dg-error "no matching function" }
|
||||
}
|
8
gcc/testsuite/g++.dg/cpp0x/pr31432.C
Normal file
8
gcc/testsuite/g++.dg/cpp0x/pr31432.C
Normal file
|
@ -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" }
|
11
gcc/testsuite/g++.dg/cpp0x/pr31434.C
Normal file
11
gcc/testsuite/g++.dg/cpp0x/pr31434.C
Normal file
|
@ -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" }
|
||||
}
|
9
gcc/testsuite/g++.dg/cpp0x/pr31437.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/pr31437.C
Normal file
|
@ -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" }
|
9
gcc/testsuite/g++.dg/cpp0x/pr31438.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/pr31438.C
Normal file
|
@ -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" }
|
9
gcc/testsuite/g++.dg/cpp0x/pr31442.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/pr31442.C
Normal file
|
@ -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>();
|
11
gcc/testsuite/g++.dg/cpp0x/pr31443.C
Normal file
11
gcc/testsuite/g++.dg/cpp0x/pr31443.C
Normal file
|
@ -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" }
|
||||
}
|
10
gcc/testsuite/g++.dg/cpp0x/pr31444.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/pr31444.C
Normal file
|
@ -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" }
|
||||
};
|
8
gcc/testsuite/g++.dg/cpp0x/pr31445.C
Normal file
8
gcc/testsuite/g++.dg/cpp0x/pr31445.C
Normal file
|
@ -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);
|
72
gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C
Normal file
72
gcc/testsuite/g++.dg/cpp0x/variadic-crash1.C
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue