This is the mail archive of the gcc-bugs@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 member class templates



Jason --

  Here's a patch that improves the handling of member class
templates.  For example, we no longer crash, or fail to link, on the
following: 

  template <class T>
  struct S1
  {
    template <class U>
    struct S2
    { 
      S2(U);

      void g() 
	{
	  S2<U> s2u (u);
	}

      U& u;
    };

    template <class U>
    void f(U u)
      {
	S2<U> s2u(u);
	s2u.g();
      }
  };

  void g()
  {
    S1<int> s1;
    s1.f(3.0);
  }

I've got a huge test case which works succesfully after applying this
patch.   Is this OK?

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

Mon May  4 22:54:12 1998  Mark Mitchell  <mmitchell@usa.net>

	* method.c (build_overload_identifier): Only use the innermost
	template arguments when mangling.
	* pt.c (tsubst_template_argument_vector): New function.
	(complete_template_args): Deal with the situation where the
	extra_args contain more than one level of arguments.
	(lookup_template_class): Deal with member template classes, which
	may have more than one level of arguments.
	(tsubst): Don't tsbust into the TREE_TYPE of an IDENTIFIER_NODE.
	Improve handling of member template classes.  Use
	DECL_PRIMARY_TEMPLATE instead of inline expansion.  Use
	tsubst_template_argument_vector where appropriate.
	(regenerate_decl_from_template): Break out from ...
	(instantiate_decl): Here.

Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.43
diff -c -p -r1.43 method.c
*** method.c	1998/04/17 08:32:50	1.43
--- method.c	1998/05/05 05:42:32
*************** build_overload_identifier (name)
*** 894,900 ****
      {
        tree template, parmlist, arglist, tname;
        template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
!       arglist = TREE_VALUE (template);
        template = TREE_PURPOSE (template);
        tname = DECL_NAME (template);
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
--- 894,900 ----
      {
        tree template, parmlist, arglist, tname;
        template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
!       arglist = innermost_args (TREE_VALUE (template), 0);
        template = TREE_PURPOSE (template);
        tname = DECL_NAME (template);
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.124
diff -c -p -r1.124 pt.c
*** pt.c	1998/04/26 16:30:10	1.124
--- pt.c	1998/05/05 05:42:53
*************** static tree tsubst_friend_class PROTO((t
*** 103,108 ****
--- 110,117 ----
  static tree get_bindings_real PROTO((tree, tree, tree, int));
  static int template_decl_level PROTO((tree));
  static tree maybe_get_template_decl_from_type_decl PROTO((tree));
+ static tree tsubst_template_arg_vector PROTO((tree, tree));
+ static void regenerate_decl_from_template PROTO((tree, tree));
  
  /* Do any processing required when DECL (a member template declaration
     using TEMPLATE_PARAMETERS as its innermost parameter list) is
*************** is_member_template (t)
*** 357,363 ****
  }
  
  /* Return a new template argument vector which contains all of ARGS
!    for all outer templates TYPE is contained in, but has as its 
     innermost set of arguments the EXTRA_ARGS.  If UNBOUND_ONLY, we
     are only interested in unbound template arguments, not arguments from
     enclosing templates that have been instantiated already.  */
--- 367,373 ----
  }
  
  /* Return a new template argument vector which contains all of ARGS
!    for all outer templates TMPL is contained in, but has as its 
     innermost set of arguments the EXTRA_ARGS.  If UNBOUND_ONLY, we
     are only interested in unbound template arguments, not arguments from
     enclosing templates that have been instantiated already.  */
*************** complete_template_args (tmpl, extra_args
*** 370,379 ****
    /* depth is the number of levels of enclosing args we're adding.  */
    int depth, i;
    tree args, new_args, spec_args = NULL_TREE;
!   
    my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
    my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
  
    if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
      {
        /* A specialization of a member template of a template class shows up
--- 380,395 ----
    /* depth is the number of levels of enclosing args we're adding.  */
    int depth, i;
    tree args, new_args, spec_args = NULL_TREE;
!   int extra_arg_depth;
! 
    my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
    my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
  
+   if (TREE_CODE (TREE_VEC_ELT (extra_args, 0)) == TREE_VEC)
+     extra_arg_depth = TREE_VEC_LENGTH (extra_args);
+   else
+     extra_arg_depth = 1;
+ 
    if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
      {
        /* A specialization of a member template of a template class shows up
*************** complete_template_args (tmpl, extra_args
*** 402,408 ****
  	   template args.  */
  	depth = 0;
  
!       new_args = make_tree_vec (depth + 1 + (!!spec_args));
  
        if (depth == 1)
  	TREE_VEC_ELT (new_args, 0) = args;
--- 418,424 ----
  	   template args.  */
  	depth = 0;
  
!       new_args = make_tree_vec (depth + extra_arg_depth + (!!spec_args));
  
        if (depth == 1)
  	TREE_VEC_ELT (new_args, 0) = args;
*************** complete_template_args (tmpl, extra_args
*** 424,430 ****
        if (depth == 0)
  	return extra_args;
  
!       new_args = make_tree_vec (depth + 1);
  
        /* If this isn't a member template, extra_args is for the innermost
  	 template class, so skip over it.  */
--- 440,446 ----
        if (depth == 0)
  	return extra_args;
  
!       new_args = make_tree_vec (depth + extra_arg_depth);
  
        /* If this isn't a member template, extra_args is for the innermost
  	 template class, so skip over it.  */
*************** complete_template_args (tmpl, extra_args
*** 444,453 ****
  	  }
      }
  
!   TREE_VEC_ELT (new_args, depth) = extra_args;
  
    if (spec_args)
!     TREE_VEC_ELT (new_args, depth + 1) = spec_args;
  
    return new_args;
  }
--- 460,473 ----
  	  }
      }
  
!   if (extra_arg_depth == 1)
!     TREE_VEC_ELT (new_args, depth++) = extra_args;
!   else
!     for (i = 0; i < extra_arg_depth; ++i)
!       TREE_VEC_ELT (new_args, depth++) = TREE_VEC_ELT (extra_args, i);
  
    if (spec_args)
!     TREE_VEC_ELT (new_args, depth) = spec_args;
  
    return new_args;
  }
*************** push_template_decl_real (decl, is_friend
*** 1807,1814 ****
  	  cp_error ("  but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
  	}
      }
!   /* Get the innermost set of template arguments. */
!   args = innermost_args (args, 0);
  
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
--- 1827,1841 ----
  	  cp_error ("  but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
  	}
      }
!   /* Get the innermost set of template arguments.  We don't do this
!      for a non-template member function of a nested template class
!      because there we will never get a `partial instantiation' of the
!      function containing the outer arguments, and so we must save all
!      of the arguments here.  */
!   if (TREE_CODE (decl) != FUNCTION_DECL 
!       || template_class_depth (ctx) <= 1
!       || primary)
!     args = innermost_args (args, 0);
  
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
*************** lookup_template_class (d1, arglist, in_d
*** 2865,2875 ****
  	   || (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template))) 
  	       == FUNCTION_DECL))
      {
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
  
!       arglist = coerce_template_parms (parmlist, arglist, template,
! 				       1, 1, 0);
!       if (arglist == error_mark_node)
  	return error_mark_node;
        if (uses_template_parms (arglist))
  	{
--- 2892,2927 ----
  	   || (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template))) 
  	       == FUNCTION_DECL))
      {
+       tree arglist_for_mangling;
+ 
        parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
  
!       if (/* ARGLIST can be NULL_TREE if there are default arguments.  */
! 	  arglist != NULL_TREE
! 	  && TREE_CODE (arglist) == TREE_VEC 
! 	  && TREE_VEC_LENGTH (arglist) > 1
! 	  && list_length (DECL_TEMPLATE_PARMS (template)) > 1)
! 	{
! 	  /* We have multiple levels of arguments to coerce, at once.  */
! 	  tree new_args = 
! 	    make_tree_vec (list_length (DECL_TEMPLATE_PARMS (template)));
! 	  int i;
! 	  
! 	  for (i = TREE_VEC_LENGTH (arglist) - 1, 
! 		 t = DECL_TEMPLATE_PARMS (template); 
! 	       i >= 0 && t != NULL_TREE;
! 	       --i, t = TREE_CHAIN (t))
! 	    TREE_VEC_ELT (new_args, i) =
! 	      coerce_template_parms (TREE_VALUE (t),
! 				     TREE_VEC_ELT (arglist, i),
! 				     template, 1, 1, 0);
! 	  arglist = new_args;
! 	}
!       else
! 	arglist = coerce_template_parms (parmlist, 
! 					 innermost_args (arglist, 0),
! 					 template, 1, 1, 0);
!      if (arglist == error_mark_node)
  	return error_mark_node;
        if (uses_template_parms (arglist))
  	{
*************** lookup_template_class (d1, arglist, in_d
*** 2898,2907 ****
  	    }
  	}
  
        /* FIXME avoid duplication.  */
        mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
  						     parmlist,
! 						     arglist,
  						     context);
        id = get_identifier (mangled_name);
        IDENTIFIER_TEMPLATE (id) = d1;
