diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5c9026827ce204194c5ed8dfa0d1043a8039b222..beb54a2da118ba41df4b2a0905549e53fbec8f73 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,105 @@
+Mon Feb 23 03:04:14 1998  Jason Merrill  <jason@yorick.cygnus.com>
+
+	* typeck.c (build_x_function_call): Handle static member function
+	templates like non-templates.  Handle friend templates like normal
+	function templates.
+	* pt.c (tsubst, *_PARM): Don't use orig_level.
+	(get_bindings): Don't call add_to_template_args.
+	(instantiate_template): Likewise.
+	(tsubst, FUNCTION_DECL): Call add_to_template_args as appropriate.
+	* ptree.c (print_lang_type): Print index/level for template parms.
+
+Mon Feb 23 02:52:29 1998  Mark Mitchell  <mmitchell@usa.net>
+
+	* Make-lang.in (cc1plus): Note that cc1plus depends on
+	cp/cp-tree.h and cp/cp-tree.def.
+	
+	* cp-tree.def (TEMPLATE_CONST_PARM): Remove.
+	(TEMPLATE_PARM_INDEX): New tree code, used to indicate a
+	position in a template parameter list.
+	* cp-tree.h (template_parm_index): New structure, used as the tree
+	structure for a TEMPLATE_PARM_INDEX.
+	(TEMPLATE_PARM_IDX): New macro.
+	(TEMPLATE_PARM_LEVEL): Likewise.
+	(TEMPLATE_PARM_DESCENDANTS): Likewise.
+	(TEMPLATE_PARM_ORIG_LEVEL): Likewise.
+	(TEMPLATE_PARM_DECL): Likewise.
+	(TEMPLATE_TYPE_PARM_INDEX): Likewise.
+	(TEMPLATE_TYPE_ORIG_LEVEL): Likewise.
+	(TEMPLATE_TYPE_DECL): Likewise.
+	(TEMPLATE_CONST_IDX): Remove.
+	(TEMPLATE_CONST_LEVEL): Likewise.
+	(TEMPLATE_CONST_SET_INFO): Likewise.
+	(TEMPLATE_TYPE_SET_INFO): Likewise.
+	(TEMPLATE_TYPE_IDX): Redefine in terms of TEMPLATE_PARM_INDEX
+	node.
+	(TEMPLATE_TYPE_LEVEL): Likewise.
+	* decl.c (decls_match): Call comp_template_parms, rather than
+	expanding it inline.
+	(duplicate_decls): If two template declarations are being merged,
+	then their TEMPLATE_INFOs should be merged as well.
+	(grokfndecl): Save template-id information when declaring a friend
+	with explicit template arguments.  Pass arguments to
+	check_explicit_specialization via correct convention; at some
+	point check_explicit_specialization changed, but these call-sites
+	did not.
+	(grokdeclarator): Tidy up slightly.
+	* decl2.c (check_classfn): Tidy up slightly.  Don't assume that
+	two template functions with the same DECL_ASSEMBLER_NAME the same,
+	since the names are not yet mangled.
+	* error.c (dump_decl): Use TEMPLATE_PARM_INDEX instead of
+	TEMPLATE_CONST_PARM. 
+	(dump_expr): Likewise.  Use the TEMPLATE_PARM_DECL to get at the
+	decl for a non-type parameter, rather than printing `<tparm ...>'.
+	* friend.c (is_friend): Handle TEMPLATE_DECL friends.
+	(do_friend): Deal with template friends.
+	* lex.c (do_pending_inlines): Call
+	maybe_begin_member_template_processing, rather than
+	conditionally calling begin_member_template_processing.
+	(process_next_inline): Likewise.  Call
+	maybe_end_member_template_processing, rather than
+	conditionally calling end_member_template_processing.
+	(do_pending_defargs): Likewise.
+	(do_identifier): Use TEMPLATE_PARM_INDEX instead of
+	TEMPLATE_CONST_PARM.  
+	* method.c (build_mangled_template_parm_index): New function.
+	(build_overload_value): Use it.
+	(build_overload_name): Likewise.
+	* pt.c (finish_member_template_decl): Allow friend declarations.
+	(template_class_depth): New function.
+	(is_member_template): Rename, and modify, to become...
+	(is_member_or_friend_template): New function.
+	(end_member_template_processing): Rename, and modify, to become...
+	(maybe_end_member_template_processing).
+	(build_template_parm_index): New function.
+	(reduce_template_parm_level): New function.
+	(process_template_parm): Modify to use build_template_parm_index.
+	(current_template_args): Change name to current_template_parms.
+	(push_template_decl): Deal with friend templates.
+	(uses_template_parms): Use TEMPLATE_PARM_INDEX instead of
+	TEMPLATE_CONST_PARM.
+	(tsubst_friend_function): New function.
+	(instantiate_class_template): Generate the DECL_FRIENDLIST
+	for a new instantiation by using tsubst_friend_function rather
+	than just tsubst.
+	(tsubst): Don't tsubst into a type which is a TEMPLATE_DECL.
+	Use TEMPLATE_PARM_INDEX instead of TEMPLATE_CONST_PARM, and the
+	appropriate new macros.  Use reduce_template_parm_level to
+	generate lower-level template parameters.  Handle tsubst'ing into
+	TEMPLATE_DECLS that declare TEMPLATE_TEMPLATE_PARMS.  Don't forget
+	to tsubst the DECL_CONTEXT and DECL_CLASS_CONTEXT of newly created
+	templates.  Similarly for the template parameters for a new
+	template.
+	(tsubst_copy): Tidy up slightly.  Use TEMPLATE_PARM_INDEX instead
+	of TEMPLATE_CONST_PARM.  Handle TYPE_DECLs by tsubsting into them.
+	(unify): Use TEMPLATE_PARM_INDEX instead of TEMPLATE_CONST_PARM.  
+	(get_bindings): Call add_to_template_args if necessary.
+	(instantiate_decl): Handle instantiations of friend templates.
+	* search.c (lookup_field_1): Don't treat the TYPE_FIELDS of a
+	TEMPLATE_TYPE_PARM as a list of fields; it's not!
+	* spew.c (yylex): Do a little manual constant propogation to
+	clarify the code.
+	
 Sun Feb 22 19:53:29 1998  Jeffrey A Law  (law@cygnus.com)
 
 	* error.c: Include sys/types.h.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index a9e4e1ca87e4f73487bd1017ee730696b1cd71b6..6ed167830c8478cb6aeb2fe916ff40475fb93da9 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -124,7 +124,8 @@ CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)/cp/decl2.c \
  $(srcdir)/cp/parse.y $(srcdir)/cp/sig.c $(srcdir)/cp/typeck2.c \
  $(srcdir)/cp/repo.c
 
-cc1plus: $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o
+cc1plus: $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o \
+	$(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def
 	cd cp; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) ../cc1plus
 #
 # Build hooks:
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index ab126fa707206797b8acaf475404d0f8bccea309..74d64412cb8a6e0164cc9c57da0561d4a72cd42c 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -87,23 +87,60 @@ DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", 'e', 3)
  */
 DEFTREECODE (TEMPLATE_DECL, "template_decl", 'd', 0)
 
+/* Index into a template parameter list.  The TEMPLATE_PARM_IDX gives
+   the index (from 0) of the parameter, while the TEMPLATE_PARM_LEVEL
+   gives the level (from 1) of the parameter.
+
+   Here's an example:
+   
+   template <class T> // Index 0, Level 1.
+   struct S
+   {
+      template <class U, // Index 0, Level 2.
+                class V> // Index 1, Level 2.
+      void f();
+   };  
+
+   The DESCENDANTS will be a chain of TEMPLATE_PARM_INDEXs descended
+   from this one.  The first descendant will have the same IDX, but
+   its LEVEL will be one less.  The TREE_CHAIN field is used to chain
+   together the descendants.  The TEMPLATE_PARM_DECL is the
+   declaration of this parameter, either a TYPE_DECL or CONST_DECL.
+   The TEMPLATE_PARM_ORIG_LEVEL is the LEVEL of the most distant
+   parent, i.e., the LEVEL that the parameter originally had when it
+   was declared.  For example, if we instantiate S<int>, we will have:
+
+   struct S<int>
+   {
+     template <class U, // Index 0, Level 1, Orig Level 2
+               class V> // Index 1, Level 1, Orig Level 2
+     void f();
+   };
+  
+   The LEVEL is the level of the parameter when we are worrying about
+   the types of things; the ORIG_LEVEL is the level when we are
+   worrying about instantiating things.  */
+DEFTREECODE (TEMPLATE_PARM_INDEX, "template_parm_index", 'c', 
+	     /* The addition of (sizeof(char*) - 1) in the next
+		expression is to ensure against the case where
+		sizeof(char*) does not evenly divide
+		sizeof(HOST_WIDE_INT).  */
+	     2 + ((3 * sizeof (HOST_WIDE_INT) + sizeof(char*) - 1)
+		  / sizeof (char*)))
+
 /* Index into a template parameter list.  This parameter must be a type.
-   Use TYPE_FIELDS to find parmlist and index.  */
+   The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX.  */
 DEFTREECODE (TEMPLATE_TYPE_PARM, "template_type_parm", 't', 0)
 
 /* Index into a template parameter list.  This parameter must be a type.
    If it is used in signature of a template, TEMPLATE_INFO is NULL_TREE.
    Otherwise it is used to declare a type like TT<int>.
-   Use TYPE_FIELDS to find parmlist and index.  */
+   The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX.  */
 DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", 't', 0)
 
 /* A type designated by 'typename T::t'. */
 DEFTREECODE (TYPENAME_TYPE, "typename_type", 't', 0)
 
-/* 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.
 
    Thunks are used to implement multiple inheritance:
@@ -179,3 +216,9 @@ DEFTREECODE (AMBIG_CONV, "ambig_conv", 'e', 1)
 DEFTREECODE (RVALUE_CONV, "rvalue_conv", 'e', 1)
 
 DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
+
+/*
+Local variables:
+mode:c
+End:
+*/
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a254db88a06feb3a610fd8be404e6feb7c05c8e1..de6384944d199a96fd732d749579d28938f87329 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -47,6 +47,17 @@ typedef struct
   int new_type_flag;
 } flagged_type_tree;
 
+typedef struct 
+{
+  char common[sizeof (struct tree_common)];
+  struct rtx_def *rtl;	/* Unused, but required to match up with what
+			   the middle-end expects.  */
+  HOST_WIDE_INT index;
+  HOST_WIDE_INT level;
+  HOST_WIDE_INT orig_level;
+  tree decl;
+} template_parm_index;
+
 /* To identify to the debug emitters if it should pay attention to the
    flag `-Wtemplate-debugging'.  */
 #define HAVE_TEMPLATES 1
