Patchwork PR c++/51641 - Lookup finds enclosing class member instead of template parameter

login
register
mail settings
Submitter Dodji Seketeli
Date Jan. 27, 2012, 11:19 p.m.
Message ID <m3zkd8ka21.fsf@redhat.com>
Download mbox | patch
Permalink /patch/138365/
State New
Headers show

Comments

Dodji Seketeli - Jan. 27, 2012, 11:19 p.m.
Jason Merrill <jason@redhat.com> writes:

> Comparing by same_type_p means that we treat any template parameter of
> the appropriate level and index as equivalent.  But that should be OK,
> since we only have one set of level N template parameters in scope.
> So I think we should be able to just compare the level of the template
> parameter to the level of the parameters of the template.  Right?

OK.  I understand that just comparing levels like that is not a good
enough implementation for parameter_of_template_p in the general case.
So I removed that function and did the test inline in
binding_to_template_parms_of_scope_p instead.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	PR c++/51641
	* cp-tree.h (template_type_parameter_p): Declare new function.
	(parameter_of_template_p): Remove
	* pt.c (template_type_parameter_p): Define new function.
	(parameter_of_template_p): Remove.
	* name-lookup.c (binding_to_template_parms_of_scope_p): Don't rely
	on parameter_of_template_p anymore.  Compare the level of the
	template parameter to the depth of the template.

gcc/testsuite/

	PR c++/51641
	* g++.dg/lookup/hidden-class17.C: New test.
---
 gcc/cp/cp-tree.h                             |    2 +-
 gcc/cp/name-lookup.c                         |   36 ++++++++++++++++-----
 gcc/cp/pt.c                                  |   44 +++++++-------------------
 gcc/testsuite/g++.dg/lookup/hidden-class17.C |   22 +++++++++++++
 4 files changed, 62 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/hidden-class17.C
Jason Merrill - Jan. 29, 2012, 9 p.m.
On 01/27/2012 06:19 PM, Dodji Seketeli wrote:
> +  /* BINDING_VALUE must be a template parm.  */
> +  if (binding_value == NULL_TREE
> +      && (!DECL_P (binding_value)
> +          || !DECL_TEMPLATE_PARM_P (binding_value)))
> +    return false;

I think the && should be || here.

OK with that change.

Jason

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f27755e..71bca53 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5357,10 +5357,10 @@  extern bool explicit_class_specialization_p     (tree);
 extern int push_tinst_level                     (tree);
 extern void pop_tinst_level                     (void);
 extern struct tinst_level *outermost_tinst_level(void);
-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/name-lookup.c b/gcc/cp/name-lookup.c
index 2351342..3330138 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4466,21 +4466,39 @@  static bool
 binding_to_template_parms_of_scope_p (cxx_binding *binding,
 				      cp_binding_level *scope)
 {
-  tree binding_value;
+  tree binding_value, tmpl;
+  int level;
 
   if (!binding || !scope)
     return false;
 
   binding_value = binding->value ?  binding->value : binding->type;
+  /* BINDING_VALUE must be a template parm.  */
+  if (binding_value == NULL_TREE
+      && (!DECL_P (binding_value)
+          || !DECL_TEMPLATE_PARM_P (binding_value)))
+    return false;
 
-  return (scope
-	  && scope->this_entity
-	  && get_template_info (scope->this_entity)
-	  && PRIMARY_TEMPLATE_P (TI_TEMPLATE
-				 (get_template_info (scope->this_entity)))
-	  && parameter_of_template_p (binding_value,
-				      TI_TEMPLATE (get_template_info \
-						    (scope->this_entity))));
+  /*  The level of BINDING_VALUE.  */
+  level =
+    template_type_parameter_p (binding_value)
+    ? TEMPLATE_PARM_LEVEL (TEMPLATE_TYPE_PARM_INDEX
+			 (TREE_TYPE (binding_value)))
+    : TEMPLATE_PARM_LEVEL (DECL_INITIAL (binding_value));
+
+  /* The template of the current scope, iff said scope is a primary
+     template.  */
+  tmpl =
+    (scope
+     && scope->this_entity
+     && get_template_info (scope->this_entity)
+     && PRIMARY_TEMPLATE_P (TI_TEMPLATE (get_template_info (scope->this_entity))))
+    ? TI_TEMPLATE (get_template_info (scope->this_entity))
+    : NULL_TREE;
+
+  /* If the level of the parm BINDING_VALUE equals the depth of TMPL,
+     then BINDING_VALUE is a parameter of TMPL.  */
+  return (tmpl && level == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)));
 }
 
 /* Return the innermost non-namespace binding for NAME from a scope
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e440be7..76d09aa 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.  */
 
@@ -8137,38 +8149,6 @@  outermost_tinst_level (void)
   return level;
 }
 
-/* Returns TRUE if PARM is a parameter of the template TEMPL.  */
-
-bool
-parameter_of_template_p (tree parm, tree templ)
-{
-  tree parms;
-  int i;
-
-  if (!parm || !templ)
-    return false;
-
-  gcc_assert (DECL_TEMPLATE_PARM_P (parm));
-  gcc_assert (TREE_CODE (templ) == TEMPLATE_DECL);
-
-  parms = DECL_TEMPLATE_PARMS (templ);
-  parms = INNERMOST_TEMPLATE_PARMS (parms);
-
-  for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
-    {
-      tree p = TREE_VALUE (TREE_VEC_ELT (parms, i));
-      if (p == error_mark_node)
-	continue;
-
-      if (parm == p
-	  || (DECL_INITIAL (parm)
-	      && DECL_INITIAL (parm) == DECL_INITIAL (p)))
-	return true;
-    }
-
-  return false;
-}
-
 /* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL.  ARGS is the
    vector of template arguments, as for tsubst.
 
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;
+