--- 2950,2964 ----
  	    }
  	}
  
+       if (TREE_CODE (arglist) == TREE_VEC)
+ 	arglist_for_mangling = innermost_args (arglist, 0);
+       else
+ 	arglist_for_mangling = arglist;
+ 
        /* FIXME avoid duplication.  */
        mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
  						     parmlist,
! 						     arglist_for_mangling,
  						     context);
        id = get_identifier (mangled_name);
        IDENTIFIER_TEMPLATE (id) = d1;
*************** innermost_args (args, is_spec)
*** 3829,3839 ****
       tree args;
       int is_spec;
  {
!   if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
      return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
    return args;
  }
  
  /* Take the tree structure T and replace template parameters used therein
     with the argument vector ARGS.  IN_DECL is an associated decl for
     diagnostics.
--- 3886,3931 ----
       tree args;
       int is_spec;
  {
!   if (args != NULL_TREE && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
      return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
    return args;
  }
  
+ /* Substitute ARGS into the vector of template arguments T.  */
+ 
+ tree
+ tsubst_template_arg_vector (t, args)
+      tree t;
+      tree args;
+ {
+   int len = TREE_VEC_LENGTH (t), need_new = 0, i;
+   tree *elts = (tree *) alloca (len * sizeof (tree));
+   
+   bzero ((char *) elts, len * sizeof (tree));
+   
+   for (i = 0; i < len; i++)
+     {
+       if (TREE_VEC_ELT (t, i) != NULL_TREE
+ 	  && TREE_CODE (TREE_VEC_ELT (t, i)) == TREE_VEC)
+ 	elts[i] = tsubst_template_arg_vector (TREE_VEC_ELT (t, i), args);
+       else
+ 	elts[i] = maybe_fold_nontype_arg
+ 	  (tsubst_expr (TREE_VEC_ELT (t, i), args, NULL_TREE));
+       
+       if (elts[i] != TREE_VEC_ELT (t, i))
+ 	need_new = 1;
+     }
+   
+   if (!need_new)
+     return t;
+   
+   t = make_tree_vec (len);
+   for (i = 0; i < len; i++)
+     TREE_VEC_ELT (t, i) = elts[i];
+   
+   return t;
+ }
+ 
  /* Take the tree structure T and replace template parameters used therein
     with the argument vector ARGS.  IN_DECL is an associated decl for
     diagnostics.
*************** tsubst (t, args, in_decl)
*** 3857,3863 ****
--- 3949,3957 ----
    type = TREE_TYPE (t);
    if (type == unknown_type_node)
      my_friendly_abort (42);
+ 
    if (type && TREE_CODE (t) != FUNCTION_DECL
+       && TREE_CODE (t) != IDENTIFIER_NODE
        && TREE_CODE (t) != TYPENAME_TYPE
        && TREE_CODE (t) != TEMPLATE_DECL)
      type = tsubst (type, args, in_decl);
*************** tsubst (t, args, in_decl)
*** 3881,3894 ****
  	  tree context;
  	  tree r;
  
! 	  context = 
! 	    TYPE_CONTEXT (t) 
! 	    ? tsubst (TYPE_CONTEXT (t), args, in_decl) : NULL_TREE;
  
  	  r = lookup_template_class (t, argvec, in_decl, context);
  
  	  return cp_build_type_variant (r, TYPE_READONLY (t),
! 				TYPE_VOLATILE (t));
  	}
  
        /* else fall through */
