Member Templates

Mark Mitchell mmitchell@usa.net
Fri Sep 5 15:57:00 GMT 1997


Several of you are trying out the C++ member templates patch I posted
several days ago.  Thank you!

Thanks to Jason Merrill, who has provided considerable insight, I have
a much improved version of the patch.  Since so many of you have sent
me mail saying that you're trying the patch, I thought I should post
the newest version, which fixes several of the most obvious bugs in
the original.

It seems probable that this version will be in the next snapshot.

I'd appreciate reports of success or failure with this new version.

The patch below is against the 970904 snapshot.

Thanks,

-- 
Mark Mitchell		mmitchell@usa.net
Stanford University	http://www.stanford.edu

Index: gcc/cp/ChangeLog
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/ChangeLog,v
retrieving revision 1.1.1.4
retrieving revision 1.4
diff -c -p -r1.1.1.4 -r1.4
*** ChangeLog	1997/09/04 18:09:44	1.1.1.4
--- ChangeLog	1997/09/05 20:23:58	1.4
***************
*** 1,3 ****
--- 1,45 ----
+ Fri Sep  5 01:37:17 1997  Mark Mitchell  <mmitchell@usa.net>
+ 
+ 	* cp-tree.h (INNERMOST_TEMPLATE_PARMS): New macro.
+ 	(DECL_INNERMOST_TEMPLATE_PARMS): Likewise.
+ 	(PRIMARY_TEMPLATE_P): Use it.
+ 	* call.c (build_overload_call_real): Use it.
+ 	* class.c (instantiate_type): Likewise.
+ 	* decl.c (decls_match): Likewise.
+ 	* method.c (build_overload_identifier): Likewise.
+ 	* pt.c (push_template_decl): Likewise.
+ 	(classtype_mangled_name): Likewise.
+ 	(lookup_template_class): Likewise.
+ 	
+ 	* cp-tree.h (DECL_NTPARMS): Change name from DECL_NT_PARMS to
+ 	DECL_NTPARMS to conform to usage elsewhere.
+ 	* call.c (add_template_candidate): Likewise.
+ 	* class.c (instantiate_type): Likewise.
+ 	* pt.c (instantiate_template): Likewise.
+ 	(get_bindings): Likewise.
+ 	
+ 	* class.c (grow_method): Use DECL_FUNCTION_TEMPLATE_P instead of
+ 	is_member_template.
+ 
+ 	* pt.c (unify): Undo changes to allow multiple levels of template
+ 	parameters. 
+ 	(type_unification): Likewise.
+ 	(fn_type_unification): Likewise.
+ 	(get_class_bindings): Likewise.
+ 	* cp-tree.h (Likewise).
+ 	
+ 	* decl.c (replace_defarg): Check that the type of the default
+ 	parameter does not invlove a template type before complaining
+ 	about the initialization.
+ 
+ 	* error.c (dump_expr): Deal with template constant parameters in
+ 	member templates correctly.
+ 
+ 	* pt.c (is_member_template): Deal with class specializations
+ 	correctly. 
+ 	(tsubst): Handle "partial instantiation" of member templates
+ 	correctly. 
+ 	
  Wed Sep  3 11:09:25 1997  Jason Merrill  <jason@yorick.cygnus.com>
  
  	* typeck.c (c_expand_return): Always convert_for_initialization
*************** Wed Sep  3 00:02:53 1997  Jason Merrill 
*** 15,20 ****
--- 57,159 ----
  
  	* typeck.c (convert_arguments): Don't arbitrarily choose the first
   	of a set of overloaded functions.
+ 
+ Wed Sep  3 12:30:24 1997  Mark Mitchell  <mmitchell@usa.net>
+ 
+ 	* pt.c (type_uniciation): Change calling squence to allow for
+ 	multiple levels of template parameters.
+ 	(tsubst_expr): Likewise.
+ 	(tsubst): Likewise.
+ 	(tsubst_copy): Likewise.
+ 	(instantiate_template): Likewise.
+ 	(unify): Likewise.
+ 	* call.c (build_overload_call_real): Use it.
+ 	(add_builtin_candidate): Use it.
+ 	(build_new_method_call): Use it.
+ 	* class.c (instantiate_type): Use it.
+ 	* decl.c (grokdeclarator): Use it.
+ 	* decl2.c (finish_file): Use it.
+ 	* method.c (build_overload_identifier): Use it.
+ 	
+ 	* call.c (add_template_candidate):  Add additional parameter for
+ 	the function return type.  Call fn_type_unification istead of
+ 	type_unification.
+ 	(build_user_type_conversion_1): Handle member templates.
+ 	(build_new_function_call): Likewise.
+ 	(build_new_op): Likewise.
+ 	(build_new_method_call): Likewise.
+ 	
+ 	* class.c (grow_method): Don't give an error message indicating
+  	that two member templates with the same name are ambiguous.
+ 	(finish_struct): Treat member template functions just like member
+  	functions.
+ 	
+ 	* cp-tree.h (check_member_template): Add declaration.
+ 	(begin_member_template_processing): Likewise.
+ 	(end_member_template_processing): Likewise.
+ 	(fn_type_unification): Likewise.
+ 	(is_member_template): Likewise.
+ 	(tsubst): Change prototype.
+ 	(tsubst_expr): Likewise.
+ 	(tsubst_copy): Likewise.
+ 	(instantiate_template): Likewise.
+ 	(get_bindings): Likewise.
+ 
+ 	* decl.c (decls_match): Handle multiple levels of template
+ 	parameters. 
+ 	(pushdecl): Handle template type params just like other type
+ 	declarations. 
+ 	(push_class_level_binding): Return immediately if the
+ 	class_binding_level is NULL.
+ 	(grokfndecl): If check_classfn() returns a member_template, use
+ 	the result of the template, not the template itself.
+ 	
+ 	* decl2.c (check_member_template): New function.  Check to see
+ 	that the entity declared to be a member template can be one.
+ 	(check_classfn): Allow redeclaration of member template functions
+ 	with different types; the new functions can be specializations or
+ 	explicit instantiations.
+ 	
+ 	* error.c (dump_decl): Handle multiple levels of template
+ 	parametesr. 
+ 	(dump_function_decl): Update to handle function	templates.
+ 
+ 	* lex.c (do_pending_inlines): Set up template parameter context
+ 	for member templates.
+ 	(process_next_inline): Likewise.
+ 
+ 	* method. (build_overload_identifier): Adjust for multiple levels
+ 	of template parameters.
+ 	
+ 	* parse.y (fn.def2): Add member templates.
+ 	(component_decl_1): Likewise.
+ 
+ 	* pt.c (begin_member_template_processing): New function.
+ 	(end_member_template_processing): Likewise.
+ 	(is_member_template): Likewise.
+ 	(fn_type_unification): Likewise.
+ 	(current_template_parms): Return a vector of all the template
+ 	parms, not just the innermost level of parms.
+ 	(push_template_decl): Deal with the possibility of member
+ 	templates. 
+ 	(lookup_template_class): Likewise.
+ 	(uses_template_parms): Likewise.
+ 	(tsubst): Modify processing to TEMPLATE_TYPE_PARM and
+ 	TEMPLATE_CONST_PARM to deal with multiple levels of template
+ 	arguments.   Add processing of TEMPLATE_DECL to produce new
+ 	TEMPLATE_DECLs from old ones.
+ 	(do_decl_instantiation): Handle member templates.
+ 
+ 	* search.c (lookup_fnfields_1): Handle member template conversion
+ 	operators. 
+ 
+ 	* tree.c (cp_tree_equal): Check the levels, as well as the
+ 	indices, of TEMPLATE_CONST_PARMs.
+ 
+ 	* typeck.c (comptypes): Check the levels, as well as the indices,
+ 	fo TEMPLATE_TYPE_PARMs.
+ 	(build_x_function_call): Treat member templates like member
+ 	functions. 
  
  Tue Sep  2 12:09:13 1997  Jason Merrill  <jason@yorick.cygnus.com>
  
Index: gcc/cp/call.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/call.c,v
retrieving revision 1.1.1.4
retrieving revision 1.4
diff -c -p -r1.1.1.4 -r1.4
*** call.c	1997/09/04 18:09:45	1.1.1.4
--- call.c	1997/09/05 20:23:59	1.4
*************** static tree build_this PROTO((tree));
*** 77,83 ****
  static struct z_candidate * splice_viable PROTO((struct z_candidate *));
  static int any_viable PROTO((struct z_candidate *));
  static struct z_candidate * add_template_candidate
! 	PROTO((struct z_candidate *, tree, tree, int));
  static struct z_candidate * add_builtin_candidates
  	PROTO((struct z_candidate *, enum tree_code, enum tree_code,
  	       tree, tree *, int));
--- 77,83 ----
  static struct z_candidate * splice_viable PROTO((struct z_candidate *));
  static int any_viable PROTO((struct z_candidate *));
  static struct z_candidate * add_template_candidate
! 	PROTO((struct z_candidate *, tree, tree, tree, int));
  static struct z_candidate * add_builtin_candidates
  	PROTO((struct z_candidate *, enum tree_code, enum tree_code,
  	       tree, tree *, int));
*************** build_overload_call_real (fnname, parms,
*** 2838,2848 ****
  	}
        if (TREE_CODE (function) == TEMPLATE_DECL)
  	{
! 	  int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
! 	  tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
  	  int i;
  
! 	  i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
  				TYPE_ARG_TYPES (TREE_TYPE (function)),
  				parms, &template_cost, 0, 0);
  	  if (i == 0)
--- 2838,2849 ----
  	}
        if (TREE_CODE (function) == TEMPLATE_DECL)
  	{
! 	  int ntparms = DECL_NTPARMS (function);
! 	  tree targs = make_tree_vec (ntparms);
  	  int i;
  
! 	  i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (function), 
! 				&TREE_VEC_ELT (targs, 0),
  				TYPE_ARG_TYPES (TREE_TYPE (function)),
  				parms, &template_cost, 0, 0);
  	  if (i == 0)
*************** add_builtin_candidates (candidates, code
*** 4144,4163 ****
  }
  
  static struct z_candidate *
! add_template_candidate (candidates, tmpl, arglist, flags)
       struct z_candidate *candidates;
!      tree tmpl, arglist;
       int flags;
  {
!   int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
!   tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
    struct z_candidate *cand;
!   int i, dummy = 0;
    tree fn;
  
!   i = type_unification (DECL_TEMPLATE_PARMS (tmpl), targs,
! 			TYPE_ARG_TYPES (TREE_TYPE (tmpl)),
! 			arglist, &dummy, 0, 0);
    if (i != 0)
      return candidates;
  
--- 4145,4163 ----
  }
  
  static struct z_candidate *
! add_template_candidate (candidates, tmpl, arglist, return_type, flags)
       struct z_candidate *candidates;
!      tree tmpl, arglist, return_type;
       int flags;
  {
!   int ntparms = DECL_NTPARMS (tmpl);
!   tree targs = make_tree_vec (ntparms);
    struct z_candidate *cand;
!   int i;
    tree fn;
  
!   i = fn_type_unification (tmpl, targs, arglist, return_type, 0);
! 
    if (i != 0)
      return candidates;
  
*************** build_user_type_conversion_1 (totype, ex
*** 4253,4258 ****
--- 4253,4259 ----
    tree fromtype = TREE_TYPE (expr);
    tree ctors = NULL_TREE, convs = NULL_TREE, *p;
    tree args;
+   tree templates = NULL_TREE;
  
    if (IS_AGGR_TYPE (totype))
      ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
*************** build_user_type_conversion_1 (totype, ex
*** 4279,4287 ****
        if (DECL_NONCONVERTING_P (ctors))
  	continue;
  
!       candidates = add_function_candidate (candidates, ctors, args, flags);
!       candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
!       candidates->basetype_path = TYPE_BINFO (totype);
      }
  
    if (convs)
--- 4280,4301 ----
        if (DECL_NONCONVERTING_P (ctors))
  	continue;
  
!       if (TREE_CODE (ctors) == TEMPLATE_DECL) 
! 	{
! 	  templates = decl_tree_cons (NULL_TREE, ctors, templates);
! 	  candidates = 
! 	    add_template_candidate (candidates, ctors,
! 				    args, NULL_TREE, flags);
! 	} 
!       else 
! 	candidates = add_function_candidate (candidates, ctors,
! 					     args, flags); 
! 
!       if (candidates) 
! 	{
! 	  candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
! 	  candidates->basetype_path = TYPE_BINFO (totype);
! 	} 
      }
  
    if (convs)
*************** build_user_type_conversion_1 (totype, ex
*** 4308,4318 ****
        else if (ics)
  	for (; fn; fn = DECL_CHAIN (fn))
  	  {
! 	    candidates = add_function_candidate (candidates, fn, args, flags);
! 	    candidates->second_conv = ics;
! 	    candidates->basetype_path = TREE_PURPOSE (convs);
! 	    if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
! 	      candidates->viable = -1;
  	  }
      }
  
--- 4322,4345 ----
        else if (ics)
  	for (; fn; fn = DECL_CHAIN (fn))
  	  {
! 	    if (TREE_CODE (fn) == TEMPLATE_DECL)
! 	      {
! 		templates = decl_tree_cons (NULL_TREE, fn, templates);
! 		candidates = 
! 		  add_template_candidate (candidates, fn, args,
! 					  totype, flags);
! 	      } 
! 	    else 
! 	      candidates = add_function_candidate (candidates, fn,
! 						   args, flags); 
! 
! 	    if (candidates) 
! 	      {
! 		candidates->second_conv = ics;
! 		candidates->basetype_path = TREE_PURPOSE (convs);
! 		if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
! 		  candidates->viable = -1;
! 	      }
  	  }
      }
  
