On 2026-09-16 01:53:09, Eczbek wrote:
> On 2026-06-11 02:08:12, Eczbek wrote:
>> On 6/10/26 20:01, Jason Merrill wrote:
>>> On 6/10/26 4:06 PM, Eczbek wrote:
>>>> On 6/10/26 15:39, Patrick Palka wrote:
>>>>> On Wed, 10 Jun 2026, Eczbek wrote:
>>>>>
>>>>>> On 6/10/26 09:27, Patrick Palka wrote:
>>>>>>> On Tue, 9 Jun 2026, Eczbek wrote:
>>>>>>>
>>>>>>>> On 6/9/26 10:08, Patrick Palka wrote:
>>>>>>>>> On Mon, 8 Jun 2026, Eczbek wrote:
>>>>>>>>>
>>>>>>>>>> On 6/5/26 11:16, Patrick Palka wrote:
>>>>>>>>>>> On Thu, 4 Jun 2026, Eczbek wrote:
>>>>>>>>>>>
>>>>>>>>>>>> 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?
>>>>>>>>>>>
>>>>>>>>>>> I think Jason's point is that the main commit message generally
>>>>>>>>>>> shouldn't be empty, even if it just repeats what you wrote in the
>>>>>>>>>>> ChangeLog.  Though generally the ChangeLog ought to describe how the
>>>>>>>>>>> code is changed, and the context/motivation of the change should be 
>>>>>>>>>>> in
>>>>>>>>>>> the main commit message, so there shouldn't be too much overlap.
>>>>>>>>>>> Here I'd just write:
>>>>>>>>>>>
>>>>>>>>>>>      (resolve_overloaded_unification): Call unify when resolving a
>>>>>>>>>>>      conversion-function-id.
>>>>>>>>>>>      (resolve_nondeduced_context): Likewise.
>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> -- >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);
>>>>>>>>>>>> +    }
>>>>>>>>>>>
>>>>>>>>>>> This needs to be done in a loop over each conversion template in the
>>>>>>>>>>> overload set because the result of deduction can differ for each
>>>>>>>>>>> template:
>>>>>>>>>>>
>>>>>>>>>>>    struct A {
>>>>>>>>>>>      template<class T> operator T();    // #1
>>>>>>>>>>>      template<class T> operator B<T>(); // #2
>>>>>>>>>>>    };
>>>>>>>>>>>
>>>>>>>>>>>    int main() {
>>>>>>>>>>>      &A::operator B<int>; // targs would be {B<int>} for #1 and 
>>>>>>>>>>> {int} for #2
>>>>>>>>>>>    }
>>>>>>>>>>>
>>>>>>>>>>> And instead of calling lookup_template_function to form a 
>>>>>>>>>>> template-id, I
>>>>>>>>>>> think we need to call instantiate_template to directly instantiate
>>>>>>>>>>> each template for which deduction succeeded.
>>>>>>>>>>>
>>>>>>>>>>> We could factor out all this into a helper
>>>>>>>>>>>
>>>>>>>>>>>    tree resolve_conversion_function_id (tree fns, tree optype)
>>>>>>>>>>>
>>>>>>>>>>> that takes a conversion operator overload set FNS and target
>>>>>>>>>>> type OPTYPE and returns an overload set containing the instantiated
>>>>>>>>>>> functions that match the target type.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Thanks, I have this:
>>>>>>>>>>
>>>>>>>>>> tree
>>>>>>>>>> resolve_conversion_function_id (tree fns, tree optype)
>>>>>>>>>> {
>>>>>>>>>>    tree overloads = NULL_TREE;
>>>>>>>>>>    for (lkp_iterator iter (fns); iter; ++iter)
>>>>>>>>>>      {
>>>>>>>>>>        tree tmpl = *iter;
>>>>>>>>>>        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));
>>>>>>>>>>        if (unify (tparms, targs, parm, optype, UNIFY_ALLOW_NONE, 
>>>>>>>>>> false))
>>>>>>>>>>     continue;
>>>>>>>>>>        tree fn = instantiate_template (tmpl, targs, tf_none);
>>>>>>>>>>        if (!constraints_satisfied_p (fn))
>>>>>>>>>>     continue;
>>>>>>>>>>        overloads = lookup_add (fn, overloads);
>>>>>>>>>>      }
>>>>>>>>>>    return overloads;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> But how can the most "specific" overload be selected from the 
>>>>>>>>>> returned set? Please advise.
>>>>>>>>>
>>>>>>>>> That's the partial ordering step of overload resolution, done by the 
>>>>>>>>> the
>>>>>>>>> 'tourney' function, see e.g perform_overload_resolution.  But I don't 
>>>>>>>>> think we
>>>>>>>>> want to do do partial ordering here, we should just reject the code 
>>>>>>>>> if there's
>>>>>>>>> more than one viable overload after this step.  So the previous 
>>>>>>>>> example
>>>>>>>>>
>>>>>>>>>     struct A {
>>>>>>>>>       template<class T> operator T();    // #1
>>>>>>>>>       template<class T> operator B<T>(); // #2
>>>>>>>>>     };
>>>>>>>>>       int main() {
>>>>>>>>>       &A::operator B<int>; // targs would be {B<int>} for #1 and 
>>>>>>>>> {int} for #2
>>>>>>>>>     }
>>>>>>>>>
>>>>>>>>> should be rejected despite #2 being more specialized than #1.
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> That seems incomplete to me. Both Clang and MSVC appear to select the 
>>>>>>>> most specialized overload: https://godbolt.org/z/q5a755bcK
>>>>>>>
>>>>>>> Good catch. GCC behaves the same and selects the most specialized 
>>>>>>> conversion
>>>>>>> function if we turn f into a non-template to sidestep template argument
>>>>>>> deduction:
>>>>>>>
>>>>>>>    void f(B<int>(A::*)());
>>>>>>>    int main() { f(&A::operator B<int>); }
>>>>>>>
>>>>>>> So the problem is that deduction fails to deduce T=B<int> for the 
>>>>>>> function
>>>>>>> template f.  Once we can convince GCC of that then it should work by 
>>>>>>> virtue of
>>>>>>> the non-template f case working.
>>>>>>>
>>>>>>> The analogous non-conversion-function testcase is:
>>>>>>>
>>>>>>>      template<class>
>>>>>>>      struct B {};
>>>>>>>
>>>>>>>      struct A {
>>>>>>>        template<class T> void g(T);
>>>>>>>        template<class T> void g(T) requires true;
>>>>>>>      };
>>>>>>>
>>>>>>>      template<class T>
>>>>>>>      void f(void(A::*)(T));
>>>>>>>
>>>>>>>      int main() { f(&A::g<int>); }
>>>>>>>
>>>>>>> which GCC does accept by deducing T=int for f, despite multiple function
>>>>>>> templates in the overload set.  So the problem is specific to conversion
>>>>>>> functions.
>>>>>>>
>>>>>>> Using your resolve_conversion_function_id implementation, the following
>>>>>>> change to resolve_overloaded_unification seems to do the right thing
>>>>>>> without needing to implement additional "more specialized" logic:
>>>>>>>
>>>>>>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>>>>>>> index 891e89f1d763..3f079457b455 100644
>>>>>>> --- a/gcc/cp/pt.cc
>>>>>>> +++ b/gcc/cp/pt.cc
>>>>>>> @@ -25336,8 +25336,12 @@ resolve_overloaded_unification (tree tparms,
>>>>>>>       arg = TREE_OPERAND (arg, 1);
>>>>>>>
>>>>>>>     /* Strip baselink information.  */
>>>>>>> +  tree optype = NULL_TREE;
>>>>>>>     if (BASELINK_P (arg))
>>>>>>> +    {
>>>>>>> +      optype = BASELINK_OPTYPE (arg);
>>>>>>>         arg = BASELINK_FUNCTIONS (arg);
>>>>>>> +    }
>>>>>>>
>>>>>>>     if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
>>>>>>>       {
>>>>>>> @@ -25401,6 +25405,9 @@ resolve_overloaded_unification (tree tparms,
>>>>>>>          not just the function on its own.  */
>>>>>>>       return false;
>>>>>>>     else
>>>>>>> +    {
>>>>>>> +      if (optype)
>>>>>>> +       arg = resolve_conversion_function_id (arg, optype);
>>>>>>>         for (lkp_iterator iter (arg); iter; ++iter)
>>>>>>>          {
>>>>>>>            tree fn = *iter;
>>>>>>> @@ -25417,6 +25424,7 @@ resolve_overloaded_unification (tree tparms,
>>>>>>>                ++good;
>>>>>>>              }
>>>>>>>          }
>>>>>>> +    }
>>>>>>>
>>>>>>>     /* [temp.deduct.type] A template-argument can be deduced from a 
>>>>>>> pointer
>>>>>>>        to function or pointer to member function argument if the set of
>>>>>>>
>>>>>>
>>>>>>
>>>>>> Thanks, that seems to work! Here's what I have so far, and my tests. 
>>>>>> (void)&D::operator int D::*; currently fails because 
>>>>>> resolve_nondeduced_context only accepts single overloads. How should it 
>>>>>> also select the most specialized overload?
>>>>>
>>>>> I'm not sure it should.  Clang doesn't accept that code either, right?
>>>>> In any case, let's ignore that case for now and treat it as a separate
>>>>> issue because we also don't accept the non-convfn version of that code:
>>>>>
>>>>>      template<class>
>>>>>      struct B {};
>>>>>
>>>>>      struct A {
>>>>>        template<class T> void g(T);
>>>>>        template<class T> void g(T) requires true;
>>>>>      };
>>>>>
>>>>>      template<class T>
>>>>>      void f(void(A::*)(T));
>>>>>
>>>>>      int main() {
>>>>>        &A::g<int>;
>>>>>      };
>>>>
>>>> Clang doesn't accept, but MSVC does. I agree it is a good idea to ignore 
>>>> this for now. Is there an existing bug report?
>>>>
>>>> Bootstrapped/regtested again. Is the ChangeLog OK?
>>>>
>>>> -- >8 --
>>>>
>>>> Taking the address of a conversion function template instantiation
>>>> incorrectly errors.
>>>>
>>>>     PR c++/122383
>>>>
>>>> gcc/cp/ChangeLog:
>>>>
>>>>     * pt.cc (resolve_conversion_function_id): Filter a conversion
>>>>     function overload set using unify.
>>>>     (resolve_overloaded_unification): Call
>>>>     resolve_conversion_function_id when resolving
>>>>     a conversion-function-id.
>>>>     (resolve_nondeduced_context): Likewise.
>>>
>>> I'm afraid this patch is too large to go in under the "legally 
>>> insignificant" exception we've been using for previous patches of yours; 
>>> any news on that FSF copyright assignment?
>>
>> I suspected as much. I will start that now.
> 
> I have copyright assignment now!

Forgot to CC the mailing list.

> 
>>
>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>>     * g++.dg/template/conv22.C: New test.
>>>> ---
>>>>   gcc/cp/pt.cc                           | 121 +++++++++++++++++--------
>>>>   gcc/testsuite/g++.dg/template/conv22.C |  69 ++++++++++++++
>>>>   2 files changed, 151 insertions(+), 39 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..912bb6b5185 100644
>>>> --- a/gcc/cp/pt.cc
>>>> +++ b/gcc/cp/pt.cc
>>>> @@ -25174,6 +25174,31 @@ type_unification_real (tree tparms,
>>>>     return unify_success (explain_p);
>>>>   }
>>>>   +/* Subroutine of resolve_overloaded_unification and
>>>> +   resolve_nondeduced_context.  FNS is a conversion operator overload set 
>>>> and
>>>> +   OPTYPE is the target type.  Returns an overload set containing the
>>>> +   instantiated functions that match the target type.  */
>>>> +
>>>> +tree
>>>> +resolve_conversion_function_id (tree fns, tree optype)
>>>> +{
>>>> +  tree overloads = NULL_TREE;
>>>> +  for (lkp_iterator iter (fns); iter; ++iter)
>>>> +    {
>>>> +      tree tmpl = *iter;
>>>> +      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));
>>>> +      if (unify (tparms, targs, parm, optype, UNIFY_ALLOW_NONE, false))
>>>> +    continue;
>>>> +      tree fn = instantiate_template (tmpl, targs, tf_none);
>>>> +      if (!constraints_satisfied_p (fn))
>>>> +    continue;
>>>> +      overloads = lookup_add (fn, overloads);
>>>> +    }
>>>> +  return overloads;
>>>> +}
>>>> +
>>>>   /* Subroutine of type_unification_real.  Args are like the variables
>>>>      at the call site.  ARG is an overloaded function (or template-id);
>>>>      we try deducing template args from each of the overloads, and if
>>>> @@ -25193,6 +25218,7 @@ resolve_overloaded_unification (tree tparms,
>>>>     int good = 0;
>>>>     tree goodfn = NULL_TREE;
>>>>     bool addr_p;
>>>> +  tree optype = NULL_TREE;
>>>>       if (TREE_CODE (arg) == ADDR_EXPR)
>>>>       {
>>>> @@ -25212,7 +25238,10 @@ resolve_overloaded_unification (tree tparms,
>>>>       /* Strip baselink information.  */
>>>>     if (BASELINK_P (arg))
>>>> -    arg = BASELINK_FUNCTIONS (arg);
>>>> +    {
>>>> +      optype = BASELINK_OPTYPE (arg);
>>>> +      arg = BASELINK_FUNCTIONS (arg);
>>>> +    }
>>>>       if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
>>>>       {
>>>> @@ -25276,22 +25305,26 @@ resolve_overloaded_unification (tree tparms,
>>>>          not just the function on its own.  */
>>>>       return false;
>>>>     else
>>>> -    for (lkp_iterator iter (arg); iter; ++iter)
>>>> -      {
>>>> -    tree fn = *iter;
>>>> -    if (flag_noexcept_type)
>>>> -      maybe_instantiate_noexcept (fn, tf_none);
>>>> -    if (TREE_CODE (fn) == FUNCTION_DECL && !constraints_satisfied_p (fn))
>>>> -      continue;
>>>> -    tree elem = TREE_TYPE (fn);
>>>> -    if (try_one_overload (tparms, targs, tempargs, parm, elem,
>>>> -                  strict, sub_strict, addr_p, explain_p)
>>>> -        && (!goodfn || !same_type_p (goodfn, elem)))
>>>> -      {
>>>> -        goodfn = elem;
>>>> -        ++good;
>>>> -      }
>>>> -      }
>>>> +    {
>>>> +      if (optype)
>>>> +    arg = resolve_conversion_function_id (arg, optype);
>>>> +      for (lkp_iterator iter (arg); iter; ++iter)
>>>> +    {
>>>> +      tree fn = *iter;
>>>> +      if (flag_noexcept_type)
>>>> +        maybe_instantiate_noexcept (fn, tf_none);
>>>> +      if (TREE_CODE (fn) == FUNCTION_DECL && !constraints_satisfied_p 
>>>> (fn))
>>>> +        continue;
>>>> +      tree elem = TREE_TYPE (fn);
>>>> +      if (try_one_overload (tparms, targs, tempargs, parm, elem,
>>>> +                    strict, sub_strict, addr_p, explain_p)
>>>> +          && (!goodfn || !same_type_p (goodfn, elem)))
>>>> +        {
>>>> +          goodfn = elem;
>>>> +          ++good;
>>>> +        }
>>>> +    }
>>>> +    }
>>>>       /* [temp.deduct.type] A template-argument can be deduced from a 
>>>> pointer
>>>>        to function or pointer to member function argument if the set of
>>>> @@ -25335,7 +25368,7 @@ resolve_overloaded_unification (tree tparms,
>>>>   tree
>>>>   resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
>>>>   {
>>>> -  tree expr, offset, baselink;
>>>> +  tree expr, offset, baselink, optype;
>>>>     bool addr;
>>>>       if (!type_unknown_p (orig_expr))
>>>> @@ -25345,6 +25378,7 @@ resolve_nondeduced_context (tree orig_expr, 
>>>> tsubst_flags_t complain)
>>>>     addr = false;
>>>>     offset = NULL_TREE;
>>>>     baselink = NULL_TREE;
>>>> +  optype = NULL_TREE;
>>>>       if (TREE_CODE (expr) == ADDR_EXPR)
>>>>       {
>>>> @@ -25359,14 +25393,14 @@ resolve_nondeduced_context (tree orig_expr, 
>>>> tsubst_flags_t complain)
>>>>     if (BASELINK_P (expr))
>>>>       {
>>>>         baselink = expr;
>>>> +      optype = BASELINK_OPTYPE (expr);
>>>>         expr = BASELINK_FUNCTIONS (expr);
>>>>       }
>>>>   +  int good = 0;
>>>> +  tree goodfn = NULL_TREE;
>>>>     if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
>>>>       {
>>>> -      int good = 0;
>>>> -      tree goodfn = NULL_TREE;
>>>> -
>>>>         /* If we got some explicit template args, we need to plug them into
>>>>        the affected templates before we try to unify, in case the
>>>>        explicit args will completely resolve the templates in question.  */
>>>> @@ -25403,28 +25437,37 @@ resolve_nondeduced_context (tree orig_expr, 
>>>> tsubst_flags_t complain)
>>>>           }
>>>>           }
>>>>       }
>>>> -      if (good == 1)
>>>> -    {
>>>> -      expr = goodfn;
>>>> -      if (baselink)
>>>> -        expr = build_baselink (BASELINK_BINFO (baselink),
>>>> -                   BASELINK_ACCESS_BINFO (baselink),
>>>> -                   expr, BASELINK_OPTYPE (baselink));
>>>> -      if (offset)
>>>> -        {
>>>> -          tree base
>>>> -        = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (offset, 0)));
>>>> -          expr = build_offset_ref (base, expr, addr, complain);
>>>> -        }
>>>> -      if (addr)
>>>> -        expr = cp_build_addr_expr (expr, complain);
>>>> -      return expr;
>>>> -    }
>>>> -      else if (good == 0 && badargs && (complain & tf_error))
>>>> +      if (good == 0 && badargs && (complain & tf_error))
>>>>       /* There were no good options and at least one bad one, so let the
>>>>          user know what the problem is.  */
>>>>       instantiate_template (badfn, badargs, complain);
>>>>       }
>>>> +  else if (optype)
>>>> +    {
>>>> +      expr = resolve_conversion_function_id (expr, optype);
>>>> +      if (OVL_SINGLE_P (expr))
>>>> +    {
>>>> +      goodfn = OVL_FIRST (expr);
>>>> +      good = 1;
>>>> +    }
>>>> +    }
>>>> +  if (good == 1)
>>>> +    {
>>>> +      expr = goodfn;
>>>> +      if (baselink)
>>>> +    expr = build_baselink (BASELINK_BINFO (baselink),
>>>> +                   BASELINK_ACCESS_BINFO (baselink),
>>>> +                   expr, BASELINK_OPTYPE (baselink));
>>>> +      if (offset)
>>>> +    {
>>>> +      tree base
>>>> +        = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (offset, 0)));
>>>> +      expr = build_offset_ref (base, expr, addr, complain);
>>>> +    }
>>>> +      if (addr)
>>>> +    expr = cp_build_addr_expr (expr, complain);
>>>> +      return expr;
>>>> +    }
>>>>     return orig_expr;
>>>>   }
>>>>   diff --git a/gcc/testsuite/g++.dg/template/conv22.C 
>>>> b/gcc/testsuite/g++.dg/template/conv22.C
>>>> new file mode 100644
>>>> index 00000000000..7cc85abc8c3
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/g++.dg/template/conv22.C
>>>> @@ -0,0 +1,69 @@
>>>> +// PR c++/122383
>>>> +// { dg-do compile { target c++20 } }
>>>> +
>>>> +struct A {
>>>> +  template<typename T>
>>>> +  operator T() {
>>>> +    return T();
>>>> +  }
>>>> +};
>>>> +
>>>> +struct B {
>>>> +  operator int() {
>>>> +    return 0;
>>>> +  }
>>>> +
>>>> +  template<typename T>
>>>> +  operator T() {
>>>> +    static_assert(false);
>>>> +  }
>>>> +};
>>>> +
>>>> +struct C {
>>>> +  template<typename T>
>>>> +  operator T() {
>>>> +    return T();
>>>> +  }
>>>> +
>>>> +  template<typename U>
>>>> +  operator U() requires(false) {
>>>> +    return U();
>>>> +  }
>>>> +};
>>>> +
>>>> +struct D {
>>>> +  template<typename T>
>>>> +  operator T() {
>>>> +    static_assert(false);
>>>> +  }
>>>> +
>>>> +  template<typename T, typename U>
>>>> +  operator T U::*() {
>>>> +    return 0;
>>>> +  }
>>>> +};
>>>> +
>>>> +template<typename R, typename C>
>>>> +void deduce(R(C::*)()) {}
>>>> +
>>>> +template<typename R, typename C1, typename C2>
>>>> +void deduce2(R C1::*(C2::*)()) {}
>>>> +
>>>> +void test() {
>>>> +  (void)&A::operator int;
>>>> +  auto a = &A::operator int;
>>>> +  deduce(&A::operator int);
>>>> +
>>>> +  (void)&B::operator int;
>>>> +  auto b = &B::operator int;
>>>> +  deduce(&B::operator int);
>>>> +
>>>> +  (void)&C::operator int;
>>>> +  auto c = &C::operator int;
>>>> +  deduce(&C::operator int);
>>>> +
>>>> +  // (void)&D::operator int D::*; // TODO
>>>> +  auto d = &D::operator int D::*;
>>>> +  deduce(&D::operator int D::*);
>>>> +  deduce2(&D::operator int D::*);
>>>> +}
>>>>
>>>> base-commit: b1987874feead5e98f1ea005bd1ce5ff515eda7a
>>>
>>
> 

Reply via email to