PATCH for friend template classes

Mark Mitchell mmitchell@usa.net
Mon Apr 20 22:29:00 GMT 1998


Here's a patch that makes friend template classes, e.g.:

  template <class T>
  class S1
  {
     template <class T>
     friend class S2;
  };

work much better.  Is this OK to install?

-- 
Mark Mitchell <mmitchell@usa.net>
http://home.earthlink.net/~mbmitchell
Consulting Services Available

Mon Apr 20 12:57:56 1998  Mark Mitchell  <mmitchell@usa.net>

	* cp-tree.h (CLASSTYPE_IS_TEMPLATE): New macro.
	(DECL_CLASS_TEMPLATE_P): Likewise.
	(DECL_PRIMARY_TEMPLATE): Likewise.
	(PRIMARY_TEMPLATE_P): Use it.
	(push_template_decl_real): New function.
	(redeclare_class_template): Take new template parameters as
	input. 
	(is_specialization_of): New function.
	(comp_template_args): Declare.
	* decl.c (pushtag): Handle friend template classes.
	(xref_tag): Likewise.  Use new calling convention for
	redeclare_class_template.
	* decl2.c (grok_x_components): Handle friend templates.
	* friend.c (is_friend): Use is_specialization_of where
	appropriate.  Deal with friend class templates.
	(make_friend_class): Let a class template be friends with itself.
	* pt.c (comp_template_args): Remove declaration.
	(tsubst_friend_class): New function.
	(push_template_decl_real): New function.
	(push_template_decl): Use it.
	(redeclare_class_template): Adjust for new calling convention.
	(comp_template_args): Give it external linkage.
	(instantiate_class_type): Use tsubst_friend_class to deal
	with friend templates.
	* typeck.c (comptypes): Use comp_template_args, rather than
	expanding it inline.
	* parse.y (component_decl): Handle a nested template type 
	like other component type declarations.
	
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.55
diff -c -p -r1.55 cp-tree.h
*** cp-tree.h	1998/04/17 21:25:36	1.55
--- cp-tree.h	1998/04/20 19:50:06
*************** struct lang_decl
*** 1126,1131 ****
--- 1129,1143 ----
  #define DELETE_EXPR_USE_VEC(NODE)	TREE_LANG_FLAG_1 (NODE)
  #define LOOKUP_EXPR_GLOBAL(NODE)	TREE_LANG_FLAG_0 (NODE)
  
