Jason Merrill <ja...@redhat.com> writes: > On 8/7/24 7:31 PM, Arsen Arsenović wrote: >> Enlargening the function-specific data block is not great. > > Indeed, I think it would be better to search DECL_SAVED_TREE for a RETURN_STMT > once we've decided to give an error.
The trouble with that is that finish_return_stmt currently uses input_location as the location for the entire return expr, so the location ends up being after the entire return value. I've hacked in a way to provide a different location to finih_return_stmt, when applying it like below, the produced result is the first result in the original email: diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 6cfe42f3bdd6..44b45f16b026 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -14965,12 +14965,15 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) /* Build the return-statement, check co-return first, since type deduction is not valid there. */ + auto l = make_location (token->location, + token->location, + input_location); if (keyword == RID_CO_RETURN) statement = finish_co_return_stmt (token->location, expr); else if (FNDECL_USED_AUTO (current_function_decl) && in_discarded_stmt) /* Don't deduce from a discarded return statement. */; else - statement = finish_return_stmt (expr); + statement = finish_return_stmt (expr, l); /* Look for the final `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); } ... without this change (so, using input_location), the result is: test.cc:38:11: error: a ‘return’ statement is not allowed in coroutine; did you mean ‘co_return’? 38 | return {}; | ^ ... which is not the best. That's the change I'm referring to in the original post that I haven't ran the testsuite on. Changing that location allows for simply searching DECL_SAVED_TREE (fndecl), though, and getting a good location out of it. >> I've >> considered changing the location of RETURN_STMT expressions to cover >> everything from the return expression to input_location after parsing >> the returned expr. The result of that is: >> test.cc:38:3: error: a ‘return’ statement is not allowed in coroutine; did >> you mean ‘co_return’? >> 38 | return {}; >> | ^~~~~~~~~ >> test.cc:37:3: note: function was made a coroutine here >> 37 | co_return; >> | ^~~~~~~~~ >> ... so, not bad, but I'm not sure how intrusive such a change would be >> (haven't tried the testsuite). The current patch produces: >> test.cc:36:3: error: a ‘return’ statement is not allowed in coroutine; did >> you mean ‘co_return’? >> 36 | return {}; >> | ^~~~~~ >> test.cc:35:3: note: function was made a coroutine here >> 35 | co_return; >> | ^~~~~~~~~ >> Is there a better location to use here or is the current (latter) one >> OK? > > The latter seems fine. > >> I haven't managed to found a nicer existing one. We also can't >> stash it in coroutine_info because a function might not have that at >> time we parse a return. >> Tested on x86_64-pc-linux-gnu. >> Have a lovely evening. >> ---------- >8 ---------- >> We now point out why a function is a coroutine. >> gcc/cp/ChangeLog: >> * coroutines.cc (coro_function_valid_p): Change how we diagnose >> returning coroutines. >> * cp-tree.h (struct language_function): Add first_return_loc >> field. Tracks the location of the first return encountered >> during parsing. >> (current_function_first_return_loc): New macro. Expands to the >> current functions' first_return_loc. >> * parser.cc (cp_parser_jump_statement): If parsing a RID_RETURN, >> save its location to current_function_first_return_loc. >> gcc/testsuite/ChangeLog: >> * g++.dg/coroutines/co-return-syntax-08-bad-return.C: Update to >> match new diagnostic. >> --- >> gcc/cp/coroutines.cc | 14 +++-- >> gcc/cp/cp-tree.h | 6 +++ >> gcc/cp/parser.cc | 4 ++ >> .../co-return-syntax-08-bad-return.C | 52 +++++++++++++++++-- >> 4 files changed, 68 insertions(+), 8 deletions(-) >> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc >> index 0f4dc42ec1c8..f32c7a2eec8d 100644 >> --- a/gcc/cp/coroutines.cc >> +++ b/gcc/cp/coroutines.cc >> @@ -968,11 +968,15 @@ coro_function_valid_p (tree fndecl) >> if (current_function_returns_value || current_function_returns_null) >> { >> - /* TODO: record or extract positions of returns (and the first coro >> - keyword) so that we can add notes to the diagnostic about where >> - the bad keyword is and what made the function into a coro. */ >> - error_at (f_loc, "a %<return%> statement is not allowed in coroutine;" >> - " did you mean %<co_return%>?"); >> + coroutine_info *coro_info = get_or_insert_coroutine_info (fndecl); >> + auto retloc = current_function_first_return_loc; >> + gcc_checking_assert (retloc && coro_info->first_coro_keyword); >> + >> + auto_diagnostic_group diaggrp; >> + error_at (retloc, "a %<return%> statement is not allowed in >> coroutine;" >> + " did you mean %<co_return%>?"); >> + inform (coro_info->first_coro_keyword, >> + "function was made a coroutine here"); >> return false; >> } >> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h >> index 911d1d7924cc..68c681150a1f 100644 >> --- a/gcc/cp/cp-tree.h >> +++ b/gcc/cp/cp-tree.h >> @@ -2123,6 +2123,8 @@ struct GTY(()) language_function { >> tree x_vtt_parm; >> tree x_return_value; >> + location_t first_return_loc; >> + >> BOOL_BITFIELD returns_value : 1; >> BOOL_BITFIELD returns_null : 1; >> BOOL_BITFIELD returns_abnormally : 1; >> @@ -2217,6 +2219,10 @@ struct GTY(()) language_function { >> #define current_function_return_value \ >> (cp_function_chain->x_return_value) >> +/* Location of the first 'return' stumbled upon during parsing. */ >> + >> +#define current_function_first_return_loc >> cp_function_chain->first_return_loc >> + >> /* In parser.cc. */ >> extern tree cp_literal_operator_id (const char *); >> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc >> index eb102dea8299..6cfe42f3bdd6 100644 >> --- a/gcc/cp/parser.cc >> +++ b/gcc/cp/parser.cc >> @@ -14957,6 +14957,10 @@ cp_parser_jump_statement (cp_parser* parser, tree >> &std_attrs) >> AGGR_INIT_EXPR_MUST_TAIL (ret_expr) = musttail_p; >> else >> set_musttail_on_return (expr, token->location, musttail_p); >> + >> + /* Save where we saw this keyword. */ >> + if (current_function_first_return_loc == UNKNOWN_LOCATION) >> + current_function_first_return_loc = token->location; >> } >> /* Build the return-statement, check co-return first, since type >> diff --git >> a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C >> b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C >> index 148ee4543e87..1e5d9e7a65a1 100644 >> --- a/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C >> +++ b/gcc/testsuite/g++.dg/coroutines/co-return-syntax-08-bad-return.C >> @@ -27,6 +27,7 @@ struct Coro { >> auto final_suspend () noexcept { return coro::suspend_always{}; } >> void return_void () { } >> void unhandled_exception() { } >> + auto yield_value (auto) noexcept { return coro::suspend_always{}; } >> }; >> }; >> @@ -34,10 +35,55 @@ extern int x; >> // Diagnose disallowed "return" in coroutine. >> Coro >> -bar () // { dg-error {a 'return' statement is not allowed} } >> +bar () >> { >> if (x) >> - return Coro(); >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> else >> - co_return; >> + co_return; // { dg-note "function was made a coroutine here" } >> +} >> + >> +Coro >> +bar1 () >> +{ >> + if (x) >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> + else >> + co_await std::suspend_never{}; // { dg-note "function was made a >> coroutine here" } >> +} >> + >> +Coro >> +bar2 () >> +{ >> + if (x) >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> + else >> + co_yield 123; // { dg-note "function was made a coroutine here" } >> +} >> + >> +Coro >> +bar3 () >> +{ >> + if (x) >> + co_return; // { dg-note "function was made a coroutine here" } >> + else >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> +} >> + >> +Coro >> +bar4 () >> +{ >> + if (x) >> + co_await std::suspend_never{}; // { dg-note "function was made a >> coroutine here" } >> + else >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> +} >> + >> +Coro >> +bar5 () >> +{ >> + if (x) >> + co_yield 123; // { dg-note "function was made a coroutine here" } >> + else >> + return Coro(); // { dg-error {a 'return' statement is not allowed} } >> } -- Arsen Arsenović
signature.asc
Description: PGP signature