--- 3975,4006 ----
  	  tree context;
  	  tree r;
  
! 	  if (TYPE_CONTEXT (t) != NULL_TREE)
! 	    {
! 	      context = tsubst (TYPE_CONTEXT (t), args, in_decl);
! 	  
! 	      if (TREE_CODE (context) != FUNCTION_DECL)
! 		{
! 		  /* For a member class template, we need all the
! 		     template arguments.  */
! 		  if (CLASSTYPE_IS_TEMPLATE (TYPE_CONTEXT (t)))
! 		    argvec = 
! 		      add_to_template_args (CLASSTYPE_TI_ARGS (context),
! 					    argvec);
! 
! 		  if (CLASSTYPE_TEMPLATE_INFO (context))
! 		    argvec = 
! 		      complete_template_args (CLASSTYPE_TI_TEMPLATE (context),
! 					      argvec, 0);
! 		}
! 	    }
! 	  else
! 	    context = NULL_TREE;
  
  	  r = lookup_template_class (t, argvec, in_decl, context);
  
  	  return cp_build_type_variant (r, TYPE_READONLY (t),
! 					TYPE_VOLATILE (t));
  	}
  
        /* else fall through */
*************** tsubst (t, args, in_decl)
*** 4157,4163 ****
  	  }
  
  	if (PRIMARY_TEMPLATE_P (t))