+ /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
+    TEMPLATE_DECL.  This macro determines whether or not a given class
+    type is really a template type, as opposed to an instantiation or
+    specialization of one.  */
+ #define CLASSTYPE_IS_TEMPLATE(NODE)  \
+   (CLASSTYPE_TEMPLATE_INFO (NODE)    \
+    && !CLASSTYPE_USE_TEMPLATE (NODE) \
+    && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
+ 
  #define TYPENAME_TYPE_FULLNAME(NODE)	CLASSTYPE_SIZE (NODE)
  
  /* Nonzero in INT_CST means that this int is negative by dint of
*************** extern int flag_new_for_scope;
*** 1399,1410 ****
    (TREE_CODE (NODE) == TEMPLATE_DECL \
     && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
  
  /* A `primary' template is one that has its own template header.  A
     member function of a class template is a template, but not primary.
!    A member template is primary.  */
! #define PRIMARY_TEMPLATE_P(NODE) \
!   (TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)) == (NODE))
  
  #define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
    (TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
  
--- 1411,1433 ----
    (TREE_CODE (NODE) == TEMPLATE_DECL \
     && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
  
+ /* Nonzero for a DECL that represents a template class.  */
+ #define DECL_CLASS_TEMPLATE_P(NODE) \
+   (TREE_CODE (NODE) == TEMPLATE_DECL \
+    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
+    && !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
+ 
  /* A `primary' template is one that has its own template header.  A
     member function of a class template is a template, but not primary.
!    A member template is primary.  Friend templates are primary, too.  */
  
+ /* Returns the primary template corresponding to these parameters.  */
+ #define DECL_PRIMARY_TEMPLATE(NODE) \
+   (TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)))
+ 
+ /* Returns non-zero if NODE is a primary template.  */
+ #define PRIMARY_TEMPLATE_P(NODE) (DECL_PRIMARY_TEMPLATE (NODE) == NODE)
+ 
  #define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
    (TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
  
*************** extern tree end_template_parm_list		PROT
*** 2422,2428 ****
  extern void end_template_decl			PROTO((void));
  extern tree current_template_args		PROTO((void));
  extern tree push_template_decl			PROTO((tree));
! extern void redeclare_class_template            PROTO((tree));
  extern tree lookup_template_class		PROTO((tree, tree, tree, tree));
  extern tree lookup_template_function            PROTO((tree, tree));
  extern int uses_template_parms			PROTO((tree));
--- 2445,2452 ----
  extern void end_template_decl			PROTO((void));
  extern tree current_template_args		PROTO((void));
  extern tree push_template_decl			PROTO((tree));
! extern tree push_template_decl_real		PROTO((tree, int));
! extern void redeclare_class_template            PROTO((tree, tree));
  extern tree lookup_template_class		PROTO((tree, tree, tree, tree));
  extern tree lookup_template_function            PROTO((tree, tree));
  extern int uses_template_parms			PROTO((tree));
*************** extern void do_pushlevel			PROTO((void))
*** 2454,2459 ****
--- 2478,2486 ----
  extern int is_member_template                   PROTO((tree));
  extern int comp_template_parms                  PROTO((tree, tree));
  extern int template_class_depth                 PROTO((tree));
+ extern int is_specialization_of                 PROTO((tree, tree));
+ extern int comp_template_args                   PROTO((tree, tree));
+ 
  extern int processing_specialization;
  extern int processing_explicit_instantiation;
  
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.94
diff -c -p -r1.94 decl.c
*** decl.c	1998/04/17 08:05:16	1.94
--- decl.c	1998/04/20 19:43:43
*************** pop_everything ()
*** 2155,2161 ****
  }
  
  /* Push a tag name NAME for struct/class/union/enum type TYPE.
!    Normally put into into the inner-most non-tag-transparent scope,
     but if GLOBALIZE is true, put it in the inner-most non-class scope.
     The latter is needed for implicit declarations.  */
  
--- 2155,2161 ----
  }
  
  /* Push a tag name NAME for struct/class/union/enum type TYPE.
!    Normally put it into the inner-most non-tag-transparent scope,
     but if GLOBALIZE is true, put it in the inner-most non-class scope.
     The latter is needed for implicit declarations.  */
  
*************** pushtag (name, type, globalize)
*** 2224,2233 ****
  	  TYPE_NAME (type) = d;
  	  DECL_CONTEXT (d) = context;
  
! 	  if (! globalize && processing_template_decl
  	      && IS_AGGR_TYPE (type))
  	    {
! 	      d = push_template_decl (d);
  	      if (b->pseudo_global && b->level_chain->parm_flag == 2)
  		pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
  				     b->level_chain);
--- 2224,2237 ----
  	  TYPE_NAME (type) = d;
  	  DECL_CONTEXT (d) = context;
  
! 	  if ((!globalize || 
! 	       (current_class_type != NULL_TREE
! 		&& (processing_template_decl > 
! 		    template_class_depth (current_class_type))))
! 	      && processing_template_decl
  	      && IS_AGGR_TYPE (type))
  	    {
! 	      d = push_template_decl_real (d, globalize);
  	      if (b->pseudo_global && b->level_chain->parm_flag == 2)
  		pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
  				     b->level_chain);
