> On 17 Sep 2024, at 20:06, Jason Merrill <ja...@redhat.com> wrote:
>
> On 9/17/24 8:26 PM, Iain Sandoe wrote:
>>> On 17 Sep 2024, at 18:24, Jason Merrill <ja...@redhat.com> wrote:
>>>
>>> On 8/29/24 5:22 PM, Iain Sandoe wrote:
>>>> Tested on x86_64-darwin/linux, powerpc64le linux, OK for trunk?
>>>> thanks,
>>>> Iain
>>>> --- >8 ---
>>>> Awaiters always need to have a coroutine state frame copy since
>>>> they persist across potential supensions. It simplifies the later
>>>> analysis considerably to assign these early which we do when
>>>> building co_await expressions.
>>>> The cleanups in r15-3146-g47dbd69b1, unfortunately elided some of
>>>> processing used to cater for cases where the var created from an
>>>> xvalue, or is a pointer/reference type.
>>>
>>> This seems closely related to CWG2472, which was resolved as NAD; it sounds
>>> to me like an xvalue should be cast to an lvalue referring to the same
>>> object, not that it should be used to initialize a new variable of class
>>> type. See below...
>> Ah … I am not sure how to do that cast (mechanically) - but that would also
>> do what is required.
>
> int&& f();
> reinterpret_cast<int&>(f()) // lvalue
> -or-
> int&& r = f(); // r is an lvalue
(I was meaning more the APIs to implement the same action inside the compiler).
>
>>>> Corrected thus.
>>>> PR c++/116506
>>>> gcc/cp/ChangeLog:
>>>> * coroutines.cc (build_co_await): Ensure that xvalues are
>>>> materialised. Handle references/pointer values in awaiter
>>>> access expressions.
>>>> gcc/testsuite/ChangeLog:
>>>> * g++.dg/coroutines/pr116506.C: New test.
>>>> Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
>>>> ---
>>>> gcc/cp/coroutines.cc | 39 ++++++++++------
>>>> gcc/testsuite/g++.dg/coroutines/pr116506.C | 53 ++++++++++++++++++++++
>>>> 2 files changed, 77 insertions(+), 15 deletions(-)
>>>> create mode 100644 gcc/testsuite/g++.dg/coroutines/pr116506.C
>>>> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
>>>> index d4d74838eb4..d208ce429db 100644
>>>> --- a/gcc/cp/coroutines.cc
>>>> +++ b/gcc/cp/coroutines.cc
>>>> @@ -1130,13 +1130,12 @@ build_co_await (location_t loc, tree a,
>>>> suspend_point_kind suspend_kind,
>>>> if (o_type && !VOID_TYPE_P (o_type))
>>>> o_type = complete_type_or_else (o_type, o);
>>>> - if (!o_type)
>>>> + if (!o_type || o_type == error_mark_node)
>>>> return error_mark_node;
>>>> if (TREE_CODE (o_type) != RECORD_TYPE)
>>>> {
>>>> - error_at (loc, "awaitable type %qT is not a structure",
>>>> - o_type);
>>>> + error_at (loc, "awaitable type %qT is not a structure", o_type);
>>>> return error_mark_node;
>>>> }
>>>> @@ -1162,20 +1161,32 @@ build_co_await (location_t loc, tree a,
>>>> suspend_point_kind suspend_kind,
>>>> if (!glvalue_p (o))
>>>> o = get_target_expr (o, tf_warning_or_error);
>>>> - tree e_proxy = o;
>>>> - if (glvalue_p (o))
>>>> + /* We know that we need a coroutine state frame variable for the
>>>> awaiter,
>>>> + since it must persist across suspension; so where one is needed,
>>>> build
>>>> + it now. */
>>>> + if (INDIRECT_REF_P (o))
>>>> + o = TREE_OPERAND (o, 0);
>>>> + tree e_proxy = STRIP_NOPS (o);
>>>> + o_type = TREE_TYPE (e_proxy);
>>>
>>> So if you have an lvalue 'o' derived from a reference, this will change 'o'
>>> to be the reference, or if it's derived from a pointer, to the pointer.
>>> This seems like weird special-casing to me. If you need a frame variable,
>>> how about always creating a reference variable for glvalue o, regardless of
>>> how that glvalue was derived?
>>>
>>> Why would you need a variable for an xvalue, but not for an lvalue?
>> The intent is to ensure that awaiter instances are lvalues so that they are
>> correctly preserved across suspensions - the reason for calling them out
>> specifically (c.f. any other temporary) is that doing so makes the analysis
>> code simpler.
>
> My point is that being an lvalue is distinct from being a variable, except
> for prvalues that need to be materialized; an xvalue you can cast to an
> value, e.g.
>
> int&& f();
> reinterpret_cast<int&>(f()) // lvalue
>
> It's true that initializing a variable is a way to turn an xvalue into an
> lvalue without reinterpret_cast:
>
> int&& r = f(); // r is an lvalue
>
> but it's not clear to me that it's worth paying the space in the coroutine
> frame if we don't also need it for lvalue o.
>
> Why don't you need a variable to preserve o across suspensions if it's a call
> returning lvalue reference?
We always need a space for the awaiter, unless it is already a
variable/parameter (or part of one).
> I suspect that the simple case is not lvalue_p, but !TREE_SIDE_EFFECTS.
That is likely where I’m going wrong - we must not generate a variable for any
case that already has one (or a parm), but we must for any case that is a
temporary.
So, I should adjust the logic to use !TREE_SIDE_EFFECTS.
does the intention make sense now?
thanks
Iain
>
> Jason