diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1f6553790a5..ab231aaaa0f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11602,6 +11602,7 @@ tsubst_friend_function (tree decl, tree args)
 	    ;
 	  else
 	    {
+	      tree old_template = most_general_template (old_decl);
 	      tree new_template = TI_TEMPLATE (new_friend_template_info);
 	      tree new_args = TI_ARGS (new_friend_template_info);
 
@@ -11639,7 +11640,7 @@ tsubst_friend_function (tree decl, tree args)
 		  /* Reassign any specializations already in the hash table
 		     to the new more general template, and add the
 		     additional template args.  */
-		  for (t = DECL_TEMPLATE_INSTANTIATIONS (old_decl);
+		  for (t = DECL_TEMPLATE_INSTANTIATIONS (old_template);
 		       t != NULL_TREE;
 		       t = TREE_CHAIN (t))
 		    {
@@ -11652,15 +11653,15 @@ tsubst_friend_function (tree decl, tree args)
 
 		      decl_specializations->remove_elt (&elt);
 
-		      DECL_TI_ARGS (spec)
-			= add_outermost_template_args (new_args,
-						       DECL_TI_ARGS (spec));
+		      tree& spec_args = DECL_TI_ARGS (spec);
+		      spec_args = add_outermost_template_args
+			(new_args, INNERMOST_TEMPLATE_ARGS (spec_args));
 
 		      register_specialization
-			(spec, new_template, DECL_TI_ARGS (spec), true, 0);
+			(spec, new_template, spec_args, true, 0);
 
 		    }
-		  DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE;
+		  DECL_TEMPLATE_INSTANTIATIONS (old_template) = NULL_TREE;
 		}
 	    }
 
diff --git a/gcc/testsuite/g++.dg/template/friend80.C b/gcc/testsuite/g++.dg/template/friend80.C
new file mode 100644
index 00000000000..5c417e12dd0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend80.C
@@ -0,0 +1,25 @@
+// PR c++/112288
+// { dg-do compile { target c++11 } }
+
+template<class T>
+struct slot {
+  template<class U>
+  friend constexpr bool slot_allocated(slot<T>, U);
+};
+
+template<class T>
+struct allocate_slot {
+  template<class U>
+  friend constexpr bool slot_allocated(slot<T>, U) { return true; }
+};
+
+template<class T, bool = slot_allocated(slot<T>{}, 42)>
+constexpr int next(int) { return 1; }
+
+template<class T>
+constexpr int next(...) { return (allocate_slot<T>{}, 0); }
+
+// slot_allocated<slot<int>, int>() not defined yet
+static_assert(next<int>(0) == 0, "");
+// now it's defined, need to make existing spec point to defn or else ICE
+static_assert(next<int>(0) == 1, "");
diff --git a/gcc/testsuite/g++.dg/template/friend81.C b/gcc/testsuite/g++.dg/template/friend81.C
new file mode 100644
index 00000000000..cefcca03ab4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend81.C
@@ -0,0 +1,28 @@
+// PR c++/112288
+// { dg-do link }
+
+template<class T> struct A;
+template<class T> struct B;
+
+A<int>* a;
+B<int>* b;
+
+template<class T>
+struct B {
+  template<class U>
+  friend int f(A<T>*, B*, U); // #1
+};
+
+template struct B<int>; // f declared
+int n = f(a, b, 0); // f<int> specialized
+
+template<class T>
+struct A {
+  template<class U>
+  friend int f(A*, B<T>*, U) { return 42; } // #2
+};
+
+template struct A<int>; // f defined, need to make existing f<int> point to defn
+int m = f(a, b, 0); // reuses existing specialization f<int>
+
+int main() { }
diff --git a/gcc/testsuite/g++.dg/template/friend81a.C b/gcc/testsuite/g++.dg/template/friend81a.C
new file mode 100644
index 00000000000..b4e4c9ec52a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend81a.C
@@ -0,0 +1,30 @@
+// PR c++/112288
+// { dg-do link }
+// A version of friend81.C where A and B take a different number of template
+// parameters.
+
+template<class T> struct A;
+template<class T, class = T> struct B;
+
+A<int>* a;
+B<int>* b;
+
+template<class T, class>
+struct B {
+  template<class U>
+  friend int f(A<T>*, B*, U); // #1
+};
+
+template struct B<int>; // f declared
+int n = f(a, b, 0); // f<int> specialized
+
+template<class T>
+struct A {
+  template<class U>
+  friend int f(A*, B<T>*, U) { return 42; } // #2
+};
+
+template struct A<int>; // f defined, need to make existing f<int> point to defn
+int m = f(a, b, 0); // reuses existing specialization f<int>
+
+int main() { }