@@ -1340,6 +1351,18 @@ extern int flag_new_for_scope;
 #define TYPE_WAS_ANONYMOUS(NODE) (TYPE_LANG_SPECIFIC (NODE)->type_flags.was_anonymous)
 
 /* C++: all of these are overloaded!  These apply only to TYPE_DECLs.  */
+
+/* The format of each node in the DECL_FRIENDLIST is as follows:
+
+   The TREE_PURPOSE will be the name of a function, i.e., an
+   IDENTIFIER_NODE.  The TREE_VALUE will be itself a TREE_LIST, the
+   list of functions with that name which are friends.  The
+   TREE_PURPOSE of each node in this sublist will be error_mark_node,
+   if the function was declared a friend individually, in which case
+   the TREE_VALUE will be the function_decl.  If, however, all
+   functions with a given name in a class were declared to be friends,
+   the TREE_PUROSE will be the class type, and the TREE_VALUE will be
+   NULL_TREE.  */
 #define DECL_FRIENDLIST(NODE)		(DECL_INITIAL (NODE))
 
 /* The DECL_ACCESS is used to record under which context
@@ -1352,6 +1375,17 @@ extern int flag_new_for_scope;
 #define SET_DECL_REFERENCE_SLOT(NODE,VAL) ((NODE)->decl.arguments=VAL)
 
 /* Accessor macros for C++ template decl nodes.  */
+
+/* The DECL_TEMPLATE_PARMS are a list.  The TREE_PURPOSE of each node
+   indicates the level of the template parameters, with 1 being the
+   outermost set of template parameters.  The TREE_VALUE is a vector,
+   whose elements are the template parameters at each level.  Each
+   element in the vector is a TREE_LIST, whose TREE_VALUE is a
+   PARM_DECL (if the parameter is a non-type parameter), or a
+   TYPE_DECL (if the parameter is a type parameter).  The TREE_PURPOSE
+   is the default value, if any.  The TEMPLATE_PARM_INDEX for the
+   parameter is avilable as the DECL_INITIAL (for a PARM_DECL) or as
+   the TREE_TYPE (for a TYPE_DECL).  */
 #define DECL_TEMPLATE_PARMS(NODE)       DECL_ARGUMENTS(NODE)
 #define DECL_INNERMOST_TEMPLATE_PARMS(NODE) \
    INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (NODE))
@@ -1374,6 +1408,12 @@ extern int flag_new_for_scope;
   (TREE_CODE (NODE) == TEMPLATE_DECL \
    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
 
+/* A `primary' template is one which depends on no tbemplate parameters
+   except those specified in its parameter list.  So, a template
+   member of a non-template class is primary, and every global
+   function template is primary, but a member function of a template
+   class is not primary, neither is a member template of a template
+   class.  */
 #define PRIMARY_TEMPLATE_P(NODE) \
   (TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)) == (NODE))
 
@@ -1934,24 +1974,27 @@ extern tree current_class_type;	/* _TYPE: the type of the current class */
 
 #define WANT_ARITH	(WANT_INT | WANT_FLOAT)
 
-/* Anatomy of a DECL_FRIENDLIST (which is a TREE_LIST):
-   purpose = friend name (IDENTIFIER_NODE);
-   value = TREE_LIST of FUNCTION_DECLS;
-   chain, type = EMPTY;  */
 #define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
 #define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
 
+/* These macros are used to access a TEMPLATE_PARM_INDEX.  */
+#define TEMPLATE_PARM_IDX(NODE) (((template_parm_index*) NODE)->index)
+#define TEMPLATE_PARM_LEVEL(NODE) (((template_parm_index*) NODE)->level)
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
+#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (((template_parm_index*) NODE)->orig_level)
+#define TEMPLATE_PARM_DECL(NODE) (((template_parm_index*) NODE)->decl)
+
 /* These macros are for accessing the fields of TEMPLATE_TYPE_PARM 
    and TEMPLATE_TEMPLATE_PARM nodes.  */