*************** xref_tag (code_type_node, name, binfo, g
*** 10806,10811 ****
--- 10810,10824 ----
  	{
  	  /* 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);
+ 
  	  if (ref && TREE_CODE (ref) == TYPE_DECL
  	      && TREE_CODE (TREE_TYPE (ref)) == code)
  	    ref = TREE_TYPE (ref);
*************** xref_tag (code_type_node, name, binfo, g
*** 10892,10898 ****
  	}
  
        if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
! 	redeclare_class_template (ref);
      }
  
    if (binfo)
--- 10905,10911 ----
  	}
  
        if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
! 	redeclare_class_template (ref, current_template_parms);
      }
  
    if (binfo)
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.61
diff -c -p -r1.61 decl2.c
*** decl2.c	1998/04/17 15:29:44	1.61
--- decl2.c	1998/04/20 19:43:54
*************** grok_x_components (specs, components)
*** 870,877 ****
  	    tcode = class_type_node;
  	  else if (IS_SIGNATURE (t))
  	    tcode = signature_type_node;
! 	  
! 	  t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
  	  return NULL_TREE;
  	  break;
  
--- 873,888 ----
  	    tcode = class_type_node;
  	  else if (IS_SIGNATURE (t))
  	    tcode = signature_type_node;
! 
! 	  if (CLASSTYPE_IS_TEMPLATE (t))
! 	    /* In this case, the TYPE_IDENTIFIER will be something
! 	       like S<T>, rather than S, so to get the correct name we
! 	       look at the template.  */
! 	    x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
! 	  else
! 	    x = TYPE_IDENTIFIER (t);
! 
! 	  t = xref_tag (tcode, x, NULL_TREE, 0);
  	  return NULL_TREE;
  	  break;
  
Index: friend.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/friend.c,v
retrieving revision 1.12
diff -c -p -r1.12 friend.c
*** friend.c	1998/04/01 17:05:25	1.12
--- friend.c	1998/04/20 19:43:55
*************** is_friend (type, supplicant)
*** 71,95 ****
  
  		  if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
  		    {
! 		      tree t;
  
- 		      /* Perhaps this function is a specialization of
- 			 a friend template.  */
- 		      for (t = supplicant;
- 			   t != NULL_TREE;
- 			   t = DECL_TEMPLATE_INFO (t) ? 
- 			     DECL_TI_TEMPLATE (t) : NULL_TREE)
- 			/* FIXME: The use of comptypes here, and below, is
- 			   bogus, since two specializations of a
- 			   template parameter with non-type parameters
- 			   may have the same type, but be different.  */
- 			if (comptypes (TREE_TYPE (t),
- 				       TREE_TYPE (TREE_VALUE (friends)), 1))
- 			  return 1;
- 
  		      continue;
  		    }
  
  		  if (comptypes (TREE_TYPE (supplicant),
  				 TREE_TYPE (TREE_VALUE (friends)), 1))
  		    return 1;
--- 71,87 ----
  
  		  if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
  		    {
! 		      if (is_specialization_of (supplicant, 
! 						TREE_VALUE (friends)))
! 			return 1;
  
  		      continue;
  		    }
  
+ 		  /* FIXME: The use of comptypes here is bogus, since
+ 		     two specializations of a template with non-type
+ 		     parameters may have the same type, but be
+ 		     different.  */
  		  if (comptypes (TREE_TYPE (supplicant),
  				 TREE_TYPE (TREE_VALUE (friends)), 1))
  		    return 1;
*************** is_friend (type, supplicant)
*** 106,113 ****
        
        list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
        for (; list ; list = TREE_CHAIN (list))
! 	if (supplicant == TREE_VALUE (list))
! 	  return 1;
      }      
  
    if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
--- 98,112 ----
        
        list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
        for (; list ; list = TREE_CHAIN (list))
! 	{
! 	  tree t = TREE_VALUE (list);
! 
! 	  if (supplicant == t
! 	      || (CLASSTYPE_IS_TEMPLATE (t)
! 		  && is_specialization_of (TYPE_MAIN_DECL (supplicant),
! 					   CLASSTYPE_TI_TEMPLATE (t))))
! 	    return 1;
! 	}
      }      
  
    if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
*************** make_friend_class (type, friend_type)
*** 249,255 ****
  	     IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
        return;
      }
!   if (type == friend_type)
      {
        pedwarn ("class `%s' is implicitly friends with itself",
  	       TYPE_NAME_STRING (type));
--- 248,257 ----
  	     IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
        return;
      }