! 	  TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
  
  	/* We don't partially instantiate partial specializations.  */
  	if (TREE_CODE (decl) == TYPE_DECL)
--- 4269,4275 ----
  	  }
  
  	if (PRIMARY_TEMPLATE_P (t))
! 	  DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
  
  	/* We don't partially instantiate partial specializations.  */
  	if (TREE_CODE (decl) == TYPE_DECL)
*************** tsubst (t, args, in_decl)
*** 4596,4625 ****
  	}
  
        /* Otherwise, a vector of template arguments.  */
!       {
! 	int len = TREE_VEC_LENGTH (t), need_new = 0, i;
! 	tree *elts = (tree *) alloca (len * sizeof (tree));
! 
! 	bzero ((char *) elts, len * sizeof (tree));
! 
! 	for (i = 0; i < len; i++)
! 	  {
! 	    elts[i] = maybe_fold_nontype_arg
! 	      (tsubst_expr (TREE_VEC_ELT (t, i), args, in_decl));
! 
! 	    if (elts[i] != TREE_VEC_ELT (t, i))
! 	      need_new = 1;
! 	  }
  
- 	if (!need_new)
- 	  return t;
- 
- 	t = make_tree_vec (len);
- 	for (i = 0; i < len; i++)
- 	  TREE_VEC_ELT (t, i) = elts[i];
- 	
- 	return t;
-       }
      case POINTER_TYPE:
      case REFERENCE_TYPE:
        {
--- 4708,4715 ----
  	}
  
        /* Otherwise, a vector of template arguments.  */
!       return tsubst_template_arg_vector (t, args);
  
      case POINTER_TYPE:
      case REFERENCE_TYPE:
        {
*************** do_type_instantiation (t, storage)
*** 6579,6584 ****
--- 6834,6908 ----
    }
  }
  
+ /* Given a function DECL, which is a specialization of TEMP, modify
+    DECL to be a re-instantiation of TEMPL with the same template
+    arguments.
+ 
+    One reason for doing this is a scenario like this:
+ 
+      template <class T>
+      void f(const T&, int i);
+ 
+      void g() { f(3, 7); }
+ 
+      template <class T>
+      void f(const T& t, const int i) { }
+ 
+    Note that when the template is first instantiated, with
+    instantiate_template, the resulting DECL will have no name for the
+    first parameter, and the wrong type for the second.  So, when we go
+    to instantiate the DECL, we regenerate it.  */
+ 
+ void
+ regenerate_decl_from_template (decl, tmpl)
+      tree decl;
+      tree tmpl;
+ {
+   tree args;
+   tree save_ti;
+   tree code_pattern;
+   tree new_decl;
+ 
+   args = DECL_TI_ARGS (decl);
+   code_pattern = DECL_TEMPLATE_RESULT (tmpl);
+ 
+   /* Trick tsubst into giving us a new decl.  CODE_PATTERN must be the
+      most distant ancestor of DECL, since that's the one that will
+      actually be altered by a redefinition.  */
+   save_ti = DECL_TEMPLATE_INFO (code_pattern);
+   DECL_TEMPLATE_INFO (code_pattern) = NULL_TREE;
+   new_decl = tsubst (code_pattern, args, NULL_TREE);
+   SET_DECL_IMPLICIT_INSTANTIATION (new_decl);
+   DECL_TEMPLATE_INFO (code_pattern) = save_ti;
+ 
+   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);
+     }
+ 
+   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;
+ 
+       if (DECL_TEMPLATE_SPECIALIZATION (new_decl) 
+ 	  && !DECL_TEMPLATE_INFO (new_decl))
+ 	/* Set up the information about what is being specialized. */
+ 	DECL_TEMPLATE_INFO (new_decl) = DECL_TEMPLATE_INFO (decl);
+     }
+ 
+   duplicate_decls (new_decl, decl);
+ 
+   if (TREE_CODE (decl) == FUNCTION_DECL)
+     DECL_INITIAL (new_decl) = NULL_TREE;
+ }
+ 
  /* Produce the definition of D, a _DECL generated from a template.  */
  
  tree
