From 0dac7ee6efaa7c73215517b26cd113aac38c00e3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 4 Sep 2007 11:43:00 -0400 Subject: [PATCH] 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: r128090 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/pt.c | 66 +++++++++++++++++++- gcc/testsuite/g++.dg/template/mem-partial1.C | 15 +++++ gcc/testsuite/g++.dg/template/mem-partial2.C | 29 +++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/template/mem-partial1.C create mode 100644 gcc/testsuite/g++.dg/template/mem-partial2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 07591343d517..b1ce8eb5a86a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2007-09-04 Jason Merrill + + 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-08-31 Paolo Carlini PR c++/32113 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 56010f397ab0..944f6ad7276e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -507,6 +507,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. */ @@ -11521,20 +11552,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); } diff --git a/gcc/testsuite/g++.dg/template/mem-partial1.C b/gcc/testsuite/g++.dg/template/mem-partial1.C new file mode 100644 index 000000000000..60cb36aea994 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/mem-partial1.C @@ -0,0 +1,15 @@ +// PR c++/14032 + +template struct outer { + template + struct inner { + static int f() { return inner::N; }; + }; + + template + struct inner { + static const int N = 1; + }; +}; + +int i = outer::inner::f(); diff --git a/gcc/testsuite/g++.dg/template/mem-partial2.C b/gcc/testsuite/g++.dg/template/mem-partial2.C new file mode 100644 index 000000000000..fba3255199d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/mem-partial2.C @@ -0,0 +1,29 @@ +// PR c++/14032 +// { dg-do run } + +template +struct outer +{ + template + struct inner // unspecialized compare != compare_with + { + static inline bool test() + { + return false; + } + }; + template // specialization compare == compare_with + struct inner + { + static inline bool test() + { + return true; + } + }; +}; +int main () +{ + bool b = outer::inner::test(); + + return b != true; +} -- 2.47.2