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]

PATCH for friend/template ICE



Here's a patch that fixes the bug you (Brendan) reported earlier
involving getline.  (The semantics of global friend templates is one of
the hardest parts of template instantiation to get right, IMHO.)

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

1998-08-20  Mark Mitchell  <mark@markmitchell.com>

	* decl.c (duplicate_decls): Always merge the old and new patterns
	for templates, regardless of whether or not the new one has
	DECL_INITIAL.  Don't throw away specializations.  Merge
	DECL_SAVED_TREE.
	* pt.c (tsubst_decl): Use the right pattern when calculating the
	complete args for a new template instance.
	(do_decl_instantiation): Fix typo in comment.
	(regenerate_decl_from_template): Deal with tricky friend template
	case.
	(instantiate_decl): Likewise.

Index: testsuite/g++.old-deja/g++.pt/friend30.C
===================================================================
RCS file: friend30.C
diff -N friend30.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- friend30.C	Thu Aug 20 13:27:48 1998
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+ 
+ template <class T, class U>
+ struct S {
+   template <class X, class Y, class Z>
+   friend X f(X, Y, Z);
+ };
+ 
+ template <class X, class Y, class Z>
+ X f(X x, Y, Z) {
+   return x;
+ }
+ 
+ template char f(char, long, short);
+ template char* f(char*, long*, short*);
+ template class S<int, double>;
+ template class S<void*, double>;
+ template double* f(double*, long*, short*);
cvs server: Diffing cp
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.182
diff -c -p -r1.182 decl.c
*** decl.c	1998/08/19 15:14:55	1.182
--- decl.c	1998/08/20 20:28:55
*************** duplicate_decls (newdecl, olddecl)
*** 2982,2998 ****
  
    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
      {
!       if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE)
! 	{
! 	  if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl),
! 				 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);
! 	  DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
! 	}
!       DECL_TEMPLATE_SPECIALIZATIONS (newdecl)
! 	= DECL_TEMPLATE_SPECIALIZATIONS (olddecl);
   
        return 1;
      }
--- 2982,2996 ----
  
    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
      {
!       if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl),
! 			     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);
!       DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
!       DECL_TEMPLATE_SPECIALIZATIONS (olddecl) 
! 	= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
! 		   DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
   
        return 1;
      }
*************** duplicate_decls (newdecl, olddecl)
*** 3067,3072 ****
--- 3065,3073 ----
  	  DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
  	  DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
  	  DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
+ 	  if (DECL_LANG_SPECIFIC (newdecl)
+ 	      && DECL_LANG_SPECIFIC (olddecl))
+ 	    DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
  	}
  
        /* Merge the section attribute.
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.178
diff -c -p -r1.178 pt.c
*** pt.c	1998/08/13 17:01:58	1.178
--- pt.c	1998/08/20 20:38:17
*************** tsubst_decl (t, args, type, in_decl)
*** 4847,4853 ****
  	       specialization, and the complete set of arguments used to
  	       specialize R.  */
  	    gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
! 	    argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
  
  	    /* Check to see if we already have this specialization.  */
  	    spec = retrieve_specialization (gen_tmpl, argvec);
--- 4847,4854 ----
  	       specialization, and the complete set of arguments used to
  	       specialize R.  */
  	    gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
! 	    argvec = tsubst (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (gen_tmpl)),
! 			     args, in_decl); 
  
  	    /* Check to see if we already have this specialization.  */
  	    spec = retrieve_specialization (gen_tmpl, argvec);
