[gcc r15-3144] testsuite: Add dg-require-effective-target scheduling for some tests that set -fschedule-insns.

2024-08-24 Thread Georg-Johann Lay via Gcc-cvs
https://gcc.gnu.org/g:ac826d2f5b1fcd6c9356d5c77a1a0ef927ae2701

commit r15-3144-gac826d2f5b1fcd6c9356d5c77a1a0ef927ae2701
Author: Georg-Johann Lay 
Date:   Sat Aug 24 10:23:39 2024 +0200

testsuite: Add dg-require-effective-target scheduling for some tests that 
set -fschedule-insns.

gcc/testsuite/
* gcc.dg/torture/pr115929-2.c: Add dg-require-effective-target 
scheduling.
* gcc.dg/torture/pr116343.c: Same.

Diff:
---
 gcc/testsuite/gcc.dg/torture/pr115929-2.c | 1 +
 gcc/testsuite/gcc.dg/torture/pr116343.c   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/testsuite/gcc.dg/torture/pr115929-2.c 
b/gcc/testsuite/gcc.dg/torture/pr115929-2.c
index c8473a74da6c..02496d54d798 100644
--- a/gcc/testsuite/gcc.dg/torture/pr115929-2.c
+++ b/gcc/testsuite/gcc.dg/torture/pr115929-2.c
@@ -1,4 +1,5 @@
 /* { dg-additional-options "-fschedule-insns" } */
+/* { dg-require-effective-target scheduling } */
 
 int a, b, c, d, e, f;
 int main() {
diff --git a/gcc/testsuite/gcc.dg/torture/pr116343.c 
b/gcc/testsuite/gcc.dg/torture/pr116343.c
index ad13f0fc21c1..287a09707ec4 100644
--- a/gcc/testsuite/gcc.dg/torture/pr116343.c
+++ b/gcc/testsuite/gcc.dg/torture/pr116343.c
@@ -1,4 +1,5 @@
 // { dg-additional-options "-fschedule-insns -fno-thread-jumps -fno-dce" }
+/* { dg-require-effective-target scheduling } */
 
 int a, b, c;
 volatile int d;


[gcc r15-3145] c++: Add testcase for (now fixed) regression [PR113746]

2024-08-24 Thread Simon Martin via Gcc-cvs
https://gcc.gnu.org/g:1d09ccc4a5fe7c9a3dd37fcef34c1523a5c95819

commit r15-3145-g1d09ccc4a5fe7c9a3dd37fcef34c1523a5c95819
Author: Simon Martin 
Date:   Fri Aug 23 10:49:31 2024 +0200

c++: Add testcase for (now fixed) regression [PR113746]

The case in PR113746 used to ICE until commit r15-123-gf04dc89a991ddc.
This patch simply adds the case to the testsuite.

PR c++/113746

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash76.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/parse/crash76.C | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/gcc/testsuite/g++.dg/parse/crash76.C 
b/gcc/testsuite/g++.dg/parse/crash76.C
new file mode 100644
index ..6fbd1fa9f7eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash76.C
@@ -0,0 +1,6 @@
+// PR c++/113746
+// { dg-do compile }
+
+template struct S { // { dg-error "not been declared" }
+  enum { e0 = 0, e00 = e0 };
+};


[gcc r15-3146] c++, coroutines: Tidy up awaiter variable checks.

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:47dbd69b1b31d34e28bf617d7991e6ad6a8bb957

commit r15-3146-g47dbd69b1b31d34e28bf617d7991e6ad6a8bb957
Author: Iain Sandoe 
Date:   Thu Aug 22 08:10:14 2024 +0100

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

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 

Diff:
---
 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 7af2a1885615..d1d2164bb293 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))
+o = get_target_expr (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, o);
   e_proxy = convert_from_reference (e_proxy);
 }


[gcc r15-3147] c++, coroutines: Split the ramp build into a separate function.

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:d5da5f00d91a8344fdb366c317366bd8e93ad1b8

commit r15-3147-gd5da5f00d91a8344fdb366c317366bd8e93ad1b8
Author: Iain Sandoe 
Date:   Sat Aug 10 12:43:36 2024 +0100

c++, coroutines: Split the ramp build into a separate function.

This is primarily preparation to partition the functionality of the
coroutine transform into analysis, ramp generation and then (later)
synthesis of the coroutine body.  The patch does fix one latent
issue in the ordering of DTORs for frame parameter copies (to ensure
that they are processed in reverse order to the copy creation).

gcc/cp/ChangeLog:

* coroutines.cc (build_actor_fn): Arrange to apply any
required parameter copy DTORs in reverse order to their
creation.
(coro_rewrite_function_body): Handle revised param uses.
(morph_fn_to_coro): Split the ramp function completion
into a separate function.
(build_ramp_function): New.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc | 384 +++
 1 file changed, 201 insertions(+), 183 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index d1d2164bb293..759b16096d45 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2298,7 +2298,7 @@ static void
 build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
tree orig, hash_map *local_var_uses,
hash_map *suspend_points,
-   vec *param_dtor_list,
+   vec *param_dtor_list,
tree resume_idx_var, unsigned body_count, tree frame_size)
 {
   verify_stmt_tree (fnbody);
@@ -2513,19 +2513,15 @@ build_actor_fn (location_t loc, tree coro_frame_type, 
tree actor, tree fnbody,
   fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x);
   tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node);
   finish_if_stmt_cond (cmp, need_free_if);
-  if (param_dtor_list != NULL)
+  while (!param_dtor_list->is_empty ())
 {
-  int i;
-  tree pid;
-  FOR_EACH_VEC_ELT (*param_dtor_list, i, pid)
-   {
- tree m
-   = lookup_member (coro_frame_type, pid, 1, 0, tf_warning_or_error);
- tree a = build_class_member_access_expr (actor_frame, m, NULL_TREE,
-  false, tf_warning_or_error);
- if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error))
-   add_stmt (dtor);
-   }
+  tree pid = param_dtor_list->pop ();
+  tree m = lookup_member (coro_frame_type, pid, 1, 0, tf_warning_or_error);
+  gcc_checking_assert (m);
+  tree a = build_class_member_access_expr (actor_frame, m, NULL_TREE,
+   false, tf_warning_or_error);
+  if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error))
+   add_stmt (dtor);
 }
 
   /* Build the frame DTOR.  */
