This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

C++ PATCH for member classes / member friends in templates



Here's a patch to improve our handling of member template friends
referring to member templates classes.  What fun, what fun.

-- 
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-04-17  Mark Mitchell  <mark@codesourcery.com>

	* decl.c (xref_tag): Revise handling of nested template
	declarations.
	* pt.c (check_explicit_specialization): Tweak handling of friend
	templates in template classes.
	(tsubst_friend_class): Handle friend declarations for nested
	member template classes.
	
Index: testsuite/g++.old-deja/g++.pt/friend41.C
===================================================================
RCS file: friend41.C
diff -N friend41.C
--- /dev/null	Sat Dec  5 20:30:03 1998
+++ friend41.C	Sat Apr 17 14:08:38 1999
@@ -0,0 +1,21 @@
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T>
+class S {
+public:
+  template <class U>
+  class C {
+  public:
+    void f() { S::i = 3; }
+  };
+
+  template <class U>
+  friend class C;
+
+private:
+  static int i;
+};
+
+
+template void S<int>::C<double>::f();
Index: testsuite/cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.347
diff -u -p -r1.347 decl.c
--- decl.c	1999/04/16 18:06:34	1.347
+++ decl.c	1999/04/17 21:08:47
@@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globaliz
   struct binding_level *b = current_binding_level;
   int got_type = 0;
   tree attributes = NULL_TREE;
+  tree context = NULL_TREE;
 
   /* If we are called from the parser, code_type_node will sometimes be a
      TREE_LIST.  This indicates that the user wrote
@@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globaliz
     }
   else
     {
-      if (current_class_type 
-	  && template_class_depth (current_class_type) 
-	  && PROCESSING_REAL_TEMPLATE_DECL_P ())
-      /* Since GLOBALIZE is non-zero, we are not looking at a
-	 definition of this tag.  Since, in addition, we are currently
-	 processing a (member) template declaration of a template
-	 class, we don't want to do any lookup at all; consider:
-
-	   template <class X>
-	   struct S1
-
-	   template <class U>
-	   struct S2
-	   { template <class V>
-	     friend struct S1; };
-	   
-	 Here, the S2::S1 declaration should not be confused with the
-	 outer declaration.  In particular, the inner version should
-	 have a template parameter of level 2, not level 1.  This
-	 would be particularly important if the member declaration
-	 were instead:
-
-	   template <class V = U> friend struct S1;
-
-	 say, when we should tsubst into `U' when instantiating S2.  */
-	ref = NULL_TREE;
-      else 
+      if (t)
 	{
-	  if (t)
-	    {
-	      /* [dcl.type.elab] If the identifier resolves to a
-		 typedef-name or a template type-parameter, the
-		 elaborated-type-specifier is ill-formed.  */
-	      if (t != TYPE_MAIN_VARIANT (t)
-		  || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
-		cp_pedwarn ("using typedef-name `%D' after `%s'",
-			    TYPE_NAME (t), tag_name (tag_code));
-	      else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
-		cp_error ("using template type parameter `%T' after `%s'",
-			  t, tag_name (tag_code));
+	  /* [dcl.type.elab] If the identifier resolves to a
+	     typedef-name or a template type-parameter, the
+	     elaborated-type-specifier is ill-formed.  */
+	  if (t != TYPE_MAIN_VARIANT (t)
+	      || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
+	    cp_pedwarn ("using typedef-name `%D' after `%s'",
+			TYPE_NAME (t), tag_name (tag_code));
+	  else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+	    cp_error ("using template type parameter `%T' after `%s'",
+		      t, tag_name (tag_code));
 
-	      ref = t;
-	    }
-	  else
-	    ref = lookup_tag (code, name, b, 0);
+	  ref = t;
+	}
+      else
+	ref = lookup_tag (code, name, b, 0);
 	  
-	  if (! ref)
-	    {
-	      /* Try finding it as a type declaration.  If that wins,
-		 use it.  */ 
-	      ref = lookup_name (name, 1);
-
-	      if (ref != NULL_TREE
-		  && processing_template_decl
-		  && DECL_CLASS_TEMPLATE_P (ref)
-		  && template_class_depth (current_class_type) == 0)
-		/* Since GLOBALIZE is true, we're declaring a global
+      if (! ref)
+	{
+	  /* Try finding it as a type declaration.  If that wins,
+	     use it.  */ 
+	  ref = lookup_name (name, 1);
+
+	  if (ref != NULL_TREE
+	      && processing_template_decl
+	      && DECL_CLASS_TEMPLATE_P (ref)
+	      && template_class_depth (current_class_type) == 0)
+	    /* Since GLOBALIZE is true, we're declaring a global
 	       template, so we want this type.  */
-		ref = DECL_RESULT (ref);
+	    ref = DECL_RESULT (ref);
 
-	      if (ref && TREE_CODE (ref) == TYPE_DECL
-		  && TREE_CODE (TREE_TYPE (ref)) == code)
-		ref = TREE_TYPE (ref);
-	      else
-		ref = NULL_TREE;
-	    }
+	  if (ref && TREE_CODE (ref) == TYPE_DECL
+	      && TREE_CODE (TREE_TYPE (ref)) == code)
+	    ref = TREE_TYPE (ref);
+	  else
+	    ref = NULL_TREE;
+	}
+
+      if (ref && current_class_type 
+	  && template_class_depth (current_class_type) 
+	  && PROCESSING_REAL_TEMPLATE_DECL_P ()) 
+	{
+	  /* Since GLOBALIZE is non-zero, we are not looking at a
+	     definition of this tag.  Since, in addition, we are currently
+	     processing a (member) template declaration of a template
+	     class, we must be very careful; consider:
+
+	       template <class X>
+	       struct S1
+
+	       template <class U>
+	       struct S2
+	       { template <class V>
+	       friend struct S1; };
+
+	     Here, the S2::S1 declaration should not be confused with the
+	     outer declaration.  In particular, the inner version should
+	     have a template parameter of level 2, not level 1.  This
+	     would be particularly important if the member declaration
+	     were instead:
+
+	       template <class V = U> friend struct S1;
+
+	     say, when we should tsubst into `U' when instantiating
+	     S2.  On the other hand, when presented with:
+
+	         template <class T>
+	         struct S1 {
+		   template <class U>
+	           struct S2 {};
+		   template <class U>
+		   friend struct S2;
+		 };
+
+              we must find the inner binding eventually.  We
+	      accomplish this by making sure that the new type we
+	      create to represent this declaration has the right
+	      TYPE_CONTEXT.  */
+	  context = TYPE_CONTEXT (ref);
+	  ref = NULL_TREE;
 	}
     }
 
