diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 924a20973b4..4b2af4f7aca 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -25218,27 +25218,61 @@ more_specialized_fn (tree pat1, tree pat2, int len)
   bool lose1 = false;
   bool lose2 = false;
 
-  /* Remove the this parameter from non-static member functions.  If
-     one is a non-static member function and the other is not a static
-     member function, remove the first parameter from that function
-     also.  This situation occurs for operator functions where we
-     locate both a member function (with this pointer) and non-member
-     operator (with explicit first operand).  */
-  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))
+  /* C++17 [temp.func.order]/3 (CWG532)
+
+     If only one of the function templates M is a non-static member of some
+     class A, M is considered to have a new first parameter inserted in its
+     function parameter list. Given cv as the cv-qualifiers of M (if any), the
+     new parameter is of type "rvalue reference to cv A" if the optional
+     ref-qualifier of M is && or if M has no ref-qualifier and the first
+     parameter of the other template has rvalue reference type. Otherwise, the
+     new parameter is of type "lvalue reference to cv A".  */
+
+  if (DECL_STATIC_FUNCTION_P (decl1) || DECL_STATIC_FUNCTION_P (decl2))
     {
-      len--; /* LEN is the number of significant arguments for DECL1 */
-      args1 = TREE_CHAIN (args1);
-      if (!DECL_STATIC_FUNCTION_P (decl2))
-	args2 = TREE_CHAIN (args2);
-    }
-  else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
-    {
-      args2 = TREE_CHAIN (args2);
-      if (!DECL_STATIC_FUNCTION_P (decl1))
+      /* Note C++20 DR2445 extended the above to static member functions, but
+	 I think think the old G++ behavior of just skipping the object
+	 parameter when comparing to a static member function was better, so
+	 let's stick with that for now.  This is CWG2834.  --jason 2023-12 */
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)) /* FIXME or explicit */
 	{
-	  len--;
+	  len--; /* LEN is the number of significant arguments for DECL1 */
 	  args1 = TREE_CHAIN (args1);
 	}
+      else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) /* FIXME or explicit */
+	args2 = TREE_CHAIN (args2);
+    }
+  else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */
+	   && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
+    {
+      /* Note DR2445 also (IMO wrongly) removed the "only one" above, which
+	 would break e.g.  cpp1y/lambda-generic-variadic5.C.  */
+      len--;
+      args1 = TREE_CHAIN (args1);
+      args2 = TREE_CHAIN (args2);
+    }
+  else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */
+	   || DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
+    {
+      /* The other is a non-member or explicit object member function;
+	 rewrite the implicit object parameter to a reference.  */
+      tree ns = DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2) ? decl2 : decl1;
+      tree &nsargs = ns == decl2 ? args2 : args1;
+      tree obtype = TREE_TYPE (TREE_VALUE (nsargs));
+
+      nsargs = TREE_CHAIN (nsargs);
+
+      cp_ref_qualifier rqual = type_memfn_rqual (TREE_TYPE (ns));
+      if (rqual == REF_QUAL_NONE)
+	{
+	  tree otherfirst = ns == decl1 ? args2 : args1;
+	  otherfirst = TREE_VALUE (otherfirst);
+	  if (TREE_CODE (otherfirst) == REFERENCE_TYPE
+	      && TYPE_REF_IS_RVALUE (otherfirst))
+	    rqual = REF_QUAL_RVALUE;
+	}
+      obtype = cp_build_reference_type (obtype, rqual == REF_QUAL_RVALUE);
+      nsargs = tree_cons (NULL_TREE, obtype, nsargs);
     }
 
   /* If only one is a conversion operator, they are unordered.  */
diff --git a/gcc/testsuite/g++.dg/template/partial-order4.C b/gcc/testsuite/g++.dg/template/partial-order4.C
new file mode 100644
index 00000000000..89555ab7060
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-order4.C
@@ -0,0 +1,17 @@
+// DR 532
+// PR c++/53499
+// [temp.func.order] says that we do ordering on the first parameter.
+
+struct A
+{
+  template <class T>
+  bool operator==(T);
+};
+
+template <class T, class U>
+bool operator==(T, U);
+
+int main()
+{
+  A() == A();
+}
diff --git a/gcc/testsuite/g++.dg/template/spec26.C b/gcc/testsuite/g++.dg/template/spec26.C
index fad8e3e1519..253d4211153 100644
--- a/gcc/testsuite/g++.dg/template/spec26.C
+++ b/gcc/testsuite/g++.dg/template/spec26.C
@@ -1,13 +1,15 @@
-// { dg-do run }
+// { dg-do compile { target c++11 } }
 // Copyright (C) 2005 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 16 Sep 2005 <nathan@codesourcery.com>
 
 // PR 23519  template specialization ordering (DR214)
 // Origin:  Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
 
+// DR532 clarified that the * expression is ambiguous.
+
 struct A
 {
-    template<class T> int operator+(T&) { return 1;}
+  template<class T> int operator+(T&) = delete;
 };
 
 template<class T> struct B
@@ -16,7 +18,7 @@ template<class T> struct B
   template<typename R> int operator*(R&) {return 3;}
 };
 
-template <typename T, typename R> int operator-(B<T>, R&) {return 4;}
+template <typename T, typename R> int operator-(B<T>, R&) = delete;
 template<class T> int operator+(A&, B<T>&) { return 5;}
 template <typename T> int operator*(T &, A&){return 6;}
 
@@ -30,6 +32,6 @@ int main()
   if ((b - a) != 2)
     return 2;
   
-  if ((b * a) != 6)
+  if ((b * a) != 6)		// { dg-error "ambiguous" }
     return 3;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
index 5b3c673898e..2819851076c 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
@@ -36,8 +36,8 @@ namespace N
     X operator+(T, std::size_t)
     { return X(); }
 
-  template<typename T>
-    X operator-(T, T)
+  template<typename T, typename U>
+    X operator-(T, U)
     { return X(); }
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
index cc9519ee618..6c00d1568ae 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
@@ -38,8 +38,8 @@ namespace N
     X operator+(T, std::size_t)
     { return X(); }
 
-  template<typename T>
-    X operator-(T, T)
+  template<typename T, typename U>
+    X operator-(T, U)
     { return X(); }
 }
 