@@ -3965,13 +3961,11 @@ rewrite_param_uses (tree *stmt, int *do_subtree 
ATTRIBUTE_UNUSED, void *d)
 /* Build up a set of info that determines how each param copy will be
handled.  */
 
-static hash_map *
-analyze_fn_parms (tree orig)
+static void
+analyze_fn_parms (tree orig, hash_map *param_uses)
 {
   if (!DECL_ARGUMENTS (orig))
-return NULL;
-
-  hash_map *param_uses = new hash_map;
+return;
 
   /* Build a hash map with an entry for each param.
  The key is the param tree.
@@ -4038,8 +4032,6 @@ analyze_fn_parms (tree orig)
   else
parm.trivial_dtor = true;
 }
-
-  return param_uses;
 }
 
 /* Small helper for the repetitive task of adding a new field to the coro
@@ -4339,13 +4331,13 @@ coro_rewrite_function_body (location_t fn_start, tree 
fnbody, tree orig,
   add_decl_expr (var);
 
   /* If we have function parms, then these will be copied to the coroutine
- frame.  Create a local (proxy) variable for each parm, since the original
- parms will be out of scope once the ramp has finished. The proxy vars will
+ frame as per [dcl.fct.def.coroutine] / 13.
+ Here, we create a local (proxy) variable for each parm, since the original
+ parms will be out of scope once the ramp has finished.  The proxy vars 
will
  get DECL_VALUE_EXPRs pointing to the frame copies, so that we can interact
  with them in the debugger.  */
-  if (param_uses)
+  if (DECL_ARGUMENTS (orig))
 {
-  gcc_checking_assert (DECL_ARGUMENTS (orig));
   /* Add a local var for each parm.  */
   for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
   arg = DECL_CHAIN (arg))
@@ -4360,7 +4352,7 @@ coro_rewrite_function_body (location_t fn_start, tree 
fnbody, tree orig,
  DECL_CHAIN (parm_i->copy_var) = var_list;
  var_list = parm_i->copy_var;
  add_decl_expr (parm_i->copy_var);
-   }
+   }
 
   /* Now replace all uses of the parms in the function body with the proxy
  

[gcc r15-3148] c++, coroutines: Separate the analysis, ramp and outlined function synthesis.

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:6303cd7e41546e95c436bd274cc972674230fe1c

commit r15-3148-g6303cd7e41546e95c436bd274cc972674230fe1c
Author: Iain Sandoe 
Date:   Wed Aug 14 17:18:32 2024 +0100

c++, coroutines: Separate the analysis, ramp and outlined function 
synthesis.

This change is preparation for fixes to the ramp and codegen to follow.

The primary motivation is that we have thee activities; analysis, ramp
synthesis and outlined coroutine body synthesis.  These are currently
carried out in sequence in the 'morph_fn_to_coro' code, which means that
we are nesting the synthesis of the outlined coroutine body inside the
finish_function call for the original function (which becomes the ramp).

The revised code splits the three interests so that the analysis can be
used independently by the ramp and body synthesis.  This avoids some issues
seen with global state that start/finish function use and allows us to
use more of the high-level APIs in fixing bugs.

The resultant implementation is more self-contained, and has less impact
on finish_function.

gcc/cp/ChangeLog:

* coroutines.cc (struct suspend_point_info, struct param_info,
struct local_var_info, struct susp_frame_data,
struct local_vars_frame_data): Move to coroutines.h.
(build_actor_fn): Use start/finish function APIs.
(build_destroy_fn): Likewise.
(coro_build_actor_or_destroy_function): No longer mark the
actor / destroyer as DECL_COROUTINE_P.
(coro_rewrite_function_body): Use class members.
(cp_coroutine_transform::wrap_original_function_body): Likewise.
(build_ramp_function): Replace by...
(cp_coroutine_transform::complete_ramp_function): ...this.
(cp_coroutine_transform::cp_coroutine_transform): New.
(cp_coroutine_transform::~cp_coroutine_transform): New
(morph_fn_to_coro): Replace by...
(cp_coroutine_transform::apply_transforms): ...this.
(cp_coroutine_transform::finish_transforms): New.
* cp-tree.h (morph_fn_to_coro): Remove.
* decl.cc (emit_coro_helper): Remove.
(finish_function): Revise handling of coroutine transforms.
* coroutines.h: New file.

Signed-off-by: Iain Sandoe 
Co-authored-by: Arsen Arsenović 

Diff:
---
 gcc/cp/coroutines.cc | 647 ++-
 gcc/cp/coroutines.h  | 132 +++
 gcc/cp/cp-tree.h |   1 -
 gcc/cp/decl.cc   |  80 +++
 4 files changed, 446 insertions(+), 414 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 759b16096d45..a7d4021c6c1c 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gcc-rich-location.h"
 #include "hash-map.h"
+#include "coroutines.h"
 
 static bool coro_promise_type_found_p (tree, location_t);
 
@@ -2049,16 +2050,6 @@ await_statement_expander (tree *stmt, int *do_subtree, 
void *d)
   return res;
 }
 
-/* Suspend point hash_map.  */
-
-struct suspend_point_info
-{
-  /* coro frame field type.  */
-  tree awaitable_type;
-  /* coro frame field name.  */
-  tree await_field_id;
-};
-
 struct await_xform_data
 {
   tree actor_fn;   /* Decl for context.  */
@@ -2136,37 +2127,6 @@ transform_await_wrapper (tree *stmt, int *do_subtree, 
void *d)
   return NULL_TREE;
 }
 
