Re: [PATCH] c++: resolvedness of resolve_nondeduced_context result [PR126406]

Jason Merrill <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On 7/30/26 10:31 AM, Patrick Palka wrote:
> On Thu, 30 Jul 2026, Jason Merrill wrote:
> 
>> On 7/29/26 3:40 PM, Patrick Palka wrote:
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
>>> OK for trunk/16?
>>>
>>> -- >8 --
>>>
>>> In r16-5967-gbae0ed69e1862a we removed the mark_used logic from
>>> resolve_nondeduced_context under the rationale that it should be the
>>> callers' responsiblity to mark it.  Resolving a template-id overload
>>> shouldn't constitute an ODR-used on its own,
>>
>> Hmm, https://eel.is/c++draft/basic#def.odr-4.1 (plus p8) seems to say it does,
>> as it's the selected member of an overload set in a potentially-evaluated
>> context.
> 
> I see, so resolve_nondeduced_context should call mark_used after all?
> And should it also call mark_used on non-template-id overloads?
> 
>> For r16-5967, I don't see why the patch made a difference to the testcase; in
>> convert_to_void resolve_nondeduced_function is followed by
>> mark_single_function, so we should return error_mark_node regardless of where
>> we first call mark_used.
> 
> The problem is that convert_to_void didn't propagate error_mark_node
> result from mark_used, instead it just returned void_node.  So we could
> have more simply fixed that PR by just propagating error_mark_node
> but I was under the impression that resolve_nondeduced_function shouldn't
> call mark_used at all which incidentally fixes the PR at a higher level
> (resolve_nondeduced_function can no longer return error_mark_node).
> 
>>> and callers would have to
>>> call mark_used anyway to uniformly handle all overloads, including
>>> non-template-id ones.
>>
>> Yes, so r16-5967 is consistent with the comment to mark_single_function.
> 
> But I thought the mentioned [basic.def.odr]/4.1 and /8 suggests
> resolve_nondeduced_function could safely call mark_single_function?

Yes, but the comment to mark_single_function suggests otherwise, and the 
standard_conversion case seems relevant.

Certainly the state before r16-5967 was inconsistent between template 
and non-template cases, and perhaps unconditionally calling 
mark_single_function would help to clarify the cases we need to handle 
differently.

I think maybe we used to mark single non-template functions immediately 
in finish_id_expression, but stopped to avoid duplicate diagnostics?

>>> Removing this logic however now means that resolve_nondeduced_context
>>> could return a specialization whose type is not yet fully resolved
>>> (i.e. has an uninstantiated noexcept or undeduced return type), and
>>> callers that immediately inspect TREE_TYPE of the result (such as
>>> standard_conversion and build_conditional_expr) now misbehave.
>>
>> I think the important case is standard_conversion; at that point we likely
>> haven't finished overload resolution, so the selection is still tentative and
>> so odr-use would be premature.  Though that's why we have tf_conv.  But then,
>> it looks like mark_used wrongly misses resolving auto if tf_conv.
> 
> Yeah, I'm not immediately sure whether tf_conv users expected it resolve
> auto and instaniate noexcept etc.

tf_conv is trying to make sense of a single candidate, which it can't do 
in general without resolving auto.

It shouldn't need to instantiate noexcept unless to match function 
pointer types.

>> In build_conditional_expr it looks like we no longer have anything that will
>> mark_used the resolved operand, i.e. we're missing a call to
>> mark_single_function.  Does this lead to missed instantiation if the return
>> type isn't deduced?
> 
> It causes us to reject the newly added cond2a with:
> 
>    cond2a.C:17:29: error: use of ‘decltype ((b ?  f<int> : <throw-expression>)) g() [with T = int; decltype ((b ?  f<int> : <throw-expression>)) = void (&)()]’ before deduction of ‘auto’
>
> And for
> 
>      bool b;
> 
>      template < class T > void f ()
>      {
>        __builtin_printf("Hello World!\n");
>      }
> 
>      template < class T > void g ()
>      {
>        auto p = !b ? f<int> : throw 0;
>        p();
>      }
> 
>      int main() {
>        g<int>();
>      }
> 
> it seems we eventually call mark_single_function on f<int> from
> cp_build_addr_expr_1, so no missed instantiation in that case at least.

OK, good.  We might add a comment about that after the resolve_.

I guess that also affects the 'addr' case in resolve_nondeduced_context.

>> The function comment for resolve_nondeduced_context should mention that most
>> uses also want mark_single_function.
> 
> They should _eventually_ call mark_single_function, not necessarily
> immediately after, right?

Right.

> For sake of backporting we should we then just revert r16-5967 and
> instead check error_mark_node result from mark_single_function
> in convert_to_void?

Yes, that sounds good for 16.  But it looks like we already do?

Jason
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.