-#define TEMPLATE_TYPE_IDX(NODE) TREE_INT_CST_LOW (TYPE_FIELDS (NODE))
-#define TEMPLATE_TYPE_LEVEL(NODE) TREE_INT_CST_HIGH (TYPE_FIELDS (NODE))
-#define TEMPLATE_TYPE_SET_INFO(NODE,I,L) \
-  (TYPE_FIELDS (NODE) = build_int_2 (I, L))
-/* These macros are for accessing the fields of TEMPLATE_CONST_PARM nodes.  */
-#define TEMPLATE_CONST_IDX(NODE) (TREE_INT_CST_LOW(NODE))
-#define TEMPLATE_CONST_LEVEL(NODE) (TREE_INT_CST_HIGH(NODE))
-#define TEMPLATE_CONST_SET_INFO(NODE,I,L) \
-  (TEMPLATE_CONST_IDX (NODE) = I, TEMPLATE_CONST_LEVEL (NODE) = L)
+#define TEMPLATE_TYPE_PARM_INDEX(NODE) (TYPE_FIELDS (NODE))
+#define TEMPLATE_TYPE_IDX(NODE) \
+  (TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_LEVEL(NODE) \
+  (TEMPLATE_PARM_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_ORIG_LEVEL(NODE) \
+  (TEMPLATE_PARM_ORIG_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_DECL(NODE) \
+  (TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 
 /* in lex.c  */
 /* Indexed by TREE_CODE, these tables give C-looking names to
@@ -2336,8 +2379,8 @@ 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 maybe_begin_member_template_processing PROTO((tree));
+extern void maybe_end_member_template_processing PROTO((tree));
 extern tree finish_member_template_decl         PROTO((tree, tree));
 extern void begin_template_parm_list		PROTO((void));
 extern void begin_specialization                PROTO((void));
@@ -2382,6 +2425,7 @@ extern int more_specialized_class		PROTO((tree, tree));
 extern void do_pushlevel			PROTO((void));
 extern int is_member_template                   PROTO((tree));
 extern int comp_template_parms                  PROTO((tree, tree));
+extern int template_class_depth                 PROTO((tree));
 extern int processing_specialization;
 extern int processing_explicit_instantiation;
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ce35770dbc9f966479bcfa0ef0ec658f6918e420..d05c493632897dd44547511972373a1732cd7d32 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2311,47 +2311,15 @@ decls_match (newdecl, olddecl)
   else if (TREE_CODE (newdecl) == TEMPLATE_DECL
 	   && TREE_CODE (olddecl) == TEMPLATE_DECL)
     {
-	tree newargs = DECL_TEMPLATE_PARMS (newdecl);
-	tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
-	int i;
-
-	/* Run through all the levels of template parameters, 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
-	  types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
-				     DECL_TEMPLATE_RESULT (newdecl));
+      if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
+				DECL_TEMPLATE_PARMS (olddecl)))
+	return 0;
+      
+      if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
+	types_match = 1;
+      else
+	types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
+				   DECL_TEMPLATE_RESULT (newdecl));
     }
   else
     {
@@ -2760,6 +2728,7 @@ duplicate_decls (newdecl, olddecl)
 	    cp_error ("invalid redeclaration of %D", newdecl);
 	  TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
 	  DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
+	  DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
 	}
       return 1;
     }
@@ -4504,7 +4473,10 @@ make_implicit_typename (context, t)
 
    If PREFER_TYPE is > 0, we prefer TYPE_DECLs.
    If PREFER_TYPE is -2, we're being called from yylex(). (UGLY)
-   Otherwise we prefer non-TYPE_DECLs.  */
+   Otherwise we prefer non-TYPE_DECLs.  
+
+   If NONCLASS is non-zero, we don't look for the NAME in class scope,
+   using IDENTIFIER_CLASS_VALUE.  */
 
 static tree
 lookup_name_real (name, prefer_type, nonclass)
@@ -7461,8 +7433,15 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
   if (friendp && 
       TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
-    /* A friend declaration of the form friend void f<>().  */
-    SET_DECL_IMPLICIT_INSTANTIATION (decl);
+    {
+      /* A friend declaration of the form friend void f<>().  Record
+	 the information in the TEMPLATE_ID_EXPR.  */
+      SET_DECL_IMPLICIT_INSTANTIATION (decl);
+      DECL_TEMPLATE_INFO (decl) 
+	= perm_tree_cons (TREE_OPERAND (orig_declarator, 0),
+			  TREE_OPERAND (orig_declarator, 1),
+			  NULL_TREE);
+    }
 
   /* Caller will do the rest of this.  */
   if (check < 0)
@@ -7485,8 +7464,8 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
       decl = check_explicit_specialization (orig_declarator, decl,
 					    template_count, 
-					    funcdef_flag ? 2 : 
-					    (friendp ? 3 : 0));
+					    2 * (funcdef_flag != 0) + 
+					    4 * (friendp != 0));
 
       if (check)
 	{
@@ -7532,8 +7511,8 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
       decl = check_explicit_specialization (orig_declarator, decl,
 					    template_count, 
-					    funcdef_flag ? 2 : 
-					    (friendp ? 3 : 0));
+					    2 * (funcdef_flag != 0) + 
+					    4 * (friendp != 0));
 
       if (ctype != NULL_TREE && check)
 	{
@@ -7952,10 +7931,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
 		if (TREE_CODE (fns) == IDENTIFIER_NODE)
 		  dname = fns;
-		else if (really_overloaded_fn (fns))
+		else if (is_overloaded_fn (fns))
 		  dname = DECL_NAME (get_first_fn (fns));
 		else
-		  dname = DECL_NAME (fns);
+		  my_friendly_abort (0);
 	      }
 	  /* fall through */
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index c598c1adbf6f0f9f9bc95ed6e77027c158dff17a..c847a2782b564989b3d9ec041c5d8f2f689f757b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1431,19 +1431,22 @@ check_classfn (ctype, function)
 	  if (fn_name == DECL_NAME (*methods))
 	    {
 	    got_it:
-	      fndecl = *methods;
-	      while (fndecl)
+	      for (fndecl = *methods; fndecl != NULL_TREE;
+		   fndecl = DECL_CHAIN (fndecl))
 		{
-		  if (DECL_ASSEMBLER_NAME (function) == DECL_ASSEMBLER_NAME (fndecl))
+		  /* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL is
+		     not mangled, so the check below does not work
+		     correctly in that case.  */
+		  if (TREE_CODE (function) != TEMPLATE_DECL
+		      && TREE_CODE (fndecl) != TEMPLATE_DECL
+		      && (DECL_ASSEMBLER_NAME (function) 
+			  == DECL_ASSEMBLER_NAME (fndecl)))
 		    return fndecl;
-#if 0
-		  /* This doesn't work for static member functions that are
-                     pretending to be methods.  */
-		  /* We have to do more extensive argument checking here, as
-		     the name may have been changed by asm("new_name").  */
-		  if (decls_match (function, fndecl))
-		    return fndecl;
-#else
+
+		  /* We cannot simply call decls_match because this
+		     doesn't work for static member functions that are 
+                     pretending to be methods, and because the name
+		     may have been changed by asm("new_name").  */ 
 		  if (DECL_NAME (function) == DECL_NAME (fndecl))
 		    {
 		      tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function));
@@ -1471,8 +1474,6 @@ check_classfn (ctype, function)
 			templates = 
 			  scratch_tree_cons (NULL_TREE, fndecl, templates);
 		    }
-#endif
-		  fndecl = DECL_CHAIN (fndecl);
 		}
 	      break;		/* loser */
 	    }
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index e236153013ad2b218efeb99b7c43c2add1b78320..04517814a6928aca358572451aac099488f9d9f7 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -856,7 +856,7 @@ dump_decl (t, v)
     case CONST_DECL:
       if ((TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == ENUMERAL_TYPE)
 	  || (DECL_INITIAL (t) &&
-	      TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_CONST_PARM))
+	      TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_PARM_INDEX))
 	goto general;
       else if (DECL_NAME (t))
 	dump_decl (DECL_NAME (t), v);
@@ -1527,33 +1527,12 @@ dump_expr (t, nop)
 	break;
       }
 
-    case TEMPLATE_CONST_PARM:
+    case TEMPLATE_PARM_INDEX:
       {
 	int l = current_template_parms ? 
 	  list_length (current_template_parms) : 0;
 
-	if (l >= TEMPLATE_CONST_LEVEL (t))
-	  {
-	    int i;
-	    tree parms = current_template_parms;
-	    tree r;
-	    
-	    for (i = 0; i < l - TEMPLATE_CONST_LEVEL (t); ++i)
-	      {
-		parms = TREE_CHAIN (parms);
-		my_friendly_assert (parms != NULL_TREE, 0);
-	      }
-	    
-	    r = TREE_VEC_ELT (TREE_VALUE (parms),
-			      TEMPLATE_CONST_IDX (t));
-	    dump_decl (TREE_VALUE (r), -1);
-	  }
-	else
-	  {
-	    OB_PUTS ("<tparm ");
-	    OB_PUTI (TEMPLATE_CONST_IDX (t));
-	    OB_PUTS (">");
-	  }
+	dump_decl (TEMPLATE_PARM_DECL (t), -1);
       }
       break;
 
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 028706ad21b49fa6055657bca665d5037c224586..f28e049cfa4b46f1b44579cdf1a9310085822ad6 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -33,22 +33,7 @@ Boston, MA 02111-1307, USA.  */
 static void add_friend PROTO((tree, tree));
 static void add_friends PROTO((tree, tree, tree));
 
-/* Friend data structures:
-
-   Lists of friend functions come from TYPE_DECL nodes.  Since all
-   aggregate types are automatically typedef'd, these nodes are guaranteed
-   to exist.
-
-   The TREE_PURPOSE of a friend list is the name of the friend,
-   and its TREE_VALUE is another list.
-
-   For each element of that list, either the TREE_VALUE or the TREE_PURPOSE
-   will be filled in, but not both.  The TREE_VALUE of that list is an
-   individual function which is a friend.  The TREE_PURPOSE of that list
-   indicates a type in which all functions by that name are friends.
-
-   Lists of friend classes come from _TYPE nodes.  Love that consistency
-   thang.  */
+/* Friend data structures are described in cp-tree.h.  */
 
 int
 is_friend (type, supplicant)
