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

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? I suspect that the simple case is not lvalue_p, but !TREE_SIDE_EFFECTS.

Jason

Reply via email to