!   /* If the TYPE is a template then it makes sense for it to be
!      friends with itself; this means that each instantiation is
!      friends with all other instantiations.  */
!   if (type == friend_type && !CLASSTYPE_IS_TEMPLATE (type))
      {
        pedwarn ("class `%s' is implicitly friends with itself",
  	       TYPE_NAME_STRING (type));
Index: pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.117
diff -c -p -r1.117 pt.c
*** pt.c	1998/04/17 21:25:37	1.117
--- pt.c	1998/04/20 19:45:04
*************** static int push_tinst_level PROTO((tree)
*** 75,81 ****
  static tree classtype_mangled_name PROTO((tree));
  static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
  static tree tsubst_expr_values PROTO((tree, tree));
- static int comp_template_args PROTO((tree, tree));
  static int list_eq PROTO((tree, tree));
  static tree get_class_bindings PROTO((tree, tree, tree, tree));
  static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
--- 75,80 ----
*************** static tree reduce_template_parm_level P
*** 100,105 ****
--- 99,105 ----
  static tree build_template_decl PROTO((tree, tree));
  static int mark_template_parm PROTO((tree, void *));
  static tree tsubst_friend_function PROTO((tree, tree));
+ static tree tsubst_friend_class PROTO((tree, tree));
  static tree get_bindings_real PROTO((tree, tree, tree, int));
  
  /* Do any processing required when DECL (a member template declaration
*************** add_to_template_args (args, extra_args)
*** 487,499 ****
  void
  begin_template_parm_list ()
  {
    pushlevel (0);
    declare_pseudo_global_level ();
    ++processing_template_decl;
    note_template_header (0);
  }
  
- 
  /* We've just seen template <>. */
  
  void
--- 487,512 ----
  void
  begin_template_parm_list ()
  {
+   /* We use a non-tag-transparent scope here, which causes pushtag to
+      put tags in this scope, rather than in the enclosing class or
+      namespace scope.  This is the right thing, since we want
+      TEMPLATE_DECLS, and not TYPE_DECLS for template classes.  For a
+      global template class, push_template_decl handles putting the
+      TEMPLATE_DECL into top-level scope.  For a nested template class,
+      e.g.:
+ 
+        template <class T> struct S1 {
+          template <class T> struct S2 {}; 
+        };
+ 
+      pushtag contains special code to call pushdecl_with_scope on the
+      TEMPLATE_DECL for S2.  */
    pushlevel (0);
    declare_pseudo_global_level ();
    ++processing_template_decl;
    note_template_header (0);
  }
  
  /* We've just seen template <>. */
  
  void
*************** begin_specialization ()
*** 502,508 ****
    note_template_header (1);
  }
  
- 
  /* Called at then end of processing a declaration preceeded by
     template<>.  */
  
--- 515,520 ----
*************** end_specialization ()
*** 512,518 ****
    reset_specialization ();
  }
  
- 
  /* Any template <>'s that we have seen thus far are not referring to a
     function specialization. */
  
--- 524,529 ----
*************** reset_specialization ()
*** 523,529 ****
    template_header_count = 0;
  }
  
- 
  /* We've just seen a template header.  If SPECIALIZATION is non-zero,
     it was of the form template <>.  */
  
--- 534,539 ----
*************** note_template_header (specialization)
*** 535,541 ****
    template_header_count++;
  }
  
- 
  /* We're beginning an explicit instantiation.  */
  
  void
--- 545,550 ----
*************** end_explicit_instantiation ()
*** 552,558 ****
    --processing_explicit_instantiation;
  }
  
- 
  /* Retrieve the specialization (in the sense of [temp.spec] - a
     specialization is either an instantiation or an explicit
     specialization) of TMPL for the given template ARGS.  If there is
--- 561,566 ----
*************** retrieve_specialization (tmpl, args)
*** 578,585 ****
--- 586,624 ----
    return NULL_TREE;
  }
  
+ /* Returns non-zero iff DECL is a specialization of TMPL.  */
  
