Member Templates

Mark Mitchell mmitchell@usa.net
Tue Sep 2 03:42:00 GMT 1997


I have implemented member template functions in g++.  Member template
functions are member functions that are themselves templates.  For
example:

temlate <class T>
struct S
{
  template <class U>
  void f(U u);       // A member template.
};

Member templates are a part of the forthcoming ISO C++ standard, are
are used extensively in STL.  Until now, g++ did not provide this
feature, and disabled member templates in the SGI implementation of
STL provided as part of libstdc++.

I have tested many simple uses of member template functions, and tried
a few STL examples.  There are likely to be bugs remaining, however.
I know that speciailizations of member templates must be declared
in-class (although they may be defined out-of-class); this is a
limitation relative to the ISO draft.

Please report those bugs to me, rather than to the official g++
maintainers, as this patch is not yet a part of the egcs or gcc2
distributions.  If you apply this patch, you should check that any
bugs you find in programs not involving member templates also exist in
the raw distribution; it is possible that this patch will break
existing programs.  This code is provided on an "as-is" basis; egcs is
after all the *experimental* GNU compiler system.  However, I dir run
"make check" at the top of egcs tree, and observed no differences from
the egcs-970828 distribution.

I will be working with the maintainers in an attempt to get this patch
(perhaps in some modified form) incorporated into both distributions
when appropriate.  (It seems possible that it would appear in egcs
before gcc2.)

Here is one small program which works with the patch:

  supernova% cat test.cpp
  #include <iostream.h>
  #include <vector>
  #include <list>
  #include <string>

  void main()
  {
    list<string> l;
    l.push_back("member");
    l.push_back("templates");
    l.push_back("work");

    vector<string> v(l.begin(), l.end());

    for (vector<string>::iterator i = v.begin();
	 i != v.end();
	 ++i) {
      cout << *i << " ";
    }
    cout << "\n";
  }
  supernova% g++ test.cpp
  supernova% ./a.out
  member templates work 

Note that here that the vectors are constructed from list input
iterators, rather than vector input iterators.  This requires use of
vector's member template constructor:

    template <class InputIterator>
    vector(InputIterator first, InputIterator last) :
      start(0), finish(0), end_of_storage(0) {
        range_initialize(first, last, iterator_category(first));
    }

The first patch below sets a flag in libstdc++ to activate member
templates in the STL.  The second (much longer) patch modifies g++ to
handle member templates.  If you do not apply the first patch, libstdc++
will not make use of member templates, but you may still use them in
your code.

Please let me know what successes and failures you have; I will
endeavor to fix those bugs that you find, ability and time
permitting. 

Thank you,

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

-----STL Patch-----

Index: libstdc++/stl/stl_config.h
===================================================================
RCS file: /home/mitchell/Repository/egcs/libstdc++/stl/stl_config.h,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 stl_config.h
*** stl_config.h	1997/08/26 06:24:12	1.1.1.1
--- stl_config.h	1997/08/30 07:53:21
***************
*** 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

-----Main Patch-----

