diff options
author | Jason Merrill <jason@redhat.com> | 2007-09-04 08:27:21 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2007-09-04 08:27:21 -0400 |
commit | dc28490d05f5ef25c5ff24ef946f48f402a20be8 (patch) | |
tree | 4ac72e6f1563682b5e0b76abbdf4a562498a349b /gcc/cp/pt.c | |
parent | a1a826110720eda37c73f829daa4ee243ee953f5 (diff) | |
download | gcc-dc28490d05f5ef25c5ff24ef946f48f402a20be8.zip gcc-dc28490d05f5ef25c5ff24ef946f48f402a20be8.tar.gz gcc-dc28490d05f5ef25c5ff24ef946f48f402a20be8.tar.bz2 |
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
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r-- | gcc/cp/pt.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 68716f1..aafb964 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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); } |