*************** do_decl_instantiation (declspecs, declar
*** 7460,7466 ****
    else if (DECL_TEMPLATE_SPECIALIZATION (decl))
      /* [temp.spec]
  
!        No program shall both explicit instantiation and explicit
         specialize a template.  */
      {
        cp_error ("explicit instantiation of `%#D' after", decl);
--- 7461,7467 ----
    else if (DECL_TEMPLATE_SPECIALIZATION (decl))
      /* [temp.spec]
  
!        No program shall both explicitly instantiate and explicitly
         specialize a template.  */
      {
        cp_error ("explicit instantiation of `%#D' after", decl);
*************** regenerate_decl_from_template (decl, tmp
*** 7649,7654 ****
--- 7650,7658 ----
    tree code_pattern;
    tree new_decl;
    tree gen_tmpl;
+   tree subst_args;
+   int args_depth;
+   int parms_depth;
    int unregistered;
  
    args = DECL_TI_ARGS (decl);
*************** regenerate_decl_from_template (decl, tmp
*** 7667,7681 ****
       register_specialization for it.  */
    my_friendly_assert (unregistered, 0);
  
!   /* Do the substitution to get the new declaration.  */
!   new_decl = tsubst (code_pattern, args, NULL_TREE);
  
    if (TREE_CODE (decl) == VAR_DECL)
      {
        /* Set up DECL_INITIAL, since tsubst doesn't.  */
        pushclass (DECL_CONTEXT (decl), 2);
        DECL_INITIAL (new_decl) = 
! 	tsubst_expr (DECL_INITIAL (code_pattern), args, 
  		     DECL_TI_TEMPLATE (decl));
        popclass (1);
      }
--- 7671,7721 ----
       register_specialization for it.  */
    my_friendly_assert (unregistered, 0);
  
!   /* Do the substitution to get the new declaration.  Normally, of
!      course, we want the full set of ARGS.  However, one peculiar case
!      is code like this: 
! 
!        template <class T> struct S { 
! 	 template <class U> friend void f();
!        };
!        template <class U> friend void f() {}
!        template S<int>;
!        template void f<double>();
! 
!      Here, the ARGS for the instantiation of will be {int, double}.
!      But, we only need as many ARGS as there are levels of template
!      parameters in CODE_PATTERN.  We are careful not to get fooled
!      into reducing the ARGS in situations like:
! 
!        template <class T> struct S { template <class U> void f(U); }
!        template <class T> template <> void S<T>::f(int) {}
! 
!      which we can spot because the innermost template args for the
!      CODE_PATTERN don't use any template parameters.  */
!   args_depth = TMPL_ARGS_DEPTH (args);
!   parms_depth = 
!     TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (code_pattern)));
!   if (args_depth > parms_depth
!       && !DECL_TEMPLATE_SPECIALIZATION (code_pattern))
!     {
!       int i;
! 
!       subst_args = make_temp_vec (parms_depth);
!       for (i = 0; i < parms_depth; ++i)
! 	TREE_VEC_ELT (subst_args, i) = 
! 	  TREE_VEC_ELT (args, i + (args_depth - parms_depth));
!     }
!   else
!     subst_args = args;
  
+   new_decl = tsubst (code_pattern, subst_args, NULL_TREE);
+ 
    if (TREE_CODE (decl) == VAR_DECL)
      {
        /* Set up DECL_INITIAL, since tsubst doesn't.  */
        pushclass (DECL_CONTEXT (decl), 2);
        DECL_INITIAL (new_decl) = 
! 	tsubst_expr (DECL_INITIAL (code_pattern), subst_args, 
  		     DECL_TI_TEMPLATE (decl));
        popclass (1);
      }
*************** instantiate_decl (d)
*** 7747,7762 ****
    if (! push_tinst_level (d))
      return d;
  
!   for (td = tmpl; 
!        DECL_TEMPLATE_INSTANTIATION (td) 
! 	 /* This next clause handles friend templates defined inside
! 	    class templates.  The friend templates are not really
! 	    instantiations from the point of view of the language, but
! 	    they are instantiations from the point of view of the
! 	    compiler.  */
! 	 || (DECL_TEMPLATE_INFO (td) && !DECL_TEMPLATE_SPECIALIZATION (td)); 
         )
!     td = DECL_TI_TEMPLATE (td);
  
    code_pattern = DECL_TEMPLATE_RESULT (td);
  
--- 7787,7846 ----
    if (! push_tinst_level (d))
      return d;
  
!   /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
!      for the instantiation.  This is not always the most general
!      template.  Consider, for example:
! 
!         template <class T>
! 	struct S { template <class U> void f();
! 	           template <> void f<int>(); };
! 
!      and an instantiation of S<double>::f<int>.  We want TD to be the
!      specialization S<T>::f<int>, not the more general S<T>::f<U>.  */
!   td = tmpl;
!   for (td = tmpl;
!        /* An instantiation cannot have a definition, so we need a
! 	  more general template.  */
!        DECL_TEMPLATE_INSTANTIATION (td)
! 	 /* We must also deal with friend templates.  Given:
! 
! 	      template <class T> struct S { 
! 		template <class U> friend void f() {};
! 	      };
! 	 
! 	    S<int>::f<U> say, is not an instantiation of S<T>::f<U>,
! 	    so far as the language is concerned, but that's still
! 	    where we get the pattern for the instantiation from.  On
! 	    ther hand, if the definition comes outside the class, say:
! 
!  	      template <class T> struct S { 
! 	        template <class U> friend void f();
!               };
! 	      template <class U> friend void f() {}
! 
! 	    we don't need to look any further.  That's what the check for
! 	    DECL_INITIAL is for.  */
! 	|| (TREE_CODE (d) == FUNCTION_DECL
! 	    && DECL_TEMPLATE_INFO (td) 
! 	    && !DECL_TEMPLATE_SPECIALIZATION (td)
! 	    && !DECL_INITIAL (DECL_TEMPLATE_RESULT (td)));
         )
!     {
!       /* The present template, TD, should not be a definition.  If it
! 	 were a definition, we should be using it!  Note that we
! 	 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); 
!       
!       /* Fetch the more general template.  */
!       td = DECL_TI_TEMPLATE (td);
!     }
  
    code_pattern = DECL_TEMPLATE_RESULT (td);
  


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