-/* This caches information that we determine about function params,
-   their uses and copies in the coroutine frame.  */
-
-struct param_info
-{
-  tree field_id; /* The name of the copy in the coroutine frame.  */
-  tree copy_var; /* The local var proxy for the frame copy.  */
-  vec *body_uses; /* Worklist of uses, void if there are none.  */
-  tree frame_type;   /* The type used to represent this parm in the frame.  */
-  tree orig_type;/* The original type of the parm (not as passed).  */
-  tree guard_var;/* If we need a DTOR on exception, this bool guards it.  
*/
-  tree fr_copy_dtor; /* If we need a DTOR on exception, this is it.  */
-  bool by_ref;   /* Was passed by reference.  */
-  bool pt_ref;   /* Was a pointer to object.  */
-  bool rv_ref;   /* Was an rvalue ref.  */
-  bool trivial_dtor; /* The frame type has a trivial DTOR.  */
-  bool this_ptr; /* Is 'this' */
-  bool lambda_cobj;  /* Lambda capture object */
-};
-
-struct local_var_info
-{
-  tree field_id;
-  tree field_idx;
-  tree frame_type;
-  bool is_lambda_capture;
-  bool is_static;
-  bool has_value_expr_p;
-  location_t def_loc;
-};
-
 /* For figuring out what local variable usage we have.  */
 struct local_vars_transform
 {
@@ -2299,7 +2259,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, 
tree actor, tree fnbody,
tree orig, hash_map *local_var_uses,
hash_map *suspend_points

[gcc r15-3149] c++, coroutines: Separate allocator work from the ramp body build.

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:624fb5b4407b4b9c23ca813a49b928d650d52480

commit r15-3149-g624fb5b4407b4b9c23ca813a49b928d650d52480
Author: Iain Sandoe 
Date:   Fri Aug 16 17:56:57 2024 +0100

c++, coroutines: Separate allocator work from the ramp body build.

This splits out the building of the allocation and deallocation expressions
and runs them early in the ramp build, so that we can exit if they are not
usable, before we start building the ramp body.

Likewise move checks for other required resources to the begining of the
ramp builder.

This is preparation for work needed to update the allocation/destruction
in cases where we have excess alignment of the promise or other saved frame
state.

gcc/cp/ChangeLog:

* call.cc (build_op_delete_call_1): Renamed and added a param
to allow the caller to prioritize two argument usual deleters.
(build_op_delete_call): New.
(build_coroutine_op_delete_call): New.
* coroutines.cc (coro_get_frame_dtor): Rename...
(build_coroutine_frame_delete_expr):... to this; simplify to
use build_op_delete_call for all cases.
(build_actor_fn): Use revised frame delete function.
(build_coroutine_frame_alloc_expr): New.
(cp_coroutine_transform::complete_ramp_function): Rename...
(cp_coroutine_transform::build_ramp_function): ... to this.
Reorder code to carry out checks for prerequisites before the
codegen. Split out the allocation/delete code.
(cp_coroutine_transform::apply_transforms): Use revised name.
* coroutines.h: Rename function.
* cp-tree.h (build_coroutine_op_delete_call): New.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: Use revised
diagnostics.
* g++.dg/coroutines/coro-bad-gro-00-class-gro-scalar-return.C:
Likewise.
* g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C:
Likewise.
* g++.dg/coroutines/coro-bad-grooaf-00-static.C: Likewise.
* g++.dg/coroutines/ramp-return-b.C: Likewise.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/call.cc |  34 +-
 gcc/cp/coroutines.cc   | 452 +++--
 gcc/cp/coroutines.h|   2 +-
 gcc/cp/cp-tree.h   |   3 +
 .../coroutines/coro-bad-alloc-01-bad-op-del.C  |   2 +-
 .../coro-bad-gro-00-class-gro-scalar-return.C  |   4 +-
 .../coro-bad-gro-01-void-gro-non-class-coro.C  |   4 +-
 .../g++.dg/coroutines/coro-bad-grooaf-00-static.C  |   6 +-
 gcc/testsuite/g++.dg/coroutines/ramp-return-b.C|   8 +-
 9 files changed, 280 insertions(+), 235 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 0fe679aae9fe..623e4c66c117 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7851,6 +7851,9 @@ usual_deallocation_fn_p (tree fn)
SIZE is the size of the memory block to be deleted.
GLOBAL_P is true if the delete-expression should not consider
class-specific delete operators.
+   CORO_P is true if the allocation is for a coroutine, where the two argument
+   usual deallocation should be chosen in preference to the single argument
+   version in a class context.
PLACEMENT is the corresponding placement new call, or NULL_TREE.
 
If this call to "operator delete" is being generated as part to
@@ -7859,10 +7862,10 @@ usual_deallocation_fn_p (tree fn)
we call a deallocation function), then ALLOC_FN is the allocation
function.  */
 