Index: gcc/cp/ChangeLog
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/ChangeLog,v
retrieving revision 1.1.1.2
diff -c -p -r1.1.1.2 ChangeLog
*** ChangeLog	1997/08/29 02:03:50	1.1.1.2
--- ChangeLog	1997/09/01 07:47:58
***************
*** 1,3 ****
--- 1,106 ----
+ Mon Sep  1 00:11:50 1997  Mark Mitchell  <mmitchell@usa.net>
+ 
+ 	* 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. 
+ 	
+ 	* tree.c (cp_tree_equal): Check the levels, as well as the
+ 	indices, of TEMPLATE_CONST_PARMs.
+ 
+ 	* search.c (lookup_fnfields_1): Handle member template conversion
+ 	operators. 
+ 
+ 	* pt.c (current_this_ptr): New variable.
+ 	(tsubst_stmt): New function.
+ 	(begin_member_template_processing): Likewise.
+ 	(end_member_template_processing): Likewise.
+ 	(tsubst_enum): Adjust calling sequence.
+ 	(tsubst): Likewise.
+ 	(tsubst_copy): Likewise.
+ 	(get_bindings): 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 nested
+ 	templates. 
+ 	(instantiate_class_template): After tsubst'ing member template
+ 	declarations, form new function bodies for them as well.
+ 	(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.
+ 	(tsubst_copy): Use current_this_ptr to Handle `this' parameter. 
+ 	(fn_type_unification): New function.
+ 	(do_decl_instantiation): Handle member templates.
+ 	
+ 	* parse.y (fn.def2): Add member templates.
+ 	(component_decl_1): Likewise.
+ 	
+ 	* method.c (build_overload_identifier): Update for new tsubst
+ 	calling sequence.
+ 
+ 	* error.c (dump_function_decl): Update to handle function
+ 	templates.
+ 
+ 	* 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.
+ 	(finish_file): Adjust for new instantiate_template calling
+ 	sequence. 
+ 	
+ 	* decl.c (duplicate_decls): Copy member_template flag along with
+ 	all the others.
+ 	(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.
+ 	(grokdeclarator): Adjust for new tsubst calling sequence.
+ 	(start_function): When processing an inline member template, call
+ 	begin_member_template_processing() to reinitialize the template
+ 	parameter context.
+ 	(finish_function): When processing an inline member template, call
+ 	end_member_template_processing().
+ 	
+ 	* cp-tree.h (lang_decl_flags): Add new member_template flag.
+ 	Reduce size of dummy field accordingly.
+ 	(DECL_MEMBER_TEMPLATE_P): Add new predicate.
+ 	(check_member_template): Add declaration.
+ 	(begin_member_template_processing): Likewise.
+ 	(end_member_template_processing): Likewise.
+ 	(fn_type_unification): Likewise.
+ 	(tsubst): Change prototype.
+ 	(tsubst_expr): Likewise.
+ 	(tsubst_copy): Likewise.
+ 	(instantiate_template): Likewise.
+ 	(get_bindings): Likewise.
+ 	
+ 	* cp-tree.def (TEMPLATE_CONST_PARM): Note that this tree node
+ 	needs 3 extra slots, not 2.
+ 	
+ 	* 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.
+ 	(instantiate_type): Adjust for new type_unification calling
+ 	sequence. 
+ 	
+ 	* call.c (add_template_candidate): Add additional parameter for
+ 	the function return type.  Call fn_type_unification istead of
+ 	type_unification. 
+ 	(build_overload_call_real): Adjust for new type_unification
+ 	calling sequence.
+ 	(build_user_type_conversion_1): Call add_template_candidate for
+ 	member templates.
+ 	(build_new_op): Likewise.
+ 	(build_new_method_call): Likewise.
+ 	(build_new_function_call): Adjust for new add_template_candidate
+ 	calling sequence.
+ 	(build_over_call): Adjust for new tsubst_expr calling sequence. 
+ 	
  Wed Aug 27 02:03:34 1997  Jeffrey A Law  (law@cygnus.com)
  
  	* typeck.c (expand_target_expr): Make definition match declaration.
Index: gcc/cp/call.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/call.c,v
retrieving revision 1.1.1.2
diff -c -p -r1.1.1.2 call.c
*** call.c	1997/08/29 02:03:51	1.1.1.2
--- call.c	1997/09/02 00:45:48
*************** 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,
*** 2839,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)
--- 2839,2849 ----
        if (TREE_CODE (function) == TEMPLATE_DECL)
  	{
  	  int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
! 	  tree targs = make_tree_vec (ntparms);
  	  int i;
  
! 	  i = type_unification (DECL_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
*** 4147,4166 ****
  }
  
  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;
  
--- 4148,4166 ----
  }
  
  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 = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (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
*** 4256,4261 ****
--- 4256,4262 ----
    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
*** 4282,4290 ****
        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)
--- 4283,4304 ----
        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
*** 4311,4321 ****
        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;
  	  }
      }
  
--- 4325,4348 ----
        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
*** 4357,4362 ****
--- 4384,4396 ----
    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)
*** 4430,4436 ****
  	    {
  	      templates = decl_tree_cons (NULL_TREE, t, templates);
  	      candidates = add_template_candidate
! 		(candidates, t, args, LOOKUP_NORMAL);
  	    }
  	  else
  	    candidates = add_function_candidate
--- 4464,4470 ----
  	    {
  	      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
*** 4715,4721 ****
  	{
  	  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);
--- 4749,4755 ----
  	{
  	  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
*** 4732,4744 ****
        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);
  	}
      }
  
--- 4766,4792 ----
        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)
*** 5186,5192 ****
  	/* 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),
--- 5234,5240 ----
  	/* 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
*** 5329,5334 ****
--- 5377,5383 ----
    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
*** 5409,5425 ****
        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);
  	}
      }
  
--- 5458,5492 ----
        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
*** 5460,5465 ****
--- 5527,5538 ----
        && ((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
diff -c -p -r1.1.1.2 class.c
*** class.c	1997/08/29 02:03:51	1.1.1.2
--- class.c	1997/09/01 06:47:56
*************** 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_MEMBER_TEMPLATE_P (x) 
! 	      && ! DECL_MEMBER_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
*** 5063,5071 ****
  		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)
--- 5066,5075 ----
  		if (TREE_CODE (elem) == TEMPLATE_DECL)
  		  {
  		    int n = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (elem));
! 		    tree t = make_tree_vec (n);
  		    int i, d = 0;
! 		    i = type_unification (DECL_TEMPLATE_PARMS (elem), 
! 					  & TREE_VEC_ELT (t, 0),
  					  TYPE_ARG_TYPES (TREE_TYPE (elem)),
  					  TYPE_ARG_TYPES (lhstype), &d, 0, 1);
  		    if (i == 0)
Index: gcc/cp/cp-tree.def
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 cp-tree.def
*** cp-tree.def	1997/08/26 06:23:55	1.1.1.1
--- cp-tree.def	1997/08/30 07:26:07
*************** 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
diff -c -p -r1.1.1.1 cp-tree.h
*** cp-tree.h	1997/08/26 06:23:55	1.1.1.1
--- cp-tree.h	1997/09/01 06:54:59
*************** struct lang_decl_flags
*** 932,938 ****
    unsigned nonconverting : 1;
    unsigned declared_inline : 1;
    unsigned not_really_extern : 1;
!   unsigned dummy : 4;
  
    tree access;
    tree context;
--- 932,939 ----
    unsigned nonconverting : 1;
    unsigned declared_inline : 1;
    unsigned not_really_extern : 1;
!   unsigned member_template : 1;
!   unsigned dummy : 3;
  
    tree access;
    tree context;
*************** struct lang_decl
*** 1002,1007 ****
--- 1003,1013 ----
     member function.  */
  #define DECL_STATIC_FUNCTION_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.static_function)
  
+ /* Nonzero for FUNCTION_DECL meants that this decl is a member
+    template function. */
+ #define DECL_MEMBER_TEMPLATE_P(NODE) \
+  (DECL_LANG_SPECIFIC (NODE)->decl_flags.member_template)
+ 
  /* Nonzero for a class member means that it is shared between all objects
     of that class.  */
  #define SHARED_MEMBER_P(NODE) \
*************** extern tree grok_alignof			PROTO((tree))
*** 2112,2117 ****
--- 2118,2124 ----
  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));
--- 2306,2317 ----
  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));
--- 2321,2329 ----
  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));
--- 2334,2340 ----
  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));
Index: gcc/cp/decl.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/decl.c,v
retrieving revision 1.1.1.2
diff -c -p -r1.1.1.2 decl.c
*** decl.c	1997/08/29 02:03:52	1.1.1.2
--- decl.c	1997/09/02 00:46:46
*************** duplicate_decls (newdecl, olddecl)
*** 2660,2665 ****
--- 2660,2666 ----
        DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
        DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
        DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
+       DECL_MEMBER_TEMPLATE_P (newdecl) |= DECL_MEMBER_TEMPLATE_P (olddecl);
      }
  
    /* Deal with C++: must preserve virtual function table size.  */
*************** pushdecl (x)
*** 3000,3006 ****
    /* 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)
--- 3001,3007 ----
    /* 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)
*** 3490,3495 ****
--- 3491,3501 ----
       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
*** 7229,7234 ****
--- 7235,7244 ----
        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
*** 7267,7272 ****
--- 7277,7286 ----
        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
*** 8931,8938 ****
  		    && 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
--- 8945,8954 ----
  		    && 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
*************** start_function (declspecs, declarator, a
*** 11107,11112 ****
--- 11123,11137 ----
      {
        decl1 = declarator;
  
+       if (DECL_MEMBER_TEMPLATE_P (decl1) 
+ 	  && ! DECL_TEMPLATE_INSTANTIATION (decl1))
+ 	/* Set up the template context.  This happens when
+ 	   processing inline member templates; the template
+ 	   information is gone by the point inlines are processe, so
+ 	   we restore it here. 
+ 	   */
+ 	begin_member_template_processing (DECL_TI_ARGS (decl1));
+       
        if (! DECL_ARGUMENTS (decl1)
  	  && !DECL_STATIC_FUNCTION_P (decl1)
  	  && DECL_CONTEXT (decl1)
*************** finish_function (lineno, call_poplevel, 
*** 12266,12271 ****
--- 12291,12300 ----
    named_label_uses = NULL;
    current_class_ptr = NULL_TREE;
    current_class_ref = NULL_TREE;
+ 
+   if (DECL_MEMBER_TEMPLATE_P (fndecl) 
+       && ! DECL_TEMPLATE_INSTANTIATION (fndecl))
+     end_member_template_processing ();
  }
  
  /* Create the FUNCTION_DECL for a function definition.
*************** finish_method (decl)
*** 12440,12446 ****
  
    /* We used to check if the context of FNDECL was different from
       current_class_type as another way to get inside here.  This didn't work
!      for String.cc in libg++.  */
    if (DECL_FRIEND_P (fndecl))
      {
        CLASSTYPE_INLINE_FRIENDS (current_class_type)
--- 12469,12476 ----
  
    /* We used to check if the context of FNDECL was different from
       current_class_type as another way to get inside here.  This didn't work
!      for String.cc in libg++.  In the case of template member
!      functions, there may be no lang_specific pointer. */
    if (DECL_FRIEND_P (fndecl))
      {
        CLASSTYPE_INLINE_FRIENDS (current_class_type)
Index: gcc/cp/decl2.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/decl2.c,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 decl2.c
*** decl2.c	1997/08/26 06:23:55	1.1.1.1
--- decl2.c	1997/09/02 05:26:24
*************** delete_sanity (exp, size, doing_vec, use
*** 1280,1285 ****
--- 1280,1348 ----
      }
  }
  
+ 
+ /* 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;
+ 	}
+       DECL_MEMBER_TEMPLATE_P (decl) = 
+ 	DECL_MEMBER_TEMPLATE_P (tmpl) = 1;
+ 
+       /* 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 A local class shall not have member templates. */
+ 	  cp_error ("declaration of of member template `%#D' in local class",
+ 		    decl);
+ 	}
+ 
+       sorry ("member templates classes");
+ 
+       /* We don't handle member template classes yet. */
+       DECL_MEMBER_TEMPLATE_P (decl) = 
+ 	DECL_MEMBER_TEMPLATE_P (tmpl) = 1;
+     }
+   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)
*** 1293,1298 ****
--- 1356,1362 ----
    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)
