diff options
-rw-r--r-- | 15.0.0/gentoo/70_all_PR116506-coro.patch | 295 | ||||
-rw-r--r-- | 15.0.0/gentoo/71_all_PR116914-coro.patch | 51 | ||||
-rw-r--r-- | 15.0.0/gentoo/README.history | 5 |
3 files changed, 351 insertions, 0 deletions
diff --git a/15.0.0/gentoo/70_all_PR116506-coro.patch b/15.0.0/gentoo/70_all_PR116506-coro.patch new file mode 100644 index 0000000..4e670fc --- /dev/null +++ b/15.0.0/gentoo/70_all_PR116506-coro.patch @@ -0,0 +1,295 @@ +From 06475fcc5b72fdb9b24e7e39703942e1e3f2f0d5 Mon Sep 17 00:00:00 2001 +From: Iain Sandoe <iain@sandoe.co.uk> +Date: Thu, 29 Aug 2024 11:18:24 +0100 +Subject: [PATCH] c++, coroutines: Fix awaiter var creation [PR116506]. + +Awaiters always need to have a coroutine state frame copy since +they persist across potential supensions. It simplifies the later +analysis considerably to assign these early which we do when +building co_await expressions. + +The cleanups in r15-3146-g47dbd69b1, unfortunately elided some of +processing used to cater for cases where the var created from an +xvalue, or is a pointer/reference type. + +Corrected thus. + + PR c++/116506 + PR c++/116880 + +gcc/cp/ChangeLog: + + * coroutines.cc (build_co_await): Ensure that xvalues are + materialised. Handle references/pointer values in awaiter + access expressions. + +gcc/testsuite/ChangeLog: + + * g++.dg/coroutines/pr116506.C: New test. + * g++.dg/coroutines/pr116880.C: New test. + +Signed-off-by: Iain Sandoe <iain@sandoe.co.uk> +--- + gcc/cp/coroutines.cc | 82 +++++++++++++++++----- + gcc/testsuite/g++.dg/coroutines/pr116506.C | 53 ++++++++++++++ + gcc/testsuite/g++.dg/coroutines/pr116880.C | 36 ++++++++++ + 3 files changed, 154 insertions(+), 17 deletions(-) + create mode 100644 gcc/testsuite/g++.dg/coroutines/pr116506.C + create mode 100644 gcc/testsuite/g++.dg/coroutines/pr116880.C + +diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc +index 86a5ac8999a..ba6ee41a4e7 100644 +--- a/gcc/cp/coroutines.cc ++++ b/gcc/cp/coroutines.cc +@@ -1071,6 +1071,30 @@ build_template_co_await_expr (location_t kw, tree type, tree expr, tree kind) + return aw_expr; + } + ++/* For a component ref that is not a pointer type, decide if we can use ++ this directly. */ ++static bool ++usable_component_ref (tree comp_ref) ++{ ++ if (TREE_CODE (comp_ref) != COMPONENT_REF ++ || TREE_SIDE_EFFECTS (comp_ref)) ++ return false; ++ ++ while (TREE_CODE (comp_ref) == COMPONENT_REF) ++ { ++ comp_ref = TREE_OPERAND (comp_ref, 0); ++ STRIP_NOPS (comp_ref); ++ /* x-> */ ++ if (INDIRECT_REF_P (comp_ref)) ++ return false; ++ /* operator-> */ ++ if (TREE_CODE (comp_ref) == CALL_EXPR) ++ return false; ++ STRIP_NOPS (comp_ref); ++ } ++ gcc_checking_assert (VAR_P (comp_ref) || TREE_CODE (comp_ref) == PARM_DECL); ++ return true; ++} + + /* This performs [expr.await] bullet 3.3 and validates the interface obtained. + It is also used to build the initial and final suspend points. +@@ -1133,13 +1157,12 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + if (o_type && !VOID_TYPE_P (o_type)) + o_type = complete_type_or_else (o_type, o); + +- if (!o_type) ++ if (!o_type || o_type == error_mark_node) + return error_mark_node; + + if (TREE_CODE (o_type) != RECORD_TYPE) + { +- error_at (loc, "awaitable type %qT is not a structure", +- o_type); ++ error_at (loc, "awaitable type %qT is not a structure", o_type); + return error_mark_node; + } + +@@ -1165,20 +1188,47 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + if (!glvalue_p (o)) + o = get_target_expr (o, tf_warning_or_error); + +- tree e_proxy = o; +- if (glvalue_p (o)) ++ /* We know that we need a coroutine state frame variable for the awaiter, ++ since it must persist across suspension; so where one is needed, build ++ it now. */ ++ tree e_proxy = STRIP_NOPS (o); ++ if (INDIRECT_REF_P (e_proxy)) ++ e_proxy = TREE_OPERAND (e_proxy, 0); ++ o_type = TREE_TYPE (e_proxy); ++ bool is_ptr = TYPE_PTR_P (o_type); ++ if (!is_ptr ++ && (TREE_CODE (e_proxy) == PARM_DECL ++ || usable_component_ref (e_proxy) ++ || (VAR_P (e_proxy) && !is_local_temp (e_proxy)))) + o = NULL_TREE; /* Use the existing entity. */ +- else /* We need to materialise it. */ ++ else /* We need a non-temp var. */ + { +- 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); ++ tree p_type = o_type; ++ tree o_a = o; ++ if (lvalue_p (o) && !TREE_SIDE_EFFECTS (o)) ++ { ++ if (is_ptr) ++ p_type = TREE_TYPE (p_type); ++ p_type = cp_build_reference_type (p_type, false); ++ o_a = build_address (o); ++ } ++ if (INDIRECT_REF_P (o_a)) ++ o_a = TREE_OPERAND (o_a, 0); ++ e_proxy = get_awaitable_var (suspend_kind, p_type); ++ o = cp_build_init_expr (loc, e_proxy, o_a); + } + ++ /* Build an expression for the object that will be used to call the awaitable ++ methods. */ ++ tree e_object = convert_from_reference (e_proxy); ++ if (TYPE_PTR_P (TREE_TYPE (e_object))) ++ e_object = cp_build_indirect_ref (input_location, e_object, RO_UNARY_STAR, ++ tf_warning_or_error); ++ + /* I suppose we could check that this is contextually convertible to bool. */ + tree awrd_func = NULL_TREE; + tree awrd_call +- = build_new_method_call (e_proxy, awrd_meth, NULL, NULL_TREE, LOOKUP_NORMAL, ++ = build_new_method_call (e_object, awrd_meth, NULL, NULL_TREE, LOOKUP_NORMAL, + &awrd_func, tf_warning_or_error); + + if (!awrd_func || !awrd_call || awrd_call == error_mark_node) +@@ -1192,7 +1242,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + tree h_proxy = get_coroutine_self_handle_proxy (current_function_decl); + vec<tree, va_gc> *args = make_tree_vector_single (h_proxy); + tree awsp_call +- = build_new_method_call (e_proxy, awsp_meth, &args, NULL_TREE, ++ = build_new_method_call (e_object, awsp_meth, &args, NULL_TREE, + LOOKUP_NORMAL, &awsp_func, tf_warning_or_error); + + release_tree_vector (args); +@@ -1224,7 +1274,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + /* Finally, the type of e.await_resume() is the co_await's type. */ + tree awrs_func = NULL_TREE; + tree awrs_call +- = build_new_method_call (e_proxy, awrs_meth, NULL, NULL_TREE, LOOKUP_NORMAL, ++ = build_new_method_call (e_object, awrs_meth, NULL, NULL_TREE, LOOKUP_NORMAL, + &awrs_func, tf_warning_or_error); + + if (!awrs_func || !awrs_call || awrs_call == error_mark_node) +@@ -1238,7 +1288,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + return error_mark_node; + if (coro_diagnose_throwing_fn (awrs_func)) + return error_mark_node; +- if (tree dummy = cxx_maybe_build_cleanup (e_proxy, tf_none)) ++ if (tree dummy = cxx_maybe_build_cleanup (e_object, tf_none)) + { + if (CONVERT_EXPR_P (dummy)) + dummy = TREE_OPERAND (dummy, 0); +@@ -1249,7 +1299,8 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + } + + /* We now have three call expressions, in terms of the promise, handle and +- 'e' proxies. Save them in the await expression for later expansion. */ ++ 'e' proxy expression. Save them in the await expression for later ++ expansion. */ + + tree awaiter_calls = make_tree_vec (3); + TREE_VEC_ELT (awaiter_calls, 0) = awrd_call; /* await_ready(). */ +@@ -1262,9 +1313,6 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, + } + TREE_VEC_ELT (awaiter_calls, 2) = awrs_call; /* await_resume(). */ + +- if (REFERENCE_REF_P (e_proxy)) +- e_proxy = TREE_OPERAND (e_proxy, 0); +- + tree awrs_type = TREE_TYPE (TREE_TYPE (awrs_func)); + tree suspend_kind_cst = build_int_cst (integer_type_node, + (int) suspend_kind); +diff --git a/gcc/testsuite/g++.dg/coroutines/pr116506.C b/gcc/testsuite/g++.dg/coroutines/pr116506.C +new file mode 100644 +index 00000000000..57a6e360566 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/coroutines/pr116506.C +@@ -0,0 +1,53 @@ ++// { dg-do run } ++// { dg-additional-options "-fno-exceptions" } ++ ++#include <coroutine> ++ ++bool g_too_early = true; ++std::coroutine_handle<> g_handle; ++ ++struct Awaiter { ++ Awaiter() {} ++ ~Awaiter() { ++ if (g_too_early) { ++ __builtin_abort (); ++ } ++ } ++ ++ bool await_ready() { return false; } ++ void await_suspend(std::coroutine_handle<> handle) { ++ g_handle = handle; ++ } ++ ++ void await_resume() {} ++}; ++ ++struct SuspendNever { ++ bool await_ready() noexcept { return true; } ++ void await_suspend(std::coroutine_handle<>) noexcept {} ++ void await_resume() noexcept {} ++}; ++ ++struct Coroutine { ++ struct promise_type { ++ Coroutine get_return_object() { return {}; } ++ SuspendNever initial_suspend() { return {}; } ++ SuspendNever final_suspend() noexcept { return {}; } ++ void return_void() {} ++ void unhandled_exception() {} ++ ++ Awaiter&& await_transform(Awaiter&& u) { ++ return static_cast<Awaiter&&>(u); ++ } ++ }; ++}; ++ ++Coroutine foo() { ++ co_await Awaiter{}; ++} ++ ++int main() { ++ foo(); ++ g_too_early = false; ++ g_handle.destroy(); ++} +diff --git a/gcc/testsuite/g++.dg/coroutines/pr116880.C b/gcc/testsuite/g++.dg/coroutines/pr116880.C +new file mode 100644 +index 00000000000..f0db6a26044 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/coroutines/pr116880.C +@@ -0,0 +1,36 @@ ++#include <coroutine> ++ ++struct promise_type; ++using handle_type = std::coroutine_handle<promise_type>; ++ ++struct Co { ++ handle_type handle; ++ using promise_type = ::promise_type; ++ ++ explicit Co(handle_type handle) : handle(handle) {} ++ ++ bool await_ready() { return false; } ++ std::coroutine_handle<> await_suspend(handle_type handle); ++ void await_resume() {} ++}; ++ ++struct Done {}; ++ ++struct promise_type { ++ Co get_return_object(); ++ ++ std::suspend_always initial_suspend() { return {}; }; ++ std::suspend_always final_suspend() noexcept { return {}; }; ++ void return_value(Done) {} ++ void return_value(Co&&); ++ void unhandled_exception() { throw; }; ++ Co&& await_transform(Co&& co) { return static_cast<Co&&>(co); } ++}; ++ ++Co tryToRun(); ++ ++Co init() ++{ ++ co_await tryToRun(); ++ co_return Done{}; ++} +-- +2.39.2 (Apple Git-143) diff --git a/15.0.0/gentoo/71_all_PR116914-coro.patch b/15.0.0/gentoo/71_all_PR116914-coro.patch new file mode 100644 index 0000000..100d2bb --- /dev/null +++ b/15.0.0/gentoo/71_all_PR116914-coro.patch @@ -0,0 +1,51 @@ +From 1035866a75b27bb2cac49bac1070877d95f7d3c0 Mon Sep 17 00:00:00 2001 +From: Iain Sandoe <iain@sandoe.co.uk> +Date: Sun, 29 Sep 2024 10:04:39 +0100 +Subject: [PATCH] c++, coroutines: stmt expressions some progress + +--- + gcc/cp/coroutines.cc | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc +index af8798b04ba..94bfa6ac450 100644 +--- a/gcc/cp/coroutines.cc ++++ b/gcc/cp/coroutines.cc +@@ -2131,6 +2131,14 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d) + } + else if (EXPR_P (*stmt)) + { ++ /* Look for ({}) at the top level - just recurse into these. */ ++ if (TREE_CODE (*stmt) == EXPR_STMT) ++ { ++ tree inner = EXPR_STMT_EXPR (*stmt); ++ if (TREE_CODE (inner) == STATEMENT_LIST ++ || TREE_CODE (inner) == BIND_EXPR) ++ return NULL_TREE; // process contents ++ } + process_one_statement (stmt, d); + *do_subtree = 0; /* Done subtrees. */ + } +@@ -3860,6 +3868,20 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) + if (!(cp_walk_tree (stmt, find_any_await, &await_ptr, &visited))) + return NULL_TREE; /* Nothing special to do here. */ + ++ /* Handle statement expressions. */ ++ if (TREE_CODE (expr) == EXPR_STMT) ++ { ++ tree inner = EXPR_STMT_EXPR (expr); ++ if (TREE_CODE (inner) == STATEMENT_LIST ++ || TREE_CODE (inner) == BIND_EXPR) ++ { ++ res = cp_walk_tree (&EXPR_STMT_EXPR (expr), ++ await_statement_walker, d, NULL); ++ *do_subtree = 0; ++ return res; ++ } ++ } ++ + visited.empty (); + awpts->saw_awaits = 0; + hash_set<tree> truth_aoif_to_expand; +-- +2.39.2 (Apple Git-143) diff --git a/15.0.0/gentoo/README.history b/15.0.0/gentoo/README.history index a6954a6..073283d 100644 --- a/15.0.0/gentoo/README.history +++ b/15.0.0/gentoo/README.history @@ -1,3 +1,8 @@ +16 13 October 2024 + + + 70_all_PR116506-coro.patch + + 71_all_PR116914-coro.patch + 15 7 October 2024 - 71_all_c-Allow-references-to-internal-linkage-vars-in-C-11-.patch |