On 6/1/26 4:30 PM, Patrick Palka wrote:
On Mon, 25 May 2026, Eczbek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu.

This accidentally allows `&(A::operator int);` to compile.
`auto f = &(A::operator int);` correctly errors, but emits a funny message: "note: (a pointer 
to member can only be formed with '&A::operator int<int>')"

-- >8 --

Taking the address of a conversion function template instantiation
incorrectly errors.

        PR c++/122383

gcc/cp/ChangeLog:

        * pt.cc (resolve_overloaded_unification): If expr represents a
        conversion function template instantiation, call
        lookup_template_function with baselink, then fall through to
        TEMPLATE_ID_EXPR check.
        (resolve_nondeduced_context): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/template/conv22.C: New test.
---
  gcc/cp/pt.cc                           | 22 ++++++++++++++++++++--
  gcc/testsuite/g++.dg/template/conv22.C | 18 ++++++++++++++++++
  2 files changed, 38 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..1faba19c48e 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,18 @@ 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 targs = make_tree_vec (1);
+      TREE_VEC_ELT (targs, 0) = BASELINK_OPTYPE (baselink);
+      arg = lookup_template_function (arg, targs);
+    }
if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
      {
@@ -25361,7 +25373,13 @@ 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 targs = make_tree_vec (1);
+      TREE_VEC_ELT (targs, 0) = BASELINK_OPTYPE (baselink);
+      expr = lookup_template_function (expr, 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..99a3f829b5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv22.C
@@ -0,0 +1,18 @@
+// PR c++/122383
+// { dg-do compile }
+
+struct A {
+  template<typename T>
+  operator T() {
+    return 0;
+  }
+};
+
+template<typename U>
+void f(U(A::*)()) {}
+
+int main() {
+  &A::operator int;

I'm not sure this is valid..  resolve_nondeduced_context is concerned
with the case of resolving a template-id but here we have a
conversion-function-id.  Treating it as if it's a template-id
doesn't seem sound:

I think we should deduce U=int under
https://eel.is/c++draft/temp#deduct.conv
but as I just replied separately, this patch doesn't do that yet.

https://eel.is/c++draft/temp#mem-5 is also illustrative.

And the other compilers accept it: https://godbolt.org/z/8oehM37e1

Jason

Reply via email to