On 6/2/26 16:30, Patrick Palka wrote:
> On Mon, 1 Jun 2026, Eczbek wrote:
>> On 6/1/26 16:33, Jason Merrill wrote:
>>> This assumes a template with a single template parameter; it doesn't work 
>>> for e.g.
>>>
>>> struct A {
>>>   template<typename T, typename U>
>>>   operator T U::*() {
>>>     return 0;
>>>   }
>>> };
>>>
>>> int main() {
>>>   (void) &A::operator int A::*;
>>> }
>>>
>>> to handle the general case you need to deduce the template arguments.
>>
>> Thanks, I did not consider multiple template parameters. Would this be 
>> similar to what TEMPLATE_ID_EXPR does below, or is there some existing 
>> helper that should be used? I'm not sure how to do this.
> 
> There are a couple of entrypoints to deduction, all of which ultimately
> call the main workhorse unify.  For simplicity I think we could get away
> with calling unify directly from resolve_nondeduced_context with
> 
>   tparms = DECL_TEMPLATE_PARMS of the conversion function template
>   targs = empty TREE_VEC same length as DECL_TEMPLATE_PARMS
>   parm = return type of the template
>   arg = BASELINK_OPTYPE
>   strict = UNIFY_ALLOW_NONE (I think?)
> 
> If unify succeeds, then 'targs' will contain the deduced template
> arguments that we need to instantiate the conversion function template
> with.
> 
> So for
> 
>   struct A {
>     template<class T, class U>
>     operator B<T*, U&>();
>   };
> 
>   int main() {
>     &A::operator B<int*, char&>;
>   }
> 
> we need to call unify with (where {} is shorthand for a TREE_VEC)
> 
>   tparms = {T, U}
>   targs = {NULL, NULL}
>   parm = B<T*, U&>
>   arg = B<int*, char&>
> 
> which should succeed and fill in targs with {int, char}.  Instantiating
> the template with {int, char} yields the correct specialization
> operator B<int*, char&>.

Thank you, I made something work! Bootstrapped/regtested again.

Jason mentioned that what I wrote in the changelog should be in the main commit 
message, so what should I write in the changelog instead?

-- >8 --

---
 gcc/cp/pt.cc                           | 30 ++++++++++++++++++++++++--
 gcc/testsuite/g++.dg/template/conv22.C | 28 ++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/conv22.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6992b5196fe..d914a1c817d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -25193,6 +25193,7 @@ resolve_overloaded_unification (tree tparms,
   int good = 0;
   tree goodfn = NULL_TREE;
   bool addr_p;
+  tree baselink = NULL_TREE;
 
   if (TREE_CODE (arg) == ADDR_EXPR)
     {
@@ -25212,7 +25213,22 @@ resolve_overloaded_unification (tree tparms,
 
   /* Strip baselink information.  */
   if (BASELINK_P (arg))
-    arg = BASELINK_FUNCTIONS (arg);
+    {
+      baselink = arg;
+      arg = BASELINK_FUNCTIONS (arg);
+    }
+
+  if (TREE_CODE (arg) == OVERLOAD
+      && IDENTIFIER_CONV_OP_P (OVL_NAME (arg)))
+    {
+      tree tmpl = OVL_FIRST (arg);
+      tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+      tree targs = make_tree_vec (DECL_NTPARMS (tmpl));
+      tree parm = DECL_CONV_FN_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+      tree optype = BASELINK_OPTYPE (baselink);
+      if (!unify (tparms, targs, parm, optype, UNIFY_ALLOW_NONE, false))
+       arg = lookup_template_function (tmpl, targs);
+    }
 
   if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
     {
@@ -25361,7 +25377,17 @@ resolve_nondeduced_context (tree orig_expr, 
tsubst_flags_t complain)
       baselink = expr;
       expr = BASELINK_FUNCTIONS (expr);
     }
-
+  if (TREE_CODE (expr) == OVERLOAD
+      && IDENTIFIER_CONV_OP_P (OVL_NAME (expr)))
+    {
+      tree tmpl = OVL_FIRST (expr);
+      tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+      tree targs = make_tree_vec (DECL_NTPARMS (tmpl));
+      tree parm = DECL_CONV_FN_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+      tree optype = BASELINK_OPTYPE (baselink);
+      if (!unify (tparms, targs, parm, optype, UNIFY_ALLOW_NONE, false))
+       expr = lookup_template_function (tmpl, targs);
+    }
   if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
     {
       int good = 0;
diff --git a/gcc/testsuite/g++.dg/template/conv22.C 
b/gcc/testsuite/g++.dg/template/conv22.C
new file mode 100644
index 00000000000..2e703880192
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv22.C
@@ -0,0 +1,28 @@
+// PR c++/122383
+// { dg-do compile }
+
+struct A {
+  template<typename T>
+  operator T() {
+    return 0;
+  }
+
+  template<typename T, typename U>
+  operator T U::*() {
+    return 0;
+  }
+};
+
+template<typename T>
+void f(T(A::*)()) {}
+
+template<typename T, typename U>
+void f(T U::*(A::*)()) {}
+
+int main() {
+  &A::operator int;
+  &A::operator int A::*;
+
+  f(&A::operator int);
+  f(&A::operator int A::*);
+}

base-commit: b1987874feead5e98f1ea005bd1ce5ff515eda7a
-- 
2.54.0

Reply via email to