-tree
-build_op_delete_call (enum tree_code code, tree addr, tree size,
- bool global_p, tree placement,
- tree alloc_fn, tsubst_flags_t complain)
+static tree
+build_op_delete_call_1 (enum tree_code code, tree addr, tree size,
+   bool global_p, bool coro_p, tree placement,
+   tree alloc_fn, tsubst_flags_t complain)
 {
   tree fn = NULL_TREE;
   tree fns, fnname, type, t;
@@ -8041,7 +8044,7 @@ build_op_delete_call (enum tree_code code, tree addr, 
tree size,
/* -- If the deallocation functions have class scope, the one
   without a parameter of type std::size_t is selected.  */
bool want_size;
-   if (DECL_CLASS_SCOPE_P (fn))
+   if (DECL_CLASS_SCOPE_P (fn) && !coro_p)
  want_size = false;
 
/* -- If the type is complete and if, for the second alternative
@@ -8179,6 +8182,27 @@ build_op_delete_call (enum tree_code code, tree addr, 
tree size,
   return error_mark_node;
 }
 
+/* Arguments as per build_op_delete_call_1 ().  */
+
+tree
+build_op_delete_call (enum tree_code code, tree addr, tree size, bool global_p,
+ tree placement, tree alloc_fn, tsubst_flags_t complain)
+{
+

[gcc r15-3150] c++, coroutines: Fix handling of early exceptions [PR113773].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:efc99ab2d5fdb7f2a942199b0e5b16e1e2bb8c27

commit r15-3150-gefc99ab2d5fdb7f2a942199b0e5b16e1e2bb8c27
Author: Iain Sandoe 
Date:   Sat Aug 17 12:49:41 2024 +0100

c++, coroutines: Fix handling of early exceptions [PR113773].

The responsibility for destroying part of the frame content (promise,
arg copies and the frame itself) transitions from the ramp to the
body of the coroutine once we reach the await_resume () for the
initial suspend.

We added the variable that flags the transition, but failed to act on
it.  This corrects that so that the ramp only tries to run DTORs for
objects when an exception occurs before the initial suspend await
resume has started.

PR c++/113773

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Only cleanup the
frame state on exceptions that occur before the initial await
resume has begun.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/torture/pr113773.C: New test.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   | 39 -
 gcc/testsuite/g++.dg/coroutines/torture/pr113773.C | 66 ++
 2 files changed, 92 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 77dce83adba1..cbe99ac87016 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -5119,12 +5119,22 @@ cp_coroutine_transform::build_ramp_function ()
  finish_if_stmt_cond (coro_gro_live, gro_d_if);
  finish_expr_stmt (gro_ret_dtor);
  finish_then_clause (gro_d_if);
- tree gro_d_if_scope = IF_SCOPE (gro_d_if);
- IF_SCOPE (gro_d_if) = NULL;
- gro_d_if = do_poplevel (gro_d_if_scope);
- add_stmt (gro_d_if);
+ finish_if_stmt (gro_d_if);
}
 
+  /* Before initial resume is called, the responsibility for cleanup on
+exception falls to the ramp.  After that, the coroutine body code
+should do the cleanup.  */
+  tree iarc_m = lookup_member (frame_type, coro_frame_i_a_r_c_id,
+  1, 0, tf_warning_or_error);
+  tree iarc_x
+   = build_class_member_access_expr (deref_fp, iarc_m, NULL_TREE,
+ /*preserve_reference*/false,
+ tf_warning_or_error);
+  tree not_iarc
+   = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, iarc_x);
+  tree cleanup_if = begin_if_stmt ();
+  finish_if_stmt_cond (not_iarc, cleanup_if);
   /* If the promise is live, then run its dtor if that's available.  */
   if (promise_dtor && promise_dtor != error_mark_node)
{
@@ -5132,10 +5142,7 @@ cp_coroutine_transform::build_ramp_function ()
  finish_if_stmt_cond (coro_promise_live, promise_d_if);
  finish_expr_stmt (promise_dtor);
  finish_then_clause (promise_d_if);
- tree promise_d_if_scope = IF_SCOPE (promise_d_if);
- IF_SCOPE (promise_d_if) = NULL;
- promise_d_if = do_poplevel (promise_d_if_scope);
- add_stmt (promise_d_if);
+ finish_if_stmt (promise_d_if);
}
 
   /* Clean up any frame copies of parms with non-trivial dtors.
@@ -5159,15 +5166,21 @@ cp_coroutine_transform::build_ramp_function ()
  finish_if_stmt_cond (parm_i->guard_var, dtor_if);
  finish_expr_stmt (parm_i->fr_copy_dtor);
  finish_then_clause (dtor_if);
- tree parm_d_if_scope = IF_SCOPE (dtor_if);
- IF_SCOPE (dtor_if) = NULL;
- dtor_if = do_poplevel (parm_d_if_scope);
- add_stmt (dtor_if);
+ finish_if_stmt (dtor_if);
}
}
 
-  /* We always expect to delete the frame.  */
+  /* No delete the frame if required.  */
+  tree fnf_if = begin_if_stmt ();
+  finish_if_stmt_cond (fnf_x, fnf_if);
   finish_expr_stmt (delete_frame_call);
+  finish_then_clause (fnf_if);
+  finish_if_stmt (fnf_if);
+
+  /* Finished cleanups conditional on "initial resume is not called".  */
+  finish_then_clause (cleanup_if);
+  finish_if_stmt (cleanup_if);
+
   tree rethrow = build_throw (loc, NULL_TREE, tf_warning_or_error);
   suppress_warning (rethrow);
   finish_expr_stmt (rethrow);
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr113773.C 
b/gcc/testsuite/g++.dg/coroutines/torture/pr113773.C
new file mode 100644
index ..b048b0d63f46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/pr113773.C
@@ -0,0 +1,66 @@
+//  { dg-do run }
+#include 
+#ifdef OUTPUT
+#include 
+#endif
+
+struct result {
+  operator int() {
+throw 42;
+  }
+};
+
+static int p_dtor_count = 0;
+class promise {
+public:
+  result get_return_object() { return {}; }
+  std::suspend_never initial_suspend() {
+#ifdef OUTPUT
+   

[gcc r15-3151] c++, coroutines: Only allow void get_return_object if the ramp is void [PR100476].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:a0b431033c307982123abbff752045cfe7eda47f

commit r15-3151-ga0b431033c307982123abbff752045cfe7eda47f
Author: Iain Sandoe 
Date:   Sat Aug 17 15:47:58 2024 +0100

c++, coroutines: Only allow void get_return_object if the ramp is void 
[PR100476].

Require that the value returned by get_return_object is convertible to
the ramp return.  This means that the only time we allow a void
get_return_object, is when the ramp is also a void function.

We diagnose this early to allow us to exit the ramp build if the return
values are incompatible.

PR c++/100476

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Remove special
handling of void get_return_object expressions.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C:
Adjust expected diagnostic.
* g++.dg/coroutines/pr102489.C: Avoid void get_return_object.
* g++.dg/coroutines/pr103868.C: Likewise.
* g++.dg/coroutines/pr94879-folly-1.C: Likewise.
* g++.dg/coroutines/pr94883-folly-2.C: Likewise.
* g++.dg/coroutines/pr96749-2.C: Likewise.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   | 47 ++
 .../coro-bad-gro-01-void-gro-non-class-coro.C  |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr102489.C |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr103868.C |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C  |  3 +-
 gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C  | 39 +-
 gcc/testsuite/g++.dg/coroutines/pr96749-2.C|  2 +-
 7 files changed, 48 insertions(+), 49 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index cbe99ac87016..e46b8b63c644 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4604,6 +4604,7 @@ cp_coroutine_transform::build_ramp_function ()
 
   tree promise_type = get_coroutine_promise_type (orig_fn_decl);
   tree fn_return_type = TREE_TYPE (TREE_TYPE (orig_fn_decl));
+  bool void_ramp_p = VOID_TYPE_P (fn_return_type);
 
   /* [dcl.fct.def.coroutine] / 10 (part1)
 The unqualified-id get_return_object_on_allocation_failure is looked up
@@ -4766,7 +4767,7 @@ cp_coroutine_transform::build_ramp_function ()
   tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node);
   cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
   finish_if_stmt_cond (cond, if_stmt);
-  if (VOID_TYPE_P (fn_return_type))
+  if (void_ramp_p)
{
  /* Execute the get-return-object-on-alloc-fail call...  */
  finish_expr_stmt (grooaf);
@@ -4966,17 +4967,27 @@ cp_coroutine_transform::build_ramp_function ()
 coro_get_return_object_identifier,
 fn_start, NULL, /*musthave=*/true);
   /* Without a return object we haven't got much clue what's going on.  */
-  if (get_ro == error_mark_node)
+  if (!get_ro || get_ro == error_mark_node)
 {
   BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_outer_bind);
   /* Suppress warnings about the missing return value.  */
   suppress_warning (orig_fn_decl, OPT_Wreturn_type);
   return false;
 }
+ 
+  /* Check for a bad get return object type.
+ [dcl.fct.def.coroutine] / 7 requires:
+ The expression promise.get_return_object() is used to initialize the
+ returned reference or prvalue result object ... */
+  tree gro_type = TREE_TYPE (get_ro);
+  if (VOID_TYPE_P (gro_type) && !void_ramp_p)
+{
+  error_at (fn_start, "no viable conversion from % provided by"
+   " % to return type %qT", fn_return_type);
+  return false;
+}
 
   tree gro_context_body = push_stmt_list ();
-  tree gro_type = TREE_TYPE (get_ro);
-  bool gro_is_void_p = VOID_TYPE_P (gro_type);
 
   tree gro = NULL_TREE;
   tree gro_bind_vars = NULL_TREE;
@@ -4985,8 +4996,11 @@ cp_coroutine_transform::build_ramp_function ()
   tree gro_cleanup_stmt = NULL_TREE;
   /* We have to sequence the call to get_return_object before initial
  suspend.  */
-  if (gro_is_void_p)
-r = get_ro;
+  if (void_ramp_p)
+{
+  gcc_checking_assert (VOID_TYPE_P (gro_type));
+  r = get_ro;
+}
   else if (same_type_p (gro_type, fn_return_type))
 {
  /* [dcl.fct.def.coroutine] / 7
@@ -5067,28 +5081,11 @@ cp_coroutine_transform::build_ramp_function ()
  for an object of the return type.  */
 
   if (same_type_p (gro_type, fn_return_type))
-r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig_fn_decl);
-  else if (!gro_is_void_p)
+r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig_fn_decl);
+  else
 /* check_return_expr will automatically return gro as an rvalue via
treat_lvalue_as_rvalue_p.  */
 r = gro;
