From b003c4b14b3f889e6707db68d2c6545eda7a203b Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sat, 17 Oct 2020 11:21:11 +0100 Subject: [PATCH] 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. --- gcc/cp/coroutines.cc | 25 +++++++++++++++++++ gcc/testsuite/g++.dg/coroutines/pr97438.C | 30 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 gcc/testsuite/g++.dg/coroutines/pr97438.C diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index ba813454a0b..9b9141e51fd 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -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 @@ -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" + " % and %", + coro_info->promise_type); + inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_void)), + "% declared here"); + inform (DECL_SOURCE_LOCATION (BASELINK_FUNCTIONS (has_ret_val)), + "% 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); diff --git a/gcc/testsuite/g++.dg/coroutines/pr97438.C b/gcc/testsuite/g++.dg/coroutines/pr97438.C new file mode 100644 index 00000000000..95376648ed7 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr97438.C @@ -0,0 +1,30 @@ +#if __has_include() +#include +#else +#include +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::promise_type' declares both 'return_value' and 'return_void'} } + co_return 17; +} -- 2.30.2