re PR c++/14032 (Specialization of inner template using outer template argument doesn't work)

PR c++/14032
        * pt.c (most_specialized_class): Substitute outer template
        arguments into the arguments of a member template partial
        specialization.
        (strip_innermost_template_args): New fn.

From-SVN: r128076
This commit is contained in:
Jason Merrill 2007-09-04 08:27:21 -04:00 committed by Jason Merrill
parent a1a8261107
commit dc28490d05
2 changed files with 73 additions and 1 deletions

View File

@ -1,3 +1,11 @@
2007-09-04 Jason Merrill <jason@redhat.com>
PR c++/14032
* pt.c (most_specialized_class): Substitute outer template
arguments into the arguments of a member template partial
specialization.
(strip_innermost_template_args): New fn.
2007-09-03 Daniel Jacobowitz <dan@codesourcery.com>
* Make-lang.in (g++spec.o): Remove SHLIB_MULTILIB.

View File

@ -519,6 +519,37 @@ get_innermost_template_args (tree args, int n)
return new_args;
}
/* The inverse of get_innermost_template_args: Return all but the innermost
EXTRA_LEVELS levels of template arguments from the ARGS. */
static tree
strip_innermost_template_args (tree args, int extra_levels)
{
tree new_args;
int n = TMPL_ARGS_DEPTH (args) - extra_levels;
int i;
gcc_assert (n >= 0);
/* If N is 1, just return the outermost set of template arguments. */
if (n == 1)
return TMPL_ARGS_LEVEL (args, 1);
/* If we're not removing anything, just return the arguments we were
given. */
gcc_assert (extra_levels >= 0);
if (extra_levels == 0)
return args;
/* Make a new set of arguments, not containing the inner arguments. */
new_args = make_tree_vec (n);
for (i = 1; i <= n; ++i)
SET_TMPL_ARGS_LEVEL (new_args, i,
TMPL_ARGS_LEVEL (args, i));
return new_args;
}
/* We've got a template header coming up; push to a new level for storing
the parms. */
@ -13591,20 +13622,53 @@ most_specialized_class (tree type, tree tmpl)
int fate;
bool ambiguous_p;
tree args;
tree outer_args = NULL_TREE;
tmpl = most_general_template (tmpl);
args = CLASSTYPE_TI_ARGS (type);
/* For determining which partial specialization to use, only the
innermost args are interesting. */
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
outer_args = strip_innermost_template_args (args, 1);
args = INNERMOST_TEMPLATE_ARGS (args);
}
for (t = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); t; t = TREE_CHAIN (t))
{
tree partial_spec_args;
tree spec_args;
tree parms = TREE_VALUE (t);
partial_spec_args = CLASSTYPE_TI_ARGS (TREE_TYPE (t));
spec_args = get_class_bindings (TREE_VALUE (t),
if (outer_args)
{
int i;
/* Discard the outer levels of args, and then substitute in the
template args from the enclosing class. */
partial_spec_args = INNERMOST_TEMPLATE_ARGS (partial_spec_args);
partial_spec_args = tsubst_template_args
(partial_spec_args, outer_args, tf_none, NULL_TREE);
/* PARMS already refers to just the innermost parms, but the
template parms in partial_spec_args had their levels lowered
by tsubst, so we need to do the same for the parm list. We
can't just tsubst the TREE_VEC itself, as tsubst wants to
treat a TREE_VEC as an argument vector. */
parms = copy_node (parms);
for (i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i)
TREE_VEC_ELT (parms, i) =
tsubst (TREE_VEC_ELT (parms, i), outer_args, tf_none, NULL_TREE);
}
spec_args = get_class_bindings (parms,
partial_spec_args,
args);
if (spec_args)
{
if (outer_args)
spec_args = add_to_template_args (outer_args, spec_args);
list = tree_cons (spec_args, TREE_VALUE (t), list);
TREE_TYPE (list) = TREE_TYPE (t);
}