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
> 
> 

Reply via email to