-  else if (CLASS_TYPE_P (fn_return_type))
-

[gcc r15-3152] c++, coroutines: Allow convertible get_return_on_allocation_fail [PR109682].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:f4915e6c4cd42e7d6f397dc36fab507cc47dad05

commit r15-3152-gf4915e6c4cd42e7d6f397dc36fab507cc47dad05
Author: Iain Sandoe 
Date:   Sat Aug 17 16:55:29 2024 +0100

c++, coroutines: Allow convertible get_return_on_allocation_fail [PR109682].

We have been requiring the get_return_on_allocation_fail() call to have the
same type as the ramp.  This is not intended by the standard, so relax that
to allow anything convertible to the ramp return.

PR c++/109682

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Allow for cases where
get_return_on_allocation_fail has a type convertible to the ramp
return type.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/pr109682.C: New test.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   | 19 ++-
 gcc/testsuite/g++.dg/coroutines/pr109682.C | 28 
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index e46b8b63c644..1a6e191454d3 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4761,25 +4761,18 @@ cp_coroutine_transform::build_ramp_function ()
 control to the caller of the coroutine and the return value is
 obtained by a call to T::get_return_object_on_allocation_failure(),
 where T is the promise type.  */
-
-  gcc_checking_assert (same_type_p (fn_return_type, TREE_TYPE (grooaf)));
   tree if_stmt = begin_if_stmt ();
   tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node);
   cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
   finish_if_stmt_cond (cond, if_stmt);
+  r = NULL_TREE;
   if (void_ramp_p)
-   {
- /* Execute the get-return-object-on-alloc-fail call...  */
- finish_expr_stmt (grooaf);
- /* ... but discard the result, since we return void.  */
- finish_return_stmt (NULL_TREE);
-   }
+   /* Execute the get-return-object-on-alloc-fail call...  */
+   finish_expr_stmt (grooaf);
   else
