[gcc r15-3144] testsuite: Add dg-require-effective-target scheduling for some tests that set -fschedule-insns.
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]
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.
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.
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.
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.
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].
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].
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].
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].
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].
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].
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
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) *)