+ int
+ is_specialization_of (decl, tmpl)
+      tree decl;
+      tree tmpl;
+ {
+   tree t;
+ 
+   if (TREE_CODE (decl) == FUNCTION_DECL)
+     {
+       for (t = decl; 
+ 	   t != NULL_TREE;
+ 	   t = DECL_TEMPLATE_INFO (t) ? DECL_TI_TEMPLATE (t) : NULL_TREE)
+ 	if (t == tmpl)
+ 	  return 1;
+     }
+   else 
+     {
+       my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 0);
  
+       for (t = TREE_TYPE (decl);
+ 	   t != NULL_TREE;
+ 	   t = CLASSTYPE_USE_TEMPLATE (t)
+ 	     ? TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) : NULL_TREE)
+ 	if (comptypes (TYPE_MAIN_VARIANT (t), 
+ 		       TYPE_MAIN_VARIANT (TREE_TYPE (tmpl)), 1))
+ 	  return 1;
+     }  
+ 
+   return 0;
+ }
+ 
  /* Register the specialization SPEC as a specialization of TMPL with
     the indicated ARGS.  */
  
*************** register_specialization (spec, tmpl, arg
*** 647,653 ****
       = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
  }
  
- 
  /* Print the list of candidate FNS in an error message.  */
  
  static void
--- 686,691 ----
*************** determine_specialization (template_id, d
*** 784,791 ****
    *targs_out = TREE_PURPOSE (templates);
    return TREE_VALUE (templates);
  }
! 
! 	
  /* Check to see if the function just declared, as indicated in
     DECLARATOR, and in DECL, is a specialization of a function
     template.  We may also discover that the declaration is an explicit
--- 822,828 ----
    *targs_out = TREE_PURPOSE (templates);
    return TREE_VALUE (templates);
  }
!       
  /* Check to see if the function just declared, as indicated in
     DECLARATOR, and in DECL, is a specialization of a function
     template.  We may also discover that the declaration is an explicit
*************** check_explicit_specialization (declarato
*** 1160,1166 ****
    return decl;
  }
  
- 
  /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
     parameters.  These are represented in the same format used for
     DECL_TEMPLATE_PARMS.  */
--- 1197,1202 ----
*************** int comp_template_parms (parms1, parms2)
*** 1213,1219 ****
    return 1;
  }
  
- 
  /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
     ORIG_LEVEL, DECL, and TYPE.  */
  
--- 1249,1254 ----
*************** build_template_parm_index (index, level,
*** 1235,1241 ****
    return t;
  }
  
- 
  /* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
     TEMPLATE_PARM_LEVEL has been decreased by LEVELS.  If such a
     TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
--- 1270,1275 ----
*************** mark_template_parm (t, data)
*** 1520,1538 ****
  /* Creates a TEMPLATE_DECL for the indicated DECL using the template
     parameters given by current_template_args, or reuses a
     previously existing one, if appropriate.  Returns the DECL, or an
!    equivalent one, if it is replaced via a call to duplicate_decls.  */
  
  tree
