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

Reply via email to