@@ -83,6 +68,31 @@ is_friend (type, supplicant)
 		{
 		  if (ctype == TREE_PURPOSE (friends))
 		    return 1;
+
+		  if (TREE_VALUE (friends) == NULL_TREE)
+		    continue;
+
+		  if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
+		    {
+		      tree t;
+
+		      /* Perhaps this function is a specialization of
+			 a friend template.  */
+		      for (t = supplicant;
+			   t != NULL_TREE;
+			   t = DECL_TEMPLATE_INFO (t) ? 
+			     DECL_TI_TEMPLATE (t) : NULL_TREE)
+			/* FIXME: The use of comptypes here, and below, is
+			   bogus, since two specializations of a
+			   template parameter with non-type parameters
+			   may have the same type, but be different.  */
+			if (comptypes (TREE_TYPE (t),
+				       TREE_TYPE (TREE_VALUE (friends)), 1))
+			  return 1;
+
+		      continue;
+		    }
+
 		  if (comptypes (TREE_TYPE (supplicant),
 				 TREE_TYPE (TREE_VALUE (friends)), 1))
 		    return 1;
@@ -302,9 +312,15 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
      tree quals;
      int funcdef_flag;
 {
+  int is_friend_template = 0;
+
   /* Every decl that gets here is a friend of something.  */
   DECL_FRIEND_P (decl) = 1;
 
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    is_friend_template = processing_template_decl >
+      template_class_depth (current_class_type);
+
   if (ctype)
     {
       tree cname = TYPE_NAME (ctype);
@@ -319,18 +335,21 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
 
 	  /* This will set up DECL_ARGUMENTS for us.  */
 	  grokclassfn (ctype, cname, decl, flags, quals);
-	  if (TYPE_SIZE (ctype) != 0)
+
+	  if (is_friend_template)
+	    decl = DECL_TI_TEMPLATE (push_template_decl (decl));
+
+	  if (TYPE_SIZE (ctype) != 0 
+	      && template_class_depth (ctype) == 0)
 	    decl = check_classfn (ctype, decl);
 
 	  if (TREE_TYPE (decl) != error_mark_node)
 	    {
-	      if (TYPE_SIZE (ctype))
+	      if (TYPE_SIZE (ctype) || template_class_depth (ctype) > 0)
 		add_friend (current_class_type, decl);
 	      else
-		{
-		  cp_error ("member `%D' declared as friend before type `%T' defined",
-			    decl, ctype);
-		}
+		cp_error ("member `%D' declared as friend before type `%T' defined",
+			  decl, ctype);
 	    }
 	}
       else
@@ -386,10 +405,21 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
 	{
 	  /* We can call pushdecl here, because the TREE_CHAIN of this
 	     FUNCTION_DECL is not needed for other purposes.  Don't do this
-	     for a template instantiation. */
-	  decl = pushdecl (decl);
+	     for a template instantiation.  */
+	  if (!is_friend_template)
+	    {  
+	      /* However, we don't call pushdecl() for a friend
+		 function of a template class, since in general,
+		 such a declaration depends on template
+		 parameters.  Instead, we call pushdecl when the
+		 class is instantiated.  */
+	      if (template_class_depth (current_class_type) == 0)
+		decl = pushdecl (decl);
+	    }
+	  else 
+	    decl = push_template_decl (decl); 
 
-	  if (! funcdef_flag && ! flag_guiding_decls
+	  if (! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
 	      && current_template_parms && uses_template_parms (decl))
 	    {
 	      static int explained;
@@ -405,8 +435,8 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
 	}
 
       make_decl_rtl (decl, NULL_PTR, 1);
-      add_friend (current_class_type, decl);
-
+      add_friend (current_class_type, 
+		  is_friend_template ? DECL_TI_TEMPLATE (decl) : decl);
       DECL_FRIEND_P (decl) = 1;
     }
   else
diff --git a/gcc/cp/gxxint.texi b/gcc/cp/gxxint.texi
index 5f7346561c5ca5283f6eef4e04557330f002538a..cf9aaa9a12d9a961caeaf584a6dd88e27dedb68f 100644
--- a/gcc/cp/gxxint.texi
+++ b/gcc/cp/gxxint.texi
@@ -1684,14 +1684,14 @@ as a @samp{Z} followed by the encoding of the type.
 
 A function template specialization (either an instantiation or an
 explicit specialization) is encoded by an @samp{H} followed by the
-encoding of the template parameters, as described above, followed by 
-an @samp{_}, the encoding of the argument types template function (not the
-specialization), another @samp{_}, and the return type.  (Like the
-argument types, the return type is the return type of the function
+encoding of the template parameters, as described above, followed by an
+@samp{_}, the encoding of the argument types to the template function
+(not the specialization), another @samp{_}, and the return type.  (Like
+the argument types, the return type is the return type of the function
 template, not the specialization.)  Template parameters in the argument
 and return types are encoded by an @samp{X} for type parameters, or a
-@samp{Y} for constant parameters, and an index indicating their position
-in the template parameter list declaration.
+@samp{Y} for constant parameters, an index indicating their position
+in the template parameter list declaration, and their template depth.
 
 @subsection Arrays
 
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 550ca34d0761ff7121bcf16a750416de0580ed14..8d6d62229c501028528014ed8b90cdb4f387a934 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -1213,8 +1213,7 @@ do_pending_inlines ()
   context = hack_decl_function_context (t->fndecl);
   if (context)
     push_cp_function_context (context);
-  if (is_member_template (t->fndecl))
-    begin_member_template_processing (t->fndecl);
+  maybe_begin_member_template_processing (t->fndecl);
   if (t->len > 0)
     {
       feed_input (t->buf, t->len);
@@ -1252,8 +1251,7 @@ process_next_inline (t)
   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 ();
+  maybe_end_member_template_processing (i->fndecl);
   if (context)
     pop_cp_function_context (context);
   i = i->next;
@@ -1276,8 +1274,7 @@ process_next_inline (t)
       context = hack_decl_function_context (i->fndecl);
       if (context)
 	push_cp_function_context (context);
-      if (is_member_template (i->fndecl))
-	begin_member_template_processing (i->fndecl);
+      maybe_begin_member_template_processing (i->fndecl);
       feed_input (i->buf, i->len);
       lineno = i->lineno;
       input_filename = i->filename;
@@ -1891,8 +1888,7 @@ do_pending_defargs ()
 	{
 	  push_nested_class (TREE_PURPOSE (defarg_fns), 1);
 	  pushlevel (0);
-	  if (is_member_template (defarg_fn))
-	    begin_member_template_processing (defarg_fn);
+	  maybe_begin_member_template_processing (defarg_fn);
 
 	  if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
 	    {
@@ -1920,8 +1916,7 @@ do_pending_defargs ()
 	    return;
 	  }
 
-      if (is_member_template (defarg_fn))
-	end_member_template_processing ();
+      maybe_end_member_template_processing (defarg_fn);
       poplevel (0, 0, 0);
       pop_nested_class (1);
     }
@@ -2946,7 +2941,7 @@ do_identifier (token, parsing)
 	}
       if (! processing_template_decl
 	  || (DECL_INITIAL (id)
-	      && TREE_CODE (DECL_INITIAL (id)) == TEMPLATE_CONST_PARM))
+	      && TREE_CODE (DECL_INITIAL (id)) == TEMPLATE_PARM_INDEX))
 	id = DECL_INITIAL (id);
     }
   else
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index a3ff1ac10edf5fe105a67bee1d45d5c5cba1da07..8be513b982889826dac6c2bfd771e92a0bc241cf 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -602,6 +602,24 @@ build_overload_int (value, in_template)
   icat (TREE_INT_CST_LOW (value));
 }
 
+
+/* Output S followed by a representation of the TEMPLATE_PARM_INDEX
+   supplied in INDEX.  */
+
+static void 
+build_mangled_template_parm_index (s, index)
+     char* s;
+     tree index;
+{
+  OB_PUTCP (s);
+  build_underscore_int (TEMPLATE_PARM_IDX (index));
+  /* We use the LEVEL, not the ORIG_LEVEL, because the mangling is a
+     representation of the function from the point of view of its
+     type.  */
+  build_underscore_int (TEMPLATE_PARM_LEVEL (index));
+}
+
+
 static void
 build_overload_value (type, value, in_template)
      tree type, value;
@@ -619,11 +637,9 @@ build_overload_value (type, value, in_template)
       numeric_output_need_bar = 0;
     }
 
-  if (TREE_CODE (value) == TEMPLATE_CONST_PARM)
+  if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
     {
-      OB_PUTC ('Y');
-      build_underscore_int (TEMPLATE_CONST_IDX (value));
-      build_underscore_int (TEMPLATE_CONST_LEVEL (value));
+      build_mangled_template_parm_index ("Y", value);
       return;
     }
 
@@ -761,13 +777,19 @@ build_overload_value (type, value, in_template)
 	  sorry ("template instantiation with pointer to method that is too complex");
 	  return;
 	}
-      if (TREE_CODE (value) == INTEGER_CST
-	  || TREE_CODE (value) == TEMPLATE_CONST_PARM)
+      if (TREE_CODE (value) == INTEGER_CST)
 	{
 	  build_overload_int (value, in_template);
 	  numeric_output_need_bar = 1;
 	  return;
 	}
+      else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+	{
+	  build_mangled_template_parm_index ("", value);
+	  numeric_output_need_bar = 1;
+	  return;
+	}
+
       value = TREE_OPERAND (value, 0);
       if (TREE_CODE (value) == VAR_DECL)
 	{
@@ -1374,33 +1396,27 @@ process_overload_item (parmtype, extra_Gcode)
          declaration. */
       if (CLASSTYPE_TEMPLATE_INFO (parmtype))
         {
-          OB_PUTC ('t');
-          OB_PUTC ('z');
-          OB_PUTC ('X');
-          build_underscore_int (TEMPLATE_TYPE_IDX (parmtype));
-          build_underscore_int (TEMPLATE_TYPE_LEVEL (parmtype));
-
-          build_template_parm_names (
-            DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
-            CLASSTYPE_TI_ARGS (parmtype));
+	  build_mangled_template_parm_index ("tzX",
+					     TEMPLATE_TYPE_PARM_INDEX 
+					     (parmtype));
+          build_template_parm_names
+            (DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
+	     CLASSTYPE_TI_ARGS (parmtype));
         }
       else
         {
-          OB_PUTC ('Z');
-          OB_PUTC ('z');
-          OB_PUTC ('X');
-          build_underscore_int (TEMPLATE_TYPE_IDX (parmtype));
-          build_underscore_int (TEMPLATE_TYPE_LEVEL (parmtype));
-
-          build_template_template_parm_names (
-            DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype)));
+	  build_mangled_template_parm_index ("ZzX",
+					     TEMPLATE_TYPE_PARM_INDEX 
+					     (parmtype));
+          build_template_template_parm_names
+            (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype)));
         }
       break;
 
     case TEMPLATE_TYPE_PARM:
