Hello, In the example of the patch, the U in 'typename U::X r' should bind to the template parameter U rather than the class member U.
I think the problem comes from parameter_of_template_p that compares parameters by using pointer equality, rather than by using type equivalence like compparms does. As a result, binding_to_template_parms_of_scope_p and then outer_binding (via binding_to_template_parms_of_scope_p) misses the template parameter U and returns the class member U instead. Fixed thus, tested on x86_64-unknown-linux-gnu against trunk. OK for trunk when stage 1 opens? gcc/cp/ PR c++/51641 * cp-tree.h (template_type_parameter_p): Declare ... * pt.c (template_type_parameter_p): ... new function. (parameter_of_template_p): Rely on type equivalence rather than pointer equality to compare template parms. gcc/testsuite/ PR c++/51641 * g++.dg/lookup/hidden-class17.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/pt.c | 29 ++++++++++++++++++++++--- gcc/testsuite/g++.dg/lookup/hidden-class17.C | 22 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/hidden-class17.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f27755e..972c600 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5361,6 +5361,7 @@ extern bool parameter_of_template_p (tree, tree); extern void init_template_processing (void); extern void print_template_statistics (void); bool template_template_parameter_p (const_tree); +bool template_type_parameter_p (const_tree); extern bool primary_template_instantiation_p (const_tree); extern tree get_primary_template_innermost_parameters (const_tree); extern tree get_template_parms_at_level (tree, int); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e440be7..cb9554a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2890,6 +2890,18 @@ template_template_parameter_p (const_tree parm) return DECL_TEMPLATE_TEMPLATE_PARM_P (parm); } +/* Return true iff PARM is a DECL representing a type template + parameter. */ + +bool +template_type_parameter_p (const_tree parm) +{ + return (parm + && (TREE_CODE (parm) == TYPE_DECL + || TREE_CODE (parm) == TEMPLATE_DECL) + && DECL_TEMPLATE_PARM_P (parm)); +} + /* Return the template parameters of T if T is a primary template instantiation, NULL otherwise. */ @@ -8160,10 +8172,19 @@ parameter_of_template_p (tree parm, tree templ) if (p == error_mark_node) continue; - if (parm == p - || (DECL_INITIAL (parm) - && DECL_INITIAL (parm) == DECL_INITIAL (p))) - return true; + if (template_type_parameter_p (parm)) + { + if (same_type_p (TREE_TYPE (parm), TREE_TYPE (p))) + return true; + } + else + { + if (DECL_INITIAL (parm) + && DECL_INITIAL (p) + && same_type_p (TREE_TYPE (DECL_INITIAL (parm)), + TREE_TYPE (DECL_INITIAL (p)))) + return true; + } } return false; diff --git a/gcc/testsuite/g++.dg/lookup/hidden-class17.C b/gcc/testsuite/g++.dg/lookup/hidden-class17.C new file mode 100644 index 0000000..3d5ccec --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/hidden-class17.C @@ -0,0 +1,22 @@ +// Origin PR c++/51641 +// { dg-do compile } + +struct A { + struct B { typedef int X; }; +}; + +template<class B> struct C : A { + B::X q; // Ok: A::B. + struct U { typedef int X; }; + template<class U> + struct D; +}; + +template<class B> +template<class U> +struct C<B>::D { + typename U::X r; // { dg-error "" } +}; + +C<int>::D<double> y; + -- 1.7.6.5 -- Dodji