*************** build_user_type_conversion_1 (totype, ex
*** 4354,4359 ****
--- 4381,4393 ----
    for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
      p = &(TREE_OPERAND (*p, 0));
  
+   /* Pedantically, it is ill-formed to define a function that could
+      also be a template instantiation, but we won't implement that
+      until things settle down.  */
+   if (templates && ! cand->template && ! DECL_INITIAL (cand->fn)
+       && TREE_CODE (TREE_TYPE (cand->fn)) != METHOD_TYPE)
+     add_maybe_template (cand->fn, templates);
+ 
    *p = build
      (USER_CONV,
       (DECL_CONSTRUCTOR_P (cand->fn)
*************** build_new_function_call (fn, args, obj)
*** 4427,4433 ****
  	    {
  	      templates = decl_tree_cons (NULL_TREE, t, templates);
  	      candidates = add_template_candidate
! 		(candidates, t, args, LOOKUP_NORMAL);
  	    }
  	  else
  	    candidates = add_function_candidate
--- 4461,4467 ----
  	    {
  	      templates = decl_tree_cons (NULL_TREE, t, templates);
  	      candidates = add_template_candidate
! 		(candidates, t, args, NULL_TREE, LOOKUP_NORMAL);
  	    }
  	  else
  	    candidates = add_function_candidate
*************** build_new_op (code, flags, arg1, arg2, a
*** 4713,4719 ****
  	{
  	  templates = decl_tree_cons (NULL_TREE, fns, templates);
  	  candidates = add_template_candidate
! 	    (candidates, fns, arglist, flags);
  	}
        else
  	candidates = add_function_candidate (candidates, fns, arglist, flags);
--- 4747,4753 ----
  	{
  	  templates = decl_tree_cons (NULL_TREE, fns, templates);
  	  candidates = add_template_candidate
! 	    (candidates, fns, arglist, TREE_TYPE (fnname), flags);
  	}
        else
  	candidates = add_function_candidate (candidates, fns, arglist, flags);
*************** build_new_op (code, flags, arg1, arg2, a
*** 4730,4742 ****
        mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
        for (; fn; fn = DECL_CHAIN (fn))
  	{
  	  if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
! 	    candidates = add_function_candidate
! 	      (candidates, fn, mem_arglist, flags);
  	  else
! 	    candidates = add_function_candidate (candidates, fn, arglist, flags);
! 	  
! 	  candidates->basetype_path = TREE_PURPOSE (fns);
  	}
      }
  
--- 4764,4790 ----
        mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
        for (; fn; fn = DECL_CHAIN (fn))
  	{
+ 	  tree this_arglist;
+ 
  	  if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
! 	    this_arglist = mem_arglist;
  	  else
! 	    this_arglist = arglist;
! 
! 	  if (TREE_CODE (fn) == TEMPLATE_DECL)
! 	    {
! 	      /* A member template. */
! 	      templates = decl_tree_cons (NULL_TREE, fn, templates);
! 	      candidates = add_template_candidate
! 		(candidates, fn, this_arglist, 
! 		 TREE_TYPE (fnname), LOOKUP_NORMAL);
! 	    }
! 	  else
! 	    candidates = add_function_candidate
! 	      (candidates, fn, this_arglist, flags);
! 
! 	  if (candidates) 
! 	    candidates->basetype_path = TREE_PURPOSE (fns);
  	}
      }
  
*************** build_over_call (fn, convs, args, flags)
*** 5189,5195 ****
  	/* This came from a template.  Instantiate the default arg here,
  	   not in tsubst.  */
  	arg = tsubst_expr (arg,
! 			   &TREE_VEC_ELT (DECL_TI_ARGS (fn), 0),
  			   TREE_VEC_LENGTH (DECL_TI_ARGS (fn)), NULL_TREE);
        converted_args = tree_cons
  	(NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg),
--- 5237,5243 ----
  	/* This came from a template.  Instantiate the default arg here,
  	   not in tsubst.  */
  	arg = tsubst_expr (arg,
! 			   DECL_TI_ARGS (fn),
  			   TREE_VEC_LENGTH (DECL_TI_ARGS (fn)), NULL_TREE);
        converted_args = tree_cons
  	(NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg),
*************** build_new_method_call (instance, name, a
*** 5332,5337 ****
--- 5380,5386 ----
    tree basetype, mem_args, fns, instance_ptr;
    tree pretty_name;
    tree user_args = args;
+   tree templates = NULL_TREE;
  
    /* If there is an extra argument for controlling virtual bases,
       remove it for error reporting.  */
*************** build_new_method_call (instance, name, a
*** 5412,5428 ****
        mem_args = tree_cons (NULL_TREE, instance_ptr, args);
        for (; t; t = DECL_CHAIN (t))
  	{
  	  /* We can end up here for copy-init of same or base class.  */
  	  if (name == ctor_identifier
  	      && (flags & LOOKUP_ONLYCONVERTING)
  	      && DECL_NONCONVERTING_P (t))
  	    continue;
  	  if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
! 	    candidates = add_function_candidate
! 	      (candidates, t, mem_args, flags);
  	  else
! 	    candidates = add_function_candidate (candidates, t, args, flags);
! 	  candidates->basetype_path = TREE_PURPOSE (fns);
  	}
      }
  
--- 5461,5494 ----
        mem_args = tree_cons (NULL_TREE, instance_ptr, args);
        for (; t; t = DECL_CHAIN (t))
  	{
+ 	  tree this_arglist;
+ 
  	  /* We can end up here for copy-init of same or base class.  */
  	  if (name == ctor_identifier
  	      && (flags & LOOKUP_ONLYCONVERTING)
  	      && DECL_NONCONVERTING_P (t))
  	    continue;
  	  if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
! 	    this_arglist = mem_args;
  	  else
! 	    this_arglist = args;
! 
! 	  if (TREE_CODE (t) == TEMPLATE_DECL)
! 	    {
! 	      /* A member template. */
! 	      templates = decl_tree_cons (NULL_TREE, t, templates);
! 	      candidates = 
! 		add_template_candidate (candidates, t,
! 					this_arglist,
! 					TREE_TYPE (name), 
! 					LOOKUP_NORMAL); 
! 	    }
! 	  else 
! 	    candidates = add_function_candidate (candidates, t,
! 						 this_arglist, flags);
! 
! 	  if (candidates)
! 	    candidates->basetype_path = TREE_PURPOSE (fns);
  	}
      }
  
*************** build_new_method_call (instance, name, a
*** 5463,5468 ****
--- 5529,5540 ----
        && ((instance == current_class_ref && (dtor_label || ctor_label))
  	  || resolves_to_fixed_type_p (instance, 0)))
      flags |= LOOKUP_NONVIRTUAL;
+ 
+   /* Pedantically, it is ill-formed to define a function that could
+      also be a template instantiation, but we won't implement that
+      until things settle down.  */
+   if (templates && ! cand->template && ! DECL_INITIAL (cand->fn))
+     add_maybe_template (cand->fn, templates);
  
    return build_over_call
      (cand->fn, cand->convs,
Index: gcc/cp/class.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/class.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -c -p -r1.1.1.2 -r1.4
*** class.c	1997/08/29 02:03:51	1.1.1.2
--- class.c	1997/09/05 20:23:59	1.4
*************** grow_method (fndecl, method_vec_ptr)
*** 1883,1889 ****
  	      cp_error_at ("`%D' overloaded", fndecl);
  	      cp_error_at ("previous declaration as `%D' here", x);
  	    }
! 	  if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (x))
  	    {
  	      /* Friend-friend ambiguities are warned about outside
  		 this loop.  */
--- 1883,1891 ----
  	      cp_error_at ("`%D' overloaded", fndecl);
  	      cp_error_at ("previous declaration as `%D' here", x);
  	    }
! 	  if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (x)
! 	      && ! DECL_FUNCTION_TEMPLATE_P (x)
! 	      && ! DECL_FUNCTION_TEMPLATE_P (fndecl))
  	    {
  	      /* Friend-friend ambiguities are warned about outside
  		 this loop.  */
*************** finish_struct (t, list_of_fieldlists, at
*** 4384,4390 ****
  		}
  	    }
  
! 	  if (TREE_CODE (x) == FUNCTION_DECL)
  	    {
  	      DECL_CLASS_CONTEXT (x) = t;
  	      if (last_x)
--- 4386,4393 ----
  		}
  	    }
  
