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:
struct A {
template<class T> operator T*();
};
int main() {
&A::operator long; // resolves to A::operator T* [with T=long]?!
}
> +
> + f(&A::operator int);
This seems invalid too. https://eel.is/c++draft/temp#deduct.call-6
says overload sets containing a function template are a non-deduced
context, so I don't see why we should deduce U=int.
> +}
>
> base-commit: b1987874feead5e98f1ea005bd1ce5ff515eda7a
> --
> 2.54.0
>
>