-   {
- /* Get the fallback return object.  */
- r = build_cplus_new (fn_return_type, grooaf, tf_warning_or_error);
- finish_return_stmt (r);
-   }
+   /* Get the fallback return object.  */
+   r = grooaf;
+  finish_return_stmt (r);
   finish_then_clause (if_stmt);
   finish_if_stmt (if_stmt);
 }
diff --git a/gcc/testsuite/g++.dg/coroutines/pr109682.C 
b/gcc/testsuite/g++.dg/coroutines/pr109682.C
new file mode 100644
index ..24aab921ab22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr109682.C
@@ -0,0 +1,28 @@
+
+#include 
+#include 
+
+struct test
+{
+  test () {}
+  test (int) {}
+
+  struct promise_type {
+test get_return_object () { return {}; }
+// vvv
+static int get_return_object_on_allocation_failure () { return {}; }
+std::suspend_never initial_suspend () noexcept { return {}; }
+std::suspend_never final_suspend () noexcept { return {}; }
+void return_void () {}
+void unhandled_exception () {}
+  };
+};
+
+test
+f () { co_return; }
+
+int
+main ()
+{
+  f ();
+}


[gcc r15-3153] c++, coroutines: Fix ordering of return object conversions [PR115908].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:68ee624bc52ba1154040a904db56dd2f9c3af1f6

commit r15-3153-g68ee624bc52ba1154040a904db56dd2f9c3af1f6
Author: Iain Sandoe 
Date:   Sun Aug 18 14:54:38 2024 +0100

c++, coroutines: Fix ordering of return object conversions [PR115908].

[dcl.fct.def.coroutine]/7 says:
The expression promise.get_return_object() is used to initialize the 
returned
reference or prvalue result object of a call to a coroutine. The call to
get_return_object is sequenced before the call to initial_suspend and is
invoked at most once.

The issue is about when any conversions are carried out if the type of
the g_r_o call is not the same as the ramp return.  Currently, we have been
doing this by materialising the g_r_o return value and passing that to
finish_return_expr() which handles the necessary conversions and checks.

As the PR shows, this does not work as expected.

In the revised version we carry out the work of the conversions when
intialising the return slot (with the same facilities that are used by
finish_return_expr()).  We do this before the call that initiates the
coroutine body, satisfying the requirements for one call before initial
suspend.

The return expression becomes a trivial 'return '.

This simplifies the ramp logic considerably, since we no longer need to
keep track of the temporarily-materialised g_r_o value.

PR c++/115908

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Rework the return
value initialisation to initialise the return slot always from
get_return_object,  even if that implies carrying out conversions
to do so.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/pr115908.C: New test.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   | 161 ++---
 gcc/testsuite/g++.dg/coroutines/pr115908.C |  75 ++
 2 files changed, 129 insertions(+), 107 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 1a6e191454d3..b45efab2b517 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4605,6 +4605,8 @@ cp_coroutine_transform::build_ramp_function ()
   tree promise_type = get_coroutine_promise_type (orig_fn_decl);
   tree fn_return_type = TREE_TYPE (TREE_TYPE (orig_fn_decl));
   bool void_ramp_p = VOID_TYPE_P (fn_return_type);
+  /* We know there was no return statement, that is intentional.  */
+  suppress_warning (orig_fn_decl, OPT_Wreturn_type);
 
   /* [dcl.fct.def.coroutine] / 10 (part1)
 The unqualified-id get_return_object_on_allocation_failure is looked up
@@ -4946,28 +4948,18 @@ cp_coroutine_transform::build_ramp_function ()
   promise_dtor = cxx_maybe_build_cleanup (p, tf_warning_or_error);
 }
 
-  /* Set up a new bind context for the GRO.  */
-  tree gro_context_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
-  /* Make and connect the scope blocks.  */
-  tree gro_block = make_node (BLOCK);
-  BLOCK_SUPERCONTEXT (gro_block) = top_block;
-  BLOCK_SUBBLOCKS (top_block) = gro_block;
-  BIND_EXPR_BLOCK (gro_context_bind) = gro_block;
-  add_stmt (gro_context_bind);
-
   tree get_ro
 = coro_build_promise_expression (orig_fn_decl, p,
 coro_get_return_object_identifier,
 fn_start, NULL, /*musthave=*/true);
+
   /* Without a return object we haven't got much clue what's going on.  */
   if (!get_ro || get_ro == error_mark_node)
 {
   BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_outer_bind);
-  /* Suppress warnings about the missing return value.  */
-  suppress_warning (orig_fn_decl, OPT_Wreturn_type);
   return false;
 }
- 
+
   /* Check for a bad get return object type.
  [dcl.fct.def.coroutine] / 7 requires:
  The expression promise.get_return_object() is used to initialize the
@@ -4980,119 +4972,76 @@ cp_coroutine_transform::build_ramp_function ()
   return false;
 }
 
-  tree gro_context_body = push_stmt_list ();
+  /* Initialize the resume_idx_var to 0, meaning "not started".  */
+  tree resume_idx_m
+= lookup_member (frame_type, coro_resume_index_id,
+/*protect=*/1, /*want_type=*/0, tf_warning_or_error);
+  tree resume_idx
+= build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false,
+ tf_warning_or_error);
+  r = build_int_cst (short_unsigned_type_node, 0);
+  r = cp_build_init_expr (loc, resume_idx, r);
+  finish_expr_stmt (r);
 
-  tree gro = NULL_TREE;
-  tree gro_bind_vars = NULL_TREE;
   /* Used for return objects in the RESULT slot.  */