*** 1309,1314 ****
--- 1373,1379 ----
  
        while (++methods != end)
  	{
+ 	  fndecl = *methods;
  	  if (fn_name == DECL_NAME (*methods))
  	    {
  	    got_it:
*************** check_classfn (ctype, function)
*** 1340,1354 ****
--- 1405,1446 ----
  				     TREE_TYPE (TREE_TYPE (fndecl)), 1)
  			  && compparms (p1, p2, 3))
  			return fndecl;
+ 
+ 		      if (DECL_MEMBER_TEMPLATE_P (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 ()
*** 2789,2795 ****
  
    for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
      {
!       tree *args, fn, decl = TREE_VALUE (fnname);
  
        if (DECL_INITIAL (decl))
  	continue;
--- 2881,2887 ----
  
    for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
      {
!       tree args, fn, decl = TREE_VALUE (fnname);
  
        if (DECL_INITIAL (decl))
  	continue;
*************** finish_file ()
*** 2797,2803 ****
        fn = TREE_PURPOSE (fnname);
        args = get_bindings (fn, decl);
        fn = instantiate_template (fn, args);
-       free (args);
        instantiate_decl (fn);
      }
  
--- 2889,2894 ----
Index: gcc/cp/error.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/error.c,v
retrieving revision 1.2
diff -c -p -r1.2 error.c
*** error.c	1997/08/26 07:24:54	1.2
--- error.c	1997/09/01 16:44:34
*************** dump_function_decl (t, v)
*** 801,810 ****
       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))
--- 801,817 ----
       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))
