[gcc r15-3019] gnat: fix lto-type-mismatch between C_Version_String and gnat_version_string [PR115917]
https://gcc.gnu.org/g:9cbcf8d1de159e6113fafb5dc2feb4a7e467a302 commit r15-3019-g9cbcf8d1de159e6113fafb5dc2feb4a7e467a302 Author: Arsen Arsenović Date: Thu Aug 15 19:17:41 2024 +0200 gnat: fix lto-type-mismatch between C_Version_String and gnat_version_string [PR115917] gcc/ada/ChangeLog: PR ada/115917 * gnatvsn.ads: Add note about the duplication of this value in version.c. * version.c (VER_LEN_MAX): Define to the same value as Gnatvsn.Ver_Len_Max. (gnat_version_string): Use VER_LEN_MAX as bound. Diff: --- gcc/ada/gnatvsn.ads | 3 ++- gcc/ada/version.c | 5 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gcc/ada/gnatvsn.ads b/gcc/ada/gnatvsn.ads index 6cf170dc4ca..ca7744b9767 100644 --- a/gcc/ada/gnatvsn.ads +++ b/gcc/ada/gnatvsn.ads @@ -83,7 +83,8 @@ package Gnatvsn is -- space to store any possible version string value for checks. This -- value should never be decreased in the future, but it would be -- OK to increase it if absolutely necessary. If it is increased, - -- be sure to increase GNAT.Compiler.Version.Ver_Len_Max as well. + -- be sure to increase GNAT.Compiler.Version.Ver_Len_Max, and to update + -- the VER_LEN_MAX define in version.c as well. Ver_Prefix : constant String := "GNAT Version: "; -- Prefix generated by binder. If it is changed, be sure to change diff --git a/gcc/ada/version.c b/gcc/ada/version.c index 5e64edd0b17..2fa9b8c2c85 100644 --- a/gcc/ada/version.c +++ b/gcc/ada/version.c @@ -31,4 +31,7 @@ #include "version.h" -char gnat_version_string[] = version_string; +/* Logically a reference to Gnatvsn.Ver_Len_Max. Please keep in sync. */ +#define VER_LEN_MAX 256 + +char gnat_version_string[VER_LEN_MAX] = version_string;
[gcc r15-3202] coroutines: diagnose usage of alloca in coroutines
https://gcc.gnu.org/g:c73d7f3c66c0b5865edd6880cd0d6be723cfbb8d commit r15-3202-gc73d7f3c66c0b5865edd6880cd0d6be723cfbb8d Author: Arsen Arsenović Date: Fri Aug 2 13:17:40 2024 +0200 coroutines: diagnose usage of alloca in coroutines We do not support it currently, and the resulting memory can only be used inside a single resumption, so best not confuse the user with it. PR c++/115858 - Incompatibility of coroutines and alloca() gcc/ChangeLog: * coroutine-passes.cc (execute_early_expand_coro_ifns): Emit a sorry if a statement is an alloca call. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr115858.C: New test. Diff: --- gcc/coroutine-passes.cc| 10 ++ gcc/testsuite/g++.dg/coroutines/pr115858.C | 23 +++ 2 files changed, 33 insertions(+) diff --git a/gcc/coroutine-passes.cc b/gcc/coroutine-passes.cc index c0d6eca7c070..9124ecae5916 100644 --- a/gcc/coroutine-passes.cc +++ b/gcc/coroutine-passes.cc @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "tree-pass.h" #include "ssa.h" +#include "calls.h" #include "cgraph.h" #include "pretty-print.h" #include "diagnostic-core.h" @@ -306,6 +307,15 @@ execute_early_expand_coro_ifns (void) { gimple *stmt = gsi_stmt (gsi); + /* Tell the user about 'alloca', we don't support it yet. */ + if (gimple_alloca_call_p (stmt)) + { + sorry_at (gimple_location (stmt), + "% is not yet supported in coroutines"); + gsi_next (&gsi); + continue; + } + if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) { gsi_next (&gsi); diff --git a/gcc/testsuite/g++.dg/coroutines/pr115858.C b/gcc/testsuite/g++.dg/coroutines/pr115858.C new file mode 100644 index ..3dfe820dbdfd --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr115858.C @@ -0,0 +1,23 @@ +#include + +struct task +{ + struct promise_type + { +void return_void () {} +task get_return_object () { return {}; } +void unhandled_exception () {} +std::suspend_never initial_suspend () { return {}; } +std::suspend_never final_suspend () noexcept { return {}; } + }; +}; + +task +f () +{ + void* a = __builtin_alloca (10); + // { dg-message "sorry, unimplemented: 'alloca' is not yet supported in coroutines" "" { target *-*-* } {.-1} } + void* b = __builtin_alloca_with_align (10, 16); + // { dg-message "sorry, unimplemented: 'alloca' is not yet supported in coroutines" "" { target *-*-* } {.-1} } + co_return; +}
[gcc r15-3203] c++/coros: do not assume coros don't nest [PR113457]
https://gcc.gnu.org/g:5cca7517c5868b7b9aa13992145eb6082ac5d5b9 commit r15-3203-g5cca7517c5868b7b9aa13992145eb6082ac5d5b9 Author: Arsen Arsenović Date: Fri Aug 23 20:19:05 2024 +0200 c++/coros: do not assume coros don't nest [PR113457] In the testcase presented in the PR, during template expansion, an tsubst of an operand causes a lambda coroutine to be processed, causing it to get an initial suspend and final suspend. The code for assigning awaitable var names (get_awaitable_var) assumed that the sequence Is -> Is -> Fs -> Fs is impossible (i.e. that one could only 'open' one coroutine before closing it at a time), and reset the counter used for unique numbering each time a final suspend occured. This assumption is false in a few cases, usually when lambdas are involved. Instead of storing this counter in a static-storage variable, we can store it in coroutine_info. This struct is local to each function, so we don't need to worry about "cross-contamination" nor resetting. PR c++/113457 gcc/cp/ChangeLog: * coroutines.cc (struct coroutine_info): Add integer field awaitable_number. This is a counter used for assigning unique names to awaitable temporaries. (get_awaitable_var): Use awaitable_number from coroutine_info instead of the static int awn. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr113457-1.C: New test. * g++.dg/coroutines/pr113457.C: New test. Diff: --- gcc/cp/coroutines.cc | 19 ++- gcc/testsuite/g++.dg/coroutines/pr113457-1.C | 25 gcc/testsuite/g++.dg/coroutines/pr113457.C | 178 +++ 3 files changed, 216 insertions(+), 6 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index c3e08221cc91..5bfd7943fb81 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -96,6 +96,10 @@ struct GTY((for_user)) coroutine_info tree return_void; /* The expression for p.return_void() if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this function into a coroutine. */ + + /* Temporary variable number assigned by get_awaitable_var. */ + int awaitable_number = 0; + /* Flags to avoid repeated errors for per-function issues. */ bool coro_ret_type_error_emitted; bool coro_promise_error_emitted; @@ -995,15 +999,18 @@ enum suspend_point_kind { static tree get_awaitable_var (suspend_point_kind suspend_kind, tree v_type) { - static int awn = 0; + auto cinfo = get_coroutine_info (current_function_decl); + gcc_checking_assert (cinfo); char *buf; switch (suspend_kind) { - default: buf = xasprintf ("Aw%d", awn++); break; - case CO_YIELD_SUSPEND_POINT: buf = xasprintf ("Yd%d", awn++); break; - case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break; - case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); awn = 0; break; - } +default: buf = xasprintf ("Aw%d", cinfo->awaitable_number++); break; +case CO_YIELD_SUSPEND_POINT: + buf = xasprintf ("Yd%d", cinfo->awaitable_number++); + break; +case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break; +case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); break; +} tree ret = get_identifier (buf); free (buf); ret = build_lang_decl (VAR_DECL, ret, v_type); diff --git a/gcc/testsuite/g++.dg/coroutines/pr113457-1.C b/gcc/testsuite/g++.dg/coroutines/pr113457-1.C new file mode 100644 index ..fcf67e15271c --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr113457-1.C @@ -0,0 +1,25 @@ +// https://gcc.gnu.org/PR113457 +#include + +struct coro +{ + struct promise_type + { +std::suspend_never initial_suspend (); +std::suspend_never final_suspend () noexcept; +void return_void (); +void unhandled_exception (); +coro get_return_object (); + }; +}; + +struct not_quite_suspend_never : std::suspend_never +{}; + +coro +foo () +{ + co_await std::suspend_never{}, +[] () -> coro { co_return; }, +co_await not_quite_suspend_never{}; +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr113457.C b/gcc/testsuite/g++.dg/coroutines/pr113457.C new file mode 100644 index ..add45a2f8921 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr113457.C @@ -0,0 +1,178 @@ +// https://gcc.gnu.org/PR113457 +namespace std { +template _Up __declval(int); +template auto declval() noexcept -> decltype(__declval<_Tp>(0)); +template struct remove_cv { + using type = __remove_cv(_Tp); +}; +template using remove_cv_t = typename remove_cv<_Tp>::type; +template struct remove_reference { + using type = __remove_reference(_Tp); +}; +template +using remove_reference_t = typename remove_reference<_Tp>::type; +template inline constexpr bool is_array_v = __is_array(_Tp); +template struct remove_cvref {}; +namespace ranges
[gcc r15-3234] c++/coroutines: fix actor cases not being added to the current switch [PR109867]
https://gcc.gnu.org/g:ff0cba200af72f2514ebc987a99027f314d4cc99 commit r15-3234-gff0cba200af72f2514ebc987a99027f314d4cc99 Author: Arsen Arsenović Date: Wed Jul 24 20:43:01 2024 +0200 c++/coroutines: fix actor cases not being added to the current switch [PR109867] Previously, we were building and inserting case_labels manually, which led to them not being added into the currently running switch via c_add_case_label. This led to false diagnostics that the user could not act on. PR c++/109867 gcc/cp/ChangeLog: * coroutines.cc (expand_one_await_expression): Replace uses of build_case_label with finish_case_label. (build_actor_fn): Ditto. (create_anon_label_with_ctx): Remove now-unused function. gcc/testsuite/ChangeLog: * g++.dg/coroutines/torture/pr109867.C: New test. Reviewed-by: Iain Sandoe Diff: --- gcc/cp/coroutines.cc | 52 +- gcc/testsuite/g++.dg/coroutines/torture/pr109867.C | 23 ++ 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 31dc39afeee2..f243fe9adae2 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1708,20 +1708,6 @@ coro_build_artificial_var (location_t loc, const char *name, tree type, type, ctx, init); } -/* Helpers for label creation: - 1. Create a named label in the specified context. */ - -static tree -create_anon_label_with_ctx (location_t loc, tree ctx) -{ - tree lab = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node); - - DECL_CONTEXT (lab) = ctx; - DECL_ARTIFICIAL (lab) = true; - DECL_IGNORED_P (lab) = true; - TREE_USED (lab) = true; - return lab; -} /* 2. Create a named label in the specified context. */ @@ -1935,22 +1921,16 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) data->coro_fp); r = cp_build_init_expr (cond, r); finish_switch_cond (r, sw); - r = build_case_label (integer_zero_node, NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (r); /* case 0: */ + finish_case_label (loc, integer_zero_node, NULL_TREE); /* case 0: */ /* Implement the suspend, a scope exit without clean ups. */ r = build_call_expr_internal_loc (loc, IFN_CO_SUSPN, void_type_node, 1, is_cont ? cont : susp); r = coro_build_cvt_void_expr_stmt (r, loc); add_stmt (r); /* goto ret; */ - r = build_case_label (integer_one_node, NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (r); /* case 1: */ + finish_case_label (loc, integer_one_node, NULL_TREE); /* case 1: */ r = build1_loc (loc, GOTO_EXPR, void_type_node, resume_label); add_stmt (r); /* goto resume; */ - r = build_case_label (NULL_TREE, NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (r); /* default:; */ + finish_case_label (loc, NULL_TREE, NULL_TREE); /* default:; */ r = build1_loc (loc, GOTO_EXPR, void_type_node, destroy_label); add_stmt (r); /* goto destroy; */ @@ -2291,9 +2271,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree destroy_dispatcher = begin_switch_stmt (); finish_switch_cond (rat, destroy_dispatcher); - tree ddeflab = build_case_label (NULL_TREE, NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (ddeflab); + tree ddeflab = finish_case_label (loc, NULL_TREE, NULL_TREE); tree b = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); b = coro_build_cvt_void_expr_stmt (b, loc); add_stmt (b); @@ -2304,18 +2282,15 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, frame itself. */ tree del_promise_label = create_named_label_with_ctx (loc, "coro.delete.promise", actor); - b = build_case_label (build_int_cst (short_unsigned_type_node, 1), NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (b); + finish_case_label (loc, build_int_cst (short_unsigned_type_node, 1), +NULL_TREE); add_stmt (build_stmt (loc, GOTO_EXPR, del_promise_label)); short unsigned lab_num = 3; for (unsigned destr_pt = 0; destr_pt < body_count; destr_pt++) { tree l_num = build_int_cst (short_unsigned_type_node, lab_num); - b = build_case_label (l_num, NULL_TREE, - create_anon_label_with_ctx (loc, actor)); - add_stmt (b); + finish_case_label (loc, l_num, NULL_TREE); b = build_call_expr_internal_loc (loc, IFN_CO_ACTOR, void_type_node, 1, l_num); b = coro_build_cvt_void_expr_stmt (b, loc); @@ -2333,15 +2308,12 @@ build_actor_fn (location_t loc
[gcc r15-3285] c++: don't remove labels during coro-early-expand-ifns [PR105104]
https://gcc.gnu.org/g:d9c54e9a036189e8961ec17e118fccf794d7bfab commit r15-3285-gd9c54e9a036189e8961ec17e118fccf794d7bfab Author: Arsen Arsenović Date: Fri Aug 16 19:07:01 2024 +0200 c++: don't remove labels during coro-early-expand-ifns [PR105104] In some scenarios, it is possible for the CFG cleanup to cause one of the labels mentioned in CO_YIELD, which coro-early-expand-ifns intends to remove, to become part of some statement. As a result, when that label is removed, the statement it became part of becomes invalid, crashing the compiler. There doesn't appear to be a reason to remove the labels (anymore, at least), so let's not do that. PR c++/105104 gcc/ChangeLog: * coroutine-passes.cc (execute_early_expand_coro_ifns): Don't remove any labels. gcc/testsuite/ChangeLog: * g++.dg/coroutines/torture/pr105104.C: New test. Diff: --- gcc/coroutine-passes.cc| 26 -- gcc/testsuite/g++.dg/coroutines/torture/pr105104.C | 40 ++ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/gcc/coroutine-passes.cc b/gcc/coroutine-passes.cc index 9124ecae5916..0f8e24f8d551 100644 --- a/gcc/coroutine-passes.cc +++ b/gcc/coroutine-passes.cc @@ -294,9 +294,6 @@ execute_early_expand_coro_ifns (void) /* Some of the possible YIELD points will hopefully have been removed by earlier optimisations; record the ones that are still present. */ hash_map, tree> destinations; - /* Labels we added to carry the CFG changes, we need to remove these to - avoid confusing EH. */ - hash_set to_remove; /* List of dispatch points to update. */ auto_vec actor_worklist; basic_block bb; @@ -384,8 +381,6 @@ execute_early_expand_coro_ifns (void) } else dst_dest = dst_tgt; - to_remove.add (res_tgt); - to_remove.add (dst_tgt); /* lose the co_yield. */ gsi_remove (&gsi, true); stmt = gsi_stmt (gsi); /* next. */ @@ -473,27 +468,6 @@ execute_early_expand_coro_ifns (void) } } - /* Remove the labels we inserted to map our hidden CFG, this - avoids confusing block merges when there are also EH labels. */ - FOR_EACH_BB_FN (bb, cfun) -for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) - { - gimple *stmt = gsi_stmt (gsi); - if (glabel *glab = dyn_cast (stmt)) - { - tree rem = gimple_label_label (glab); - if (to_remove.contains (rem)) - { - gsi_remove (&gsi, true); - to_remove.remove (rem); - continue; /* We already moved to the next insn. */ - } - } - else - break; - gsi_next (&gsi); - } - /* Changed the CFG. */ todoflags |= TODO_cleanup_cfg; return todoflags; diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C new file mode 100644 index ..fcc783e3066d --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C @@ -0,0 +1,40 @@ +// https://gcc.gnu.org/PR105104 +// { dg-additional-options "-O" } + +#include + +// ICE during GIMPLE pass: coro-early-expand-ifs. final_awaiter::await_resume is +// non-void, and optimizations are enabled. + +struct return_object +{ + struct promise_type + { +static constexpr std::suspend_always initial_suspend () noexcept +{ + return {}; +} + +struct final_awaiter +{ + static constexpr bool await_ready () noexcept { return false; } + static constexpr void await_suspend (std::coroutine_handle<>) noexcept {} + static constexpr int await_resume () noexcept { return {}; } +}; +static constexpr final_awaiter final_suspend () noexcept { return {}; } + +static void unhandled_exception () { throw; } + +return_object get_return_object () { return {}; } + +static constexpr void return_void () noexcept {} + }; +}; + +return_object +coroutine () +{ + co_return; +} + +return_object f = coroutine ();
[gcc r15-3453] coros: mark .CO_YIELD as LEAF [PR106973]
https://gcc.gnu.org/g:7b7ad3f4b2455072f42e7884b93fd96ebb920bc8 commit r15-3453-g7b7ad3f4b2455072f42e7884b93fd96ebb920bc8 Author: Arsen Arsenović Date: Tue Sep 3 17:14:13 2024 +0200 coros: mark .CO_YIELD as LEAF [PR106973] We rely on .CO_YIELD calls being followed by an assignment (optionally) and then a switch/if in the same basic block. This implies that a .CO_YIELD can never end a block. However, since a call to .CO_YIELD is still a call, if the function containing it calls setjmp, GCC thinks that the .CO_YIELD can introduce abnormal control flow, and generates an edge for the call. We know this is not the case; .CO_YIELD calls get removed quite early on and have no effect, and result in no other calls, so .CO_YIELD can be considered a leaf function, preventing generating an edge when calling it. PR c++/106973 - coroutine generator and setjmp PR c++/106973 gcc/ChangeLog: * internal-fn.def (CO_YIELD): Mark as ECF_LEAF. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr106973.C: New test. Diff: --- gcc/internal-fn.def| 2 +- gcc/testsuite/g++.dg/coroutines/pr106973.C | 22 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 75b527b1ab0..23b4ab02b30 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -569,7 +569,7 @@ DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL) /* For coroutines. */ DEF_INTERNAL_FN (CO_ACTOR, ECF_NOTHROW | ECF_LEAF, NULL) -DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW | ECF_LEAF, NULL) DEF_INTERNAL_FN (CO_SUSPN, ECF_NOTHROW, NULL) DEF_INTERNAL_FN (CO_FRAME, ECF_PURE | ECF_NOTHROW | ECF_LEAF, NULL) diff --git a/gcc/testsuite/g++.dg/coroutines/pr106973.C b/gcc/testsuite/g++.dg/coroutines/pr106973.C new file mode 100644 index 000..6db6cbc7711 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr106973.C @@ -0,0 +1,22 @@ +// https://gcc.gnu.org/PR106973 +// { dg-require-effective-target indirect_jumps } +#include +#include + +struct generator; +struct generator_promise { + generator get_return_object(); + std::suspend_always initial_suspend(); + std::suspend_always final_suspend() noexcept; + std::suspend_always yield_value(int); + void unhandled_exception(); +}; + +struct generator { + using promise_type = generator_promise; +}; +jmp_buf foo_env; +generator foo() { + setjmp(foo_env); + co_yield 1; +}
[gcc r15-3454] c++: add a testcase for [PR 108620]
https://gcc.gnu.org/g:858918ef4233c837ab85819ad159bf452df3a7fb commit r15-3454-g858918ef4233c837ab85819ad159bf452df3a7fb Author: Arsen Arsenović Date: Tue Sep 3 20:58:55 2024 +0200 c++: add a testcase for [PR 108620] Fixed by r15-2540-g32e678b2ed7521. Add a testcase, as the original ones do not cover this particular failure mode. gcc/testsuite/ChangeLog: PR c++/108620 * g++.dg/coroutines/pr108620.C: New test. Diff: --- gcc/testsuite/g++.dg/coroutines/pr108620.C | 95 ++ 1 file changed, 95 insertions(+) diff --git a/gcc/testsuite/g++.dg/coroutines/pr108620.C b/gcc/testsuite/g++.dg/coroutines/pr108620.C new file mode 100644 index 000..e8016b9f8a2 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr108620.C @@ -0,0 +1,95 @@ +// https://gcc.gnu.org/PR108620 +#include +#include +#include + +template +struct task; + +template +struct task_private_data { + inline task_private_data() noexcept : data_(nullptr) {} + inline task_private_data(PrivateDataType* input) noexcept : data_(input) {} + inline task_private_data(task_private_data&& other) noexcept = default; + inline task_private_data& operator=(task_private_data&&) noexcept = default; + inline task_private_data(const task_private_data&) = delete; + inline task_private_data& operator=(const task_private_data&) = delete; + inline ~task_private_data() {} + + inline bool await_ready() const noexcept { return true; } + inline PrivateDataType* await_resume() const noexcept { return data_; } + inline void await_suspend(std::coroutine_handle<>) noexcept {} + + PrivateDataType* data_; +}; + +template +struct task_context { +PrivateDataType data_; +}; + +template +struct task { +using self_type = task; +std::shared_ptr> context_; + +task(const std::shared_ptr>& input): context_(input) {} + +static auto yield_private_data() noexcept { return task_private_data{}; } + +struct promise_type { + std::shared_ptr> context_; + + template + promise_type(Input&& input, Rest&&...) { +context_ = std::make_shared>(); +context_->data_ = std::forward(input); + } + + auto get_return_object() noexcept { return self_type{context_}; } + std::suspend_never initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void unhandled_exception() { throw; } + + template + void return_value(ReturnType&&) {} + + template + inline task_private_data yield_value( + task_private_data&& input) noexcept { +input.data_ = &context_->data_; +return task_private_data(input.data_); + } +}; +}; + +template +task call1(TArg&& arg, OutputType& output) { +OutputType* ptr = co_yield task::yield_private_data(); +output = *ptr; +co_return 0; +} + + +struct container { +std::string* ptr; +}; + +template +task call2(TArg&& arg, container& output) { +output.ptr = co_yield task::yield_private_data(); +co_return 0; +} + +int main() { + // success + std::string output1; + call1(std::string("hello1"), output1); + std::cout<< "output1: "<< output1<< std::endl; + + // crash + container output2; + auto task2 = call2(std::string("hello2"), output2); + std::cout<< "output2: "<< *output2.ptr<< std::endl; + return 0; +}
[gcc r15-2457] dir-locals: apply our C settings in C++ also
https://gcc.gnu.org/g:ebf4f095568e8e4af042f3e5a8cb655d9172 commit r15-2457-gebf4f095568e8e4af042f3e5a8cb655d9172 Author: Arsen Arsenović Date: Wed Jul 31 16:53:35 2024 +0200 dir-locals: apply our C settings in C++ also This also works with Emacs 30 Tree-Sitter C and C++ modes, as they are submodes. ChangeLog: * .dir-locals.el: Change c-mode to a list of C, C++ and ObjC modes that Emacs currently provides. Diff: --- .dir-locals.el | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.dir-locals.el b/.dir-locals.el index fa031cbded99..2c12b3866633 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -18,6 +18,10 @@ (tcl-continued-indent-level . 4) (indent-tabs-mode . t))) (nil . ((bug-reference-url-format . "https://gcc.gnu.org/PR%s";))) + ;; Please keep C and C++ in sync. (c-mode . ((c-file-style . "GNU") (indent-tabs-mode . t) - (fill-column . 79 + (fill-column . 79))) + (c++-mode . ((c-file-style . "GNU") + (indent-tabs-mode . t) + (fill-column . 79
[gcc r15-2540] c++/coroutines: only defer expanding co_{await, return, yield} if dependent [PR112341]
https://gcc.gnu.org/g:32e678b2ed752154b2f96719e33f11a7c6417f20 commit r15-2540-g32e678b2ed752154b2f96719e33f11a7c6417f20 Author: Arsen Arsenović Date: Tue Jul 30 23:36:24 2024 +0200 c++/coroutines: only defer expanding co_{await,return,yield} if dependent [PR112341] By doing so, we can get diagnostics in template decls when we know we can. For instance, in the following: awaitable g(); template task f() { co_await g(); co_yield 1; co_return "foo"; } ... the coroutine promise type in each statement is always std::coroutine_handle::promise_type, and all of the operands are not type-dependent, so we can always compute the resulting types (and expected types) of these expressions and statements. Also, when we do not know the type of the CO_AWAIT_EXPR or CO_YIELD_EXPR, we now return NULL_TREE as the type rather than unknown_type_node. This is more correct, since the type is not unknown, it just isn't determined yet. This also means we can remove the CO_AWAIT_EXPR and CO_YIELD_EXPR special-cases from type_dependent_expression_p. PR c++/112341 - error: insufficient contextual information to determine type on co_await result in function template gcc/cp/ChangeLog: PR c++/112341 * coroutines.cc (struct coroutine_info): Also cache the traits type. (ensure_coro_initialized): New function. Makes sure we have initialized the coroutine state successfully, or informs the caller should it fail to do so. Extracted from coro_promise_type_found_p. (coro_get_traits_class): New function. Gets the (cached) coroutine traits type for a given coroutine. Extracted from coro_promise_type_found_p and refactored to cache the result. (coro_promise_type_found_p): Use the two functions above. (build_template_co_await_expr): New function. Builds a CO_AWAIT_EXPR representing a CO_AWAIT_EXPR in a template declaration. (build_co_await): Use the above if processing_template_decl, and give it a proper type. (coro_dependent_p): New function. Returns true iff its argument is a type-dependent expression OR the current functions traits class is type dependent. (finish_co_await_expr): Defer expansion only in the case coro_dependent_p returns true. (finish_co_yield_expr): Ditto. (finish_co_return_stmt): Ditto. * pt.cc (type_dependent_expression_p): Do not treat CO_AWAIT/CO_YIELD specially. gcc/testsuite/ChangeLog: PR c++/112341 * g++.dg/coroutines/pr112341-2.C: New test. * g++.dg/coroutines/pr112341-3.C: New test. * g++.dg/coroutines/torture/co-yield-03-tmpl-nondependent.C: New test. * g++.dg/coroutines/pr112341.C: New test. Diff: --- gcc/cp/coroutines.cc | 157 - gcc/cp/pt.cc | 5 - gcc/testsuite/g++.dg/coroutines/pr112341-2.C | 25 gcc/testsuite/g++.dg/coroutines/pr112341-3.C | 65 + gcc/testsuite/g++.dg/coroutines/pr112341.C | 21 +++ .../torture/co-yield-03-tmpl-nondependent.C| 140 ++ 6 files changed, 376 insertions(+), 37 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 127a1c06b56e..91bbe6b0a0eb 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -85,6 +85,7 @@ struct GTY((for_user)) coroutine_info tree actor_decl;/* The synthesized actor function. */ tree destroy_decl; /* The synthesized destroy function. */ tree promise_type; /* The cached promise type for this function. */ + tree traits_type; /* The cached traits type for this function. */ tree handle_type; /* The cached coroutine handle for this function. */ tree self_h_proxy; /* A handle instance that is used as the proxy for the one that will eventually be allocated in the coroutine @@ -429,11 +430,12 @@ find_promise_type (tree traits_class) return promise_type; } +/* Perform initialization of the coroutine processor state, if not done + before. */ + static bool -coro_promise_type_found_p (tree fndecl, location_t loc) +ensure_coro_initialized (location_t loc) { - gcc_assert (fndecl != NULL_TREE); - if (!coro_initialized) { /* Trees we only need to create once. @@ -466,6 +468,30 @@ coro_promise_type_found_p (tree fndecl, location_t loc) coro_initialized = true; } + return true; +} + +/* Try to get the coroutine traits class. */ +static tree +coro_get_traits_class (tree fndecl, location_t loc) +{ + gcc_assert (fndecl != NULL_TREE); + gcc_assert (coro_initialize
[gcc r15-2702] c++/coroutines: check for members we use in handle_types [PR105475]
https://gcc.gnu.org/g:5b4476a165565cb20729c0a97a3f43b060595209 commit r15-2702-g5b4476a165565cb20729c0a97a3f43b060595209 Author: Arsen Arsenović Date: Thu Jul 25 22:41:34 2024 +0200 c++/coroutines: check for members we use in handle_types [PR105475] Currently, it is possible to ICE GCC by giving it sufficiently broken code, where sufficiently broken means a std::coroutine_handle missing a default on the promise_type template argument, and missing members. As the code generator relies on lookups in the coroutine_handle never failing (and has no way to signal that error), lets do it ahead of time, save the result, and use that. This saves us some lookups and allows us to propagate an error. PR c++/105475 - coroutines: ICE in coerce_template_parms, at cp/pt.cc:9183 gcc/cp/ChangeLog: PR c++/105475 * coroutines.cc (struct coroutine_info): Add from_address. Carries the from_address member we looked up earlier. (coro_resume_identifier): Remove. Unused. (coro_init_identifiers): Do not initialize the above. (void_coro_handle_address): New variable. Contains the baselink for the std::coroutine_handle::address() instance method. (get_handle_type_address): New function. Looks up and validates handle_type::address in a given handle_type. (get_handle_type_from_address): New function. Looks up and validates handle_type::from_address in a given handle_type. (coro_promise_type_found_p): Remove reliance on coroutine_handle<> defaulting the promise type to void. Store get_handle_type_* results where appropriate. (get_coroutine_from_address): New helper. Gets the handle_type::from_address BASELINK from a coroutine_info. (build_actor_fn): Use the get_coroutine_from_address helper and void_coro_handle_address. gcc/testsuite/ChangeLog: PR c++/105475 * g++.dg/coroutines/pr103868.C: Add std::coroutine_handle members we check for now. * g++.dg/coroutines/pr105287.C: Ditto. * g++.dg/coroutines/pr105301.C: Ditto. * g++.dg/coroutines/pr94528.C: Ditto. * g++.dg/coroutines/pr94879-folly-1.C: Ditto. * g++.dg/coroutines/pr94883-folly-2.C: Ditto. * g++.dg/coroutines/pr98118.C: Ditto. * g++.dg/coroutines/pr105475.C: New test. * g++.dg/coroutines/pr105475-1.C: New test. * g++.dg/coroutines/pr105475-2.C: New test. * g++.dg/coroutines/pr105475-3.C: New test. * g++.dg/coroutines/pr105475-4.C: New test. * g++.dg/coroutines/pr105475-5.C: New test. * g++.dg/coroutines/pr105475-6.C: New test. * g++.dg/coroutines/pr105475-broken-spec.C: New test. * g++.dg/coroutines/pr105475-broken-spec-2.C: New test. Diff: --- gcc/cp/coroutines.cc | 138 ++--- gcc/testsuite/g++.dg/coroutines/pr103868.C | 2 + gcc/testsuite/g++.dg/coroutines/pr105287.C | 2 + gcc/testsuite/g++.dg/coroutines/pr105301.C | 5 +- gcc/testsuite/g++.dg/coroutines/pr105475-1.C | 27 gcc/testsuite/g++.dg/coroutines/pr105475-2.C | 29 + gcc/testsuite/g++.dg/coroutines/pr105475-3.C | 29 + gcc/testsuite/g++.dg/coroutines/pr105475-4.C | 41 ++ gcc/testsuite/g++.dg/coroutines/pr105475-5.C | 29 + gcc/testsuite/g++.dg/coroutines/pr105475-6.C | 29 + .../g++.dg/coroutines/pr105475-broken-spec-2.C | 33 + .../g++.dg/coroutines/pr105475-broken-spec.C | 29 + gcc/testsuite/g++.dg/coroutines/pr105475.C | 28 + gcc/testsuite/g++.dg/coroutines/pr94528.C | 11 +- gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C | 10 +- gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C | 10 +- gcc/testsuite/g++.dg/coroutines/pr98118.C | 10 +- 17 files changed, 439 insertions(+), 23 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index af03f5e0f744..742f0e505976 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -91,6 +91,7 @@ struct GTY((for_user)) coroutine_info one that will eventually be allocated in the coroutine frame. */ tree promise_proxy; /* Likewise, a proxy promise instance. */ + tree from_address; /* handle_type from_address function. */ tree return_void; /* The expression for p.return_void() if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this function into a coroutine. */ @@ -203,7 +204,6 @@ static GTY(()) tree coro_final_suspend_identifier; static GTY(()) tree coro_return_void_identifier; static GTY(()) tree coro_retu
[gcc r15-3922] c++: simplify handling implicit INDIRECT_REF and co_await in convert_to_void
https://gcc.gnu.org/g:de03ef6337b0a368d61c74b790313b4216c7ed6e commit r15-3922-gde03ef6337b0a368d61c74b790313b4216c7ed6e Author: Arsen Arsenović Date: Fri Sep 20 13:13:02 2024 +0200 c++: simplify handling implicit INDIRECT_REF and co_await in convert_to_void convert_to_void has, so far, when converting a co_await expression to void altered the await_resume expression of a co_await so that it is also converted to void. This meant that the type of the await_resume expression, which is also supposed to be the type of the whole co_await expression, was not the same as the type of the CO_AWAIT_EXPR tree. While this has not caused problems so far, it is unexpected, I think. Also, convert_to_void had a special case when an INDIRECT_REF wrapped a CALL_EXPR. In this case, we also diagnosed maybe_warn_nodiscard. This was a duplication of logic related to converting call expressions to void. Instead, we can generalize a bit, and rather discard the expression that was implicitly dereferenced instead. This patch changes the diagnostic of: void f(struct S* x) { static_cast(*x); } ... from: warning: indirection will not access object of incomplete type 'volatile S' in statement ... to: warning: implicit dereference will not access object of type ‘volatile S’ in statement ... but should have no impact in other cases. gcc/cp/ChangeLog: * coroutines.cc (co_await_get_resume_call): Return a tree directly, rather than a tree pointer. * cp-tree.h (co_await_get_resume_call): Adjust signature accordingly. * cvt.cc (convert_to_void): Do not alter CO_AWAIT_EXPRs when discarding them. Simplify handling implicit INDIRECT_REFs. gcc/testsuite/ChangeLog: * g++.dg/coroutines/nodiscard-1.C: New test. Diff: --- gcc/cp/coroutines.cc | 4 +- gcc/cp/cp-tree.h | 2 +- gcc/cp/cvt.cc | 102 +- gcc/testsuite/g++.dg/coroutines/nodiscard-1.C | 77 +++ 4 files changed, 132 insertions(+), 53 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 50904e0d004e..8e4c55a800e4 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -730,14 +730,14 @@ coro_get_destroy_function (tree decl) /* Given a CO_AWAIT_EXPR AWAIT_EXPR, return its resume call. */ -tree* +tree co_await_get_resume_call (tree await_expr) { gcc_checking_assert (TREE_CODE (await_expr) == CO_AWAIT_EXPR); tree vec = TREE_OPERAND (await_expr, 3); if (!vec) return nullptr; - return &TREE_VEC_ELT (vec, 2); + return TREE_VEC_ELT (vec, 2); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7c438eca16d6..39c065eecf6d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8782,7 +8782,7 @@ extern tree coro_get_actor_function (tree); extern tree coro_get_destroy_function (tree); extern tree coro_get_ramp_function (tree); -extern tree* co_await_get_resume_call (tree await_expr); +extern tree co_await_get_resume_call (tree await_expr); /* contracts.cc */ diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index df02b8faaf51..526937d36181 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1272,88 +1272,96 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) complete_type (type); int is_complete = COMPLETE_TYPE_P (type); - /* Can't load the value if we don't know the type. */ - if (is_volatile && !is_complete) + /* Don't load the value if this is an implicit dereference, or if + the type needs to be handled by ctors/dtors. */ + if (is_reference) { -if (complain & tf_warning) +if (is_volatile && (complain & tf_warning) + /* A co_await expression, in its await_resume expression, also + contains an implicit dereference. As a result, we don't + need to warn about them here. */ + && TREE_CODE (TREE_OPERAND (expr, 0)) != CO_AWAIT_EXPR) switch (implicit) { case ICV_CAST: warning_at (loc, 0, "conversion to void will not access " - "object of incomplete type %qT", type); + "object of type %qT", type); break; case ICV_SECOND_OF_COND: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in second operand " - "of conditional expression", type); + warning_at (loc, 0, "implicit dereference will not access " +
[gcc r15-3921] c++/coro: prevent ICV_STATEMENT diagnostics in temp promotion [PR116502]
https://gcc.gnu.org/g:05e4f07cad1eacf869c10622cae2a9cdee3b6a7a commit r15-3921-g05e4f07cad1eacf869c10622cae2a9cdee3b6a7a Author: Arsen Arsenović Date: Wed Aug 28 21:59:18 2024 +0200 c++/coro: prevent ICV_STATEMENT diagnostics in temp promotion [PR116502] If such a diagnostic is necessary, it has already been emitted, otherwise, it is not correct and emitting it here is inactionable by the user, and bogus. PR c++/116502 gcc/cp/ChangeLog: * coroutines.cc (maybe_promote_temps): Convert temporary initializers to void without complaining. gcc/testsuite/ChangeLog: * g++.dg/coroutines/maybe-unused-1.C: New test. * g++.dg/coroutines/pr116502.C: New test. Diff: --- gcc/cp/coroutines.cc | 12 ++--- gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C | 33 gcc/testsuite/g++.dg/coroutines/pr116502.C | 33 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 4c7ea1dd3216..50904e0d004e 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3203,7 +3203,13 @@ maybe_promote_temps (tree *stmt, void *d) to run the initializer. If the initializer is a conditional expression, we need to collect and declare any promoted variables nested within it. DTORs for such -variables must be run conditionally too. */ +variables must be run conditionally too. + +Since here we're synthetically processing code here, we've already +emitted any Wunused-result warnings. Below, however, we call +finish_expr_stmt, which will convert its operand to void, and could +result in such a diagnostic being emitted. To avoid that, convert to +void ahead of time. */ if (t->var) { tree var = t->var; @@ -3213,7 +3219,7 @@ maybe_promote_temps (tree *stmt, void *d) if (TREE_CODE (t->init) == COND_EXPR) process_conditional (t, vlist); else - finish_expr_stmt (t->init); + finish_expr_stmt (convert_to_void (t->init, ICV_STATEMENT, tf_none)); if (tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error)) { tree cl = build_stmt (sloc, CLEANUP_STMT, expr_list, cleanup, var); @@ -3232,7 +3238,7 @@ maybe_promote_temps (tree *stmt, void *d) if (TREE_CODE (t->init) == COND_EXPR) process_conditional (t, vlist); else - finish_expr_stmt (t->init); + finish_expr_stmt (convert_to_void (t->init, ICV_STATEMENT, tf_none)); if (expr_list) { if (TREE_CODE (expr_list) != STATEMENT_LIST) diff --git a/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C b/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C new file mode 100644 index ..68d59d83e8eb --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C @@ -0,0 +1,33 @@ +// https://gcc.gnu.org/PR116502 +#include + +struct SuspendNever { + bool await_ready() noexcept; + void await_suspend(std::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct Coroutine; + +struct PromiseType { + Coroutine get_return_object(); + SuspendNever initial_suspend(); + SuspendNever final_suspend() noexcept; + void return_void(); + void unhandled_exception(); +}; + +struct Coroutine { + using promise_type = PromiseType; +}; + +struct Awaiter { + bool await_ready(); + void await_suspend(std::coroutine_handle<>); + [[nodiscard]] int& await_resume(); +}; + +Coroutine foo() +{ + co_await Awaiter {}; // { dg-warning "Wunused-result" } +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr116502.C b/gcc/testsuite/g++.dg/coroutines/pr116502.C new file mode 100644 index ..95cc0bc8a983 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116502.C @@ -0,0 +1,33 @@ +// https://gcc.gnu.org/PR116502 +#include + +struct SuspendNever { + bool await_ready() noexcept; + void await_suspend(std::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct Coroutine; + +struct PromiseType { + Coroutine get_return_object(); + SuspendNever initial_suspend(); + SuspendNever final_suspend() noexcept; + void return_void(); + void unhandled_exception(); +}; + +struct Coroutine { + using promise_type = PromiseType; +}; + +struct Awaiter { + bool await_ready(); + void await_suspend(std::coroutine_handle<>); + [[nodiscard]] int& await_resume(); +}; + +Coroutine foo() +{ + (void)co_await Awaiter {}; +}
[gcc r15-3923] c++/coro: ignore cleanup_point_exprs while expanding awaits [PR116793]
https://gcc.gnu.org/g:d888a8a8dcf391197ae82e2bbf99507effc27950 commit r15-3923-gd888a8a8dcf391197ae82e2bbf99507effc27950 Author: Arsen Arsenović Date: Tue Sep 24 18:16:01 2024 +0200 c++/coro: ignore cleanup_point_exprs while expanding awaits [PR116793] If we reach a CLEANUP_POINT_EXPR while trying to walk statements, we actually care about the statement or statement list contained within it. Indeed, such a construction started happening with r15-3513-g964577c31df206, after temporary promotion. In the test case presented in PR116793, the compiler generated:T002_2_3]; int T002 [value-expr: frame_ptr->T002_2_3]; <) >; struct _cleanup_task Aw0 [value-expr: frame_ptr->Aw0_2_3]; <) >; < Aw0 {_cleanup_task::await_ready (&Aw0), _cleanup_task::await_suspend<_task1::promise_type> (&Aw0, TARGET_EXPR ), <<< Unknown tree: aggr_init_expr 4 await_resume D.22443 &Aw0 >>>} 0 >>>) >; <; } D.22467 = 1; int & i [value-expr: frame_ptr->i_1_2]; < (NON_LVALUE_EXPR )) >;>>; ... i.e. a statement list within a cleanup point. In such a case, we don't actually care about the cleanup point, but we do care about the statement inside, so, we can just walk down into the CLEANUP_POINT_EXPR. PR c++/116793 gcc/cp/ChangeLog: * coroutines.cc (await_statement_expander): Just process subtrees if encountering a CLEANUP_POINT_EXPR. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116793-1.C: New test. Diff: --- gcc/cp/coroutines.cc | 4 +++- gcc/testsuite/g++.dg/coroutines/pr116793-1.C | 26 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 8e4c55a800e4..86a5ac8999ac 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2063,7 +2063,9 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d) tree res = NULL_TREE; /* Process a statement at a time. */ - if (STATEMENT_CLASS_P (*stmt) || TREE_CODE (*stmt) == BIND_EXPR) + if (STATEMENT_CLASS_P (*stmt) + || TREE_CODE (*stmt) == BIND_EXPR + || TREE_CODE (*stmt) == CLEANUP_POINT_EXPR) return NULL_TREE; /* Just process the sub-trees. */ else if (TREE_CODE (*stmt) == STATEMENT_LIST) { diff --git a/gcc/testsuite/g++.dg/coroutines/pr116793-1.C b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C new file mode 100644 index ..ed2bdd26996a --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C @@ -0,0 +1,26 @@ +// https://gcc.gnu.org/PR116793 +#include +#include +struct _cleanup_task { + bool await_ready() const noexcept; + template + bool await_suspend(std::coroutine_handle parent) noexcept; + std::tuple await_resume() noexcept; +}; +struct _task1 { + struct promise_type final { +std::suspend_always initial_suspend() noexcept; +_task1 get_return_object() noexcept; +void unhandled_exception() noexcept; +struct awaiter final { + bool await_ready() noexcept; + void await_resume() noexcept; + void await_suspend(std::coroutine_handle h) noexcept; +}; +awaiter final_suspend() noexcept; + }; +}; +_cleanup_task func(int &&); +_task1 g() { + auto &&[i] = co_await func(3); +}
[gcc r15-6447] libstdc++: add missing return in generator assignment operator [PR118196]
https://gcc.gnu.org/g:9a1cb52cae2d48d2fc18d01b534bf4e3203f0cc1 commit r15-6447-g9a1cb52cae2d48d2fc18d01b534bf4e3203f0cc1 Author: Arsen Arsenović Date: Tue Dec 24 12:50:28 2024 +0100 libstdc++: add missing return in generator assignment operator [PR118196] libstdc++-v3/ChangeLog: PR libstdc++/118196 * include/std/generator (generator::operator=(generator)): Add missing 'return *this;'. * testsuite/24_iterators/range_generators/pr118196.cc: New test. Diff: --- libstdc++-v3/include/std/generator | 1 + .../testsuite/24_iterators/range_generators/pr118196.cc | 13 + 2 files changed, 14 insertions(+) diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator index 3a19d535ef86..7d7e9b708657 100644 --- a/libstdc++-v3/include/std/generator +++ b/libstdc++-v3/include/std/generator @@ -717,6 +717,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { swap(__other._M_coro, this->_M_coro); swap(__other._M_began, this->_M_began); + return *this; } _Iterator diff --git a/libstdc++-v3/testsuite/24_iterators/range_generators/pr118196.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/pr118196.cc new file mode 100644 index ..ae161df2a4a6 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_generators/pr118196.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++23 } } +#include "" + +std::generator +generator(); + +void +try_reassigning() +{ + auto gen = generator(); + auto gen2 = generator(); + gen = std::move(gen2); +}
[gcc r15-6084] c++: Implement a coroutine language debug dump
https://gcc.gnu.org/g:fcdc0d8963adfa99315a7895b5685ac102182cdf commit r15-6084-gfcdc0d8963adfa99315a7895b5685ac102182cdf Author: Arsen Arsenović Date: Thu Sep 5 19:53:07 2024 +0200 c++: Implement a coroutine language debug dump This provides to people working on coroutines, as well as writing tests for coroutines, a way to have insight into the results and inputs of the coroutine transformation passes, which is quite essential to understanding what happens in the coroutine transformation. Currently, the information dumped is the pre-transform function (which is not otherwise available), the generated ramp function, the generated frame type, the transformed actor/resumer, and the destroyer stub. While debugging this, I've also encountered a minor bug in c-pretty-print.cc, where it tried to check DECL_REGISTER of DECLs that did not support it. I've added a check for that. Similary, I found one in pp_cxx_template_parameter, where TREE_TYPE was called on the list cell the template parameter was in rather than on the parameter itself. I've fixed that. And, lastly, there appeared to be no way to pretty-print a FIELD_DECL, so I added support to cxx_pretty_printer::declaration for it (by reusing the VAR_DECL path). Co-authored-by: Iain Sandoe gcc/c-family/ChangeLog: * c-pretty-print.cc (c_pretty_printer::storage_class_specifier): Check that we're looking at a PARM_DECL or VAR_DECL before looking at DECL_REGISTER. gcc/cp/ChangeLog: * coroutines.cc (dump_record_fields): New helper. Iterates a RECORD_TYPEs TYPE_FIELDS and pretty-prints them. (dmp_str): New. The lang-coro dump stream. (coro_dump_id): New. ID of the lang-coro dump. (coro_dump_flags): New. Flags passed to the lang-coro dump. (coro_maybe_dump_initial_function): New helper. Prints, if dumping is enabled, the fndecl passed to it as the original function. (coro_maybe_dump_ramp): New. Prints the ramp function passed to it, if dumping is enabled. (coro_maybe_dump_transformed_functions): New. (cp_coroutine_transform::apply_transforms): Initialize the lang-coro dump. Call coro_maybe_dump_initial_function on the original function, as well as coro_maybe_dump_ramp, after the transformation into the ramp is finished. (cp_coroutine_transform::finish_transforms): Call coro_maybe_dump_transformed_functions on the built actor and destroy. * cp-objcp-common.cc (cp_register_dumps): Register the coroutine dump. * cp-tree.h (coro_dump_id): Declare as extern. * cxx-pretty-print.cc (pp_cxx_template_parameter): Don't call TREE_TYPE on a TREE_LIST cell. (cxx_pretty_printer::declaration): Handle FIELD_DECL similar to VAR_DECL. gcc/ChangeLog: * dumpfile.cc (FIRST_ME_AUTO_NUMBERED_DUMP): Bump to 6 for sake of the coroutine dump. Diff: --- gcc/c-family/c-pretty-print.cc | 3 +- gcc/cp/coroutines.cc | 124 + gcc/cp/cp-objcp-common.cc | 2 + gcc/cp/cp-tree.h | 1 + gcc/cp/cxx-pretty-print.cc | 3 +- gcc/dumpfile.cc| 2 +- 6 files changed, 132 insertions(+), 3 deletions(-) diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index b772d8d8ae2b..c48336f88295 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -753,7 +753,8 @@ c_pretty_printer::storage_class_specifier (tree t) pp_c_ws_string (this, "typedef"); else if (DECL_P (t)) { - if (DECL_REGISTER (t)) + if ((TREE_CODE (t) == PARM_DECL || VAR_P (t)) + && DECL_REGISTER (t)) pp_c_ws_string (this, "register"); else if (TREE_STATIC (t) && VAR_P (t)) pp_c_ws_string (this, "static"); diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 7585229d94ab..242afbe9a251 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -34,6 +34,123 @@ along with GCC; see the file COPYING3. If not see #include "hash-map.h" #include "coroutines.h" +/* = Debug. = */ + +#include "langhooks.h" +#include "cxx-pretty-print.h" + +/* Walk through the fields of the type TYP and print them to the pretty printer + PP. */ + +static void +dump_record_fields (cxx_pretty_printer *pp, tree typ) +{ + pp->type_id (typ); + pp_newline_and_indent (pp, 2); + pp_left_brace (pp); + pp_indentation (pp) += 2; + + /* We'll be on a new line, we don't need padding. */ + pp->set_padding (pp_none); + + for (tree tmp = TYPE_FIELDS (typ); tmp; tmp = DECL_CHAIN (tmp)) +{ + pp_newline_and_indent (pp, 0)
[gcc r15-5577] doc/cpp: Document __has_include_next
https://gcc.gnu.org/g:ffeee625c53d882171af436222a7b18ed9ed89e1 commit r15-5577-gffeee625c53d882171af436222a7b18ed9ed89e1 Author: Arsen Arsenović Date: Fri Oct 18 23:14:58 2024 +0200 doc/cpp: Document __has_include_next While hacking on an unrelated change, I noticed that __has_include_next hasn't been documented at all. This patch adds it to the __has_include manual node. gcc/ChangeLog: * doc/cpp.texi (__has_include): Document __has_include_next also. (Conditional Syntax): Mention __has_include_next in the description for the __has_include menu entry. Diff: --- gcc/doc/cpp.texi | 40 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index a83aa263df0f..970c0a393971 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -3204,7 +3204,8 @@ directive}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}. * @code{__has_builtin}:: * @code{__has_feature}:: * @code{__has_extension}:: -* @code{__has_include}:: +* @code{__has_include}::@code{__has_include} and + @code{__has_include_next} * @code{__has_embed}:: @end menu @@ -3607,22 +3608,27 @@ details of which identifiers are accepted by these function-like macros, see the Clang documentation}}. @node @code{__has_include} -@subsection @code{__has_include} +@subsection @code{__has_include}, @code{__has_include_next} @cindex @code{__has_include} - -The special operator @code{__has_include (@var{operand})} may be used in -@samp{#if} and @samp{#elif} expressions to test whether the header referenced -by its @var{operand} can be included using the @samp{#include} directive. Using -the operator in other contexts is not valid. The @var{operand} takes -the same form as the file in the @samp{#include} directive (@pxref{Include -Syntax}) and evaluates to a nonzero value if the header can be included and -to zero otherwise. Note that that the ability to include a header doesn't -imply that the header doesn't contain invalid constructs or @samp{#error} -directives that would cause the preprocessor to fail. - -The @code{__has_include} operator by itself, without any @var{operand} or -parentheses, acts as a predefined macro so that support for it can be tested -in portable code. Thus, the recommended use of the operator is as follows: +@cindex @code{__has_include_next} + +The special operators @code{__has_include (@var{operand})} and +@code{__has_include_next (@var{operand})} may be used in @samp{#if} and +@samp{#elif} expressions to test whether the header referenced by their +@var{operand} can be included using the @samp{#include} and +@samp{#include_next} directive, respectively. Using the operators in +other contexts is not valid. The @var{operand} takes the same form as +the file in the @samp{#include} and @samp{#include_next} directives +respectively (@pxref{Include Syntax}) and the operators evaluate to a +nonzero value if the header can be included and to zero otherwise. Note +that that the ability to include a header doesn't imply that the header +doesn't contain invalid constructs or @samp{#error} directives that +would cause the preprocessor to fail. + +The @code{__has_include} and @code{__has_include_next} operators by +themselves, without any @var{operand} or parentheses, act as +predefined macros so that support for them can be tested in portable +code. Thus, the recommended use of the operators is as follows: @smallexample #if defined __has_include @@ -3645,6 +3651,8 @@ but not with others that don't. #endif @end smallexample +The same holds for @code{__has_include_next}. + @node @code{__has_embed} @subsection @code{__has_embed} @cindex @code{__has_embed}
[gcc r15-6409] warn-access: ignore template parameters when matching operator new/delete [PR109224]
https://gcc.gnu.org/g:7d83a32aacd6005c0c038c74562e35d70f6a77a8 commit r15-6409-g7d83a32aacd6005c0c038c74562e35d70f6a77a8 Author: Arsen Arsenović Date: Thu Aug 1 17:38:15 2024 +0200 warn-access: ignore template parameters when matching operator new/delete [PR109224] Template parameters on a member operator new cannot affect its member status nor whether it is a singleton or array operator new, hence, we can ignore it for purposes of matching. Similar logic applies to the placement operator delete. In the PR (and a lot of idiomatic coroutine code generally), operator new is templated in order to be able to inspect (some of) the arguments passed to the coroutine, to make allocation-related decisions. However, the coroutine implementation will not call a placement delete form, so it cannot get templated. As a result, when demangling, we have an extra template DEMANGLE_COMPONENT_TEMPLATE around the actual operator new, but not operator delete. This terminates new_delete_mismatch_p early. PR middle-end/109224 - Wmismatched-new-delete false positive with a templated operator new (common with coroutines) gcc/ChangeLog: PR middle-end/109224 * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Strip DEMANGLE_COMPONENT_TEMPLATE from the operator new and operator after demangling. gcc/testsuite/ChangeLog: PR middle-end/109224 * g++.dg/warn/Wmismatched-new-delete-9.C: New test. Diff: --- gcc/gimple-ssa-warn-access.cc | 18 - .../g++.dg/warn/Wmismatched-new-delete-9.C | 47 ++ gcc/testsuite/g++.dg/warn/pr109224.C | 25 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 820f23825254..1eb9d2ee4bac 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -1765,7 +1765,23 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl) void *np = NULL, *dp = NULL; demangle_component *ndc = cplus_demangle_v3_components (new_str, 0, &np); demangle_component *ddc = cplus_demangle_v3_components (del_str, 0, &dp); - bool mismatch = ndc && ddc && new_delete_mismatch_p (*ndc, *ddc); + + /* Sometimes, notably quite often with coroutines, 'operator new' is + templated. However, template arguments can't change whether a given + new/delete is a singleton or array one, nor what it is a member of, so + the template arguments can be safely ignored for the purposes of checking + for mismatches. */ + + auto strip_dc_template = [] (demangle_component* dc) + { +if (dc->type == DEMANGLE_COMPONENT_TEMPLATE) + dc = dc->u.s_binary.left; +return dc; + }; + + bool mismatch = (ndc && ddc + && new_delete_mismatch_p (*strip_dc_template (ndc), +*strip_dc_template (ddc))); free (np); free (dp); return mismatch; diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C new file mode 100644 index ..d431f4049e87 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C @@ -0,0 +1,47 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-additional-options "-Wmismatched-new-delete" } */ +/* PR middle-end/109224 */ +/* Verify that we consider templated operator new matching with its operator + delete. */ + +#include + +struct foo +{ + template + void* operator new (std::size_t sz, Args&&...); + template + void* operator new[] (std::size_t sz, Args&&...); + + void operator delete (void* x); + void operator delete[] (void* x); + + template + void operator delete (void* x, Args&&...); + template + void operator delete[] (void* x, Args&&...); +}; + +void +f () +{ + delete (new (123, true) foo); + delete[] (new (123, true) foo[123]); + + delete (new (123, true) foo[123]); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + delete[] (new (123, true) foo); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + + foo::operator delete (foo::operator new (1, 123, true), 123, true); + foo::operator delete[] (foo::operator new[] (123, 123, true), 123, true); + + foo::operator delete (foo::operator new[] (123, 123, true), 123, true); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + foo::operator delete[] (foo::operator new (1, 123, true), 123, true); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } +} diff --git a/gcc/testsuite/g++.dg/warn/pr109224.C b/gcc/t
[gcc r15-7129] d, ada/spec: only sub nostd{inc, lib} rather than nostd{inc, lib}*
https://gcc.gnu.org/g:fbc94ff6e7615c7e5aeff8f3e0a2f894889e1b4f commit r15-7129-gfbc94ff6e7615c7e5aeff8f3e0a2f894889e1b4f Author: Arsen Arsenović Date: Mon Sep 2 21:29:53 2024 +0200 d,ada/spec: only sub nostd{inc,lib} rather than nostd{inc,lib}* This prevents the gcc driver erroneously accepting -nostdlib++ when it should not when Ada was enabled. Also, similarly, -nostdinc* (where * is nonempty) is unhandled by either the Ada or D compiler, so the spec should not substitute those either (thanks for pointing that out, Jakub). Brought to my attention by Michał Górny . gcc/ada/ChangeLog: * gcc-interface/lang-specs.h: Replace %{nostdinc*} %{nostdlib*} with %{nostdinc} %{nostdlib}. gcc/d/ChangeLog: * lang-specs.h: Replace %{nostdinc*} with %{nostdinc}. gcc/testsuite/ChangeLog: * gcc.dg/driver-nostdlibstar.c: New test. Diff: --- gcc/ada/gcc-interface/lang-specs.h | 6 +++--- gcc/d/lang-specs.h | 2 +- gcc/testsuite/gcc.dg/driver-nostdlibstar.c | 4 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h index 2ba0f1d20a74..bfa41afe621b 100644 --- a/gcc/ada/gcc-interface/lang-specs.h +++ b/gcc/ada/gcc-interface/lang-specs.h @@ -37,7 +37,7 @@ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %{!S:%{!c:%e-c or -S required for Ada}}\ gnat1 %{I*} %{k8:-gnatk8} %{!Q:-quiet}\ -%{nostdinc*} %{nostdlib*}\ +%{nostdinc} %{nostdlib}\ %{fcompare-debug-second:-gnatd_A} \ %{O*} %{W*} %{w} %{p} %{pg:-p} " ADA_DUMPS_OPTIONS " \ %{coverage:-fprofile-arcs -ftest-coverage} " @@ -55,7 +55,7 @@ "\ %{!c:%e-c required for gnat2why}\ gnat1why %{I*} %{k8:-gnatk8} %{!Q:-quiet}\ -%{nostdinc*} %{nostdlib*}\ +%{nostdinc} %{nostdlib}\ %{a} " ADA_DUMPS_OPTIONS " \ %{gnatea:-gnatez} %{g*&m*&f*} \ %1 %{o*:%w%*-gnatO} \ @@ -66,7 +66,7 @@ "\ %{!c:%e-c required for gnat2scil}\ gnat1scil %{I*} %{k8:-gnatk8} %{!Q:-quiet}\ -%{nostdinc*} %{nostdlib*}\ +%{nostdinc} %{nostdlib}\ %{a} " ADA_DUMPS_OPTIONS " \ %{gnatea:-gnatez} %{g*&m*&f*} \ %1 %{o*:%w%*-gnatO} \ diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h index 2292e7eac9fa..64e7a5f25988 100644 --- a/gcc/d/lang-specs.h +++ b/gcc/d/lang-specs.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see {".dd", "@d", 0, 1, 0 }, {".di", "@d", 0, 1, 0 }, {"@d", - "%{!E:d21 %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \ + "%{!E:d21 %i %(cc1_options) %I %{nostdinc} %{i*} %{I*} %{J*} \ %{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \ %{X:-Xf %b.json} %{Xf*} \ diff --git a/gcc/testsuite/gcc.dg/driver-nostdlibstar.c b/gcc/testsuite/gcc.dg/driver-nostdlibstar.c new file mode 100644 index ..b3b208248abe --- /dev/null +++ b/gcc/testsuite/gcc.dg/driver-nostdlibstar.c @@ -0,0 +1,4 @@ +// Test that the GCC driver (which has no concept of libstdc++) rejects -nostdlib++ +// { dg-additional-options "-nostdlib++" } +// { dg-prune-output "compilation terminated" } +// { dg-error "unrecognized command-line option '-nostdlib\\+\\+'" "" { target *-*-* } 0 }