diff mbox series

c++, coroutines: Tidy up awaiter variable checks.

Message ID 20240821083422.63063-1-iain@sandoe.co.uk
State New
Headers show
Series c++, coroutines: Tidy up awaiter variable checks. | expand

Commit Message

Iain Sandoe Aug. 21, 2024, 8:34 a.m. UTC
Tested on x86_64-darwin, powerpc64le-linux, and against cppcoro and folly
coroutines testsuites, OK for trunk?
thanks
Iain

--- 8< ---

When we build an await expression, we might need to materialise the awaiter
if it is a prvalue.  This re-implements this using core APIs instead of local
code.

gcc/cp/ChangeLog:

	* coroutines.cc (build_co_await): Simplify checks for the cases that
	we need to materialise an awaiter.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
---
 gcc/cp/coroutines.cc | 59 +++++++++-----------------------------------
 1 file changed, 11 insertions(+), 48 deletions(-)

Comments

Jason Merrill Aug. 21, 2024, 8:27 p.m. UTC | #1
On 8/21/24 4:34 AM, Iain Sandoe wrote:
> Tested on x86_64-darwin, powerpc64le-linux, and against cppcoro and folly
> coroutines testsuites, OK for trunk?
> thanks
> Iain
> 
> --- 8< ---
> 
> When we build an await expression, we might need to materialise the awaiter
> if it is a prvalue.  This re-implements this using core APIs instead of local
> code.
> 
> gcc/cp/ChangeLog:
> 
> 	* coroutines.cc (build_co_await): Simplify checks for the cases that
> 	we need to materialise an awaiter.
> 
> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
> ---
>   gcc/cp/coroutines.cc | 59 +++++++++-----------------------------------
>   1 file changed, 11 insertions(+), 48 deletions(-)
> 
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index 3356e7f5b24..1f1ea5c2fe4 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -1149,55 +1149,18 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind,
>     if (!awrs_meth || awrs_meth == error_mark_node)
>       return error_mark_node;
>   
> -  /* To complete the lookups, we need an instance of 'e' which is built from
> -     'o' according to [expr.await] 3.4.
> -
> -     If we need to materialize this as a temporary, then that will have to be
> -     'promoted' to a coroutine frame var.  However, if the awaitable is a
> -     user variable, parameter or comes from a scope outside this function,
> -     then we must use it directly - or we will see unnecessary copies.
> -
> -     If o is a variable, find the underlying var.  */
> -  tree e_proxy = STRIP_NOPS (o);
> -  if (INDIRECT_REF_P (e_proxy))
> -    e_proxy = TREE_OPERAND (e_proxy, 0);
> -  while (TREE_CODE (e_proxy) == COMPONENT_REF)
> -    {
> -      e_proxy = TREE_OPERAND (e_proxy, 0);
> -      if (INDIRECT_REF_P (e_proxy))
> -	e_proxy = TREE_OPERAND (e_proxy, 0);
> -      if (TREE_CODE (e_proxy) == CALL_EXPR)
> -	{
> -	  /* We could have operator-> here too.  */
> -	  tree op = TREE_OPERAND (CALL_EXPR_FN (e_proxy), 0);
> -	  if (DECL_OVERLOADED_OPERATOR_P (op)
> -	      && DECL_OVERLOADED_OPERATOR_IS (op, COMPONENT_REF))
> -	    {
> -	      e_proxy = CALL_EXPR_ARG (e_proxy, 0);
> -	      STRIP_NOPS (e_proxy);
> -	      gcc_checking_assert (TREE_CODE (e_proxy) == ADDR_EXPR);
> -	      e_proxy = TREE_OPERAND (e_proxy, 0);
> -	    }
> -	}
> -      STRIP_NOPS (e_proxy);
> -    }
> -
> -  /* Only build a temporary if we need it.  */
> -  STRIP_NOPS (e_proxy);
> -  if (TREE_CODE (e_proxy) == PARM_DECL
> -      || (VAR_P (e_proxy) && !is_local_temp (e_proxy)))
> +  /* [expr.await]/3.3 If o would be a prvalue, the temporary
> +     materialization conversion ([conv.rval]) is applied.  */
> +  if (!glvalue_p (o) && !xvalue_p (o))
> +    o = build_target_expr_with_type (o, TREE_TYPE (o), tf_warning_or_error);

