diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 64fc782289a9205e984031143d997c00f2d9178f..f1249c8c4bdb7cc0ef18e9ef7007d3b674ee284a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,11 @@
 1998-05-26  Mark Mitchell  <mark@markmitchell.com>
 
+	* friend.c (is_friend): Use comptypes, rather than == to compare
+	types.  Modify for new representation of template friends.
+	(make_friend_class): Likewise.
+	* pt.c (tsubst_friend_class): Undo 1998-05-21 change.  Tweak.
+	(instantiate_class_template): Deal with template friends.
+
 	* decl.c (store_parm_decls): Remove redundant call to
 	expand_main_function.
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f65fbd437ef5d05569cac9d56ea8abe3817e8765..129047a5d16aa7569d6a74686768b3b53882a967 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -905,7 +905,9 @@ struct lang_type
 /* Same, but cache a list whose value is the binfo of this type.  */
 #define CLASSTYPE_BINFO_AS_LIST(NODE) (TYPE_LANG_SPECIFIC(NODE)->binfo_as_list)
 
-/* A list of class types with which this type is a friend.  */
+/* A list of class types with which this type is a friend.  The
+   TREE_VALUE is normally a TYPE, but will be a TEMPLATE_DECL in the
+   case of a template friend.  */
 #define CLASSTYPE_FRIEND_CLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->friend_classes)
 
 #ifdef MI_MATRIX
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 6f40f0adad8c5416e5cb2319a051f8887748dbcd..8adeb600450efd54897f1f57ed46ef81f8adb02a 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -64,7 +64,7 @@ is_friend (type, supplicant)
 	      tree friends = TREE_VALUE (list);
 	      for (; friends ; friends = TREE_CHAIN (friends))
 		{
-		  if (ctype == TREE_PURPOSE (friends))
+		  if (comptypes (ctype, TREE_PURPOSE (friends), 1))
 		    return 1;
 
 		  if (TREE_VALUE (friends) == NULL_TREE)
@@ -102,10 +102,9 @@ is_friend (type, supplicant)
 	{
 	  tree t = TREE_VALUE (list);
 
-	  if (supplicant == t
-	      || (CLASSTYPE_IS_TEMPLATE (t)
-		  && is_specialization_of (TYPE_MAIN_DECL (supplicant),
-					   CLASSTYPE_TI_TEMPLATE (t))))
+	  if (TREE_CODE (t) == TEMPLATE_DECL ? 
+	      is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
+	      comptypes (supplicant, t, 1))
 	    return 1;
 	}
     }      
@@ -241,6 +240,7 @@ make_friend_class (type, friend_type)
      tree type, friend_type;
 {
   tree classes;
+  int is_template_friend;
 
   if (IS_SIGNATURE (type))
     {
@@ -253,25 +253,36 @@ make_friend_class (type, friend_type)
 	     IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
       return;
     }
-  /* If the TYPE is a template then it makes sense for it to be
-     friends with itself; this means that each instantiation is
-     friends with all other instantiations.  */
-  if (type == friend_type && !CLASSTYPE_IS_TEMPLATE (type))
+  if (processing_template_decl > template_class_depth (type))
+    /* If the TYPE is a template then it makes sense for it to be
+       friends with itself; this means that each instantiation is
+       friends with all other instantiations.  */
+    is_template_friend = 1;
+  else if (comptypes (type, friend_type, 1))
     {
       pedwarn ("class `%s' is implicitly friends with itself",
 	       TYPE_NAME_STRING (type));
       return;
     }
+  else
+    is_template_friend = 0;
 
   GNU_xref_hier (TYPE_NAME_STRING (type),
 		 TYPE_NAME_STRING (friend_type), 0, 0, 1);
 
+  if (is_template_friend)
+    friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
+
   classes = CLASSTYPE_FRIEND_CLASSES (type);
-  while (classes && TREE_VALUE (classes) != friend_type)
+  while (classes 
+	 /* Stop if we find the same type on the list.  */
+	 && !(TREE_CODE (TREE_VALUE (classes)) == TEMPLATE_DECL ?
+	      friend_type == TREE_VALUE (classes) :
+	      comptypes (TREE_VALUE (classes), friend_type, 1)))
     classes = TREE_CHAIN (classes);
-  if (classes)
-    warning ("class `%s' is already friends with class `%s'",
-	     TYPE_NAME_STRING (TREE_VALUE (classes)), TYPE_NAME_STRING (type));
+  if (classes) 
+    cp_warning ("`%T' is already a friend of `%T'",
+		TREE_VALUE (classes), type);
   else
     {
       CLASSTYPE_FRIEND_CLASSES (type)
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend20.C b/gcc/testsuite/g++.old-deja/g++.pt/friend20.C
new file mode 100644
index 0000000000000000000000000000000000000000..40d5370a81044a49f816adc4bc18e7c04a5b23a1
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend20.C
@@ -0,0 +1,10 @@
+// Build don't link:
+
+template <class T = int> struct A;
+
+template <class T> struct B
+{
+  friend class A<T>;
+};
+
+template class B<int>;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend21.C b/gcc/testsuite/g++.old-deja/g++.pt/friend21.C
new file mode 100644
index 0000000000000000000000000000000000000000..c724f8c992f0e0f3e631ad8c5f2d070d6d5d4802
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend21.C
@@ -0,0 +1,30 @@
+// Build don't link:
+
+template <class T> struct A {
+  static void f();
+};
+
+template <class T> class B
+{
+  friend class A<T>;
+  static int i;
+};
+
+template <class T> class C
+{
+  template <class U>
+  friend class A<U>;
+
+  static int i;
+};
+
+template <class T>
+void A<T>::f()
+{
+  B<T>::i = 3;
+  C<T>::i = 3;
+  C<double>::i = 3;
+  B<double>::i = 3; // ERROR - member `i' is private
+}
+
+template void A<int>::f(); // ERROR - instantiated from here