Index: gcc/cp/method.c
===================================================================
RCS file: /home/mitchell/Repository/egcs/gcc/cp/method.c,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 method.c
*** method.c	1997/08/26 06:23:56	1.1.1.1
--- method.c	1997/08/28 17:42:08
*************** build_overload_identifier (name)
*** 664,670 ****
  	    }
  	  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);
--- 664,670 ----
  	    }
  	  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.1
diff -c -p -r1.1.1.1 parse.y
*** parse.y	1997/08/26 06:23:56	1.1.1.1
--- parse.y	1997/09/02 05:28:04
*************** 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:
*** 2709,2715 ****
  				  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? ^^^ */
--- 2725,2746 ----
  				  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.1
diff -c -p -r1.1.1.1 pt.c
*** pt.c	1997/08/26 06:23:56	1.1.1.1
--- pt.c	1997/09/02 05:39:53
*************** static tree *maybe_template_tail = &mayb
*** 63,68 ****
--- 63,71 ----
  
  int minimal_parse_mode;
  
+ static tree current_this_ptr;
+ static int processing_template_member;
+ 
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free free
  
*************** 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.  */
--- 79,152 ----
  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 tsubst_stmt PROTO((tree, tree, int, tree));
! static tree add_to_template_args PROTO((tree, int));
! 
! void 
! begin_member_template_processing (parms)
!      tree parms;
! {
!   int i;
! 
!   ++processing_template_decl;
!   ++processing_template_member;
!   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);
! 
!       if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM)
! 	pushdecl (TYPE_NAME (parm));
!       else 
! 	pushdecl (parm);
!     }
! }
! 
! 
! void 
! end_member_template_processing ()
! {
!   if (! processing_template_decl || ! processing_template_member)
!     return;
! 
!   --processing_template_decl;
!   --processing_template_member;
!   current_template_parms = TREE_CHAIN (current_template_parms);
! }
! 
! 
! tree
! add_to_template_args(args, nargs)
!      tree args;
!      int nargs;
! {
!   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) 
!     = make_tree_vec (nargs);
! 
!   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));
--- 286,295 ----
  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;
  }
--- 297,323 ----
        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)
*** 296,301 ****
--- 376,382 ----
    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);
--- 390,438 ----
  	}
        else
  	tmpl = DECL_TI_TEMPLATE (decl);
+       
+       if (DECL_MEMBER_TEMPLATE_P (decl))
+ 	{
+ 	  a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+ 	  t = DECL_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))
  	t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
!       else if (CLASSTYPE_TEMPLATE_INFO (ctx))
  	t = DECL_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 (args), 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)
*** 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.  */
--- 456,461 ----
*************** 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;
  	}
--- 510,519 ----
  	  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;
--- 569,575 ----
  	}
        else
  	{
! 	  tree t = tsubst (TREE_TYPE (parm), vec,
  			   TREE_VEC_LENGTH (vec), in_decl);
  	  if (processing_template_decl)
  	    val = arg;
*************** uses_template_parms (t)
*** 925,930 ****
--- 1034,1040 ----
        return uses_template_parms (TREE_OPERAND (t, 0));
  
        /* template parm nodes */
+     case TEMPLATE_DECL:
      case TEMPLATE_TYPE_PARM:
      case TEMPLATE_CONST_PARM:
        return 1;
*************** 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;
  
--- 1319,1325 ----
  	    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);
