> On 13 Jan 2026, at 11:02, Jason Merrill <[email protected]> wrote:
>
> On 1/9/26 6:01 PM, Iain Sandoe wrote:
>>> On 9 Jan 2026, at 08:37, Nathaniel Shead <[email protected]> wrote:
>>>
>>> On Fri, Jan 09, 2026 at 08:19:33AM +0000, Iain Sandoe wrote:
>>>> Hi Nathaniel.
>>>>
>>>> thanks for looking at this (both language features were in flux at the same
>>>> time and I don’t think the interaction was especially well-considered).
>>>>
>>>>> On 9 Jan 2026, at 04:39, Nathaniel Shead <[email protected]>
>>>>> wrote:
>>>>>
>>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
>>>>>
>>>>> -- >8 --
>>>>>
>>>>> While working on another issue I found that currently modules do not
>>>>> work with coroutines at all. This patch fixes a number of issues in
>>>>> both the coroutines logic and modules logic to ensure that they play
>>>>> well together. To summarize:
>>>>>
>>>>> - The coroutine proxy objects did not have a DECL_CONTEXT set (required
>>>>> for modules to merge declarations).
>>>>>
>>>>> - The coroutine transformation functions were always considered
>>>>> non-inline, even for an inline ramp function, which meant that modules
>>>>> didn't realise it needed to stream a definition.
>>>>
>>>> I am somewhat concerned about the proposed change here (it looks like
>>>> an ABI change - albeit an addition so, presumably, not breaking).
>>>>
>>>> The principle is that the three functions are all considered to be part of
>>>> the
>>>> same entity, where the user-visible interface is only the ramp and the
>>>> coroutine
>>>> handle.
>>>>
>>>> That is, I don’t think that this is an ‘exposure’ in the sense of P1815
>>>> since
>>>> the split into ramp/actor/destroyer is an internal detail invisible to the
>>>> end
>>>> user.
>>>>
>>>
>>> I think perhaps my wording wasn't clear; this wasn't so much about
>>> internal linkage (though that of course is also related) but about vague
>>> linkage. Consider the following TU:
>>>
>>> #include <coroutine>
>>> struct simple_promise;
>>> struct simple_coroutine : std::coroutine_handle<simple_promise> {
>>> using promise_type = ::simple_promise;
>>> };
>>> struct simple_promise {
>>> simple_coroutine get_return_object() { return {
>>> simple_coroutine::from_promise(*this) }; }
>>> std::suspend_always initial_suspend() noexcept { return {}; }
>>> std::suspend_always final_suspend() noexcept { return {}; }
>>> void return_void() {}
>>> void unhandled_exception() {}
>>> };
>>> inline simple_coroutine foo() {
>>> co_return;
>>> }
>>>
>>> We do not emit foo as it is unused, but we do emit the transform
>>> functions (e.g. _Z3fooP13_Z3foov.Frame.actor).
>> I think that is https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102528
>>> These functions are
>>> also not marked as '.globl' (they are not TREE_PUBLIC and so are
>>> considered internal to the TU), so a different TU calling a
>>> forward-declared 'foo' would get undefined references to the actor
>>> function etc.
>> I’m not sure what you mean by ‘forward-declared’ here; for foo() to be
>> usable there must be TU(s) in which foo() is emitted - that/those TU(s)
>> need to contain the helpers.
>>> My assumption was that the intention is that they are all meant to come
>>> along for the ride with each other wrt linkage; that is, in this case
>>> foo has vague linkage, so foo.actor and foo.destroy should be as well,
>>> and will be emitted iff foo is. Rather than every TU having copies of
>>> the transform functions.
>> I agree that this seems more space-efficient (at the expense of emitting more
>> vague-linkage symbols). I think it would, however break the assumptions
>> made if, for example, foo () in one TU was able to link against the helpers
>> in
>> another - since the details of the lowering are compiler-specific.
>
> We can avoid that by putting them all in the same comdat group.
I’ve drafted a patch on my coroutines WIP branch that does this, which should
work for ELF and PE-coff.
However, we still need to deal with platforms that do not support comdat
(or only support it in a limited way).
Iain
>
> Jason