! 	  if (TREE_CODE (x) == FUNCTION_DECL 
! 	      || DECL_FUNCTION_TEMPLATE_P (x))
  	    {
  	      DECL_CLASS_CONTEXT (x) = t;
  	      if (last_x)
*************** instantiate_type (lhstype, rhs, complain
*** 5062,5073 ****
  	      for (elem = get_first_fn (rhs); elem; elem = DECL_CHAIN (elem))
  		if (TREE_CODE (elem) == TEMPLATE_DECL)
  		  {
! 		    int n = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (elem));
! 		    tree *t = (tree *) alloca (sizeof (tree) * n);
  		    int i, d = 0;
! 		    i = type_unification (DECL_TEMPLATE_PARMS (elem), t,
! 					  TYPE_ARG_TYPES (TREE_TYPE (elem)),
! 					  TYPE_ARG_TYPES (lhstype), &d, 0, 1);
  		    if (i == 0)
  		      {
  			if (save_elem)
--- 5065,5078 ----
  	      for (elem = get_first_fn (rhs); elem; elem = DECL_CHAIN (elem))
  		if (TREE_CODE (elem) == TEMPLATE_DECL)
  		  {
! 		    int n = DECL_NTPARMS (elem);
! 		    tree t = make_tree_vec (n);
  		    int i, d = 0;
! 		    i = 
! 		      type_unification (DECL_INNERMOST_TEMPLATE_PARMS (elem), 
! 					&TREE_VEC_ELT (t, 0),
! 					TYPE_ARG_TYPES (TREE_TYPE (elem)),
! 					TYPE_ARG_TYPES (lhstype), &d, 0, 1);
  		    if (i == 0)
  		      {
  			if (save_elem)
Index: gcc/cp/cp-tree.def
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -c -p -r1.1.1.1 -r1.2
*** cp-tree.def	1997/08/26 06:23:55	1.1.1.1
--- cp-tree.def	1997/09/02 06:38:38	1.2
*************** DEFTREECODE (TYPENAME_TYPE, "typename_ty
*** 91,97 ****
  
  /* Index into a template parameter list.  This parameter must not be a
     type.  */
! DEFTREECODE (TEMPLATE_CONST_PARM, "template_const_parm", "c", 2)
  
  /* A thunk is a stub function.
  
--- 91,97 ----
  
  /* Index into a template parameter list.  This parameter must not be a
     type.  */
! DEFTREECODE (TEMPLATE_CONST_PARM, "template_const_parm", "c", 3)
  
  /* A thunk is a stub function.
  
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -c -p -r1.1.1.1 -r1.4
*** cp-tree.h	1997/08/26 06:23:55	1.1.1.1
--- cp-tree.h	1997/09/05 20:23:59	1.4
*************** struct lang_decl
*** 1091,1096 ****
--- 1091,1097 ----
  #define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE))
  #define CLASSTYPE_TI_ARGS(NODE)     TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE))
  #define CLASSTYPE_TI_SPEC_INFO(NODE) TI_SPEC_INFO (CLASSTYPE_TEMPLATE_INFO (NODE))
+ #define INNERMOST_TEMPLATE_PARMS(NODE)  TREE_VALUE(NODE)
  
  #define DECL_SAVED_TREE(NODE)		DECL_MEMFUNC_POINTER_TO (NODE)
  #define COMPOUND_STMT_NO_SCOPE(NODE)	TREE_LANG_FLAG_0 (NODE)
*************** extern int flag_new_for_scope;
*** 1334,1339 ****
--- 1335,1344 ----
  
  /* Accessor macros for C++ template decl nodes.  */
  #define DECL_TEMPLATE_PARMS(NODE)       DECL_ARGUMENTS(NODE)
+ #define DECL_INNERMOST_TEMPLATE_PARMS(NODE) \
+    INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (NODE))
+ #define DECL_NTPARMS(NODE) \
+    TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE))
  /* For class templates.  */
  #define DECL_TEMPLATE_SPECIALIZATIONS(NODE)     DECL_SIZE(NODE)
  /* For function, method, class-data templates.  */
*************** extern int flag_new_for_scope;
*** 1346,1352 ****
     && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
  
  #define PRIMARY_TEMPLATE_P(NODE) \
!   (TREE_TYPE (DECL_TEMPLATE_PARMS (NODE)) == (NODE))
  
  #define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
    (TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
--- 1351,1357 ----
     && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
  
  #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))))
*************** extern tree grok_alignof			PROTO((tree))
*** 2112,2117 ****
--- 2117,2123 ----
  extern tree grok_array_decl			PROTO((tree, tree));
  extern tree delete_sanity			PROTO((tree, tree, int, int));
  extern tree check_classfn			PROTO((tree, tree));
+ extern void check_member_template               PROTO((tree));
  extern tree grokfield				PROTO((tree, tree, tree, tree, tree));
  extern tree grokbitfield			PROTO((tree, tree, tree));
  extern tree groktypefield			PROTO((tree, tree));
*************** extern void synthesize_method			PROTO((t
*** 2299,2308 ****
  extern tree get_id_2				PROTO((char *, tree));
  
  /* in pt.c */
! extern tree tsubst				PROTO ((tree, tree*, int, tree));
! extern tree tsubst_expr				PROTO ((tree, tree*, int, tree));
! extern tree tsubst_copy				PROTO ((tree, tree*, int, tree));
  extern tree tsubst_chain			PROTO((tree, tree));
  extern void begin_template_parm_list		PROTO((void));
  extern tree process_template_parm		PROTO((tree, tree));
  extern tree end_template_parm_list		PROTO((tree));
--- 2305,2316 ----
  extern tree get_id_2				PROTO((char *, tree));
  
  /* in pt.c */
! extern tree tsubst				PROTO ((tree, tree, int, tree));
! extern tree tsubst_expr				PROTO ((tree, tree, int, tree));
! extern tree tsubst_copy				PROTO ((tree, tree, int, tree));
  extern tree tsubst_chain			PROTO((tree, tree));
+ extern void begin_member_template_processing    PROTO((tree));
+ extern void end_member_template_processing      PROTO((void));
  extern void begin_template_parm_list		PROTO((void));
  extern tree process_template_parm		PROTO((tree, tree));
  extern tree end_template_parm_list		PROTO((tree));
*************** extern void push_template_decl			PROTO((
*** 2312,2319 ****
  extern tree lookup_template_class		PROTO((tree, tree, tree));
  extern int uses_template_parms			PROTO((tree));
  extern tree instantiate_class_template		PROTO((tree));
! extern tree instantiate_template		PROTO((tree, tree *));
  extern void overload_template_name		PROTO((tree));
  extern int type_unification			PROTO((tree, tree *, tree, tree, int *, int, int));
  struct tinst_level *tinst_for_decl		PROTO((void));
  extern void mark_decl_instantiated		PROTO((tree, int));
--- 2320,2328 ----
  extern tree lookup_template_class		PROTO((tree, tree, tree));
  extern int uses_template_parms			PROTO((tree));
  extern tree instantiate_class_template		PROTO((tree));
! extern tree instantiate_template		PROTO((tree, tree));
  extern void overload_template_name		PROTO((tree));
+ extern int fn_type_unification                  PROTO((tree, tree, tree, tree, int));
  extern int type_unification			PROTO((tree, tree *, tree, tree, int *, int, int));
  struct tinst_level *tinst_for_decl		PROTO((void));
  extern void mark_decl_instantiated		PROTO((tree, int));
*************** extern void do_type_instantiation		PROTO
*** 2324,2330 ****
  extern tree instantiate_decl			PROTO((tree));
  extern tree lookup_nested_type_by_name		PROTO((tree, tree));
  extern tree do_poplevel				PROTO((void));
! extern tree *get_bindings			PROTO((tree, tree));
  /* CONT ... */
  extern void add_tree				PROTO((tree));
  extern void add_maybe_template			PROTO((tree, tree));
--- 2333,2339 ----
  extern tree instantiate_decl			PROTO((tree));
  extern tree lookup_nested_type_by_name		PROTO((tree, tree));
  extern tree do_poplevel				PROTO((void));
! extern tree get_bindings			PROTO((tree, tree));
  /* CONT ... */
  extern void add_tree				PROTO((tree));
  extern void add_maybe_template			PROTO((tree, tree));
*************** extern tree most_specialized			PROTO((tr
*** 2333,2338 ****
--- 2342,2348 ----
  extern tree most_specialized_class		PROTO((tree, tree));
  extern int more_specialized_class		PROTO((tree, tree));
  extern void do_pushlevel			PROTO((void));
+ extern int is_member_template                   PROTO((tree));
  
  /* in repo.c */
  extern void repo_template_used			PROTO((tree));
Index: gcc/cp/decl.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/decl.c,v
retrieving revision 1.1.1.3
retrieving revision 1.4
diff -c -p -r1.1.1.3 -r1.4
*** decl.c	1997/09/04 18:09:46	1.1.1.3
--- decl.c	1997/09/05 20:24:00	1.4
*************** decls_match (newdecl, olddecl)
*** 2306,2328 ****
      {
  	tree newargs = DECL_TEMPLATE_PARMS (newdecl);
  	tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
! 	int i, len = TREE_VEC_LENGTH (newargs);
  
! 	if (TREE_VEC_LENGTH (oldargs) != len)
! 	  return 0;
! 	
! 	for (i = 0; i < len; i++)
  	  {
! 	    tree newarg = TREE_VALUE (TREE_VEC_ELT (newargs, i));
! 	    tree oldarg = TREE_VALUE (TREE_VEC_ELT (oldargs, i));
! 	    if (TREE_CODE (newarg) != TREE_CODE (oldarg))
! 	      return 0;
! 	    else if (TREE_CODE (newarg) == TYPE_DECL)
! 	      /* continue */;
! 	    else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
  	      return 0;
  	  }
  
  	if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
  	  types_match = 1;
  	else
--- 2306,2345 ----
      {
  	tree newargs = DECL_TEMPLATE_PARMS (newdecl);
  	tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
! 	int i;
  
! 	/* Run through all the levels of template parmaters, checking
! 	   that they match.  */
! 	while (newargs && oldargs) 
  	  {
! 	    int len = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS (newargs));
! 
! 	    if (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS (oldargs)) != len)
  	      return 0;
+ 	    
+ 	    for (i = 0; i < len; i++)
+ 	      {
+ 		tree newarg = 
+ 		  TREE_VALUE (TREE_VEC_ELT 
+ 			      (INNERMOST_TEMPLATE_PARMS (newargs), i));
+ 		tree oldarg = 
+ 		  TREE_VALUE (TREE_VEC_ELT 
+ 			      (INNERMOST_TEMPLATE_PARMS (oldargs), i));
+ 		if (TREE_CODE (newarg) != TREE_CODE (oldarg))
+ 		  return 0;
+ 		else if (TREE_CODE (newarg) == TYPE_DECL)
+ 		  /* continue */;
+ 		else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
+ 		  return 0;
+ 	      }
+ 	    newargs = TREE_CHAIN (newargs);
+ 	    oldargs = TREE_CHAIN (oldargs);
  	  }
  
+ 	if ((newargs == NULL_TREE) != (oldargs == NULL_TREE))
+ 	  /* One declaration has more levels that the other. */
+ 	  return 0;
+ 
  	if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
  	  types_match = 1;
  	else
*************** pushdecl (x)
*** 3003,3009 ****
    /* Type are looked up using the DECL_NAME, as that is what the rest of the
       compiler wants to use.  */
    if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
!       || TREE_CODE (x) == NAMESPACE_DECL)
      name = DECL_NAME (x);
  
    if (name)
--- 3020,3026 ----
    /* Type are looked up using the DECL_NAME, as that is what the rest of the
       compiler wants to use.  */
    if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
!       || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM)
      name = DECL_NAME (x);
  
    if (name)
*************** push_class_level_binding (name, x)
*** 3493,3498 ****
--- 3510,3520 ----
       tree name;
       tree x;
  {
+   /* The class_binding_level will be NULL if x is a template 
+      parameter name in a member template.  */
+   if (!class_binding_level)
+     return;
+ 
    if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
        && purpose_member (name, class_binding_level->class_shadowed))
      return;
*************** grokfndecl (ctype, type, declarator, vir
*** 7232,7237 ****
--- 7254,7263 ----
        if (check)
  	{
  	  tmp = check_classfn (ctype, decl);
+ 
+ 	  if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
+ 	    tmp = DECL_TEMPLATE_RESULT(tmp);
+ 
  	  if (tmp && DECL_ARTIFICIAL (tmp))
  	    cp_error ("definition of implicitly-declared `%D'", tmp);
  	  if (tmp && duplicate_decls (decl, tmp))
*************** grokfndecl (ctype, type, declarator, vir
*** 7270,7275 ****
--- 7296,7305 ----
        if (ctype != NULL_TREE && check)
  	{
  	  tmp = check_classfn (ctype, decl);
+ 
+ 	  if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
+ 	    tmp = DECL_TEMPLATE_RESULT(tmp);
+ 	      
  	  if (tmp && DECL_STATIC_FUNCTION_P (tmp)
  	      && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
  	    {
*************** grokdeclarator (declarator, declspecs, d
*** 8934,8941 ****
  		    && uses_template_parms (current_class_type))
  		  {
  		    tree args = current_template_args ();
! 		    type = tsubst (type, &TREE_VEC_ELT (args, 0),
! 				   TREE_VEC_LENGTH (args), NULL_TREE);
  		  }
  
  		/* This pop_nested_class corresponds to the
--- 8964,8973 ----
  		    && uses_template_parms (current_class_type))
  		  {
  		    tree args = current_template_args ();
! 		    type = tsubst (type, args,
! 				   TREE_VEC_LENGTH (TREE_VEC_ELT
! 						    (args, 0)),
! 				   NULL_TREE);
  		  }
  
  		/* This pop_nested_class corresponds to the
*************** void
*** 10038,10044 ****
  replace_defarg (arg, init)
       tree arg, init;
  {
!   if (! processing_template_decl
        && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
      cp_pedwarn ("invalid type `%T' for default argument to `%T'",
  		TREE_TYPE (init), TREE_VALUE (arg));
--- 10070,10076 ----
  replace_defarg (arg, init)
       tree arg, init;
  {
!   if (! processing_template_decl && ! uses_template_parms (TREE_VALUE (arg))
        && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
      cp_pedwarn ("invalid type `%T' for default argument to `%T'",
  		TREE_TYPE (init), TREE_VALUE (arg));
Index: gcc/cp/decl2.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/decl2.c,v
retrieving revision 1.1.1.3
retrieving revision 1.3
diff -c -p -r1.1.1.3 -r1.3
*** decl2.c	1997/09/04 18:09:46	1.1.1.3
--- decl2.c	1997/09/04 20:27:28	1.3
*************** delete_sanity (exp, size, doing_vec, use
*** 1282,1287 ****
--- 1282,1343 ----
      }
  }
  
+ 
+ /* Report an error if the indicated template declaration is not the
+    sort of thing that should be a member template.
+    */
+ 
+ void
+ check_member_template (tmpl)
+      tree tmpl;
+ {
+   tree decl;
+ 
+   my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+   decl = DECL_TEMPLATE_RESULT (tmpl);
+ 
+   if (TREE_CODE (decl) == FUNCTION_DECL) 
+     {
+       if (current_function_decl)
+ 	/* 14.5.2.2 [temp.mem]
+ 	   
+ 	   A local class shall not have member templates. */
+ 	cp_error ("declaration of of member template `%#D' in local class",
+ 		  decl);
+       
+       if (DECL_VIRTUAL_P (decl)) 
+ 	{
+ 	  /* 14.5.2.3 [temp.mem]
+ 
+ 	     A member function template shall not be virtual.  */
+ 	  cp_error 
+ 	    ("invalid use of `virtual' in template declaration of `%#D'",
+ 	     decl);
+ 	  DECL_VIRTUAL_P (decl) = 0;
+ 	}
+ 
+       /* The debug-information generating code doesn't know what to do
+ 	 with member templates.  */ 
+       DECL_IGNORED_P (tmpl) = 1;
+     } 
+   else if (TREE_CODE (decl) == TYPE_DECL &&
+ 	   AGGREGATE_TYPE_P (TREE_TYPE (decl)))
+     {
+       if (current_function_decl)
+ 	/* 14.5.2.2 [temp.mem]
+ 
+ 	   A local class shall not have member templates.  */
+ 	cp_error ("declaration of of member template `%#D' in local class",
+ 		  decl);
+ 
+       /* We don't handle member template classes yet. */
+       sorry ("member templates classes");
+     }
+   else
+     cp_error ("template declaration of `%#D'", decl);
+ }
+ 
+ 
  /* Sanity check: report error if this function FUNCTION is not
     really a member of the class (CTYPE) it is supposed to belong to.
     CNAME is the same here as it is for grokclassfn above.  */
*************** check_classfn (ctype, function)
*** 1295,1300 ****
--- 1351,1357 ----
    tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
    tree *methods = 0;
    tree *end = 0;
+   tree templates = NULL_TREE;
  
    if (method_vec != 0)
      {
*************** check_classfn (ctype, function)
*** 1311,1316 ****
--- 1368,1374 ----
  
        while (++methods != end)
  	{
+ 	  fndecl = *methods;
  	  if (fn_name == DECL_NAME (*methods))
  	    {
  	    got_it:
*************** check_classfn (ctype, function)
*** 1342,1356 ****
--- 1400,1439 ----
  				     TREE_TYPE (TREE_TYPE (fndecl)), 1)
  			  && compparms (p1, p2, 3))
  			return fndecl;
+ 
+ 		      if (is_member_template (fndecl)) 
+ 			/* This function might be an instantiation
+ 			   or specialization of fndecl.  */
+ 			templates = 
+ 			  tree_cons (NULL_TREE, fndecl, templates);
  		    }
  #endif
  		  fndecl = DECL_CHAIN (fndecl);
  		}
  	      break;		/* loser */
  	    }
+ 	  else if (TREE_CODE (fndecl) == TEMPLATE_DECL 
+ 		   && IDENTIFIER_TYPENAME_P (DECL_NAME (fndecl))
+ 		   && IDENTIFIER_TYPENAME_P (fn_name))
+ 	    /* The method in the class is a member template
+ 	       conversion operator.  We are declaring another
+ 	       conversion operator.  It is possible that even though
+ 	       the names don't match, there is some specialization
+ 	       occurring.  */
+ 	    templates = 
+ 	      tree_cons (NULL_TREE, fndecl, templates);
  	}
      }
  
+   if (templates)
+     /* This function might be an instantiation or a specialization.
+        We should verify that this is possible.  If it is, we must
+        somehow add the new declaration to the method vector for the
+        class.  Perhaps we should use add_method?  For now, we simply
+        return NULL_TREE, which lets the caller know that this
+        function is new, but we don't print an error message.  */
+     return NULL_TREE;
+ 
    if (methods != end)
      {
        tree fndecl = *methods;
*************** finish_file ()
*** 2792,2798 ****
  
    for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
      {
!       tree *args, fn, decl = TREE_VALUE (fnname);
  
        if (DECL_INITIAL (decl))
  	continue;
--- 2875,2881 ----
  
    for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
      {
!       tree args, fn, decl = TREE_VALUE (fnname);
  
        if (DECL_INITIAL (decl))
  	continue;
*************** finish_file ()
*** 2800,2806 ****
        fn = TREE_PURPOSE (fnname);
        args = get_bindings (fn, decl);
        fn = instantiate_template (fn, args);
-       free (args);
        instantiate_decl (fn);
      }
  
--- 2883,2888 ----
Index: gcc/cp/error.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/error.c,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -c -p -r1.1.1.2 -r1.5
*** error.c	1997/08/29 02:03:54	1.1.1.2
--- error.c	1997/09/05 20:24:00	1.5
*************** dump_decl (t, v)
*** 722,754 ****
  
      case TEMPLATE_DECL:
        {
! 	tree args = DECL_TEMPLATE_PARMS (t);
! 	int i, len = args ? TREE_VEC_LENGTH (args) : 0;
! 	OB_PUTS ("template <");
! 	for (i = 0; i < len; i++)
  	  {
! 	    tree arg = TREE_VEC_ELT (args, i);
! 	    tree defval = TREE_PURPOSE (arg);
! 	    arg = TREE_VALUE (arg);
! 	    if (TREE_CODE (arg) == TYPE_DECL)
! 	      {
! 		OB_PUTS ("class ");
! 		OB_PUTID (DECL_NAME (arg));
! 	      }
! 	    else
! 	      dump_decl (arg, 1);
  
! 	    if (defval)
  	      {
! 		OB_PUTS (" = ");
! 		dump_decl (defval, 1);
! 	      }
  		
! 	    OB_PUTC2 (',', ' ');
  	  }
! 	if (len != 0)
! 	  OB_UNPUT (2);
! 	OB_PUTC2 ('>', ' ');
  
  	if (TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL)
  	  dump_type (TREE_TYPE (t), v);
--- 722,763 ----
  
      case TEMPLATE_DECL:
        {
! 	tree orig_args = DECL_TEMPLATE_PARMS (t);
! 	tree args;
! 	int i; 
! 	for (args = orig_args = nreverse (orig_args); 
! 	     args;
! 	     args = TREE_CHAIN (args))
  	  {
! 	    int len = TREE_VEC_LENGTH (TREE_VALUE (args));
  
! 	    OB_PUTS ("template <");
! 	    for (i = 0; i < len; i++)
  	      {
! 		tree arg = TREE_VEC_ELT (TREE_VALUE (args), i);
! 		tree defval = TREE_PURPOSE (arg);
! 		arg = TREE_VALUE (arg);
! 		if (TREE_CODE (arg) == TYPE_DECL)
! 		  {
! 		    OB_PUTS ("class ");
! 		    OB_PUTID (DECL_NAME (arg));
! 		  }
! 		else
! 		  dump_decl (arg, 1);
! 		
! 		if (defval)
! 		  {
! 		    OB_PUTS (" = ");
! 		    dump_decl (defval, 1);
! 		  }
  		
! 		OB_PUTC2 (',', ' ');
! 	      }
! 	    if (len != 0)
! 	      OB_UNPUT (2);
! 	    OB_PUTC2 ('>', ' ');
  	  }
! 	nreverse(orig_args);
  
  	if (TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL)
  	  dump_type (TREE_TYPE (t), v);
*************** dump_function_decl (t, v)
*** 801,811 ****
       tree t;
       int v;
  {
!   tree name = DECL_ASSEMBLER_NAME (t);
!   tree fntype = TREE_TYPE (t);
!   tree parmtypes = TYPE_ARG_TYPES (fntype);
    tree cname = NULL_TREE;
  
    /* Friends have DECL_CLASS_CONTEXT set, but not DECL_CONTEXT.  */
    if (DECL_CONTEXT (t))
      cname = DECL_CLASS_CONTEXT (t);
--- 810,827 ----
       tree t;
       int v;
  {
!   tree name;
!   tree fntype;
!   tree parmtypes;
    tree cname = NULL_TREE;
  
+   if (TREE_CODE (t) == TEMPLATE_DECL)
+     t = DECL_TEMPLATE_RESULT (t);
+ 
+   name = DECL_ASSEMBLER_NAME (t);
+   fntype = TREE_TYPE (t);
+   parmtypes = TYPE_ARG_TYPES (fntype);
+ 
    /* Friends have DECL_CLASS_CONTEXT set, but not DECL_CONTEXT.  */
    if (DECL_CONTEXT (t))
      cname = DECL_CLASS_CONTEXT (t);
*************** dump_expr (t, nop)
*** 1349,1356 ****
      case TEMPLATE_CONST_PARM:
        if (current_template_parms)
  	{
! 	  tree r = TREE_VEC_ELT (TREE_VALUE (current_template_parms),
! 				 TEMPLATE_CONST_IDX (t));
  	  dump_decl (TREE_VALUE (r), -1);
  	}
        else
--- 1365,1381 ----
      case TEMPLATE_CONST_PARM:
        if (current_template_parms)
  	{
! 	  int i;
! 	  tree parms;
! 	  tree r;
! 
! 	  for (parms = current_template_parms;
! 	       TREE_CHAIN (parms);
! 	       parms = TREE_CHAIN (parms))
! 	    ;
! 
! 	  r = TREE_VEC_ELT (TREE_VALUE (parms),
! 			    TEMPLATE_CONST_IDX (t));
  	  dump_decl (TREE_VALUE (r), -1);
  	}
        else
Index: gcc/cp/lex.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/lex.c,v
retrieving revision 1.1.1.2
diff -c -p -r1.1.1.2 lex.c
*** lex.c	1997/09/04 18:09:46	1.1.1.2
--- lex.c	1997/09/05 07:32:06
*************** do_pending_inlines ()
*** 1190,1195 ****
--- 1190,1197 ----
    context = hack_decl_function_context (t->fndecl);
    if (context)
      push_cp_function_context (context);
+   if (is_member_template (t->fndecl))
+     begin_member_template_processing (DECL_TI_ARGS (t->fndecl));
    if (t->len > 0)
      {
        feed_input (t->buf, t->len);
*************** process_next_inline (t)
*** 1226,1232 ****
  {
    tree context;
    struct pending_inline *i = (struct pending_inline *) TREE_PURPOSE (t);
!   context = hack_decl_function_context (i->fndecl);
    if (context)
      pop_cp_function_context (context);
    i = i->next;
--- 1228,1236 ----
  {
    tree context;
    struct pending_inline *i = (struct pending_inline *) TREE_PURPOSE (t);
!   context = hack_decl_function_context (i->fndecl);  
!   if (is_member_template (i->fndecl))
!     end_member_template_processing ();
    if (context)
      pop_cp_function_context (context);
    i = i->next;
*************** process_next_inline (t)
*** 1249,1254 ****
--- 1253,1260 ----
        context = hack_decl_function_context (i->fndecl);
        if (context)
  	push_cp_function_context (context);
+       if (is_member_template (i->fndecl))
+ 	begin_member_template_processing (DECL_TI_ARGS (i->fndecl));
        feed_input (i->buf, i->len);
        lineno = i->lineno;
        input_filename = i->filename;
Index: gcc/cp/method.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/method.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -c -p -r1.1.1.2 -r1.4
*** method.c	1997/09/04 18:09:47	1.1.1.2
--- method.c	1997/09/05 20:24:00	1.4
*************** build_overload_identifier (name)
*** 648,654 ****
        arglist = TREE_VALUE (template);
        template = TREE_PURPOSE (template);
        tname = DECL_NAME (template);
!       parmlist = DECL_ARGUMENTS (template);
        nparms = TREE_VEC_LENGTH (parmlist);
        OB_PUTC ('t');
        icat (IDENTIFIER_LENGTH (tname));
--- 648,654 ----
        arglist = TREE_VALUE (template);
        template = TREE_PURPOSE (template);
        tname = DECL_NAME (template);
!       parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
        nparms = TREE_VEC_LENGTH (parmlist);
        OB_PUTC ('t');
        icat (IDENTIFIER_LENGTH (tname));
*************** build_overload_identifier (name)
*** 666,672 ****
  	    }
  	  else
  	    {
! 	      parm = tsubst (parm, &TREE_VEC_ELT (arglist, 0),
  			     TREE_VEC_LENGTH (arglist), NULL_TREE);
  	      /* It's a PARM_DECL.  */
  	      build_overload_name (TREE_TYPE (parm), 0, 0);
--- 666,672 ----
  	    }
  	  else
  	    {
! 	      parm = tsubst (parm, arglist,
  			     TREE_VEC_LENGTH (arglist), NULL_TREE);
  	      /* It's a PARM_DECL.  */
  	      build_overload_name (TREE_TYPE (parm), 0, 0);
Index: gcc/cp/parse.y
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/parse.y,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -c -p -r1.1.1.2 -r1.3
*** parse.y	1997/09/04 18:09:47	1.1.1.2
--- parse.y	1997/09/04 20:27:31	1.3
*************** fn.def2:
*** 699,704 ****
--- 699,720 ----
  		  $$ = start_method (specs, $2); goto rest_of_mdef; }
  	| constructor_declarator
  		{ $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
+         | template_header fn.def2 
+                 { 
+ 		  end_template_decl (); 
+ 		  if ($2 && DECL_TEMPLATE_INFO ($2))
+ 		    {
+ 		      $$ = DECL_TI_TEMPLATE ($2); 
+ 		      check_member_template ($$);
+ 		    }
+ 		  else if ($2)
+ 		    $$ = $2;
+ 		  else 
+ 		    {
+ 		      cp_error("invalid member template declaration");
+ 		      $$ = NULL_TREE;
+ 		    }
+ 		}
  	;
  
  return_id:
*************** component_decl_1:
*** 2711,2717 ****
  				  build_tree_list ($3, NULL_TREE)); }
  	| using_decl
  		{ $$ = do_class_using_decl ($1); }
! 	;
  
  /* The case of exactly one component is handled directly by component_decl.  */
  /* ??? Huh? ^^^ */
--- 2727,2748 ----
  				  build_tree_list ($3, NULL_TREE)); }
  	| using_decl
  		{ $$ = do_class_using_decl ($1); }
!         | template_header component_decl_1 
!                 { 
! 		  end_template_decl (); 
! 		  if ($2 && DECL_TEMPLATE_INFO ($2))
! 		    {
! 		      $$ = DECL_TI_TEMPLATE ($2); 
! 		      check_member_template ($$);
! 		    }
! 		  else if ($2)
! 		    $$ = $2;
! 		  else
! 		    {
! 		      cp_error("invalid member template declaration");
! 		      $$ = NULL_TREE;
! 		    }
! 		}
  
  /* The case of exactly one component is handled directly by component_decl.  */
  /* ??? Huh? ^^^ */
Index: gcc/cp/pt.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/pt.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -c -p -r1.1.1.2 -r1.4
*** pt.c	1997/09/04 18:09:47	1.1.1.2
--- pt.c	1997/09/05 20:24:01	1.4
*************** static int comp_template_args PROTO((tre
*** 76,82 ****
  static int list_eq PROTO((tree, tree));
  static tree get_class_bindings PROTO((tree, tree, tree));
  static tree coerce_template_parms PROTO((tree, tree, tree));
! static tree tsubst_enum	PROTO((tree, tree *, int));
  
  /* We've got a template header coming up; push to a new level for storing
     the parms.  */
--- 76,226 ----
  static int list_eq PROTO((tree, tree));
  static tree get_class_bindings PROTO((tree, tree, tree));
  static tree coerce_template_parms PROTO((tree, tree, tree));
! static tree tsubst_enum	PROTO((tree, tree, int));
! static tree add_to_template_args PROTO((tree, tree));
! 
! /* Restore the template parameter context. */
! 
! void 
! begin_member_template_processing (parms)
!      tree parms;
! {
!   int i;
! 
!   ++processing_template_decl;
!   current_template_parms 
!     = tree_cons (build_int_2 (0, processing_template_decl),
! 		 parms, current_template_parms);
!   for (i = 0; i < TREE_VEC_LENGTH (parms); ++i) 
!     {
!       tree parm = TREE_VEC_ELT (parms, i);
! 
!       switch (TREE_CODE (parm))
! 	{
! 	case TEMPLATE_TYPE_PARM:
! 	  pushdecl (TYPE_NAME (parm));
! 	  break;
! 
! 	case TEMPLATE_CONST_PARM:
! 	  pushdecl (parm);
! 	  break;
! 	  
! 	default:
! 	  my_friendly_abort (0);
! 	}
!     }
! }
! 
! /* Undo the effects of begin_member_template_processing. */
! 
! void 
! end_member_template_processing ()
! {
!   if (! processing_template_decl)
!     return;
! 
!   --processing_template_decl;
!   current_template_parms = TREE_CHAIN (current_template_parms);
! }
! 
! /* Returns non-zero iff T is a member template function.  Works if T
!    is either a FUNCTION_DECL or a TEMPLATE_DECL.  */
! 
! int
! is_member_template (t)
!      tree t;
! {
!   int r = 0;
! 
!   if (DECL_FUNCTION_MEMBER_P (t) ||
!       (TREE_CODE (t) == TEMPLATE_DECL && 
!        DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t))))
!     {
!       tree tmpl = NULL_TREE;
! 
!       if (DECL_FUNCTION_TEMPLATE_P (t))
! 	tmpl = t;
!       else if (DECL_TEMPLATE_INFO (t) 
! 	       && DECL_FUNCTION_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
! 	tmpl = DECL_TI_TEMPLATE (t);
! 
!       if (tmpl) 
! 	{
! 	  tree parms = DECL_TEMPLATE_PARMS (tmpl);
! 	  int parm_levels = list_length (parms);
! 	  int template_class_levels = 0;
! 	  tree ctx = DECL_CLASS_CONTEXT (t);
! 
! 	  if (CLASSTYPE_TEMPLATE_INFO (ctx))
! 	    {
! 	      tree args;
! 
! 	      /* Here, we should really count the number of levels
! 		 deep ctx is, making sure not to count any levels that
! 		 are just specializations.  Since there are no member
! 		 template classes yet, we don't have to do all that.  */
! 
! 	      if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
! 		template_class_levels = 1;
! 	      else
! 		{
! 		  int i;
! 
! 		  args = CLASSTYPE_TI_ARGS (ctx);
! 
! 		  if (args == NULL_TREE)
! 		    template_class_levels = 1;
! 		  else 
! 		    for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
! 		      if (uses_template_parms (TREE_VEC_ELT (args, i)))
! 			{
! 			  template_class_levels++;
! 			  break;
! 			}
! 		}
! 	    }
! 
! 	  if (parm_levels > template_class_levels)
! 	    r = 1;
! 	}
!     }
! 
!   return r;
! }
! 
! 
! 
! /* Return a new template argument vector which contains all of ARGS,
!    but has as its innermost set of arguments the EXTRA_ARGS.  */
! 
! tree
! add_to_template_args(args, extra_args)
!      tree args;
!      tree extra_args;
! {
!   tree new_args;
! 
!   if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)
!     {
!       new_args = make_tree_vec (2);
!       TREE_VEC_ELT (new_args, 0) = args;
!     }
!   else 
!     {
!       int i;
! 
!       new_args = make_tree_vec (TREE_VEC_LENGTH (args) - 1);
! 
!       for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
! 	TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
!     }
! 	  
!   TREE_VEC_ELT (new_args, 
! 		TREE_VEC_LENGTH (new_args) - 1) = extra_args;
! 
!   return new_args;
! }
! 
  
  /* We've got a template header coming up; push to a new level for storing
     the parms.  */
*************** tree
*** 216,222 ****
  current_template_args ()
  {
    tree header = current_template_parms;
!   tree args = NULL_TREE;
    while (header)
      {
        tree a = copy_node (TREE_VALUE (header));
--- 360,369 ----
  current_template_args ()
  {
    tree header = current_template_parms;
!   int length = list_length (header);
!   tree args = make_tree_vec (length);
!   int l = length;
! 
    while (header)
      {
        tree a = copy_node (TREE_VALUE (header));
*************** current_template_args ()
*** 224,243 ****
        TREE_TYPE (a) = NULL_TREE;
        while (i--)
  	{
! 	  tree t = TREE_VALUE (TREE_VEC_ELT (a, i));
! 	  if (TREE_CODE (t) == TYPE_DECL)
! 	    t = TREE_TYPE (t);
! 	  else
! 	    t = DECL_INITIAL (t);
  	  TREE_VEC_ELT (a, i) = t;
  	}
!       args = tree_cons (TREE_PURPOSE (header), a, args);
        header = TREE_CHAIN (header);
      }
-   args = nreverse (args);
- 
-   /* FIXME Remove this when we support member templates.  */
-   args = TREE_VALUE (args);
  
    return args;
  }
--- 371,397 ----
        TREE_TYPE (a) = NULL_TREE;
        while (i--)
  	{
! 	  tree t = TREE_VEC_ELT (a, i);
! 
! 	  /* t will be a list if we are called from withing a
! 	     begin/end_template_parm_list pair, but a vector directly
! 	     if withing a begin/end_member_template_processing pair.
! 	     */
! 	  if (TREE_CODE (t) == TREE_LIST) 
! 	    {
! 	      t = TREE_VALUE (t);
! 	      
! 	      if (TREE_CODE (t) == TYPE_DECL)
! 		t = TREE_TYPE (t);
! 	      else
! 		t = DECL_INITIAL (t);
! 	    }
! 
  	  TREE_VEC_ELT (a, i) = t;
  	}
!       TREE_VEC_ELT (args, --l) = a;
        header = TREE_CHAIN (header);
      }
  
    return args;
  }
*************** push_template_decl (decl)
*** 290,301 ****
    if (! ctx || TYPE_BEING_DEFINED (ctx))
      {
        tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
!       DECL_TEMPLATE_PARMS (tmpl) = TREE_VALUE (current_template_parms);
        DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
      }
    else
      {
        tree t;
  
        if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
  	cp_error ("must specialize `%#T' before defining member `%#D'",
--- 444,458 ----
    if (! ctx || TYPE_BEING_DEFINED (ctx))
      {
        tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
!       DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
        DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+       if (DECL_LANG_SPECIFIC (decl))
+ 	DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
      }
    else
      {
        tree t;
+       tree a;
  
        if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
  	cp_error ("must specialize `%#T' before defining member `%#D'",
*************** push_template_decl (decl)
*** 309,327 ****
  	}
        else
  	tmpl = DECL_TI_TEMPLATE (decl);
  
        if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
! 	t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
!       else
! 	t = DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (ctx));
  
!       if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (args))
  	{
  	  cp_error ("got %d template parameters for `%#D'",
! 		    TREE_VEC_LENGTH (args), decl);
  	  cp_error ("  but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
  	}
      }
  
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
--- 466,519 ----
  	}
        else
  	tmpl = DECL_TI_TEMPLATE (decl);
+       
+       if (is_member_template (tmpl))
+ 	{
+ 	  a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+ 	  t = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl));
+ 	  if (TREE_VEC_LENGTH (t) 
+ 	      != TREE_VEC_LENGTH (a))
+ 	    {
+ 	      cp_error ("got %d template parameters for `%#D'",
+ 			TREE_VEC_LENGTH (a), decl);
+ 	      cp_error ("  but %d required", TREE_VEC_LENGTH (t));
+ 	    }
+ 	  if (TREE_VEC_LENGTH (args) > 1)
+ 	    /* Get the template parameters for the enclosing template
+ 	       class.  */ 
+ 	    a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 2);
+ 	  else
+ 	    a = NULL_TREE;
+ 	}
+       else 
+ 	a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+ 
+       t = NULL_TREE;
  
        if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
! 	{
! 	  /* When processing an inline member template of a
! 	     specialized class, there is no CLASSTYPE_TI_SPEC_INFO.  */
! 	  if (CLASSTYPE_TI_SPEC_INFO (ctx))
! 	    t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
! 	}
!       else if (CLASSTYPE_TEMPLATE_INFO (ctx))
! 	t = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (ctx));
! 
!       /* There should be template arguments if and only if there is a
! 	 template class.  */
!       my_friendly_assert((a != NULL_TREE) == (t != NULL_TREE), 0);
  
!       if (t != NULL_TREE 
! 	  && TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
  	{
  	  cp_error ("got %d template parameters for `%#D'",
! 		    TREE_VEC_LENGTH (a), decl);
  	  cp_error ("  but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
  	}
      }
+   /* Get the innermost set of template arguments. */
+   args = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
  
    DECL_TEMPLATE_RESULT (tmpl) = decl;
    TREE_TYPE (tmpl) = TREE_TYPE (decl);
*************** push_template_decl (decl)
*** 330,336 ****
      tmpl = pushdecl_top_level (tmpl);
  
    if (primary)
!     TREE_TYPE (DECL_TEMPLATE_PARMS (tmpl)) = tmpl;
  
    info = perm_tree_cons (tmpl, args, NULL_TREE);
  
--- 522,528 ----
      tmpl = pushdecl_top_level (tmpl);
  
    if (primary)
!     TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
  
    info = perm_tree_cons (tmpl, args, NULL_TREE);
  
*************** push_template_decl (decl)
*** 345,352 ****
      DECL_TEMPLATE_INFO (decl) = info;
  }
  
- tree tsubst		PROTO ((tree, tree*, int, tree));
- 
  /* Convert all template arguments to their appropriate types, and return
     a vector containing the resulting values.  If any error occurs, return
     error_mark_node.  */
--- 537,542 ----
*************** coerce_template_parms (parms, arglist, i
*** 401,410 ****
  	  else if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (parms, i)))
  		   == TYPE_DECL)
  	    arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
! 			  &TREE_VEC_ELT (vec, 0), i, in_decl);
  	  else
  	    arg = tsubst_expr (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
! 			       &TREE_VEC_ELT (vec, 0), i, in_decl);
  
  	  TREE_VEC_ELT (vec, i) = arg;
  	}
--- 591,600 ----
  	  else if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (parms, i)))
  		   == TYPE_DECL)
  	    arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
! 			  vec, i, in_decl);
  	  else
  	    arg = tsubst_expr (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
! 			       vec, i, in_decl);
  
  	  TREE_VEC_ELT (vec, i) = arg;
  	}
*************** coerce_template_parms (parms, arglist, i
*** 460,466 ****
  	}
        else
  	{
! 	  tree t = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (vec, 0),
  			   TREE_VEC_LENGTH (vec), in_decl);
  	  if (processing_template_decl)
  	    val = arg;
--- 650,656 ----
  	}
        else
  	{
! 	  tree t = tsubst (TREE_TYPE (parm), vec,
  			   TREE_VEC_LENGTH (vec), in_decl);
  	  if (processing_template_decl)
  	    val = arg;
*************** classtype_mangled_name (t)
*** 656,662 ****
        tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
        char *mangled_name = mangle_class_name_for_template
  	(IDENTIFIER_POINTER (name),
! 	 DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
  	 CLASSTYPE_TI_ARGS (t));
        tree id = get_identifier (mangled_name);
        IDENTIFIER_TEMPLATE (id) = name;
--- 846,852 ----
        tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
        char *mangled_name = mangle_class_name_for_template
  	(IDENTIFIER_POINTER (name),
! 	 DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
  	 CLASSTYPE_TI_ARGS (t));
        tree id = get_identifier (mangled_name);
        IDENTIFIER_TEMPLATE (id) = name;
*************** lookup_template_class (d1, arglist, in_d
*** 740,746 ****
  
    if (PRIMARY_TEMPLATE_P (template))
      {
!       parmlist = DECL_TEMPLATE_PARMS (template);
  
        arglist = coerce_template_parms (parmlist, arglist, template);
        if (arglist == error_mark_node)
--- 930,936 ----
  
    if (PRIMARY_TEMPLATE_P (template))
      {
!       parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
  
        arglist = coerce_template_parms (parmlist, arglist, template);
        if (arglist == error_mark_node)
*************** instantiate_class_template (type)
*** 1209,1215 ****
  	    tree elt;
  
  	    TREE_VEC_ELT (bases, i) = elt
! 	      = tsubst (TREE_VEC_ELT (pbases, i), &TREE_VEC_ELT (args, 0),
  			TREE_VEC_LENGTH (args), NULL_TREE);
  	    BINFO_INHERITANCE_CHAIN (elt) = binfo;
  
--- 1399,1405 ----
  	    tree elt;
  
  	    TREE_VEC_ELT (bases, i) = elt
! 	      = tsubst (TREE_VEC_ELT (pbases, i), args,
  			TREE_VEC_LENGTH (args), NULL_TREE);
  	    BINFO_INHERITANCE_CHAIN (elt) = binfo;
  
*************** instantiate_class_template (type)
*** 1241,1247 ****
        /* These will add themselves to CLASSTYPE_TAGS for the new type.  */
        if (TREE_CODE (tag) == ENUMERAL_TYPE)
  	{
! 	  tree e, newtag = tsubst_enum (tag, &TREE_VEC_ELT (args, 0),
  					TREE_VEC_LENGTH (args));
  
  	  *field_chain = grok_enum_decls (newtag, NULL_TREE);
--- 1431,1437 ----
        /* These will add themselves to CLASSTYPE_TAGS for the new type.  */
        if (TREE_CODE (tag) == ENUMERAL_TYPE)
  	{
! 	  tree e, newtag = tsubst_enum (tag, args, 
  					TREE_VEC_LENGTH (args));
  
  	  *field_chain = grok_enum_decls (newtag, NULL_TREE);
*************** instantiate_class_template (type)
*** 1252,1258 ****
  	    }
  	}
        else
! 	tsubst (tag, &TREE_VEC_ELT (args, 0),
  		TREE_VEC_LENGTH (args), NULL_TREE);
      }
  
--- 1442,1448 ----
  	    }
  	}
        else
! 	tsubst (tag, args,
  		TREE_VEC_LENGTH (args), NULL_TREE);
      }
  
*************** instantiate_class_template (type)
*** 1260,1266 ****
    for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
      if (TREE_CODE (t) != CONST_DECL)
        {
! 	tree r = tsubst (t, &TREE_VEC_ELT (args, 0),
  			 TREE_VEC_LENGTH (args), NULL_TREE);
  	if (TREE_CODE (r) == VAR_DECL)
  	  {
--- 1450,1456 ----
    for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
      if (TREE_CODE (t) != CONST_DECL)
        {
! 	tree r = tsubst (t, args,
  			 TREE_VEC_LENGTH (args), NULL_TREE);
  	if (TREE_CODE (r) == VAR_DECL)
  	  {
*************** instantiate_class_template (type)
*** 1288,1305 ****
  
    DECL_FRIENDLIST (TYPE_MAIN_DECL (type))
      = tsubst (DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern)),
! 	      &TREE_VEC_ELT (args, 0), TREE_VEC_LENGTH (args), NULL_TREE);
  
    {
      tree d = CLASSTYPE_FRIEND_CLASSES (type)
!       = tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), &TREE_VEC_ELT (args, 0),
  		TREE_VEC_LENGTH (args), NULL_TREE);
  
      /* This does injection for friend classes.  */
      for (; d; d = TREE_CHAIN (d))
        TREE_VALUE (d) = xref_tag_from_type (TREE_VALUE (d), NULL_TREE, 1);
  
!     d = tsubst (DECL_TEMPLATE_INJECT (template), &TREE_VEC_ELT (args, 0),
  		TREE_VEC_LENGTH (args), NULL_TREE);
  
      for (; d; d = TREE_CHAIN (d))
--- 1478,1495 ----
  
    DECL_FRIENDLIST (TYPE_MAIN_DECL (type))
      = tsubst (DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern)),
! 	      args, TREE_VEC_LENGTH (args), NULL_TREE);
  
    {
      tree d = CLASSTYPE_FRIEND_CLASSES (type)
!       = tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), args,
  		TREE_VEC_LENGTH (args), NULL_TREE);
  
      /* This does injection for friend classes.  */
      for (; d; d = TREE_CHAIN (d))
        TREE_VALUE (d) = xref_tag_from_type (TREE_VALUE (d), NULL_TREE, 1);
  