--- 1351,1357 ----
        /* 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);
      }
  
--- 1362,1368 ----
  	    }
  	}
        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)
  	  {
--- 1370,1376 ----
    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)
*** 1284,1305 ****
  	grok_ctor_properties (type, t);
        else if (IDENTIFIER_OPNAME_P (DECL_NAME (t)))
  	grok_op_properties (t, DECL_VIRTUAL_P (t), 0);
      }
  
    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))
--- 1394,1494 ----
  	grok_ctor_properties (type, t);
        else if (IDENTIFIER_OPNAME_P (DECL_NAME (t)))
  	grok_op_properties (t, DECL_VIRTUAL_P (t), 0);
+ 
+       if (DECL_MEMBER_TEMPLATE_P (t)) 
+ 	{
+ 	  /* Substitute the body of the function, now that the
+ 	     declaration has been processed. */
+ 	  tree decl = DECL_TEMPLATE_RESULT (t);
+ 	  tree tmp;
+ 	  int nargs = TREE_VEC_LENGTH (args);
+ 	  tree first;
+ 	  tree new_args;
+ 	  tree new_args_this_level;
+ 	  tree saved_this_ptr;
+ 	  int i;
+ 	  int saved_lineno;
+ 	  char* saved_input_filename;
+ 
+ 	  new_args = add_to_template_args 
+ 	    (args, TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (t)));
+ 	  new_args_this_level = 
+ 	    TREE_VEC_ELT (new_args, TREE_VEC_LENGTH (new_args) - 1);
+ 
+ 	  for (i = 0; 
+ 	       i < TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (t));
+ 	       ++i)
+ 	    {
+ 	      tree parm = 
+ 		TREE_VALUE (TREE_VEC_ELT (DECL_TEMPLATE_PARMS (t), i));
+ 
+ 	      switch (TREE_CODE (parm))
+ 		{
+ 		case TYPE_DECL:
+ 		  TREE_VEC_ELT (new_args_this_level, i) = TREE_TYPE (parm);
+ 		  break;
+ 
+ 		case CONST_DECL:
+ 		  TREE_VEC_ELT (new_args_this_level, i) = 
+ 		    DECL_INITIAL (parm);
+ 		  
+ 		default:
+ 		  my_friendly_abort (0);
+ 		}
+ 	    }
+ 	  
+ 	  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ 	    {
+ 	      /* Set up the "this" pointer. */
+ 	      saved_this_ptr = current_this_ptr;
+ 	      current_this_ptr = DECL_ARGUMENTS (decl);
+ 	    }
+ 
+ 	  saved_lineno = lineno;
+ 	  saved_input_filename = input_filename;
+ 	  if (cp_file_of (t))
+ 	    input_filename = cp_file_of (t);
+ 	  processing_template_decl++;
+ 
+ 	  tmp = DECL_SAVED_TREE (decl);
+ 	  first = tsubst_stmt (tmp, new_args, nargs, t); 
+ 	  DECL_SAVED_TREE (decl) = first;
+ 	  if (tmp)
+ 	    {
+ 	      tree last = first;
+ 	      
+ 	      for (tmp = TREE_CHAIN (tmp);
+ 		   tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
+ 		{
+ 		  tree x = tsubst_stmt (tmp, new_args, nargs, NULL_TREE);
+ 		  TREE_CHAIN (last) = x;
+ 		  last = x;
+ 		}
+ 	    }
+ 
+ 	  processing_template_decl--;
+ 	  input_filename = saved_input_filename;
+ 	  lineno = saved_lineno;
+ 
+ 	  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ 	    current_this_ptr = saved_this_ptr;
+ 	}
      }
  
    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;
  {
--- 1571,1577 ----
  
  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:
        {
--- 1660,1829 ----
        }
  
      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, for example.  We need to make a new
! 	   template which is like t, but has the appropriate things
! 	   already substituted.   So, for example if we have:
! 
! 	   template <class T>
! 	   struct S
! 	   {
! 	     template <class U>
! 	     void foo(U, T);       
! 	   };
! 	   
! 	   and T is int, we need to make something like:
! 	     template <class U> void foo(U, int); 
! 
! 	   Note that foo() may well call another member function
! 	   bar(); we must change the body of foo() in this way as
! 	   well. 
! 	   */
! 	tree new_args;
! 	tree new_decl;
! 	tree new_args_this_level;
! 	tree tmpl;
! 	tree decl = DECL_TEMPLATE_RESULT (t);
! 	tree tmp;
! 	int i;
! 
! 	/* Make a new template decl.  It's just like the old one,
! 	   except that it will point to the new, tsubst'd
! 	   declaration. */
! 	tmpl = copy_node (t);
! 	copy_lang_decl (tmpl);
! 	if (DECL_LANG_SPECIFIC (tmpl))
! 	  DECL_CHAIN (tmpl) = NULL_TREE;
! 	TREE_CHAIN (tmpl) = NULL_TREE;
! 	DECL_TEMPLATE_PARMS (tmpl) 
! 	  = copy_node (DECL_TEMPLATE_PARMS (tmpl));
! 
! 	/* Place a copy of the template parameters into args, so that
! 	   uses of the old parameters will be replaced by the new
! 	   parameters, whose level will be one lower. */
! 	new_args = add_to_template_args 
! 	  (args, TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl)));
! 	new_args_this_level = 
! 	  TREE_VEC_ELT (new_args, TREE_VEC_LENGTH (new_args) - 1);
! 	
! 	for (i = 0; 
! 	     i < TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
! 	     ++i) 
! 	  {
! 	    tree parm 
! 	      = copy_node (TREE_VEC_ELT (DECL_TEMPLATE_PARMS (tmpl),
! 					 i));
! 	    TREE_VEC_ELT (DECL_TEMPLATE_PARMS (tmpl), i) = parm;
! 
! 	    parm = TREE_VALUE (parm) = copy_node (TREE_VALUE (parm));
! 
!  	    switch (TREE_CODE (parm))
!  	      {
!  	      case TYPE_DECL:
!  		{
!  		  tree p = copy_node (TREE_TYPE (parm));
! 		  copy_lang_decl(p);
! 		  TREE_TYPE (parm) = p;
! 		  TYPE_MAIN_VARIANT (p) = p;
! 		  TYPE_FIELDS (p) = copy_node (TYPE_FIELDS (p));
!  		  my_friendly_assert (TREE_CODE (p)
!  				      == TEMPLATE_TYPE_PARM, 
!  				      0);
! 		  TREE_VEC_ELT (new_args_this_level, i) = p;
! 		  TEMPLATE_TYPE_LEVEL (p)--;
!  		}
!  		break;
!  
!  	      case CONST_DECL:
!  		{
!  		  tree p = DECL_INITIAL (parm)
! 		    = copy_node (DECL_INITIAL (parm));
!  		  my_friendly_assert (TREE_CODE (p)
!  				      == TEMPLATE_CONST_PARM, 
!  				      0);
! 		  TREE_VEC_ELT (new_args_this_level, i) = p;
!  		  TEMPLATE_CONST_LEVEL (p)--;
! 		}
!  		break;
!  
!  	      default:
!  		/* What is this thing on the template parameter list? */ 
! 		my_friendly_abort (0);
!  	      }
! 	  }
! 
! 	++processing_template_decl;
! 	new_decl = tsubst (decl, new_args, nargs, in_decl);
! 	DECL_TEMPLATE_RESULT (tmpl) = new_decl;
! 	DECL_TEMPLATE_INSTANTIATIONS (t) = 
! 	  perm_tree_cons (NULL_TREE, tmpl, DECL_TEMPLATE_INSTANTIATIONS (t));
! 	DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
! 	DECL_INITIAL (new_decl) = 
! 	  tsubst (DECL_INITIAL (decl), new_args, nargs, in_decl);
! 	--processing_template_decl;
! 	DECL_SAVED_TREE (new_decl) = DECL_SAVED_TREE (decl);
! 
! 	DECL_TEMPLATE_INFO (new_decl) = 
! 	  perm_tree_cons (tmpl, new_args_this_level, NULL_TREE);
! 	TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
! 	DECL_CONTEXT (tmpl) = DECL_CONTEXT (new_decl);
! 	DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (new_decl);
! 	return tmpl;
!       }
  
      case FUNCTION_DECL:
        {
*************** do_poplevel ()
*** 2013,2019 ****
  
  tree
  tsubst_copy (t, args, nargs, in_decl)
!      tree t, *args;
       int nargs;
       tree in_decl;
  {
--- 2357,2363 ----
  
  tree
  tsubst_copy (t, args, nargs, in_decl)
!      tree t, args;
       int nargs;
       tree in_decl;
  {
*************** tsubst_copy (t, args, nargs, in_decl)
*** 2027,2033 ****
    switch (code)
      {
      case PARM_DECL:
!       return do_identifier (DECL_NAME (t), 0);
  
      case CONST_DECL:
      case FIELD_DECL:
--- 2371,2385 ----
    switch (code)
      {
      case PARM_DECL:
!       if (DECL_NAME (t) && THIS_NAME_P (DECL_NAME (t)) 
! 	  && current_this_ptr)
! 	/* Most parameters are represented as LOOKUP_EXPRs.
! 	   However, the parser uses a PARM_DECL for the `this'
! 	   pointer.  We substitute the new `this' pointer for the
! 	   instantiated class. */
! 	return current_this_ptr;
!       else
! 	return do_identifier (DECL_NAME (t), 0);
  
      case CONST_DECL:
      case FIELD_DECL:
*************** tsubst_copy (t, args, nargs, in_decl)
*** 2048,2053 ****
--- 2400,2418 ----
        mark_used (t);
        return t;
  
+     case TEMPLATE_DECL:
+       if (DECL_MEMBER_TEMPLATE_P (t))
+ 	{
+ 	  /* We might already have an instance of this template. */
+ 	  tree decls = DECL_TEMPLATE_INSTANTIATIONS (t);
+ 	  tree ctx = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, t);
+ 	  
+ 	  for (; decls; decls = TREE_CHAIN (decls))
+ 	    if (DECL_CLASS_CONTEXT (TREE_VALUE (decls)) == ctx)
+ 	      return TREE_VALUE (decls);
+ 	}
+       return t;
+ 
  #if 0
      case IDENTIFIER_NODE:
        return do_identifier (t, 0);
*************** tsubst_copy (t, args, nargs, in_decl)
*** 2239,2247 ****
      }
  }
  
  tree
  tsubst_expr (t, args, nargs, in_decl)
!      tree t, *args;
       int nargs;
       tree in_decl;
  {
--- 2604,2716 ----
      }
  }
  
+ 
+ /*
+   Return a minimally parsed statement like t, but with args substituted
+   appropriately. 
+   */
+ 
+ tree
+ tsubst_stmt (t, args, nargs, in_decl)
+      tree t;
+      tree args;
+      int nargs;
+      tree in_decl;
+ {
+   enum tree_code code;
+ 
+   if (t == NULL_TREE || t == error_mark_node)
+     return t;
+ 
+   code = TREE_CODE (t);
+ 
+   switch (code)
+     {
+     case LOOKUP_EXPR:
+     case MODOP_EXPR:
+     case CAST_EXPR:
+     case REINTERPRET_CAST_EXPR:
+     case CONST_CAST_EXPR:
+     case STATIC_CAST_EXPR:
+     case DYNAMIC_CAST_EXPR:
+     case SIZEOF_EXPR:
+     case ARROW_EXPR:
+     case DOTSTAR_EXPR:
+     case TYPEID_EXPR:
+     case EXPR_STMT:
+     case DECL_STMT:
+     case IF_STMT:
+     case FOR_STMT:
+     case WHILE_STMT:
+     case DO_STMT:
+     case RETURN_STMT:
+     case BREAK_STMT:
+     case CONTINUE_STMT:
+     case SWITCH_STMT:
+     case GOTO_STMT:
+     case CTOR_INITIALIZER:
+     case CASE_LABEL:
+     case RETURN_INIT:
+     case TRY_BLOCK:
+     case HANDLER:
+     case IDENTITY_CONV:
+     case LVALUE_CONV:
+     case QUAL_CONV:
+     case STD_CONV:
+     case PTR_CONV:
+     case PMEM_CONV:
+     case BASE_CONV:
+     case REF_BIND:
+     case USER_CONV:
+     case AMBIG_CONV:
+     case RVALUE_CONV:
+     case TAG_DEFN:
+       {
+ 	tree r = copy_node (t);
+ 	int length = tree_code_length[(int) code];
+ 	int i;
+ 
+ 	lineno = TREE_COMPLEXITY (r);
+ 	for (i = 0; i < length; i++)
+ 	  TREE_OPERAND (r, i) = 
+ 	    tsubst_stmt (TREE_OPERAND (r, i), args, nargs, in_decl);
+ 
+ 	TREE_TYPE (r) = 
+ 	  tsubst (TREE_TYPE (r), args, nargs, in_decl);
+ 	return r;
+       }
+ 
+     case COMPOUND_STMT:
+       {
+ 	tree r = copy_node (t);
+ 	int i;
+ 	tree* last = &TREE_OPERAND (r, 0);
+ 	tree substmt;
+ 
+ 	lineno = TREE_COMPLEXITY (r);
+ 	for (substmt = TREE_OPERAND (t, 0);
+ 	     substmt != NULL_TREE; 
+ 	     substmt = TREE_CHAIN (substmt))
+ 	  {
+ 	    *last = tsubst_stmt (substmt, args, nargs, in_decl);
+ 	    last = &TREE_CHAIN (*last);
+ 	  }
+ 
+ 	TREE_TYPE (r) = 
+ 	  tsubst (TREE_TYPE (r), args, nargs, in_decl);
+ 	return r;
+       }
+ 
+     default:
+       return tsubst_copy (t, args, nargs, in_decl);
+     }
+ }
+ 
+ 
+ 
  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;
--- 3012,3018 ----
  
  tree
  instantiate_template (tmpl, targ_ptr)
!      tree tmpl, targ_ptr;
  {
    tree fndecl;
    int i, len;
*************** instantiate_template (tmpl, targ_ptr)
*** 2560,2566 ****
    i = len;
    while (i--)
      {
!       tree t = targ_ptr [i];
        if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
  	{
  	  tree nt = target_type (t);
--- 3029,3035 ----
    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,2578 ****
  	      goto out;
  	    }
  	}
!       targ_ptr[i] = copy_to_permanent (t);
      }
  
    /* substitute template parameters */
--- 3041,3047 ----
  	      goto out;
  	    }
  	}
