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 friends/templates



This patch fixes ttp53.C, and also catches illegal redefinitions of
templates in instantiated friend declarations.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-11-16  Mark Mitchell  <mark@markmitchell.com>

	* cp-tree.h (DECL_TEMPLATE_INSTANTIATED): New macro.
	* decl.c (duplicate_decls): Remove special-case code to deal with
	template friends, and just do the obvious thing.
	* pt.c (register_specialization): Tweak for clarity, and also to
	clear DECL_INITIAL for an instantiation before it is merged with a
	specialization.
	(check_explicit_specialization): Fix indentation.
	(tsubst_friend_function): Handle both definitions in friend
	declaration and outside friend declarations.
	(tsubst_decl): Don't clear DECL_INITIAL for an instantiation.
	(regenerate_decl_from_template): Tweak accordingly.
	(instantiate_decl): Likewise.
	
Index: testsuite/g++.old-deja/g++.pt/friend36.C
===================================================================
RCS file: friend36.C
diff -N friend36.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend36.C	Sun Nov 15 19:03:26 1998
***************
*** 0 ****
--- 1,12 ----
+ // Build don't link:
+ 
+ template <class T>
+ void f(T) {} // ERROR - previously defined here
+ 
+ template <class U>
+ struct S {
+   template <class T>
+   friend void f(T) {} // ERROR - redeclaration
+ };
+ 
+ S<int> si;
Index: testsuite/g++.old-deja/g++.pt/ttp53.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C,v
retrieving revision 1.1
diff -c -p -r1.1 ttp53.C
*** ttp53.C	1998/10/11 19:59:27	1.1
--- ttp53.C	1998/11/16 03:03:27
*************** class H{
*** 13,19 ****
  public:
  #endif
    template<template<class, class> class Caster, typename Source>
!   static H<Type> cast(const H<Source>& s); // gets bogus error - candidate - XFAIL *-*-*
  
  #ifndef OK
    template <typename Target, typename Source>
--- 13,19 ----
  public:
  #endif
    template<template<class, class> class Caster, typename Source>
!   static H<Type> cast(const H<Source>& s);
  
  #ifndef OK
    template <typename Target, typename Source>
*************** template <class, class> class caster;
*** 26,35 ****
  
  template <typename Target, typename Source>
  H<Target> foo(const H<Source>& s){
!   return H<Target>::template cast<caster, Source>(s); // gets bogus error - no match - XFAIL *-*-*
  }
  
  int main(){
    H<int> i;
!   foo<const int>(i); // gets bogus error - instantiated from here - XFAIL *-*-*
  }
--- 26,35 ----
  
  template <typename Target, typename Source>
  H<Target> foo(const H<Source>& s){
!   return H<Target>::template cast<caster, Source>(s);
  }
  
  int main(){
    H<int> i;
!   foo<const int>(i);
  }
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.170
diff -c -p -r1.170 cp-tree.h
*** cp-tree.h	1998/11/07 12:54:32	1.170
--- cp-tree.h	1998/11/16 15:42:47
*************** Boston, MA 02111-1307, USA.  */
*** 65,70 ****
--- 65,71 ----
     Usage of DECL_LANG_FLAG_?:
     0: DECL_ERROR_REPORTED (in VAR_DECL).
     1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
+       DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
     2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
     3: DECL_IN_AGGR_P.
     4: DECL_MAYBE_TEMPLATE.
*************** extern int flag_new_for_scope;
*** 1812,1817 ****
--- 1813,1824 ----
  
  /* This function may be a guiding decl for a template.  */
  #define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
+ 
+ /* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
+    instantiated, i.e. its definition has been generated from the
+    pattern given in the the template.  */
+ #define DECL_TEMPLATE_INSTANTIATED(NODE) DECL_LANG_FLAG_1(NODE)
+ 
  /* We know what we're doing with this decl now.  */
  #define DECL_INTERFACE_KNOWN(NODE) DECL_LANG_FLAG_5 (NODE)
  
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.258
diff -c -p -r1.258 decl.c
*** decl.c	1998/11/15 19:24:38	1.258
--- decl.c	1998/11/16 15:42:55
*************** duplicate_decls (newdecl, olddecl)
*** 2989,2997 ****
  			     DECL_TEMPLATE_RESULT (olddecl)))
  	cp_error ("invalid redeclaration of %D", newdecl);
        TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