!     d = tsubst (DECL_TEMPLATE_INJECT (template), args,
  		TREE_VEC_LENGTH (args), NULL_TREE);
  
      for (; d; d = TREE_CHAIN (d))
*************** lookup_nested_type_by_name (ctype, name)
*** 1382,1388 ****
  
  tree
  tsubst (t, args, nargs, in_decl)
!      tree t, *args;
       int nargs;
       tree in_decl;
  {
--- 1572,1578 ----
  
  tree
  tsubst (t, args, nargs, in_decl)
!      tree t, args;
       int nargs;
       tree in_decl;
  {
*************** tsubst (t, args, nargs, in_decl)
*** 1471,1485 ****
        }
  
      case TEMPLATE_TYPE_PARM:
        {
! 	tree arg = args[TEMPLATE_TYPE_IDX (t)];
! 	return cp_build_type_variant
! 	  (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
! 	   TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
        }
  
!     case TEMPLATE_CONST_PARM:
!       return args[TEMPLATE_CONST_IDX (t)];
  
      case FUNCTION_DECL:
        {
--- 1661,1769 ----
        }
  
      case TEMPLATE_TYPE_PARM:
+     case TEMPLATE_CONST_PARM:
        {
! 	int idx;
! 	int level;
! 
! 	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
! 	  {
! 	    idx = TEMPLATE_TYPE_IDX (t);
! 	    level = TEMPLATE_TYPE_LEVEL (t);
! 	  }
! 	else
! 	  {
! 	    idx = TEMPLATE_CONST_IDX (t);
! 	    level = TEMPLATE_CONST_LEVEL (t);
! 	  }
! 
! 	if (TREE_VEC_LENGTH (args) > 0) 
! 	  {
! 	    tree arg = NULL_TREE;
! 
! 	    if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
! 	      {
! 		if (TREE_VEC_LENGTH (args)  >= level - 1)
! 		  arg =
! 		    TREE_VEC_ELT
! 		    (TREE_VEC_ELT (args, level - 1), idx);
! 	      }
! 	    else if (level == 1)
! 	      arg = TREE_VEC_ELT (args, idx);
! 
! 	    if (arg != NULL_TREE)
! 	      {
! 		if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
! 		  return cp_build_type_variant
! 		    (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
! 		     TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
! 		else
! 		  return arg;
! 	      }
! 	  }
! 
! 	/* If we get here, we must have been looking at a parm for a
! 	   more deeply nested template.  */
! 	my_friendly_assert((TREE_CODE (t) == TEMPLATE_CONST_PARM 
! 			    && TEMPLATE_CONST_LEVEL (t) > 1) 
! 			   || (TREE_CODE (t) == TEMPLATE_TYPE_PARM
! 			       && TEMPLATE_TYPE_LEVEL (t) > 1),
! 			   0);
! 	return t;
        }
  
!     case TEMPLATE_DECL:
!       {
! 	/* We can get here when processing a member template function
! 	   of a template class.  */
! 	tree tmpl;
! 	tree decl = DECL_TEMPLATE_RESULT (t);
! 	tree new_decl;
! 	tree parms;
! 	int i;
! 
! 	/* We might already have an instance of this template. */
! 	tree instances = DECL_TEMPLATE_INSTANTIATIONS (t);
! 	tree ctx = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, in_decl); 
! 	  
! 	for (; instances; instances = TREE_CHAIN (instances))
! 	  if (DECL_CLASS_CONTEXT (TREE_VALUE (instances)) == ctx)
! 	    return TREE_VALUE (instances);
! 
! 	/* Make a new template decl.  It will be similar to the
! 	   original, but will record the current template arguments. 
! 	   We also create a new function declaration, which is just
! 	   like the old one, but points to this new template, rather
! 	   than the old one.  */
! 	tmpl = copy_node (t);
! 	copy_lang_decl (tmpl);
! 	my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
! 	DECL_CHAIN (tmpl) = NULL_TREE;
! 	TREE_CHAIN (tmpl) = NULL_TREE;
! 	DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
! 	new_decl = tsubst (decl, args, nargs, in_decl);
! 	DECL_RESULT (tmpl) = new_decl;
! 	DECL_INITIAL (new_decl) = DECL_INITIAL (decl);
! 	DECL_TI_TEMPLATE (new_decl) = tmpl;
! 	TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
! 	DECL_TEMPLATE_INSTANTIATIONS(tmpl) = NULL_TREE;
! 
! 	/* The template parameters for this new template are all the
! 	   template parameters for the old template, except the
! 	   outermost level of parameters. */
! 	DECL_TEMPLATE_PARMS (tmpl) = 
! 	  copy_node (DECL_TEMPLATE_PARMS (tmpl));
! 	for (parms = DECL_TEMPLATE_PARMS (tmpl);
! 	     TREE_CHAIN (parms) != NULL_TREE;
! 	     parms = TREE_CHAIN (parms))
! 	  TREE_CHAIN (parms) = copy_node (TREE_CHAIN (parms));
! 
! 	/* Record this partial instantiation. */
! 	DECL_TEMPLATE_INSTANTIATIONS (t) = 
! 	  perm_tree_cons (NULL_TREE, tmpl,
! 			  DECL_TEMPLATE_INSTANTIATIONS (t));
! 	return tmpl;
!       }
  
      case FUNCTION_DECL:
        {
*************** tsubst (t, args, nargs, in_decl)
*** 1622,1629 ****
  	  {
  	    tree tmpl = DECL_TI_TEMPLATE (t);
  	    tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
! 	    tree argvec = tsubst (TREE_VALUE (DECL_TEMPLATE_INFO (t)),
! 				  args, nargs, in_decl);
  
  	    DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
  	    *declsp = perm_tree_cons (argvec, r, *declsp);
--- 1906,1923 ----
  	  {
  	    tree tmpl = DECL_TI_TEMPLATE (t);
  	    tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
! 	    tree argvec;
! 
! 	    if (DECL_TEMPLATE_INFO (tmpl) == NULL_TREE
! 		|| DECL_TI_ARGS (tmpl) == NULL_TREE)
! 	      argvec = tsubst (TREE_VALUE (DECL_TEMPLATE_INFO (t)),
! 			       args, nargs, in_decl);
! 	    else
! 	      argvec = 
! 		add_to_template_args 
! 		(DECL_TI_ARGS (tmpl),
! 		 tsubst (TREE_VALUE (DECL_TEMPLATE_INFO (t)),
! 			 args, nargs, in_decl));
  
  	    DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
  	    *declsp = perm_tree_cons (argvec, r, *declsp);
*************** do_poplevel ()
*** 2013,2019 ****
  
  tree
  tsubst_copy (t, args, nargs, in_decl)
!      tree t, *args;
       int nargs;
       tree in_decl;
  {
--- 2307,2313 ----
  
  tree
  tsubst_copy (t, args, nargs, in_decl)
!      tree t, args;
       int nargs;
       tree in_decl;
  {
*************** tsubst_copy (t, args, nargs, in_decl)
*** 2048,2053 ****
--- 2342,2353 ----
        mark_used (t);
        return t;
  
+     case TEMPLATE_DECL:
+       if (is_member_template (t))
+ 	return tsubst (t, args, nargs, in_decl);
+       else
+ 	return t;
+ 
  #if 0
      case IDENTIFIER_NODE:
        return do_identifier (t, 0);
*************** tsubst_copy (t, args, nargs, in_decl)
*** 2241,2247 ****
  
  tree
  tsubst_expr (t, args, nargs, in_decl)
!      tree t, *args;
       int nargs;
       tree in_decl;
  {
--- 2541,2547 ----
  
  tree
  tsubst_expr (t, args, nargs, in_decl)
!      tree t, args;
       int nargs;
       tree in_decl;
  {
*************** tsubst_expr (t, args, nargs, in_decl)
*** 2543,2549 ****
  
  tree
  instantiate_template (tmpl, targ_ptr)
!      tree tmpl, *targ_ptr;
  {
    tree fndecl;
    int i, len;
--- 2843,2849 ----
  
  tree
  instantiate_template (tmpl, targ_ptr)
!      tree tmpl, targ_ptr;
  {
    tree fndecl;
    int i, len;
*************** instantiate_template (tmpl, targ_ptr)
*** 2555,2566 ****
    function_maybepermanent_obstack = &permanent_obstack;
  
    my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
!   len = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
  
    i = len;
    while (i--)
      {
!       tree t = targ_ptr [i];
        if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
  	{
  	  tree nt = target_type (t);
--- 2855,2866 ----
    function_maybepermanent_obstack = &permanent_obstack;
  
    my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
!   len = DECL_NTPARMS (tmpl);
  
    i = len;
    while (i--)
      {
!       tree t = TREE_VEC_ELT (targ_ptr, i);
        if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
  	{
  	  tree nt = target_type (t);
*************** instantiate_template (tmpl, targ_ptr)
*** 2572,2580 ****
  	      goto out;
  	    }
  	}
!       targ_ptr[i] = copy_to_permanent (t);
      }
  
    /* substitute template parameters */
    fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr, len, tmpl);
  
--- 2872,2883 ----
  	      goto out;
  	    }
  	}
!       TREE_VEC_ELT (targ_ptr, i) = copy_to_permanent (t);
      }
  
+   if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
+     targ_ptr = add_to_template_args (DECL_TI_ARGS (tmpl), targ_ptr);
+ 
    /* substitute template parameters */
    fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr, len, tmpl);
  
*************** overload_template_name (type)
*** 2606,2611 ****
--- 2909,2952 ----
    pushdecl_class_level (decl);
  }
  
+ 
+ /* Like type_unfication but designed specially to handle conversion
+    operators.  */
+ 
+ int
+ fn_type_unification (fn, targs, args, return_type, strict)
+      tree fn, targs, args, return_type;
+      int strict;
+ {
+   int i, dummy = 0;
+   tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+   tree decl_arg_types = args;
+ 
+   my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
+ 
+   if (IDENTIFIER_TYPENAME_P (DECL_NAME (fn))) 
+     {
+       /* This is a template conversion operator.  Use the return types
+          as well as the argument types.  */
+       fn_arg_types = tree_cons (NULL_TREE, 
+ 				TREE_TYPE (TREE_TYPE (fn)),
+ 				fn_arg_types);
+       decl_arg_types = tree_cons (NULL_TREE,
+ 				  return_type,
+ 				  decl_arg_types);
+     }
+ 
+   i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
+ 			&TREE_VEC_ELT (targs, 0), 
+ 			fn_arg_types,
+ 			decl_arg_types,
+ 			&dummy, 0, strict);
+ 
+ 
+   return i;
+ }
+ 
+ 
  /* Type unification.
  
     We have a function template signature with one or more references to
*************** type_unification (tparms, targs, parms, 
*** 2718,2727 ****
  	      /* Have to back unify here */
  	      arg = TREE_VALUE (arg);
  	      nsubsts = 0;
! 	      ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (arg));
  	      targs = (tree *) alloca (sizeof (tree) * ntparms);
  	      parm = tree_cons (NULL_TREE, parm, NULL_TREE);
! 	      return type_unification (DECL_TEMPLATE_PARMS (arg), targs,
  				       TYPE_ARG_TYPES (TREE_TYPE (arg)),
  				       parm, &nsubsts, 0, strict);
  	    }
--- 3059,3069 ----
  	      /* Have to back unify here */
  	      arg = TREE_VALUE (arg);
  	      nsubsts = 0;
! 	      ntparms = DECL_NTPARMS (arg);
  	      targs = (tree *) alloca (sizeof (tree) * ntparms);
  	      parm = tree_cons (NULL_TREE, parm, NULL_TREE);
! 	      return type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg), 
! 				       targs,
  				       TYPE_ARG_TYPES (TREE_TYPE (arg)),
  				       parm, &nsubsts, 0, strict);
  	    }