!       TREE_VEC_ELT (targ_ptr, i) = copy_to_permanent (t);
      }
  
    /* substitute template parameters */
*************** overload_template_name (type)
*** 2606,2611 ****
--- 3075,3145 ----
    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;
+   tree last_fn_arg, saved_fn_arg; 
+   tree last_decl_arg, saved_decl_arg; 
+ 
+   if (IDENTIFIER_TYPENAME_P (DECL_NAME (fn))) 
+     {
+       /* This is a template conversion operator.  Use the return types
+          as well as the argument types. */
+       tree t;
+ 
+       for (t = fn_arg_types; 
+ 	   TREE_CHAIN (t) && 
+ 	   TREE_VALUE (TREE_CHAIN (t)) != void_type_node;
+ 	   t = TREE_CHAIN (t)) 
+ 	;
+ 
+       last_fn_arg = t;
+ 
+       for (t = decl_arg_types; 
+ 	   TREE_CHAIN (t) && 
+ 	   TREE_VALUE (TREE_CHAIN (t)) != void_type_node;
+ 	   t = TREE_CHAIN (t)) 
+ 	;
+ 
+       last_decl_arg = t;
+       
+       saved_fn_arg = TREE_CHAIN (last_fn_arg);
+       TREE_CHAIN (last_fn_arg) = 
+ 	tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
+       saved_decl_arg = TREE_CHAIN (last_decl_arg);
+       TREE_CHAIN (last_decl_arg) = 
+ 	tree_cons (NULL_TREE, return_type, NULL_TREE); 
+       TREE_CHAIN (TREE_CHAIN (last_fn_arg)) = saved_fn_arg;
+       TREE_CHAIN (TREE_CHAIN (last_decl_arg)) = saved_decl_arg;
+     }
+ 
+   i = type_unification (DECL_TEMPLATE_PARMS (fn), 
+ 			& TREE_VEC_ELT (targs, 0), 
+ 			fn_arg_types,
+ 			decl_arg_types,
+ 			&dummy, 0, strict);
+ 
+   if (IDENTIFIER_TYPENAME_P (DECL_NAME (fn))) 
+     {
+       TREE_CHAIN (last_fn_arg) = saved_fn_arg;
+       TREE_CHAIN (last_decl_arg) = saved_decl_arg;
+     }
+ 
+   return i;
+ }
+ 
+ 
  /* Type unification.
  
     We have a function template signature with one or more references to
*************** int
*** 2991,3010 ****
  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;
      }
  
--- 3525,3542 ----
  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)
*** 3040,3059 ****
  /* 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;
  }
  
--- 3572,3592 ----
  /* 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 = 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
*** 3091,3097 ****
  most_specialized (fns, decl)
       tree fns, decl;
  {
!   tree fn, champ, *args, *p;
    int fate;
  
    for (p = &fns; *p; )
--- 3624,3630 ----
  most_specialized (fns, decl)
       tree fns, decl;
  {
!   tree fn, champ, args, *p;
    int fate;
  
    for (p = &fns; *p; )
*************** most_specialized (fns, decl)
*** 3099,3105 ****
        args = get_bindings (TREE_VALUE (*p), decl);
        if (args)
  	{
- 	  free (args);
  	  p = &TREE_CHAIN (*p);
  	}
        else
--- 3632,3637 ----
*************** do_decl_instantiation (declspecs, declar
*** 3203,3208 ****
--- 3735,3741 ----
    tree fn;
    tree result = NULL_TREE;
    int extern_p = 0;
+   tree templates = NULL_TREE;
  
    if (! DECL_LANG_SPECIFIC (decl))
      {
*************** do_decl_instantiation (declspecs, declar
*** 3230,3239 ****
  	       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))
--- 3763,3801 ----
  	       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
*** 3243,3272 ****
  	  }
  	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);
--- 3805,3834 ----
  	  }
  	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)
*** 3438,3444 ****
      {
        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);
      }
--- 4000,4006 ----
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (d) = tsubst_expr
! 	(DECL_INITIAL (pattern), args,
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
*************** instantiate_decl (d)
*** 3488,3494 ****
    /* 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.  */