-      OB_PUTC ('X');
-      build_underscore_int (TEMPLATE_TYPE_IDX (parmtype));
-      build_underscore_int (TEMPLATE_TYPE_LEVEL (parmtype));
+      build_mangled_template_parm_index ("X", 
+					 TEMPLATE_TYPE_PARM_INDEX
+					 (parmtype));
       break;
         
     case TYPENAME_TYPE:
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6a6571070280b10f8136e269f5b315cc2b8df1ab..a50368aa6558a0a9b4ee3f50f1bb204f98c7c7b9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -86,6 +86,7 @@ static int  type_unification_real PROTO((tree, tree *, tree, tree, int*,
 static void note_template_header PROTO((int));
 static tree maybe_fold_nontype_arg PROTO((tree));
 static tree convert_nontype_argument PROTO((tree, tree));
+static int is_member_or_friend_template PROTO((tree, int));
 
 /* Do any processing required when DECL (a member template declaration
    using TEMPLATE_PARAMETERS as its innermost parameter list) is
@@ -109,22 +110,51 @@ finish_member_template_decl (template_parameters, decl)
       return DECL_TI_TEMPLATE (decl);
     }
 
-  if (decl)
-    return decl;
+  return decl;
+}
 
-  cp_error ("invalid member template declaration");
-  return NULL_TREE;
+/* Returns the template nesting level of the indicated class TYPE.
+   
+   For example, in:
+     template <class T>
+     struct A
+     {
+       template <class U>
+       struct B {};
+     };
+
+   A<T>::B<U> has depth two, while A<T> has depth one.  Also,
+   both A<T>::B<int> and A<int>::B<U> have depth one.  */
+
+int 
+template_class_depth (type)
+     tree type;
+{
+  int depth = 0;
+
+  /* Note: this implementation will be broken when we have nested
+     template classes.  Presumably we will have to wrap this if
+     statement a loop.  */
+  if (CLASSTYPE_TEMPLATE_INFO (type)
+      && uses_template_parms (CLASSTYPE_TI_ARGS (type)))
+    ++depth;
+
+  return depth;
 }
 
-/* Restore the template parameter context. */
+/* Restore the template parameter context for a member template or
+   a friend template defined in a class definition.  */
 
 void 
-begin_member_template_processing (decl)
+maybe_begin_member_template_processing (decl)
      tree decl;
 {
   tree parms;
   int i;
 
+  if (!is_member_or_friend_template (decl, 1))
+    return;
+
   parms = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl));
 
   ++processing_template_decl;
@@ -163,8 +193,12 @@ begin_member_template_processing (decl)
 /* Undo the effects of begin_member_template_processing. */
 
 void 
-end_member_template_processing ()
+maybe_end_member_template_processing (decl)
+     tree decl;
 {
+  if (!is_member_or_friend_template (decl, 1))
+    return;
+
   if (! processing_template_decl)
     return;
 
@@ -173,8 +207,9 @@ end_member_template_processing ()
   poplevel (0, 0, 0);
 }
 
-/* Returns non-zero iff T is a member template function.  We must be
-   careful as in 
+/* Returns non-zero iff T is a member template function, or, if
+   ALLOW_FRIEND is non-zero, a friend template function.  We must be
+   careful as in
 
      template <class T> class C { void f(); }
 
@@ -187,67 +222,56 @@ end_member_template_processing ()
    then neither C<int>::f<char> nor C<T>::f<double> is considered
    to be a member template.  */
 
-int
-is_member_template (t)
+static int
+is_member_or_friend_template (t, allow_friend)
      tree t;
+     int allow_friend;
 {
-  int r = 0;
-
   if (TREE_CODE (t) != FUNCTION_DECL
       && !DECL_FUNCTION_TEMPLATE_P (t))
     /* Anything that isn't a function or a template function is
        certainly not a member template.  */
     return 0;
 
-  if ((DECL_FUNCTION_MEMBER_P (t) 
+  if (((DECL_FUNCTION_MEMBER_P (t) 
+	|| (allow_friend && DECL_FRIEND_P (t)))
        && !DECL_TEMPLATE_SPECIALIZATION (t))
-      || (TREE_CODE (t) == TEMPLATE_DECL && 
-	  DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t))))
+      || (TREE_CODE (t) == TEMPLATE_DECL 
+	  && (DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t))
+	      || (allow_friend
+		  && DECL_FUNCTION_TEMPLATE_P (t) 
+		  && DECL_FRIEND_P (DECL_TEMPLATE_RESULT (t))
+		  && DECL_CLASS_CONTEXT (t)))))
     {
-      tree tmpl = NULL_TREE;
+      tree tmpl;
 
       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);
+      else
+	tmpl = NULL_TREE;
+
+      if (tmpl && 
+	  /* If there are more levels of template parameters than
+	     there are template classes surrounding the declaration,
+	     then we have a member template.  */
+	  list_length (DECL_TEMPLATE_PARMS (tmpl)) > 
+	  template_class_depth (DECL_CLASS_CONTEXT (t)))
+	return 1;
+    }
 
-      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);
-
-	  /* NB - The code below does not yet handle template class
-	     members, e.g. 
-	     
-	       template <class T> class C { template <class U> class D; }}
-
-	     correctly.  In that case, the D should have level 2.  */
-
-	  if (CLASSTYPE_TEMPLATE_INFO (ctx))
-	    {
-	      tree args = CLASSTYPE_TI_ARGS (ctx);
-	      int i;
-	      
-	      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;
-		    }
-	    }
+  return 0;
+}
 
-	  if (parm_levels > template_class_levels)
-	    r = 1;
-	}
-    }
+/* Returns non-zero iff T is a member template.  */
 
-  return r;
+int
+is_member_template (t)
+     tree t;
+{
+  return is_member_or_friend_template (t, 0);
 }
 
 /* Return a new template argument vector which contains all of ARGS,
@@ -595,10 +619,6 @@ determine_specialization (template_id, decl, targs_out,
    Returns DECL, or an equivalent declaration that should be used
    instead. 
    
-     0: The function is not an explicit specialization or instantiation.
-     1: The function is an explicit specialization.
-     2: The function is an explicit instantiation.
-
    FLAGS is a bitmask consisting of the following flags: 
 
    1: We are being called by finish_struct.  (We are unable to
@@ -1004,6 +1024,57 @@ int comp_template_parms (parms1, parms2)
 }
 
 
+/* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
+   ORIG_LEVEL, DECL, and TYPE.  */
+
+static tree
+build_template_parm_index (index, level, orig_level, decl, type)
+     int index;
+     int level;
+     int orig_level;
+     tree decl;
+     tree type;
+{
+  tree t = make_node (TEMPLATE_PARM_INDEX);
+  TEMPLATE_PARM_IDX (t) = index;
+  TEMPLATE_PARM_LEVEL (t) = level;
+  TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
+  TEMPLATE_PARM_DECL (t) = decl;
+  TREE_TYPE (t) = type;
+
+  return t;
+}
+
+
+/* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
+   TEMPLATE_PARM_LEVEL has been decreased by one.  If such a
+   TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
+   new one is created.  */
+
+static tree 
+reduce_template_parm_level (index, type)
+     tree index;
+     tree type;
+{
+  if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
+      || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
+	  != TEMPLATE_PARM_LEVEL (index) - 1))
+    {
+      tree decl 
+	= build_decl (TREE_CODE (TEMPLATE_PARM_DECL (index)),
+		      DECL_NAME (TEMPLATE_PARM_DECL (index)),
+		      type);
+      tree t
+	= build_template_parm_index (TEMPLATE_PARM_IDX (index),
+				     TEMPLATE_PARM_LEVEL (index) - 1,
+				     TEMPLATE_PARM_ORIG_LEVEL (index),
+				     decl, type);
+      TEMPLATE_PARM_DESCENDANTS (index) = t;
+    }
+
+  return TEMPLATE_PARM_DESCENDANTS (index);
+}
+
 /* Process information from new template parameter NEXT and append it to the
    LIST being built.  */
 
@@ -1015,6 +1086,7 @@ process_template_parm (list, next)
   tree decl = 0;
   tree defval;
   int is_type, idx;
+
   parm = next;
   my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);
   defval = TREE_PURPOSE (parm);
@@ -1030,7 +1102,7 @@ process_template_parm (list, next)
       else if (TREE_CODE (p) == TEMPLATE_DECL)
 	idx = TEMPLATE_TYPE_IDX (TREE_TYPE (DECL_TEMPLATE_RESULT (p)));
       else
-	idx = TEMPLATE_CONST_IDX (DECL_INITIAL (p));
+	idx = TEMPLATE_PARM_IDX (DECL_INITIAL (p));
       ++idx;
     }
   else
@@ -1038,7 +1110,6 @@ process_template_parm (list, next)
 
   if (!is_type)
     {
-      tree tinfo = 0;
       my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260);
       /* is a const-param */
       parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm),
@@ -1059,18 +1130,16 @@ process_template_parm (list, next)
 		   || TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE))
 	cp_pedwarn ("`%T' is not a valid type for a template constant parameter",
 		    TREE_TYPE (parm));
-      tinfo = make_node (TEMPLATE_CONST_PARM);
-      my_friendly_assert (TREE_PERMANENT (tinfo), 260.5);
       if (TREE_PERMANENT (parm) == 0)
         {
 	  parm = copy_node (parm);
 	  TREE_PERMANENT (parm) = 1;
         }
-      TREE_TYPE (tinfo) = TREE_TYPE (parm);
       decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm));
-      DECL_INITIAL (decl) = tinfo;
-      DECL_INITIAL (parm) = tinfo;
-      TEMPLATE_CONST_SET_INFO (tinfo, idx, processing_template_decl);
+      DECL_INITIAL (parm) = DECL_INITIAL (decl) 
+	= build_template_parm_index (idx, processing_template_decl,
+				     processing_template_decl,
+				     decl, TREE_TYPE (parm));
     }
   else
     {
@@ -1097,7 +1166,10 @@ process_template_parm (list, next)
       TYPE_NAME (t) = decl;
       TYPE_STUB_DECL (t) = decl;
       parm = decl;
-      TEMPLATE_TYPE_SET_INFO (t, idx, processing_template_decl);
+      TEMPLATE_TYPE_PARM_INDEX (t)
+	= build_template_parm_index (idx, processing_template_decl, 
+				     processing_template_decl,
+				     decl, TREE_TYPE (parm));
     }
   SET_DECL_ARTIFICIAL (decl);
   pushdecl (decl);