! push_template_decl (decl)
       tree decl;
  {
    tree tmpl;
    tree args;
    tree info;
    tree ctx;
    int primary;
!   int is_friend = (TREE_CODE (decl) == FUNCTION_DECL
! 		   && DECL_FRIEND_P (decl));
  
    if (is_friend)
      /* For a friend, we want the context of the friend function, not
--- 1554,1575 ----
  /* Creates a TEMPLATE_DECL for the indicated DECL using the template
     parameters given by current_template_args, or reuses a
     previously existing one, if appropriate.  Returns the DECL, or an
!    equivalent one, if it is replaced via a call to duplicate_decls.  
! 
!    If IS_FRIEND is non-zero, DECL is a friend declaration.  */
  
  tree
! push_template_decl_real (decl, is_friend)
       tree decl;
+      int is_friend;
  {
    tree tmpl;
    tree args;
    tree info;
    tree ctx;
    int primary;
! 
!   is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
  
    if (is_friend)
      /* For a friend, we want the context of the friend function, not
*************** push_template_decl (decl)
*** 1550,1565 ****
    /* For determining whether this is a primary template or not, we're really
       interested in the lexical context, not the true context.  */
    if (is_friend)
!     info = DECL_CLASS_CONTEXT (decl);
    else
      info = ctx;
  
    if (info && TREE_CODE (info) == FUNCTION_DECL)
      primary = 0;
!   else if (! info
! 	   || (TYPE_BEING_DEFINED (info) && template_header_count
! 	       && ! processing_specialization)
! 	   || (template_header_count > template_class_depth (info)))
      primary = 1;
    else
      primary = 0;
--- 1587,1601 ----
    /* For determining whether this is a primary template or not, we're really
       interested in the lexical context, not the true context.  */
    if (is_friend)
!     /* For a TYPE_DECL, there is no DECL_CLASS_CONTEXT.  */
!     info = TREE_CODE (decl) == FUNCTION_DECL 
!       ? DECL_CLASS_CONTEXT (decl) : current_class_type;
    else
      info = ctx;
  
    if (info && TREE_CODE (info) == FUNCTION_DECL)
      primary = 0;
!   else if (processing_template_decl > template_class_depth (info))
      primary = 1;
    else
      primary = 0;
*************** push_template_decl (decl)
*** 1775,1788 ****
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
  
!   if (! ctx && primary)
!     /* The check of PRIMARY ensures that we do not try to push a
!        global template friend declared in a template class; such a
!        thing may well depend on the template parameters of the class.  */
      tmpl = pushdecl_top_level (tmpl);
  
    if (primary)
!     TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
  
    info = perm_tree_cons (tmpl, args, NULL_TREE);
  
--- 1811,1824 ----
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
  
!   if (! ctx && !(is_friend && template_class_depth (info) > 0))
!     /* Note that we do not try to push a global template friend
!        declared in a template class; such a thing may well depend on
!        the template parameters of the class.  */
      tmpl = pushdecl_top_level (tmpl);
  
    if (primary)
!     DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
  
    info = perm_tree_cons (tmpl, args, NULL_TREE);
  
*************** push_template_decl (decl)
*** 1799,1817 ****
  
    return DECL_TEMPLATE_RESULT (tmpl);
  }
  
! /* Called when a class template TYPE is redeclared, e.g.:
  
       template <class T> struct S;
       template <class T> struct S {};  */
  
  void 
! redeclare_class_template (type)
       tree type;
  {
    tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
!   tree tmpl_parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
!   tree parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
    int i;
  
    if (!PRIMARY_TEMPLATE_P (tmpl))
--- 1835,1861 ----
  
    return DECL_TEMPLATE_RESULT (tmpl);
  }
+ 
+ tree
+ push_template_decl (decl)
+      tree decl;
+ {
+   return push_template_decl_real (decl, 0);
+ }
  
! /* Called when a class template TYPE is redeclared with the indicated
!    template PARMS, e.g.:
  
       template <class T> struct S;
       template <class T> struct S {};  */
  
  void 
! redeclare_class_template (type, parms)
       tree type;
+      tree parms;
  {
    tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
!   tree tmpl_parms;
    int i;
  
    if (!PRIMARY_TEMPLATE_P (tmpl))
*************** redeclare_class_template (type)
*** 1820,1825 ****
--- 1864,1872 ----
         type.  */
      return;
  
+   parms = INNERMOST_TEMPLATE_PARMS (parms);
+   tmpl_parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+ 
    if (TREE_VEC_LENGTH (parms) != TREE_VEC_LENGTH (tmpl_parms))
      {
        cp_error_at ("previous declaration `%D'", tmpl);
*************** coerce_template_parms (parms, arglist, i
*** 2484,2490 ****
  /* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
     of template arguments.  Returns 0 otherwise.  */
  
! static int
  comp_template_args (oldargs, newargs)
       tree oldargs, newargs;
  {
--- 2531,2537 ----
  /* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
     of template arguments.  Returns 0 otherwise.  */
  
! int
  comp_template_args (oldargs, newargs)
       tree oldargs, newargs;
  {
*************** tinst_for_decl ()
*** 3232,3238 ****
    return p;
  }
  
- 
  /* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL.  ARGS is the
     vector of template arguments, as for tsubst.
  
--- 3279,3284 ----
*************** tsubst_friend_function (decl, args)
*** 3321,3327 ****
--- 3367,3427 ----
    return new_friend;
  }
  
+ /* FRIEND_TYPE is a friend RECORD_TYPE or UNION_TYPE.  ARGS is the
+    vector of template arguments, as for tsubst.
+ 
+    Returns an appropriate tsbust'd friend type.  */
+ 
+ static tree
+ tsubst_friend_class (friend_type, args)
+      tree friend_type;
+      tree args;
+ {
+   tree tmpl = 
+     lookup_name (DECL_NAME (CLASSTYPE_TI_TEMPLATE (friend_type)), 1); 
+ 
+   if (tmpl != NULL_TREE && TREE_CODE (tmpl) == TYPE_DECL)
+     {
+       tree t;
+ 
+       for (t = current_class_type; t != NULL_TREE; t = TYPE_CONTEXT (t))
+ 	if (TREE_TYPE (tmpl) == t)
+ 	  /* A template class was declared friends with itself, or
+ 	     with one of its enclosing classes.  */
+ 	  return t;
+     }
+ 
+   if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
+     {
+       /* The friend template has already been declared.  Just
+ 	 check to see that the declarations match.  */
+       redeclare_class_template (TREE_TYPE (tmpl),
+ 				DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE 
+ 						     (friend_type)));
+       friend_type = TREE_TYPE (tmpl);
+     }
+   else
+     {
+       /* The friend template has not already been declared.  In this
+ 	 case, the instantiation of the template class will cause the
+ 	 injection of this template into the global scope.  */
+       tmpl = tsubst (CLASSTYPE_TI_TEMPLATE (friend_type), args, NULL_TREE);
+ 
+       /* The new TMPL is not an instantiation of anything, so we
+ 	 forget its origins.  We don't reset CLASSTYPE_TI_TEMPLATE for
+ 	 the new type because that is supposed to be the corresponding
+ 	 template decl, i.e., TMPL.  */
+       DECL_USE_TEMPLATE (tmpl) = 0;
+       DECL_TEMPLATE_INFO (tmpl) = NULL_TREE;
+       CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0;
+ 
+       /* Inject this template into the global scope.  */
+       friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
+     }
  
+   return friend_type;
+ }
+ 
  tree
  instantiate_class_template (type)
       tree type;
*************** instantiate_class_template (type)
*** 3584,3596 ****
  	    }
  	}
      }
  
!   t = CLASSTYPE_FRIEND_CLASSES (type)
!     = tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), args, NULL_TREE);
  