*************** instantiate_decl (d)
*** 6588,6594 ****
    tree ti = DECL_TEMPLATE_INFO (d);
    tree tmpl = TI_TEMPLATE (ti);
    tree args = TI_ARGS (ti);
!   tree td, temp;
    tree decl_pattern, code_pattern;
    tree save_ti;
    int nested = in_function_p ();
--- 6912,6918 ----
    tree ti = DECL_TEMPLATE_INFO (d);
    tree tmpl = TI_TEMPLATE (ti);
    tree args = TI_ARGS (ti);
!   tree td;
    tree decl_pattern, code_pattern;
    tree save_ti;
    int nested = in_function_p ();
*************** instantiate_decl (d)
*** 6697,6735 ****
  
    lineno = DECL_SOURCE_LINE (d);
    input_filename = DECL_SOURCE_FILE (d);
- 
-   /* Trick tsubst into giving us a new decl in case the template changed.  */
-   save_ti = DECL_TEMPLATE_INFO (decl_pattern);
-   DECL_TEMPLATE_INFO (decl_pattern) = NULL_TREE;
-   /* decl_pattern has all but one level of template parms bound.  Only pass
-      in that one level of args.  */
-   temp = innermost_args (args, DECL_TEMPLATE_SPECIALIZATION (decl_pattern));
-   td = tsubst (decl_pattern, temp, tmpl);
-   SET_DECL_IMPLICIT_INSTANTIATION (td);
-   DECL_TEMPLATE_INFO (decl_pattern) = save_ti;
  
!   /* And set up DECL_INITIAL, since tsubst doesn't.  */
!   if (TREE_CODE (td) == VAR_DECL)
!     {
!       pushclass (DECL_CONTEXT (d), 2);
!       DECL_INITIAL (td) = tsubst_expr (DECL_INITIAL (code_pattern), args,
! 				       tmpl);
!       popclass (1);
!     }
! 
!   if (TREE_CODE (d) == FUNCTION_DECL)
!     {
!       /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
! 	 new decl.  */ 
!       DECL_INITIAL (td) = error_mark_node;
! 
!       if (DECL_TEMPLATE_SPECIALIZATION (td) && !DECL_TEMPLATE_INFO (td))
! 	/* Set up the information about what is being specialized. */
! 	DECL_TEMPLATE_INFO (td) = DECL_TEMPLATE_INFO (d);
!     }
!   duplicate_decls (td, d);
!   if (TREE_CODE (d) == FUNCTION_DECL)
!     DECL_INITIAL (td) = 0;
  
    if (TREE_CODE (d) == VAR_DECL)
      {
--- 7021,7028 ----
  
    lineno = DECL_SOURCE_LINE (d);
    input_filename = DECL_SOURCE_FILE (d);
  
!   regenerate_decl_from_template (d, td);
  
    if (TREE_CODE (d) == VAR_DECL)
      {
Index: testsuite/g++.old-deja/g++.pt/memclass9.C
===================================================================
RCS file: memclass9.C
diff -N memclass9.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- memclass9.C	Mon May  4 22:42:53 1998
***************
*** 0 ****
--- 1,30 ----
+ template <class T>
+ struct S1
+ {
+   template <class U>
+   struct S2
+   { 
+     S2(U);
+ 
+     void g() 
+       {
+ 	S2<U> s2u (u);
+       }
+ 
+     U& u;
+   };
+ 
+   template <class U>
+   void f(U u)
+     {
+       S2<U> s2u(u);
+       s2u.g();
+     }
+ };
+ 
+ void g()
+ {
+   S1<int> s1;
+   s1.f(3.0);
+ }
+ 


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