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