coroutines: Emit error for invalid promise return types [PR97438].
At one stage, use cases were proposed for allowing the promise type to contain both return_value and return_void. That was not accepted into C++20, so we should reject it as per the PR. gcc/cp/ChangeLog: PR c++/97438 * coroutines.cc (struct coroutine_info): Add a field to record that we emitted a promise type error. (coro_promise_type_found_p): Check for the case that the promise type contains both return_void and return_value. Emit an error if so, with information about the wrong type methods. gcc/testsuite/ChangeLog: PR c++/97438 * g++.dg/coroutines/pr97438.C: New test.
This commit is contained in:
parent
619f91eaa8
commit
b003c4b14b
2 changed files with 55 additions and 0 deletions
|
@ -94,6 +94,7 @@ struct GTY((for_user)) coroutine_info
|
|||
/* Flags to avoid repeated errors for per-function issues. */
|
||||
bool coro_ret_type_error_emitted;
|
||||
bool coro_promise_error_emitted;
|
||||
bool coro_co_return_error_emitted;
|
||||
};
|
||||
|
||||
struct coroutine_info_hasher : ggc_ptr_hash<coroutine_info>
|
||||
|
@ -470,6 +471,30 @@ coro_promise_type_found_p (tree fndecl, location_t loc)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Test for errors in the promise type that can be determined now. */
|
||||
tree has_ret_void = lookup_member (coro_info->promise_type,
|
||||
coro_return_void_identifier,
|
||||
/*protect=*/1, /*want_type=*/0,
|
||||
tf_none);
|
||||
tree has_ret_val = lookup_member (coro_info->promise_type,
|
||||
coro_return_value_identifier,
|
||||
/*protect=*/1, /*want_type=*/0,
|
||||
tf_none);
|
||||
if (has_ret_void && has_ret_val)
|
||||
{
|
||||
location_t ploc = DECL_SOURCE_LOCATION (fndecl);
|
||||
if (!coro_info->coro_co_return_error_emitted)
|
||||
error_at (ploc, "the coroutine promise type %qT declares both"
|
||||
" %<return_value%> and %<return_void%>",
|
||||
coro_info->promise_type);
|
||||
inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_void)),
|
||||
"%<return_void%> declared here");
|
||||
inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_val)),
|
||||
"%<return_value%> declared here");
|
||||
coro_info->coro_co_return_error_emitted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to find the handle type for the promise. */
|
||||
tree handle_type =
|
||||
instantiate_coro_handle_for_promise_type (loc, coro_info->promise_type);
|
||||
|
|
30
gcc/testsuite/g++.dg/coroutines/pr97438.C
Normal file
30
gcc/testsuite/g++.dg/coroutines/pr97438.C
Normal file
|
@ -0,0 +1,30 @@
|
|||
#if __has_include(<coroutine>)
|
||||
#include <coroutine>
|
||||
#else
|
||||
#include <experimental/coroutine>
|
||||
namespace std { using namespace experimental; }
|
||||
#endif
|
||||
|
||||
struct dummy_coroutine {};
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
class coroutine_traits<::dummy_coroutine> {
|
||||
public:
|
||||
struct promise_type {
|
||||
void return_value(int x) { }
|
||||
void return_void() {}
|
||||
std::suspend_never initial_suspend() noexcept { return {}; }
|
||||
std::suspend_never final_suspend() noexcept { return {}; }
|
||||
dummy_coroutine get_return_object() { return {}; }
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
dummy_coroutine
|
||||
foo() { // { dg-error {the coroutine promise type 'std::__n4861::coroutine_traits<dummy_coroutine>::promise_type' declares both 'return_value' and 'return_void'} }
|
||||
co_return 17;
|
||||
}
|
Loading…
Add table
Reference in a new issue