@@ -1212,30 +1284,48 @@ build_template_decl (decl, parms)
 
   
 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
-   parameters given by current_template_args, or reuses a previously
-   existing one, if appropriate.  Returns the DECL, or an equivalent
-   one, if it is replaced via a call to duplicate_decls.  */
+   parameters given by current_template_args, or reuses a
+   previously existing one, if appropriate.  Returns the DECL, or an
+   equivalent one, if it is replaced via a call to duplicate_decls.  */
 
 tree
 push_template_decl (decl)
      tree decl;
 {
   tree tmpl;
-  tree args = NULL_TREE;
+  tree args;
   tree info;
-  tree ctx = DECL_CONTEXT (decl) ? DECL_CONTEXT (decl) : current_class_type;
-  int primary = 0;
-
-  /* Kludge! */
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl)
-      && DECL_CLASS_CONTEXT (decl))
-    ;
-  /* Note that this template is a "primary template" */
-  else if (! ctx 
-	   || (TREE_CODE_CLASS (TREE_CODE (ctx)) == 't' 
-	       && ! CLASSTYPE_TEMPLATE_INFO (ctx))
-      /* || (processing_template_decl > CLASSTYPE_TEMPLATE_LEVEL (ctx)) */)
+  tree ctx;
+  int primary;
+  int is_friend = (TREE_CODE (decl) == FUNCTION_DECL
+		   && DECL_FRIEND_P (decl));
+
+  if (is_friend)
+    /* For a friend, we want the context of the friend function, not
+       the type of which it is a friend.  */
+    ctx = DECL_CONTEXT (decl);
+  else if (DECL_REAL_CONTEXT (decl))
+    /* In the case of a virtual function, we want the class in which
+       it is defined.  */
+    ctx = DECL_REAL_CONTEXT (decl);
+  else
+    /* Otherwise, if we're currently definining some class, the DECL
+       is assumed to be a member of the class.  */
+    ctx = current_class_type;
+
+  if ((! ctx
+       || (TREE_CODE_CLASS (TREE_CODE (ctx)) == 't'
+	   && template_class_depth (ctx) == 0))
+      /* At this point, we know that the DECL is not a member of some
+	 template class.  However, a friend function declared in a
+	 template class is still not primary, since, in general it can
+	 depend on the template parameters of the enclosing class.  */
+      && !(is_friend
+	   && DECL_CLASS_CONTEXT (decl)
+	   && template_class_depth (DECL_CLASS_CONTEXT (decl)) > 0))
     primary = 1;
+  else
+    primary = 0;
 
   /* Partial specialization.  */
   if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
@@ -1263,19 +1353,28 @@ push_template_decl (decl)
 
   args = current_template_args ();
 
-  if (! ctx || TREE_CODE (ctx) == FUNCTION_DECL 
-      || TYPE_BEING_DEFINED (ctx))
+  if (!ctx 
+      || TREE_CODE (ctx) == FUNCTION_DECL
+      || TYPE_BEING_DEFINED (ctx)
+      || (is_friend && !DECL_TEMPLATE_INFO (decl)))
     {
-      tmpl = build_template_decl (decl, current_template_parms);
-      
       if (DECL_LANG_SPECIFIC (decl)
-	  && DECL_TEMPLATE_SPECIALIZATION (decl))
+	  && DECL_TEMPLATE_INFO (decl)
+	  && DECL_TI_TEMPLATE (decl))
+	tmpl = DECL_TI_TEMPLATE (decl);
+      else
 	{
-	  /* A specialization of a member template of a template
-	     class. */
-	  SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
-	  DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
-	  DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+	  tmpl = build_template_decl (decl, current_template_parms);
+	  
+	  if (DECL_LANG_SPECIFIC (decl)
+	      && DECL_TEMPLATE_SPECIALIZATION (decl))
+	    {
+	      /* A specialization of a member template of a template
+		 class. */
+	      SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
+	      DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
+	      DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+	    }
 	}
     }
   else
@@ -1325,8 +1424,7 @@ push_template_decl (decl)
 	  
 	  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))
+	  if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
 	    {
 	      cp_error ("got %d template parameters for `%#D'",
 			TREE_VEC_LENGTH (a), decl);
@@ -1372,7 +1470,10 @@ push_template_decl (decl)
   DECL_TEMPLATE_RESULT (tmpl) = decl;
   TREE_TYPE (tmpl) = TREE_TYPE (decl);
 
-  if (! ctx)
+  if (! ctx && primary)
+    /* The check of PRIMARY ensures that we do not try to push a
+       global template friend declared in a template class; such a
+       thing may well depend on the template parameters of the class.  */
     tmpl = pushdecl_top_level (tmpl);
 
   if (primary)
@@ -2014,6 +2115,9 @@ coerce_template_parms (parms, arglist, in_decl,
   return vec;
 }
 
+/* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
+   of template arguments.  Returns 0 otherwise.  */
+
 static int
 comp_template_args (oldargs, newargs)
      tree oldargs, newargs;
@@ -2540,7 +2644,7 @@ uses_template_parms (t)
       /* template parm nodes */
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case TEMPLATE_CONST_PARM:
+    case TEMPLATE_PARM_INDEX:
       return 1;
 
       /* simple type nodes */
@@ -2713,11 +2817,106 @@ tinst_for_decl ()
   return p;
 }
 
+
+/* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL.  ARGS is the
+   vector of template arguments, as for tsubst.
+
+   Returns an appropriate tsbust'd friend declaration.  */
+
+static tree
+tsubst_friend_function (decl, args)
+     tree decl;
+     tree args;
+{
+  tree new_friend;
+  
+  if (TREE_CODE (decl) == FUNCTION_DECL 
+      && DECL_TEMPLATE_INSTANTIATION (decl)
+      && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+    /* This was a friend declared with an explicit template
+       argument list, e.g.:
+       
+       friend void f<>(T);
+       
+       to indicate that f was a template instantiation, not a new
+       function declaration.  Now, we have to figure out what
+       instantiation of what template.  */
+    {
+      tree template_id;
+      tree new_args;
+      tree tmpl;
+      tree tinfo;
+
+      template_id
+	= lookup_template_function (tsubst_expr (DECL_TI_TEMPLATE (decl),
+						 args, 
+						 TREE_VEC_LENGTH (args),
+						 NULL_TREE),
+				    tsubst (DECL_TI_ARGS (decl),
+					    args,
+					    TREE_VEC_LENGTH (decl),
+					    NULL_TREE));
+      
+      /* Temporarily remove the DECL_TEMPLATE_INFO so as not to
+	 confuse tsubst.  */
+      tinfo = DECL_TEMPLATE_INFO (decl);
+      DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+      new_friend = tsubst (decl, args, TREE_VEC_LENGTH (args), NULL_TREE);
+      DECL_TEMPLATE_INFO (decl) = tinfo;
+
+      tmpl = determine_specialization (template_id,
+				       new_friend,
+				       &new_args,
+				       0, 1);
+      return instantiate_template (tmpl, new_args);
+    }
+    else
+      new_friend = tsubst (decl, args, TREE_VEC_LENGTH (args), NULL_TREE);
+	
+  /* The new_friend will look like an instantiation, to the
+     compiler, but is not an instantiation from the point of view of
+     the language.  For example, we might have had:
+     
+     template <class T> struct S {
+       template <class U> friend void f(T, U);
+     };
+     
+     Then, in S<int>, template <class U> void f(int, U) is not an
+     instantiation of anything.  */
+  DECL_USE_TEMPLATE (new_friend) = 0;
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
+  
+  if (DECL_CONTEXT (new_friend) == NULL_TREE)
+    {
+      if (TREE_CODE (new_friend) == TEMPLATE_DECL)
+	/* This declaration is a `primary' template.  */
+	TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (new_friend))
+	    = new_friend;
+
+	new_friend = pushdecl_top_level (new_friend);
+    }
+  else if (TYPE_SIZE (DECL_CONTEXT (new_friend)))
+    {
+      /* Check to see that the declaration is really present, and,
+	 possibly obtain an improved declaration.  */
+      tree fn = check_classfn (DECL_CONTEXT (new_friend),
+			       new_friend);
+      
+      if (fn)
+	new_friend = fn;
+    }
+
+  return new_friend;
+}
+
+
 tree
 instantiate_class_template (type)
      tree type;
 {
   tree template, template_info, args, pattern, t, *field_chain;
+  tree typedecl;
 
   if (type == error_mark_node)
     return error_mark_node;
@@ -2910,9 +3109,42 @@ instantiate_class_template (type)
 	grok_op_properties (t, DECL_VIRTUAL_P (t), 0);
     }
 