*************** int
*** 3022,3041 ****
  more_specialized (pat1, pat2)
       tree pat1, pat2;
  {
!   tree *targs;
    int winner = 0;
  
    targs = get_bindings (pat1, pat2);
    if (targs)
      {
-       free (targs);
        --winner;
      }
  
    targs = get_bindings (pat2, pat1);
    if (targs)
      {
-       free (targs);
        ++winner;
      }
  
--- 3364,3381 ----
  more_specialized (pat1, pat2)
       tree pat1, pat2;
  {
!   tree targs;
    int winner = 0;
  
    targs = get_bindings (pat1, pat2);
    if (targs)
      {
        --winner;
      }
  
    targs = get_bindings (pat2, pat1);
    if (targs)
      {
        ++winner;
      }
  
*************** more_specialized_class (pat1, pat2)
*** 3071,3090 ****
  /* Return the template arguments that will produce the function signature
     DECL from the function template FN.  */
  
! tree *
  get_bindings (fn, decl)
       tree fn, decl;
  {
!   int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (fn));
!   tree *targs = (tree *) malloc (sizeof (tree) * ntparms);
!   int i, dummy = 0;
!   i = type_unification (DECL_TEMPLATE_PARMS (fn), targs,
! 			TYPE_ARG_TYPES (TREE_TYPE (fn)),
! 			TYPE_ARG_TYPES (TREE_TYPE (decl)),
! 			&dummy, 0, 1);
    if (i == 0)
      return targs;
-   free (targs);
    return 0;
  }
  
--- 3411,3431 ----
  /* Return the template arguments that will produce the function signature
     DECL from the function template FN.  */
  
! tree 
  get_bindings (fn, decl)
       tree fn, decl;
  {
!   int ntparms = DECL_NTPARMS (fn);
!   tree targs = make_tree_vec (ntparms);
!   int i;
! 
!   i = fn_type_unification (fn, targs, 
! 			   TYPE_ARG_TYPES (TREE_TYPE (decl)), 
! 			   TREE_TYPE (TREE_TYPE (decl)),
! 			   1);
! 
    if (i == 0)
      return targs;
    return 0;
  }
  
*************** tree
*** 3122,3128 ****
  most_specialized (fns, decl)
       tree fns, decl;
  {
!   tree fn, champ, *args, *p;
    int fate;
  
    for (p = &fns; *p; )
--- 3463,3469 ----
  most_specialized (fns, decl)
       tree fns, decl;
  {
!   tree fn, champ, args, *p;
    int fate;
  
    for (p = &fns; *p; )
*************** most_specialized (fns, decl)
*** 3130,3136 ****
        args = get_bindings (TREE_VALUE (*p), decl);
        if (args)
  	{
- 	  free (args);
  	  p = &TREE_CHAIN (*p);
  	}
        else
--- 3471,3476 ----
*************** do_decl_instantiation (declspecs, declar
*** 3234,3239 ****
--- 3574,3580 ----
    tree fn;
    tree result = NULL_TREE;
    int extern_p = 0;
+   tree templates = NULL_TREE;
  
    if (! DECL_LANG_SPECIFIC (decl))
      {
*************** do_decl_instantiation (declspecs, declar
*** 3261,3270 ****
  	       fn = IDENTIFIER_GLOBAL_VALUE (name),
  	       fn && DECL_TEMPLATE_INSTANTIATION (fn))
  	result = fn;
      }
    else if (name = DECL_NAME (decl), fn = IDENTIFIER_GLOBAL_VALUE (name), fn)
      {
-       tree templates = NULL_TREE;
        for (fn = get_first_fn (fn); fn; fn = DECL_CHAIN (fn))
  	if (decls_match (fn, decl)
  	    && DECL_DEFER_OUTPUT (fn))
--- 3602,3640 ----
  	       fn = IDENTIFIER_GLOBAL_VALUE (name),
  	       fn && DECL_TEMPLATE_INSTANTIATION (fn))
  	result = fn;
+       else 
+ 	{
+ 	  /* Maybe this is an instantiation of a member template
+ 	     function.  */
+ 	  name = DECL_NAME (decl);
+ 	  fn = IDENTIFIER_CLASS_VALUE (name);
+ 	  
+ 	  if (! fn && IDENTIFIER_TYPENAME_P (name)) 
+ 	    {
+ 	      /* If we haven't found it, it could be a member template
+ 		 conversion operator.  */
+ 	      tree ctype = DECL_CONTEXT (decl);
+ 	      
+ 	      fn = lookup_fnfields (TYPE_BINFO (ctype), name, 1);
+ 
+ 	      if (fn)
+ 		fn = TREE_VALUE (fn);
+ 	    }
+ 
+ 	  for (; fn; fn = DECL_CHAIN (fn))
+ 	    if (decls_match (fn, decl)
+ 		&& DECL_DEFER_OUTPUT (fn))
+ 	      {
+ 		result = fn;
+ 		break;
+ 	      }
+ 	    else if (TREE_CODE (fn) == TEMPLATE_DECL)
+ 		  templates = decl_tree_cons (NULL_TREE, fn,
+ 					      templates);
+ 	}
      }
    else if (name = DECL_NAME (decl), fn = IDENTIFIER_GLOBAL_VALUE (name), fn)
      {
        for (fn = get_first_fn (fn); fn; fn = DECL_CHAIN (fn))
  	if (decls_match (fn, decl)
  	    && DECL_DEFER_OUTPUT (fn))
*************** do_decl_instantiation (declspecs, declar
*** 3274,3303 ****
  	  }
  	else if (TREE_CODE (fn) == TEMPLATE_DECL)
  	  templates = decl_tree_cons (NULL_TREE, fn, templates);
  
!       if (! result)
  	{
! 	  tree *args;
! 	  result = most_specialized (templates, decl);
! 	  if (result == error_mark_node)
! 	    {
! 	      char *str = "candidates are:";
! 	      cp_error ("ambiguous template instantiation for `%D' requested", decl);
! 	      for (fn = templates; fn; fn = TREE_CHAIN (fn))
! 		{
! 		  cp_error_at ("%s %+#D", str, TREE_VALUE (fn));
! 		  str = "               ";
! 		}
! 	      return;
! 	    }
! 	  else if (result)
  	    {
! 	      args = get_bindings (result, decl);
! 	      result = instantiate_template (result, args);
! 	      free (args);
  	    }
  	}
      }
    if (! result)
      {
        cp_error ("no matching template for `%D' found", decl);
--- 3644,3673 ----
  	  }
  	else if (TREE_CODE (fn) == TEMPLATE_DECL)
  	  templates = decl_tree_cons (NULL_TREE, fn, templates);
+     }
  
!   if (templates && !result)
!     {
!       tree args;
!       result = most_specialized (templates, decl);
!       if (result == error_mark_node)
  	{
! 	  char *str = "candidates are:";
! 	  cp_error ("ambiguous template instantiation for `%D' requested", decl);
! 	  for (fn = templates; fn; fn = TREE_CHAIN (fn))
  	    {
! 	      cp_error_at ("%s %+#D", str, TREE_VALUE (fn));
! 	      str = "               ";
  	    }
+ 	  return;
+ 	}
+       else if (result)
+ 	{
+ 	  args = get_bindings (result, decl);
+ 	  result = instantiate_template (result, args);
  	}
      }
+ 
    if (! result)
      {
        cp_error ("no matching template for `%D' found", decl);
*************** instantiate_decl (d)
*** 3477,3483 ****
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (d) = tsubst_expr
! 	(DECL_INITIAL (pattern), &TREE_VEC_ELT (args, 0),
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
--- 3847,3853 ----
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (d) = tsubst_expr
! 	(DECL_INITIAL (pattern), args,
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
*************** instantiate_decl (d)
*** 3527,3533 ****
    /* Trick tsubst into giving us a new decl in case the template changed.  */
    save_ti = DECL_TEMPLATE_INFO (pattern);
    DECL_TEMPLATE_INFO (pattern) = NULL_TREE;
!   td = tsubst (pattern, &TREE_VEC_ELT (args, 0), TREE_VEC_LENGTH (args), tmpl);
    DECL_TEMPLATE_INFO (pattern) = save_ti;
  
    /* And set up DECL_INITIAL, since tsubst doesn't.  */
--- 3897,3903 ----
    /* Trick tsubst into giving us a new decl in case the template changed.  */
    save_ti = DECL_TEMPLATE_INFO (pattern);
    DECL_TEMPLATE_INFO (pattern) = NULL_TREE;
!   td = tsubst (pattern, args, TREE_VEC_LENGTH (args), tmpl);
    DECL_TEMPLATE_INFO (pattern) = save_ti;
  
    /* And set up DECL_INITIAL, since tsubst doesn't.  */
*************** instantiate_decl (d)
*** 3535,3541 ****
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (td) = tsubst_expr
! 	(DECL_INITIAL (pattern), &TREE_VEC_ELT (args, 0),
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
--- 3905,3911 ----
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (td) = tsubst_expr
! 	(DECL_INITIAL (pattern), args,
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
*************** instantiate_decl (d)
*** 3570,3576 ****
  	{
  	  store_return_init
  	    (TREE_OPERAND (t, 0),
! 	     tsubst_expr (TREE_OPERAND (t, 1), &TREE_VEC_ELT (args, 0),
  			  TREE_VEC_LENGTH (args), tmpl));
  	  t = TREE_CHAIN (t);
  	}
--- 3940,3946 ----
  	{
  	  store_return_init
  	    (TREE_OPERAND (t, 0),
! 	     tsubst_expr (TREE_OPERAND (t, 1), args,
  			  TREE_VEC_LENGTH (args), tmpl));
  	  t = TREE_CHAIN (t);
  	}
*************** instantiate_decl (d)
*** 3591,3597 ****
        keep_next_level ();
  
        my_friendly_assert (TREE_CODE (t) == COMPOUND_STMT, 42);
!       tsubst_expr (t, &TREE_VEC_ELT (args, 0),
  		   TREE_VEC_LENGTH (args), tmpl);
  
        finish_function (lineno, 0, nested);
--- 3961,3967 ----
        keep_next_level ();
  
        my_friendly_assert (TREE_CODE (t) == COMPOUND_STMT, 42);
!       tsubst_expr (t, args,
  		   TREE_VEC_LENGTH (args), tmpl);
  
        finish_function (lineno, 0, nested);
*************** tsubst_chain (t, argvec)
*** 3613,3625 ****
  {
    if (t)
      {
!       tree first = tsubst (t, &TREE_VEC_ELT (argvec, 0),
  			   TREE_VEC_LENGTH (argvec), NULL_TREE);
        tree last = first;
  
        for (t = TREE_CHAIN (t); t; t = TREE_CHAIN (t))
  	{
! 	  tree x = tsubst (t, &TREE_VEC_ELT (argvec, 0),
  			   TREE_VEC_LENGTH (argvec), NULL_TREE);
  	  TREE_CHAIN (last) = x;
  	  last = x;
--- 3983,3995 ----
  {
    if (t)
      {
!       tree first = tsubst (t, argvec,
  			   TREE_VEC_LENGTH (argvec), NULL_TREE);
        tree last = first;
  
        for (t = TREE_CHAIN (t); t; t = TREE_CHAIN (t))
  	{
! 	  tree x = tsubst (t, argvec,
  			   TREE_VEC_LENGTH (argvec), NULL_TREE);
  	  TREE_CHAIN (last) = x;
  	  last = x;
*************** tsubst_expr_values (t, argvec)
*** 3639,3647 ****
  
    for (; t; t = TREE_CHAIN (t))
      {
!       tree pur = tsubst_copy (TREE_PURPOSE (t), &TREE_VEC_ELT (argvec, 0),
  			      TREE_VEC_LENGTH (argvec), NULL_TREE);
!       tree val = tsubst_expr (TREE_VALUE (t), &TREE_VEC_ELT (argvec, 0),
  			      TREE_VEC_LENGTH (argvec), NULL_TREE);
        *p = build_tree_list (pur, val);
        p = &TREE_CHAIN (*p);
--- 4009,4017 ----
  
    for (; t; t = TREE_CHAIN (t))
      {
!       tree pur = tsubst_copy (TREE_PURPOSE (t), argvec,
  			      TREE_VEC_LENGTH (argvec), NULL_TREE);
!       tree val = tsubst_expr (TREE_VALUE (t), argvec,
  			      TREE_VEC_LENGTH (argvec), NULL_TREE);
        *p = build_tree_list (pur, val);
        p = &TREE_CHAIN (*p);
*************** add_maybe_template (d, fns)
*** 3691,3697 ****
  
  static tree
  tsubst_enum (tag, args, nargs)
!      tree tag, *args;
       int nargs;
  {
    tree newtag = start_enum (TYPE_IDENTIFIER (tag));
--- 4061,4067 ----
  
  static tree
  tsubst_enum (tag, args, nargs)
!      tree tag, args;
       int nargs;
  {
    tree newtag = start_enum (TYPE_IDENTIFIER (tag));
Index: gcc/cp/search.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/search.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -c -p -r1.1.1.1 -r1.3
*** search.c	1997/08/26 06:23:56	1.1.1.1
--- search.c	1997/09/04 20:27:32	1.3
*************** lookup_fnfields_1 (type, name)
*** 1637,1642 ****
--- 1637,1659 ----
  	  if (DECL_NAME (*methods) == name)
  	    break;
  	}
+ 
+       /* If we didn't find it, it might have been a template
+ 	 conversion operator.  (Note that we don't look for this case
+ 	 above so that we will always find specializations first.)  */
+       if (methods == end 
+ 	  && IDENTIFIER_TYPENAME_P (name)) 
+ 	{
+ 	  methods = &TREE_VEC_ELT (method_vec, 0) + 1;
+ 	  
+ 	  while (++methods != end)
+ 	    {
+ 	      if (TREE_CODE (*methods) == TEMPLATE_DECL 
+ 		  && IDENTIFIER_TYPENAME_P (DECL_NAME (*methods)))
+ 		break;
+ 	    }
+ 	}
+ 
        if (methods != end)
  	return methods - &TREE_VEC_ELT (method_vec, 0);
      }
Index: gcc/cp/tree.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/tree.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -c -p -r1.1.1.1 -r1.2
*** tree.c	1997/08/26 06:23:57	1.1.1.1
--- tree.c	1997/09/02 06:38:44	1.2
*************** cp_tree_equal (t1, t2)
*** 2005,2011 ****
        return 0;
  
      case TEMPLATE_CONST_PARM:
!       return TEMPLATE_CONST_IDX (t1) == TEMPLATE_CONST_IDX (t2);
  
      case SIZEOF_EXPR:
        if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
--- 2005,2012 ----
        return 0;
  
      case TEMPLATE_CONST_PARM:
!       return TEMPLATE_CONST_IDX (t1) == TEMPLATE_CONST_IDX (t2)
! 	&& TEMPLATE_CONST_LEVEL (t1) == TEMPLATE_CONST_LEVEL (t2);
  
      case SIZEOF_EXPR:
        if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
Index: gcc/cp/typeck.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/typeck.c,v
retrieving revision 1.1.1.3
retrieving revision 1.3
diff -c -p -r1.1.1.3 -r1.3
*** typeck.c	1997/09/04 18:09:48	1.1.1.3
--- typeck.c	1997/09/04 20:27:32	1.3
*************** comptypes (type1, type2, strict)
*** 832,838 ****
        break;
  
      case TEMPLATE_TYPE_PARM:
!       return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2);
  
      case TYPENAME_TYPE:
        if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
--- 832,839 ----
        break;
  
      case TEMPLATE_TYPE_PARM:
!       return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
! 	&& TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2);
  
      case TYPENAME_TYPE:
        if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
*************** build_x_function_call (function, params,
*** 2296,2302 ****
      {
        tree basetype = NULL_TREE;
  
!       if (TREE_CODE (function) == FUNCTION_DECL)
  	{
  	  basetype = DECL_CLASS_CONTEXT (function);
  
--- 2297,2304 ----
      {
        tree basetype = NULL_TREE;
  
!       if (TREE_CODE (function) == FUNCTION_DECL
! 	  || DECL_FUNCTION_TEMPLATE_P (function))
  	{
  	  basetype = DECL_CLASS_CONTEXT (function);
  
Index: libstdc++/std/bastring.h
===================================================================
RCS file: /home/mitchell/Repository/egcs/libstdc++/std/bastring.h,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -c -p -r1.1.1.2 -r1.2
cvs diff: Diffing libstdc++/stl
Index: libstdc++/stl/ChangeLog
===================================================================
RCS file: /home/mitchell/Repository/egcs/libstdc++/stl/ChangeLog,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 ChangeLog
*** ChangeLog	1997/08/26 06:24:11	1.1.1.1
--- ChangeLog	1997/09/03 21:23:31
***************
*** 1,3 ****
--- 1,7 ----
+ Wed Sep  3 14:23:12 1997  Mark Mitchell  <mmitchell@usa.net>
+ 
+ 	* stl_config.h (__STL_MEMBER_TEMPLATES): Enable.
+ 
  Tue Aug  5 17:06:01 1997  Jason Merrill  <jason@yorick.cygnus.com>
  
  	* deque.h, function.h, hashtable.h, list.h, rope.h, ropeimpl.h,
Index: libstdc++/stl/stl_config.h
===================================================================
RCS file: /home/mitchell/Repository/egcs/libstdc++/stl/stl_config.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -c -p -r1.1.1.1 -r1.2
*** stl_config.h	1997/08/26 06:24:12	1.1.1.1
--- stl_config.h	1997/09/02 06:38:49	1.2
***************
*** 88,93 ****
--- 88,94 ----
  #     define __STL_NEED_EXPLICIT
  #   else
  #     define __STL_CLASS_PARTIAL_SPECIALIZATION
+ #     define __STL_MEMBER_TEMPLATES
  #   endif
  #   ifdef __EXCEPTIONS
  #     define __STL_USE_EXCEPTIONS




More information about the Gcc mailing list