!   /* This does injection for friend classes.  */
!   for (; t; t = TREE_CHAIN (t))
!     TREE_VALUE (t) = xref_tag_from_type (TREE_VALUE (t), NULL_TREE, 1);
  
    /* This does injection for friend functions. */
    if (!processing_template_decl)
--- 3684,3709 ----
  	    }
  	}
      }
+ 
+   for (t = CLASSTYPE_FRIEND_CLASSES (pattern);
+        t != NULL_TREE;
+        t = TREE_CHAIN (t))
+     {
+       tree friend_type = TREE_VALUE (t);
  
!       if (!CLASSTYPE_IS_TEMPLATE (friend_type))
! 	/* The call to xref_tag_from_type does injection for friend
! 	   classes.  */
! 	friend_type = 
! 	  xref_tag_from_type (tsubst (friend_type, args, NULL_TREE),
! 			      NULL_TREE, 1);
!       else
! 	friend_type = tsubst_friend_class (friend_type, args);
  
!       CLASSTYPE_FRIEND_CLASSES (type) = 
! 	tree_cons (NULL_TREE, friend_type,
! 		   CLASSTYPE_FRIEND_CLASSES (type));
!     }
  
    /* This does injection for friend functions. */
    if (!processing_template_decl)
Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.57
diff -c -p -r1.57 typeck.c
*** typeck.c	1998/04/17 15:52:17	1.57
--- typeck.c	1998/04/20 19:45:26
*************** comptypes (type1, type2, strict)
*** 763,788 ****
        if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
  	  && (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)
  	      || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