-       DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
-       if (DECL_TEMPLATE_INFO (newdecl))
- 	DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
        DECL_TEMPLATE_SPECIALIZATIONS (olddecl) 
  	= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
  		   DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
--- 2989,2994 ----
*************** duplicate_decls (newdecl, olddecl)
*** 3123,3133 ****
        DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
        DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
        DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
!       if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
! 	{
! 	  DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
! 	  DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
! 	}
        olddecl_friend = DECL_FRIEND_P (olddecl);
      }
  
--- 3120,3126 ----
        DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
        DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
        DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
!       DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
        olddecl_friend = DECL_FRIEND_P (olddecl);
      }
  
Index: pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.234
diff -c -p -r1.234 pt.c
*** pt.c	1998/11/15 19:24:40	1.234
--- pt.c	1998/11/16 15:43:00
*************** register_specialization (spec, tmpl, arg
*** 831,845 ****
  
  		       We transform the existing DECL in place so that
  		       any pointers to it become pointers to the
! 		       updated declaration.  */
! 		    duplicate_decls (spec, TREE_VALUE (s));
! 		    return TREE_VALUE (s);
  		  }
  	      }
  	    else if (DECL_TEMPLATE_SPECIALIZATION (fn))
  	      {
! 		duplicate_decls (spec, TREE_VALUE (s));
! 		return TREE_VALUE (s);
  	      }
  	  }
        }
--- 831,852 ----
  
  		       We transform the existing DECL in place so that
  		       any pointers to it become pointers to the
! 		       updated declaration.  
! 
! 		       If there was a definition for the template, but
! 		       not for the specialization, we want this to
! 		       look as if there is no definition, and vice
! 		       versa.  */
! 		    DECL_INITIAL (fn) = NULL_TREE;
! 		    duplicate_decls (spec, fn);
! 
! 		    return fn;
  		  }
  	      }
  	    else if (DECL_TEMPLATE_SPECIALIZATION (fn))
  	      {
! 		duplicate_decls (spec, fn);
! 		return fn;
  	      }
  	  }
        }