-  DECL_FRIENDLIST (TYPE_MAIN_DECL (type))
-    = tsubst (DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern)),
-	      args, TREE_VEC_LENGTH (args), NULL_TREE);
+  /* Construct the DECL_FRIENDLIST for the new class type.  */
+  typedecl = TYPE_MAIN_DECL (type);
+  for (t = DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern));
+       t != NULL_TREE;
+       t = TREE_CHAIN (t))
+    {
+      tree friends;
+
+      DECL_FRIENDLIST (typedecl)
+	= tree_cons (TREE_PURPOSE (t), NULL_TREE, 
+		     DECL_FRIENDLIST (typedecl));
+
+      for (friends = TREE_VALUE (t);
+	   friends != NULL_TREE;
+	   friends = TREE_CHAIN (friends))
+	{
+	  if (TREE_PURPOSE (friends) == error_mark_node)
+	    {
+	      TREE_VALUE (DECL_FRIENDLIST (typedecl))
+		= tree_cons (error_mark_node, 
+			     tsubst_friend_function (TREE_VALUE (friends),
+						     args),
+			     TREE_VALUE (DECL_FRIENDLIST (typedecl)));
+	    }
+	  else
+	    {
+	      TREE_VALUE (DECL_FRIENDLIST (typedecl))
+		= tree_cons (tsubst (TREE_PURPOSE (friends),
+				     args, TREE_VEC_LENGTH (args),
+				     NULL_TREE),
+			     NULL_TREE,
+			     TREE_VALUE (DECL_FRIENDLIST (typedecl)));
+
+	    }
+	}
+    }
 
   {
     tree d = CLASSTYPE_FRIEND_CLASSES (type)
@@ -3034,6 +3266,7 @@ maybe_fold_nontype_arg (arg)
   return arg;
 }
 
+
 /* Take the tree structure T and replace template parameters used therein
    with the argument vector ARGS.  NARGS is the number of args; should
    be removed.  IN_DECL is an associated decl for diagnostics.
@@ -3059,7 +3292,8 @@ tsubst (t, args, nargs, in_decl)
   if (type == unknown_type_node)
     my_friendly_abort (42);
   if (type && TREE_CODE (t) != FUNCTION_DECL
-      && TREE_CODE (t) != TYPENAME_TYPE)
+      && TREE_CODE (t) != TYPENAME_TYPE
+      && TREE_CODE (t) != TEMPLATE_DECL)
     type = tsubst (type, args, nargs, in_decl);
 
   switch (TREE_CODE (t))
@@ -3141,10 +3375,11 @@ tsubst (t, args, nargs, in_decl)
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case TEMPLATE_CONST_PARM:
+    case TEMPLATE_PARM_INDEX:
       {
 	int idx;
 	int level;
+	tree r = NULL_TREE;
 
 	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
 	    || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
@@ -3154,11 +3389,11 @@ tsubst (t, args, nargs, in_decl)
 	  }
 	else
 	  {
-	    idx = TEMPLATE_CONST_IDX (t);
-	    level = TEMPLATE_CONST_LEVEL (t);
+	    idx = TEMPLATE_PARM_IDX (t);
+	    level = TEMPLATE_PARM_LEVEL (t);
 	  }
 
-	if (TREE_VEC_LENGTH (args) > 0) 
+	if (TREE_VEC_LENGTH (args) > 0)
 	  {
 	    tree arg = NULL_TREE;
 
@@ -3212,14 +3447,32 @@ tsubst (t, args, nargs, in_decl)
 
 	/* 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)
-			   || (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
-			       && TEMPLATE_TYPE_LEVEL (t) > 1),
-			   0);
-	return t;
+	my_friendly_assert(level > 1, 0);
+	
+	/* Make a new version of this template parameter, but with a
+	   lower level.  */
+	switch (TREE_CODE (t))
+	  {
+	  case TEMPLATE_TYPE_PARM:
+	  case TEMPLATE_TEMPLATE_PARM:
+	    r = copy_node (t);
+	    TEMPLATE_TYPE_PARM_INDEX (r)
+	      = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
+					    r);
+	    TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
+	    TYPE_MAIN_VARIANT (r) = r;
+	    TYPE_POINTER_TO (r) = NULL_TREE;
+	    break;
+
+	  case TEMPLATE_PARM_INDEX:
+	    r = reduce_template_parm_level (t, TREE_TYPE (t));
+	    break;
+	   
+	  default:
+	    my_friendly_abort (0);
+	  }
+
+	return r;
       }
 
     case TEMPLATE_DECL:
@@ -3230,8 +3483,22 @@ tsubst (t, args, nargs, in_decl)
 	tree decl = DECL_TEMPLATE_RESULT (t);
 	tree new_decl;
 	tree parms;
+	tree* new_parms;
 	tree spec;
 
+	if (TREE_CODE (decl) == TYPE_DECL)
+	  {
+	    if (TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TEMPLATE_PARM)
+	      /* There is no tsubst'ing to be done in a template template
+		 parameter.  */
+	      return t;
+
+	    /* This must be a member template class.  We don't handle
+	       this case yet.  */
+	    sorry ("member template classes");
+	    return t;
+	  }
+
 	/* We might already have an instance of this template. */
 	spec = retrieve_specialization (t, args);
 	if (spec != NULL_TREE)
@@ -3247,6 +3514,10 @@ tsubst (t, args, nargs, in_decl)
 	my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
 	DECL_CHAIN (tmpl) = NULL_TREE;
 	TREE_CHAIN (tmpl) = NULL_TREE;
+	DECL_CONTEXT (tmpl) = tsubst (DECL_CONTEXT (t),
+				      args, nargs, in_decl);
+	DECL_CLASS_CONTEXT (tmpl) = tsubst (DECL_CLASS_CONTEXT (t),
+					    args, nargs, in_decl);
 	DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
 	new_decl = tsubst (decl, args, nargs, in_decl);
 	DECL_RESULT (tmpl) = new_decl;
@@ -3258,12 +3529,38 @@ tsubst (t, args, nargs, in_decl)
 	/* 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);
+	for (new_parms = &DECL_TEMPLATE_PARMS (tmpl),
+	       parms = DECL_TEMPLATE_PARMS (t);
 	     TREE_CHAIN (parms) != NULL_TREE;
-	     parms = TREE_CHAIN (parms))
-	  TREE_CHAIN (parms) = copy_node (TREE_CHAIN (parms));
+	     new_parms = &(TREE_CHAIN (*new_parms)),
+	       parms = TREE_CHAIN (parms))
+	  {
+	    tree new_vec = 
+	      make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+	    int i;
+
+	    for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
+	      {
+		tree default_value =
+		  TREE_PURPOSE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+		tree parm_decl = 
+		  TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+		  
+		TREE_VEC_ELT (new_vec, i)
+		  = build_tree_list (tsubst (default_value, args,
+					     nargs, in_decl),
+				     tsubst (parm_decl, args, nargs,
+					     in_decl));
+		  
+	      }
+
+	    *new_parms = 
+	      tree_cons (build_int_2 (0, 
+				      TREE_INT_CST_HIGH 
+				      (TREE_PURPOSE (parms)) - 1),
+			 new_vec,
+			 NULL_TREE);
+	  }
 
 	/* What should we do with the specializations of this member
 	   template?  Are they specializations of this new template,
@@ -3330,7 +3627,8 @@ tsubst (t, args, nargs, in_decl)
       {
 	tree r = NULL_TREE;
 	tree ctx;
-
+	tree fullargs = args;
+	tree tmpl = NULL_TREE;
 	int member;
 
 	if (DECL_CONTEXT (t) != NULL_TREE
@@ -3350,12 +3648,18 @@ tsubst (t, args, nargs, in_decl)
 	    type = tsubst (type, args, nargs, in_decl);
 	  }
 
-	/* Do we already have this instantiation?  */
+	/* If we are instantiating a specialization, get the other args.  */
 	if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
 	  {
-	    tree tmpl = DECL_TI_TEMPLATE (t);
-	    tree spec = retrieve_specialization (tmpl, args);
+	    tree spec;
+
+	    tmpl = DECL_TI_TEMPLATE (t);
+	    /* FIXME is this right for specializations?  */
+	    if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
+	      fullargs = add_to_template_args (DECL_TI_ARGS (tmpl), args);
 
+	    /* Do we already have this instantiation?  */
+	    spec = retrieve_specialization (tmpl, fullargs);
 	    if (spec)
 	      return spec;
 	  }
@@ -3432,21 +3736,19 @@ tsubst (t, args, nargs, in_decl)
 		   build_template_decl_overload since the innermost
 		   template parameters are still just template
 		   parameters; there are no corresponding subsitution