-  tree gro_ret_dtor = NULL_TREE;
-  tree gro_cleanup_stmt = NULL_TREE;
-  /* We have to sequence the call to get_return_object before initial
- suspend.  */
-  if (void

[gcc r15-3154] c++, coroutines: Rework handling of throwing_cleanups [PR102051].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:f0315f7a325ffccb446fe378fcdfccda6eead8ba

commit r15-3154-gf0315f7a325ffccb446fe378fcdfccda6eead8ba
Author: Iain Sandoe 
Date:   Sun Aug 18 22:54:50 2024 +0100

c++, coroutines: Rework handling of throwing_cleanups [PR102051].

In the fix for PR95822 (r11-7402) we set throwing_cleanup false in the top
level of the coroutine transform code.  However, as the current PR shows,
that is not sufficient.

Any use of cxx_maybe_build_cleanup() can reset the flag, which causes the
check_return_expr () logic to try to add a guard variable and set it.

For the coroutine code, we need to handle the cleanups separately, since
the responsibility for them changes after the first resume point, which
we handle in the ramp exception processing.

Fix this by forcing the "throwing_cleanup" flag false right before the
processing of the return expression.

PR c++/102051

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Handle
"throwing_cleanup" here instead of ...
(cp_coroutine_transform::apply_transforms): ... here.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/pr102051.C: New test.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   | 16 +---
 gcc/testsuite/g++.dg/coroutines/pr102051.C | 16 
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index b45efab2b517..3991de19d65c 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4990,11 +4990,16 @@ cp_coroutine_transform::build_ramp_function ()
  The expression promise.get_return_object() is used to initialize the
  glvalue result or prvalue result object of a call to a coroutine.  */
 
+  /* We must manage the cleanups ourselves, because the responsibility for
+ them changes after the initial suspend.  However, any use of
+ cxx_maybe_build_cleanup () can set the throwing_cleanup flag.  */
+  cp_function_chain->throwing_cleanup = false;
   if (void_ramp_p)
 /* We still want to call the method, even if the result is unused.  */
 r = get_ro;
   else
 {
+  /* The initial section of finish_return_expr ().  */
   bool no_warning;
   bool dangling;
   /* Without a relevant location, bad conversions in check_return_expr
@@ -5220,17 +5225,6 @@ cp_coroutine_transform::apply_transforms ()
   body_blocks = current_binding_level->blocks;
   current_binding_level->blocks = NULL_TREE;
 
-  /* If the original function has a return value with a non-trivial DTOR
- and the body contains a var with a DTOR that might throw, the decl is
- marked "throwing_cleanup".
- We do not [in the ramp, which is synthesised here], use any body var
- types with DTORs that might throw.
- The original body is transformed into the actor function which only
- contains void returns, and is also wrapped in a try-catch block.
- So (a) the 'throwing_cleanup' is not correct for the ramp and (b) we do
- not need to transfer it to the actor which only contains void returns.  */
-  cp_function_chain->throwing_cleanup = false;
-
   /* Collect information on the original function params and their use in the
  function body.  */
   analyze_fn_parms (orig_fn_decl, ¶m_uses);
diff --git a/gcc/testsuite/g++.dg/coroutines/pr102051.C 
b/gcc/testsuite/g++.dg/coroutines/pr102051.C
new file mode 100644
index ..bba98b691cc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr102051.C
@@ -0,0 +1,16 @@
+#include 
+
+struct Foo {
+~Foo() noexcept(false); // true succeeds
+struct promise_type {
+Foo get_return_object() { return {}; }
+std::suspend_never initial_suspend() { return {}; }
+void return_void() {}
+void unhandled_exception() {}
+std::suspend_always final_suspend() noexcept { return {}; }
+};
+};
+
+Foo bar() {
+co_return;
+}


[gcc r15-3155] c++, coroutines: Look through initial_await target exprs [PR110635].

2024-08-24 Thread Iain D Sandoe via Gcc-cvs
https://gcc.gnu.org/g:c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf

commit r15-3155-gc442a9b78bdbebdbcb4a8f91bc36961eb732fbdf
Author: Iain Sandoe 
Date:   Mon Aug 19 20:50:54 2024 +0100

c++, coroutines: Look through initial_await target exprs [PR110635].

In the case that the initial awaiter returns an object, the initial await
can be a target expression and we need to look at its initializer to cast
the await_resume() to void and to wrap in a compound expression that sets
the initial_await_resume_called flag.

PR c++/110635

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::wrap_original_function_body): Look through
initial await target expressions to find the actual co_await_expr
that we need to update.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/pr110635.C: New test.

Signed-off-by: Iain Sandoe 

Diff:
---
 gcc/cp/coroutines.cc   |  8 +++-
 gcc/testsuite/g++.dg/coroutines/pr110635.C | 72 ++
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3991de19d65c..c3e08221cc91 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4283,7 +4283,13 @@ cp_coroutine_transform::wrap_original_function_body ()
 a reference type, look past the indirection.  */
  if (INDIRECT_REF_P (initial_await))
initial_await = TREE_OPERAND (initial_await, 0);
- tree vec = TREE_OPERAND (initial_await, 3);
+ /* In the case that the initial_await returns a target expression
+we might need to look through that to update the await expr.  */
+ tree iaw = initial_await;
+ if (TREE_CODE (iaw) == TARGET_EXPR)
+   iaw = TARGET_EXPR_INITIAL (iaw);
+ gcc_checking_assert (TREE_CODE (iaw) == CO_AWAIT_EXPR);
+ tree vec = TREE_OPERAND (iaw, 3);
  tree aw_r = TREE_VEC_ELT (vec, 2);
  aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error);
  tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c,