*************** check_explicit_specialization (declarato
*** 1369,1375 ****
  	    /* This is not really a declaration of a specialization.
  	       It's just the name of an instantiation.  But, it's not
  	       a request for an instantiation, either.  */
! 	      SET_DECL_IMPLICIT_INSTANTIATION (decl);
  
  	  /* Register this specialization so that we can find it
  	     again.  */
--- 1376,1382 ----
  	    /* This is not really a declaration of a specialization.
  	       It's just the name of an instantiation.  But, it's not
  	       a request for an instantiation, either.  */
! 	    SET_DECL_IMPLICIT_INSTANTIATION (decl);
  
  	  /* Register this specialization so that we can find it
  	     again.  */
*************** tsubst_friend_function (decl, args)
*** 4247,4262 ****
    if (DECL_NAMESPACE_SCOPE_P (new_friend))
      {
        tree old_decl;
!       tree new_friend_args;
! 
        if (TREE_CODE (new_friend) == TEMPLATE_DECL)
! 	/* This declaration is a `primary' template.  */
! 	DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
  
-       /* We must save the DECL_TI_ARGS for NEW_FRIEND here because
- 	 pushdecl may call duplicate_decls which will free NEW_FRIEND
- 	 if possible.  */
-       new_friend_args = DECL_TI_ARGS (new_friend);
        old_decl = pushdecl_namespace_level (new_friend);
  
        if (old_decl != new_friend)
--- 4254,4283 ----
    if (DECL_NAMESPACE_SCOPE_P (new_friend))
      {
        tree old_decl;
!       tree new_friend_template_info;
!       tree new_friend_result_template_info;
!       int  new_friend_is_defn;
! 
!       /* We must save some information from NEW_FRIEND before calling
! 	 duplicate decls since that function will free NEW_FRIEND if
! 	 possible.  */
!       new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
        if (TREE_CODE (new_friend) == TEMPLATE_DECL)
! 	{
! 	  /* This declaration is a `primary' template.  */
! 	  DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
! 	  
! 	  new_friend_is_defn 
! 	    = DECL_INITIAL (DECL_RESULT (new_friend)) != NULL_TREE;
! 	  new_friend_result_template_info
! 	    = DECL_TEMPLATE_INFO (DECL_RESULT (new_friend));
! 	}
!       else
! 	{
! 	  new_friend_is_defn = DECL_INITIAL (new_friend) != NULL_TREE;
! 	  new_friend_result_template_info = NULL_TREE;
! 	}
  
        old_decl = pushdecl_namespace_level (new_friend);
  
        if (old_decl != new_friend)
*************** tsubst_friend_function (decl, args)
*** 4295,4330 ****
  	     when `C<int>' is instantiated.  Now, `f(int)' is defined
  	     in the class.  */
  
! 	  if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! 	    /* duplicate_decls will take care of this case.  */
  	    ;
! 	  else 
  	    {
! 	      tree t;
! 
! 	      for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl); 
! 		   t != NULL_TREE;
! 		   t = TREE_CHAIN (t))
  		{
! 		  tree spec = TREE_VALUE (t);
! 		  
! 		  DECL_TI_ARGS (spec) 
! 		    = add_outermost_template_args (new_friend_args,
! 						   DECL_TI_ARGS (spec));
! 		  DECL_TI_ARGS (spec)
! 		    = copy_to_permanent (DECL_TI_ARGS (spec));
! 		}
  
! 	      /* Now, since specializations are always supposed to
! 		 hang off of the most general template, we must move
! 		 them.  */
! 	      t = most_general_template (old_decl);
! 	      if (t != old_decl)
! 		{
! 		  DECL_TEMPLATE_SPECIALIZATIONS (t)
! 		    = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
! 			       DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
! 		  DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
  		}
  	    }
  
--- 4316,4370 ----
  	     when `C<int>' is instantiated.  Now, `f(int)' is defined
  	     in the class.  */
  
! 	  if (!new_friend_is_defn)
! 	    /* On the other hand, if the in-class declaration does
! 	       *not* provide a definition, then we don't want to alter
! 	       existing definitions.  We can just leave everything
! 	       alone.  */
  	    ;
! 	  else
  	    {
! 	      /* Overwrite whatever template info was there before, if
! 		 any, with the new template information pertaining to
! 		 the declaration.  */
! 	      DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
! 
! 	      if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! 		/* duplicate_decls will take care of this case.  */
! 		;
! 	      else 
  		{
! 		  tree t;
! 		  tree new_friend_args;
  
! 		  DECL_TEMPLATE_INFO (DECL_RESULT (old_decl)) 
! 		    = new_friend_result_template_info;
! 		    
! 		  new_friend_args = TI_ARGS (new_friend_template_info);
! 		  for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl); 
! 		       t != NULL_TREE;
! 		       t = TREE_CHAIN (t))
! 		    {
! 		      tree spec = TREE_VALUE (t);
! 		  
! 		      DECL_TI_ARGS (spec) 
! 			= add_outermost_template_args (new_friend_args,
! 						       DECL_TI_ARGS (spec));
! 		      DECL_TI_ARGS (spec)
! 			= copy_to_permanent (DECL_TI_ARGS (spec));
! 		    }
! 
! 		  /* Now, since specializations are always supposed to
! 		     hang off of the most general template, we must move
! 		     them.  */
! 		  t = most_general_template (old_decl);
! 		  if (t != old_decl)
! 		    {
! 		      DECL_TEMPLATE_SPECIALIZATIONS (t)
! 			= chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
! 				   DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
! 		      DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
! 		    }
  		}
  	    }
  