@@ -12487,6 +12503,7 @@ xref_tag (code_type_node, name, globaliz
 	  struct binding_level *old_b = class_binding_level;
 
 	  ref = make_lang_type (code);
+	  TYPE_CONTEXT (ref) = context;
 
 	  if (tag_code == signature_type)
 	    {
Index: testsuite/cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.287
diff -u -p -r1.287 pt.c
--- pt.c	1999/04/15 17:52:23	1.287
+++ pt.c	1999/04/17 21:08:53
@@ -1281,7 +1281,6 @@ check_explicit_specialization (declarato
 
   if (specialization || member_specialization || explicit_instantiation)
     {
-      tree gen_tmpl;
       tree tmpl = NULL_TREE;
       tree targs = NULL_TREE;
 
@@ -1435,13 +1434,34 @@ check_explicit_specialization (declarato
 	return error_mark_node;
       else
 	{
-	  gen_tmpl = most_general_template (tmpl);
+	  tree gen_tmpl = most_general_template (tmpl);
 
 	  if (explicit_instantiation)
 	    {
 	      /* We don't set DECL_EXPLICIT_INSTANTIATION here; that
-		 is done by do_decl_instantiation later.  */
-	      decl = instantiate_template (tmpl, innermost_args (targs));
+		 is done by do_decl_instantiation later.  */ 
+
+	      int arg_depth = TMPL_ARGS_DEPTH (targs);
+	      int parm_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
+
+	      if (arg_depth > parm_depth)
+		{
+		  /* If TMPL is not the most general template (for
+		     example, if TMPL is a friend template that is
+		     injected into namespace scope), then there will
+		     be too many levels fo TARGS.  Remove some of them
+		     here.  */
+		  int i;
+		  tree new_targs;
+
+		  new_targs = make_temp_vec (parm_depth);
+		  for (i = arg_depth - parm_depth; i < arg_depth; ++i)
+		    TREE_VEC_ELT (new_targs, i - (arg_depth - parm_depth))
+		      = TREE_VEC_ELT (targs, i);
+		  targs = new_targs;
+		}
+		  
+	      decl = instantiate_template (tmpl, targs);
 	      return decl;
 	    }
 	  
@@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args)
      tree args;
 {
   tree friend_type;
-  tree tmpl = lookup_name (DECL_NAME (friend_tmpl), 1); 
+  tree tmpl;
 
-  tmpl = maybe_get_template_decl_from_type_decl (tmpl);
+  /* First, we look for a class template.  */
+  tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/0); 
+  
+  /* But, if we don't find one, it might be because we're in a
+     situation like this:
+
+       template <class T>
+       struct S {
+         template <class U>
+	 friend struct S;
+       };
+
+     Here, in the scope of (say) S<int>, `S' is bound to a TYPE_DECL
+     for `S<int>', not the TEMPLATE_DECL.  */
+  if (!DECL_CLASS_TEMPLATE_P (tmpl))
+    {
+      tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/1);
+      tmpl = maybe_get_template_decl_from_type_decl (tmpl);
+    }
 
-  if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
+  if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl))
     {
       /* The friend template has already been declared.  Just
 	 check to see that the declarations match, and install any new


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]