diff --git a/gcc/testsuite/g++.dg/coroutines/pr110635.C 
b/gcc/testsuite/g++.dg/coroutines/pr110635.C
new file mode 100644
index ..ea4e0e853eb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr110635.C
@@ -0,0 +1,72 @@
+
+#define CASE 0
+#include 
+#include 
+
+struct Coroutine {
+
+struct promise_type;
+
+using handler_type = std::coroutine_handle;
+
+struct initial_suspend_awaiter {
+
+bool await_ready() noexcept {
+std::cout << "await_ready" << std::endl;
+return false;
+}
+
+void await_suspend(handler_type h) noexcept {
+std::cout << "await_suspend" << std::endl;
+}
+
+#if CASE == 0
+struct await_resume_return_object {
+await_resume_return_object() noexcept {
+std::cout << "await_resume_return_object" << std::endl;
+}
+
+~await_resume_return_object() noexcept {
+std::cout << "~await_resume_return_object" << std::endl;
+}
+};
+#elif CASE == 1
+using await_resume_return_object = struct{};
+#elif CASE == 2
+using await_resume_return_object = int;
+#else
+using await_resume_return_object = void;
+#endif
+await_resume_return_object await_resume() noexcept {
+std::cout << "await_resume" << std::endl;
+#if CASE == 0 || CASE == 1 || CASE == 2
+return {};
+#endif
+}
+
+initial_suspend_awaiter() noexcept {
+std::cout << "initial_suspend_awaiter" << std::endl;
+}
+
+~initial_suspend_awaiter() noexcept {
+std::cout << "~initial_suspend_awaiter" << std::endl;
+}
+};
+
+struct promise_type {
+void return_void() noexcept {}
+void unhandled_exception() noexcept { std::terminate();}
+initial_suspend_awaiter initial_suspend() noexcept { return {}; }
+std::suspend_never final_suspend() noexcept { return {}; }
+Coroutine get_return_object() {
+return Coroutine{handler_type::from_promise(*this)};
+}
+};
+
+handler_type handler;
+};
+
+int main() {
+auto coro = []()->Coroutine { co_return; }();
+coro.handler.resume();
+}


[gcc r15-3156] modula2: Export all string to integral and fp number conversion functions

2024-08-24 Thread Gaius Mulley via Gcc-cvs
https://gcc.gnu.org/g:ecc999b0224db06c1a7d8a4128bfa2ed162e2a61

commit r15-3156-gecc999b0224db06c1a7d8a4128bfa2ed162e2a61
Author: Gaius Mulley 
Date:   Sat Aug 24 22:43:55 2024 +0100

modula2: Export all string to integral and fp number conversion functions

Export all string to integral and floating point number conversion functions
(atof, atoi, atol, atoll, strtod, strtof, strtold, strtol, strtoll, strtoul
and strtoull).

gcc/m2/ChangeLog:

* gm2-libs/libc.def (atof): Export unqualified.
(atoi): Ditto.
(atol): Ditto.
(atoll): Ditto.
(strtod): Ditto.
(strtof): Ditto.
(strtold): Ditto.
(strtol): Ditto.
(strtoll): Ditto.
(strtoul): Ditto.
(strtoull): Ditto.

Signed-off-by: Wilken Gottwalt 

Diff:
---
 gcc/m2/gm2-libs/libc.def | 84 
 1 file changed, 84 insertions(+)

diff --git a/gcc/m2/gm2-libs/libc.def b/gcc/m2/gm2-libs/libc.def
index a314b59e43f1..e278617c2d86 100644
--- a/gcc/m2/gm2-libs/libc.def
+++ b/gcc/m2/gm2-libs/libc.def
@@ -29,6 +29,8 @@ DEFINITION MODULE FOR "C" libc ;
 FROM SYSTEM IMPORT ADDRESS, CSIZE_T, CSSIZE_T ;
 
 EXPORT UNQUALIFIED time_t, timeb, tm, ptrToTM,
+   atof, atoi, atol, atoll,
+   strtod, strtof, strtold, strtol, strtoll, strtoul, strtoull,
write, read,
system, abort,
malloc, free,
@@ -75,6 +77,88 @@ TYPE
exitP = PROCEDURE () : INTEGER ;
 
 
+(*
+ double atof(const char *nptr)
+*)
+
+PROCEDURE atof (nptr: ADDRESS) : REAL ;
+
+
+(*
+ int atoi(const char *nptr)
+*)
+
+PROCEDURE atoi (nptr: ADDRESS) : INTEGER ;
+
+
+(*
+ long atol(const char *nptr);
+*)
+
+PROCEDURE atol (nptr: ADDRESS) : CSSIZE_T ;
+
+
+(*
+ long long atoll(const char *nptr);
+*)
+
+PROCEDURE atoll (nptr: ADDRESS) : LONGINT ;
+
+
+(*
+ double strtod(const char *restrict nptr, char **_Nullable restrict endptr)
+*)
+
+PROCEDURE strtod (nptr, endptr: ADDRESS) : REAL ;
+
+
+(*
+ float strtof(const char *restrict nptr, char **_Nullable restrict endptr)
+*)
+
+PROCEDURE strtof (nptr, endptr: ADDRESS) : SHORTREAL ;
+
+
+(*
+ long double strtold(const char *restrict nptr,
+ char **_Nullable restrict endptr)
+*)
+
+PROCEDURE strtold (nptr, endptr: ADDRESS) : LONGREAL ;
+
+
+(*
+ long strtol(const char *restrict nptr, char **_Nullable restrict endptr,
+ int base)
+*)
+
+PROCEDURE strtol (nptr, endptr: ADDRESS; base: INTEGER) : CSSIZE_T ;
+
+
+(*
+ long long strtoll(const char *restrict nptr,
+   char **_Nullable restrict endptr, int base)
+*)
+
+PROCEDURE strtoll (nptr, endptr: ADDRESS; base: INTEGER) : LONGINT ;
+
+
+(*
+ unsigned long strtoul(const char *restrict nptr,
+   char **_Nullable restrict endptr, int base)
+*)
+
+PROCEDURE strtoul (nptr, endptr: ADDRESS; base: INTEGER) : CSIZE_T ;
+
+
+(*
+ unsigned long long strtoull(const char *restrict nptr,
+ char **_Nullable restrict endptr, int base)
+*)
+
+PROCEDURE strtoull (nptr, endptr: ADDRESS; base: INTEGER) : LONGCARD ;
+
+
 (*
  ssize_t write (int d, void *buf, size_t nbytes)
 *)