*************** tsubst_decl (t, args, type, in_decl)
*** 5312,5318 ****
  	DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
  	DECL_MAIN_VARIANT (r) = r;
  	DECL_RESULT (r) = NULL_TREE;
- 	DECL_INITIAL (r) = NULL_TREE;
  
  	TREE_STATIC (r) = 0;
  	TREE_PUBLIC (r) = TREE_PUBLIC (t);
--- 5352,5357 ----
*************** regenerate_decl_from_template (decl, tmp
*** 8285,8293 ****
      }
  
    if (TREE_CODE (decl) == FUNCTION_DECL)
!     /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
!        new decl.  */ 
!     DECL_INITIAL (new_decl) = error_mark_node;
  
    /* The immediate parent of the new template is still whatever it was
       before, even though tsubst sets DECL_TI_TEMPLATE up as the most
--- 8324,8336 ----
      }
  
    if (TREE_CODE (decl) == FUNCTION_DECL)
!     {
!       /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
! 	 new decl.  */ 
!       DECL_INITIAL (new_decl) = error_mark_node;
!       /* And don't complain about a duplicate definition.  */
!       DECL_INITIAL (decl) = NULL_TREE;
!     }
  
    /* The immediate parent of the new template is still whatever it was
       before, even though tsubst sets DECL_TI_TEMPLATE up as the most
*************** regenerate_decl_from_template (decl, tmp
*** 8303,8311 ****
    /* Call duplicate decls to merge the old and new declarations.  */
    duplicate_decls (new_decl, decl);
  
-   if (TREE_CODE (decl) == FUNCTION_DECL)
-     DECL_INITIAL (new_decl) = NULL_TREE;
- 
    /* Now, re-register the specialization.  */
    register_specialization (decl, gen_tmpl, args);
  }
--- 8346,8351 ----
*************** instantiate_decl (d)
*** 8332,8339 ****
    my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
  		      || TREE_CODE (d) == VAR_DECL, 0);
  
!   if ((TREE_CODE (d) == FUNCTION_DECL && DECL_INITIAL (d))
!       || (TREE_CODE (d) == VAR_DECL && !DECL_IN_AGGR_P (d)))
      /* D has already been instantiated.  It might seem reasonable to
         check whether or not D is an explict instantiation, and, if so,
         stop here.  But when an explicit instantiation is deferred
--- 8372,8378 ----
    my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
  		      || TREE_CODE (d) == VAR_DECL, 0);
  
!   if (DECL_TEMPLATE_INSTANTIATED (d))
      /* D has already been instantiated.  It might seem reasonable to
         check whether or not D is an explict instantiation, and, if so,
         stop here.  But when an explicit instantiation is deferred
*************** instantiate_decl (d)
*** 8398,8406 ****
  	 cannot restructure the loop to just keep going until we find
  	 a template with a definition, since that might go too far if
  	 a specialization was declared, but not defined.  */
-       my_friendly_assert (!(TREE_CODE (d) == FUNCTION_DECL
- 			    && DECL_INITIAL (DECL_TEMPLATE_RESULT (td))),
- 			  0);
        my_friendly_assert (!(TREE_CODE (d) == VAR_DECL
  			    && !DECL_IN_AGGR_P (DECL_TEMPLATE_RESULT (td))), 
  			  0); 
--- 8437,8442 ----
*************** instantiate_decl (d)
*** 8483,8488 ****
--- 8519,8525 ----
      }
  
    regenerate_decl_from_template (d, td);
+   DECL_TEMPLATE_INSTANTIATED (d) = 1;
  
    /* We already set the file and line above.  Reset them now in case
       they changed as a result of calling regenerate_decl_from_template.  */


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