Maybe get_target_expr instead?

> +
> +  tree e_proxy = o;
> +  if (glvalue_p (o))
> +    o = NULL_TREE; /* Use the existing entity.  */
> +  else /* We need to materialise it.  */
>       {
> -      e_proxy = o;
> -      o = NULL_TREE; /* The var is already present.  */
> -    }
> -  else
> -    {
> -      tree p_type = o_type;
> -      if (glvalue_p (o))
> -	p_type = cp_build_reference_type (p_type, !lvalue_p (o));
> -      e_proxy = get_awaitable_var (suspend_kind, p_type);
> -      o = cp_build_modify_expr (loc, e_proxy, INIT_EXPR, o,
> -				tf_warning_or_error);
> +      e_proxy = get_awaitable_var (suspend_kind, o_type);
> +      o = cp_build_init_expr (loc, e_proxy, convert_from_reference (o));

Why convert_from_reference (o)?  If o were a reference, so would o_type 
be, and therefore e_proxy, and so this would just create a type mismatch.

Jason
diff mbox series

Patch

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3356e7f5b24..1f1ea5c2fe4 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1149,55 +1149,18 @@  build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind,
   if (!awrs_meth || awrs_meth == error_mark_node)
     return error_mark_node;
 
-  /* To complete the lookups, we need an instance of 'e' which is built from
-     'o' according to [expr.await] 3.4.
-
-     If we need to materialize this as a temporary, then that will have to be
-     'promoted' to a coroutine frame var.  However, if the awaitable is a
-     user variable, parameter or comes from a scope outside this function,
-     then we must use it directly - or we will see unnecessary copies.
-
-     If o is a variable, find the underlying var.  */
-  tree e_proxy = STRIP_NOPS (o);
-  if (INDIRECT_REF_P (e_proxy))
-    e_proxy = TREE_OPERAND (e_proxy, 0);
-  while (TREE_CODE (e_proxy) == COMPONENT_REF)
-    {
-      e_proxy = TREE_OPERAND (e_proxy, 0);
-      if (INDIRECT_REF_P (e_proxy))
-	e_proxy = TREE_OPERAND (e_proxy, 0);
-      if (TREE_CODE (e_proxy) == CALL_EXPR)
-	{
-	  /* We could have operator-> here too.  */
-	  tree op = TREE_OPERAND (CALL_EXPR_FN (e_proxy), 0);
-	  if (DECL_OVERLOADED_OPERATOR_P (op)
-	      && DECL_OVERLOADED_OPERATOR_IS (op, COMPONENT_REF))
-	    {
-	      e_proxy = CALL_EXPR_ARG (e_proxy, 0);
-	      STRIP_NOPS (e_proxy);
-	      gcc_checking_assert (TREE_CODE (e_proxy) == ADDR_EXPR);
-	      e_proxy = TREE_OPERAND (e_proxy, 0);
-	    }
-	}
-      STRIP_NOPS (e_proxy);
-    }
-
-  /* Only build a temporary if we need it.  */
-  STRIP_NOPS (e_proxy);
-  if (TREE_CODE (e_proxy) == PARM_DECL
-      || (VAR_P (e_proxy) && !is_local_temp (e_proxy)))
+  /* [expr.await]/3.3 If o would be a prvalue, the temporary
+     materialization conversion ([conv.rval]) is applied.  */
+  if (!glvalue_p (o) && !xvalue_p (o))
+    o = build_target_expr_with_type (o, TREE_TYPE (o), tf_warning_or_error);
+
+  tree e_proxy = o;
+  if (glvalue_p (o))
+    o = NULL_TREE; /* Use the existing entity.  */
+  else /* We need to materialise it.  */
     {
-      e_proxy = o;
-      o = NULL_TREE; /* The var is already present.  */
-    }
-  else
-    {
-      tree p_type = o_type;
-      if (glvalue_p (o))
-	p_type = cp_build_reference_type (p_type, !lvalue_p (o));
-      e_proxy = get_awaitable_var (suspend_kind, p_type);
-      o = cp_build_modify_expr (loc, e_proxy, INIT_EXPR, o,
-				tf_warning_or_error);
+      e_proxy = get_awaitable_var (suspend_kind, o_type);
+      o = cp_build_init_expr (loc, e_proxy, convert_from_reference (o));
       e_proxy = convert_from_reference (e_proxy);
     }