--- 4050,4056 ----
    /* 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)
*** 3496,3502 ****
      {
        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);
      }
--- 4058,4064 ----
      {
        pushclass (DECL_CONTEXT (d), 2);
        DECL_INITIAL (td) = tsubst_expr
! 	(DECL_INITIAL (pattern), args,
  	 TREE_VEC_LENGTH (args), tmpl);
        popclass (1);
      }
*************** instantiate_decl (d)
*** 3531,3537 ****
  	{
  	  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);
  	}
--- 4093,4099 ----
  	{
  	  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)
*** 3552,3558 ****
        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);
--- 4114,4120 ----
        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)
*** 3574,3586 ****
  {
    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;
--- 4136,4148 ----
  {
    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)
*** 3600,3608 ****
  
    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);
--- 4162,4170 ----
  
    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)
*** 3652,3658 ****
  
  static tree
  tsubst_enum (tag, args, nargs)
!      tree tag, *args;
       int nargs;
  {
    tree newtag = start_enum (TYPE_IDENTIFIER (tag));
--- 4214,4220 ----
  
  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
diff -c -p -r1.1.1.1 search.c
*** search.c	1997/08/26 06:23:56	1.1.1.1
--- search.c	1997/08/29 21:01:44
*************** 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
diff -c -p -r1.1.1.1 tree.c
*** tree.c	1997/08/26 06:23:57	1.1.1.1
--- tree.c	1997/08/29 21:33:05
*************** 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.2
diff -c -p -r1.1.1.2 typeck.c
*** typeck.c	1997/08/29 02:03:55	1.1.1.2
--- typeck.c	1997/09/01 07:45:38
*************** 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);
  




More information about the Gcc mailing list