-		   arguments.  */
-		/* FIXME The messed up thing here is that we get here with
-		   full args and only one level of parms.  This is necessary
-		   because when we partially instantiate a member template,
-		   even though there's really only one level of parms left
-		   we re-use the parms from the original template, which
-		   have level 2.  When this is fixed we can remove the
-		   add_to_template_args from instantiate_template.  */
-		tree tparms;
+		   arguments.  We get here with full args and only one
+		   level of parms.  This is necessary because when we
+		   partially instantiate a member template, even
+		   though there's really only one level of parms, left
+		   the parms from the original template, which have
+		   level 2, may appear in the definition of the a
+		   function body.  */
+		tree tparms; 
 		tree targs;
 
 		if (!DECL_TEMPLATE_SPECIALIZATION (tmpl)) 
 		  {
 		    tparms = DECL_TEMPLATE_PARMS (tmpl);
-
 		    while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
 		      tparms = TREE_CHAIN (tparms);
 		    
@@ -3546,8 +3848,13 @@ tsubst (t, args, nargs, in_decl)
 
 	if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
 	  {
-	    tree tmpl = DECL_TI_TEMPLATE (t);
-	    tree argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
+	    tree argvec;
+
+	    /* FIXME this is ugly.  */
+	    if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)
+	      argvec = args;
+	    else
+	      argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
 
 	    if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
 	      {
@@ -4112,9 +4419,10 @@ tsubst_copy (t, args, nargs, in_decl)
     case CALL_EXPR:
       {
 	tree fn = TREE_OPERAND (t, 0);
-	if (really_overloaded_fn (fn))
+	if (is_overloaded_fn (fn))
 	  fn = tsubst_copy (get_first_fn (fn), args, nargs, in_decl);
 	else
+	  /* Sometimes FN is a LOOKUP_EXPR.  */
 	  fn = tsubst_copy (fn, args, nargs, in_decl);
 	return build_nt
 	  (code, fn, tsubst_copy (TREE_OPERAND (t, 1), args, nargs, in_decl),
@@ -4235,7 +4543,7 @@ tsubst_copy (t, args, nargs, in_decl)
     case INTEGER_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case TEMPLATE_CONST_PARM:
+    case TEMPLATE_PARM_INDEX:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
@@ -4243,6 +4551,7 @@ tsubst_copy (t, args, nargs, in_decl)
     case METHOD_TYPE:
     case ARRAY_TYPE:
     case TYPENAME_TYPE:
+    case TYPE_DECL:
       return tsubst (t, args, nargs, in_decl);
 
     case IDENTIFIER_NODE:
@@ -4577,6 +4886,8 @@ instantiate_template (tmpl, targ_ptr)
 
   my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
 
+  /* FIXME this won't work with member templates; we only have one level
+     of args here.  */
   if (DECL_FUNCTION_TEMPLATE_P (tmpl))
     {
       /* Check to see if we already have this specialization.  */
@@ -4611,9 +4922,6 @@ instantiate_template (tmpl, targ_ptr)
     }
   targ_ptr = copy_to_permanent (targ_ptr);
 
-  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);
 
@@ -5024,7 +5332,7 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts, strict)
 		tree t = TREE_VEC_ELT (parmvec, i);
 		if (TREE_CODE (t) != TEMPLATE_TYPE_PARM
 		    && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
-		    && TREE_CODE (t) != TEMPLATE_CONST_PARM)
+		    && TREE_CODE (t) != TEMPLATE_PARM_INDEX)
 		  continue;
 
 		/* This argument can be deduced.  */
@@ -5048,9 +5356,9 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts, strict)
       targs[idx] = arg;
       return 0;
 
-    case TEMPLATE_CONST_PARM:
+    case TEMPLATE_PARM_INDEX:
       (*nsubsts)++;
-      idx = TEMPLATE_CONST_IDX (parm);
+      idx = TEMPLATE_PARM_IDX (parm);
       if (targs[idx])
 	{
 	  int i = cp_tree_equal (targs[idx], arg);
@@ -5357,7 +5665,7 @@ get_bindings (fn, decl, explicit_args)
 		       DECL_NTPARMS (fn),
 		       NULL_TREE);
 
-      if (!comptypes(t, TREE_TYPE (TREE_TYPE (decl)), 1))
+      if (!comptypes (t, TREE_TYPE (TREE_TYPE (decl)), 1))
 	return NULL_TREE;
 
       return targs;
@@ -5669,6 +5977,20 @@ do_type_instantiation (t, storage)
   }
 }
 
+/* Return the TREE_VEC with the arguments for the innermost template header,
+   where ARGS is either that or the VEC of VECs for all the arguments.  */
+
+tree
+innermost_args (args)
+     tree args;
+{
+  if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+    return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+  return args;
+}
+
+/* Produce the definition of D, a _DECL generated from a template.  */
+
 tree
 instantiate_decl (d)
      tree d;
@@ -5685,7 +6007,15 @@ instantiate_decl (d)
   int line = lineno;
   char *file = input_filename;
 
-  for (td = tmpl; DECL_TEMPLATE_INSTANTIATION (td); )
+  for (td = tmpl; 
+       DECL_TEMPLATE_INSTANTIATION (td) 
+	 /* This next clause handles friend templates defined inside
+	    class templates.  The friend templates are not really
+	    instantiations from the point of view of the language, but
+	    they are instantiations from the point of view of the
+	    compiler.  */
+	 || (DECL_TEMPLATE_INFO (td) && !DECL_TEMPLATE_SPECIALIZATION (td)); 
+       )
     td = DECL_TI_TEMPLATE (td);
 
   /* In the case of a member template, decl_pattern is the partially
@@ -5781,7 +6111,10 @@ instantiate_decl (d)
   /* Trick tsubst into giving us a new decl in case the template changed.  */
   save_ti = DECL_TEMPLATE_INFO (decl_pattern);
   DECL_TEMPLATE_INFO (decl_pattern) = NULL_TREE;
-  td = tsubst (decl_pattern, args, TREE_VEC_LENGTH (args), tmpl);
+  /* FIXME this is ugly.  */
+  td = tsubst (decl_pattern,
+	       DECL_TEMPLATE_SPECIALIZATION (decl_pattern)
+	       ? args : innermost_args (args), 0, tmpl);
   SET_DECL_IMPLICIT_INSTANTIATION (td);
   DECL_TEMPLATE_INFO (decl_pattern) = save_ti;
 
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index 5a859561512b079b5e38b1364735aba0bbd057c8..4a6ce7bfaeb68a2449a6dd9ba5fc9358d6df276f 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -66,9 +66,13 @@ print_lang_type (file, node, indent)
      register tree node;
      int indent;
 {
-  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM)
+  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (node) == TEMPLATE_TEMPLATE_PARM)
     {
-      print_node (file, "tinfo", TYPE_VALUES (node), indent + 4);
+      indent_to (file, indent + 3);
+      fprintf (file, "index %d level %d orig_level %d",
+	       TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node),
+	       TEMPLATE_TYPE_ORIG_LEVEL (node));
       return;
     }
 
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 8177157e81c5e20d15fca5e7b302ebb8bf0e1f05..df391b52a2122d89dd2bbdcc722234a5a71399aa 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -794,7 +794,17 @@ static tree
 lookup_field_1 (type, name)
      tree type, name;
 {
-  register tree field = TYPE_FIELDS (type);
+  register tree field;
+
+  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+    /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM are not fields at all;
+       instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX.  (Miraculously,
+       the code often worked even when we treated the index as a list
+       of fields!)  */
+    return NULL_TREE;
+
+  field = TYPE_FIELDS (type);
 
 #ifdef GATHER_STATISTICS
   n_calls_lookup_field_1++;
@@ -804,6 +814,7 @@ lookup_field_1 (type, name)
 #ifdef GATHER_STATISTICS
       n_fields_searched++;
 #endif /* GATHER_STATISTICS */
+      my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
       if (DECL_NAME (field) == NULL_TREE
 	  && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
 	{
diff --git a/gcc/cp/spew.c b/gcc/cp/spew.c
index 95b505a3d7473fab2be202fc4210579c1176fc61..b4799d42e68ebf48f6166fa147a3b9e28b1b126c 100644
--- a/gcc/cp/spew.c
+++ b/gcc/cp/spew.c
@@ -329,7 +329,7 @@ yylex ()
 	    }
 	}
       else
-	lastiddecl = trrr;
+	lastiddecl = NULL_TREE;
       got_scope = NULL_TREE;
       /* and fall through to...  */
     case IDENTIFIER_DEFN:
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 1bd60f177b52ce01bc397346ab60f83a20ffffb6..8fb0c9f586c4c960e9f82b820621329a8a1db1ed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2070,9 +2070,9 @@ cp_tree_equal (t1, t2)
     case FUNCTION_DECL:
       return 0;
 
-    case TEMPLATE_CONST_PARM:
-      return TEMPLATE_CONST_IDX (t1) == TEMPLATE_CONST_IDX (t2)
-	&& TEMPLATE_CONST_LEVEL (t1) == TEMPLATE_CONST_LEVEL (t2);
+    case TEMPLATE_PARM_INDEX:
+      return TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+	&& TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2);
 
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 851020f99af2130a0b556bd3be4d06ee6ff37c27..3375f11db0f86dd3c3b9c101ee3286cb96e96114 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2367,11 +2367,17 @@ build_x_function_call (function, params, decl)
 	       || TREE_CODE (type) == METHOD_TYPE
 	       || TYPE_PTRMEMFUNC_P (type));
 
-  if (TREE_CODE (function) == FUNCTION_DECL
-      && DECL_STATIC_FUNCTION_P (function))
+  if ((TREE_CODE (function) == FUNCTION_DECL
+       && DECL_STATIC_FUNCTION_P (function))
+      || (TREE_CODE (function) == TEMPLATE_DECL
+	  && DECL_STATIC_FUNCTION_P (DECL_RESULT (function))))
     return build_member_call
       (DECL_CONTEXT (function), DECL_NAME (function), params);
 
+  /* A friend template.  Make it look like a toplevel declaration.  */
+  if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
+    function = build_scratch_list (NULL_TREE, function);
+
   /* Handle methods, friends, and overloaded functions, respectively.  */
   if (is_method)
     {