! 	{
! 	  int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
! 	  tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
! 	  tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
! 	
! 	  while (i--)
! 	    {
! 	      if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
! 		{
! 		  if (! comptypes (p1[i], p2[i], 1))
! 		    return 0;
! 		}
! 	      else
! 		{
! 		  if (simple_cst_equal (p1[i], p2[i]) <= 0)
! 		    return 0;
! 		}
! 	    }
! 	  return 1;
! 	}
        if (strict <= 0)
  	goto look_hard;
        return 0;
--- 763,770 ----
        if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
  	  && (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)
  	      || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
! 	return comp_template_args (CLASSTYPE_TI_ARGS (t1),
! 				   CLASSTYPE_TI_ARGS (t2));
        if (strict <= 0)
  	goto look_hard;
        return 0;
cvs server: Diffing inc
Index: parse.y
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/parse.y,v
retrieving revision 1.48
diff -c -p -r1.48 parse.y
*** parse.y	1998/04/09 20:36:45	1.48
--- parse.y	1998/04/20 19:55:19
*************** component_decl:
*** 2498,2505 ****
                  { $$ = finish_member_template_decl ($1, $2); }
  	| template_header typed_declspecs ';'
                  {
- 		  shadow_tag ($2.t);
  		  note_list_got_semicolon ($2.t);
  		  $$ = finish_member_template_decl ($1, $2.t);
  		}
  	;
--- 2404,2415 ----
                  { $$ = finish_member_template_decl ($1, $2); }
  	| template_header typed_declspecs ';'
                  {
  		  note_list_got_semicolon ($2.t);
+ 		  grok_x_components ($2.t, NULL_TREE); 
+ 		  if (TYPE_CONTEXT (TREE_VALUE ($2.t)) != current_class_type)
+ 		    /* The component was in fact a friend
+ 		       declaration.  */
+ 		    $2.t = NULL_TREE;
  		  $$ = finish_member_template_decl ($1, $2.t);
  		}
  	;
Index: friend14.C
===================================================================
RCS file: friend14.C
diff -N friend14.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend14.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,25 ----
+ // Build don't link:
+ 
+ template <class U>
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f() { S1<T>::i = 3; }
+ };
+ 
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<long>::f();
+ }
Index: friend15.C
===================================================================
RCS file: friend15.C
diff -N friend15.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend15.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,24 ----
+ // Build don't link:
+ 
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f() { S1::i = 3; }
+ };
+ 
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<char>::f();
+ }
Index: friend16.C
===================================================================
RCS file: friend16.C
diff -N friend16.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend16.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,31 ----
+ // Build don't link:
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f();
+ };
+ 
+ 
+ template <class U>
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ 
+ template <class T>
+ void S2<T>::f() 
+ {
+   S1<T>::i = 3;
+ }
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<char>::f();
+ }
Index: friend17.C
===================================================================
RCS file: friend17.C
diff -N friend17.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend17.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,28 ----
+ // Build don't link:
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f();
+ };
+ 
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ template <class T>
+ void S2<T>::f() 
+ {
+   S1::i = 3;
+ }
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<char>::f();
+ }
Index: friend18.C
===================================================================
RCS file: friend18.C
diff -N friend18.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend18.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,26 ----
+ // Build don't link:
+ 
+ template <class U>
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f() { S1<T>::i = 3; }
+ };
+ 
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<long>::f();
+ }
+ 
Index: friend19.C
===================================================================
RCS file: friend19.C
diff -N friend19.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend19.C	Mon Apr 20 13:03:18 1998
***************
*** 0 ****
--- 1,26 ----
+ // Build don't link:
+ 
+ template <class U>
+ class S1
+ {
+   template <class T>
+   friend class S2;
+ 
+   static int i;
+ };
+ 
+ 
+ template <class T>
+ class S2
+ {
+ public:
+   static void f() { S1<T>::i = 3; }
+ };
+ 
+ 
+ void g()
+ {
+   S2<double>::f();
+   S2<long>::f();
+ }
+ 



More information about the Gcc-bugs mailing list