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