thanks
Iain
--- 8< ---
Some of the lookup code is expecting to find a valid (not UNKNOWN)
location, which triggers in the reported case. To avoid this, we are
reverting the change to use UNKNOWN_LOCATION for synthesizing the
wrapper, and instead using the start and end locations of the original
function.
PR c++/120273
gcc/cp/ChangeLog:
* coroutines.cc
(cp_coroutine_transform::wrap_original_function_body): Use
function start and end locations when synthesizing code.
(cp_coroutine_transform::cp_coroutine_transform): Set the
function end location.
* coroutines.h: Add the function end location.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/coro-missing-final-suspend.C: Adjust for
changed final suspend diagnostics line number change.
* g++.dg/coroutines/coro1-missing-await-method.C: Likewise.
* g++.dg/coroutines/pr104051.C: Likewise.
* g++.dg/coroutines/pr120273.C: New test.
Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
---
gcc/cp/coroutines.cc | 22 ++++---
gcc/cp/coroutines.h | 1 +
.../coroutines/coro-missing-final-suspend.C | 4 +-
.../coroutines/coro1-missing-await-method.C | 2 +-
gcc/testsuite/g++.dg/coroutines/pr104051.C | 4 +-
gcc/testsuite/g++.dg/coroutines/pr120273.C | 58 +++++++++++++++++++
6 files changed, 77 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120273.C
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 1fbdee1b4f6..6518e9202d0 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4307,8 +4307,7 @@ cp_coroutine_transform::wrap_original_function_body ()
{
/* Avoid the code here attaching a location that makes the debugger jump.
*/
iloc_sentinel stable_input_loc (fn_start);
- location_t loc = UNKNOWN_LOCATION;
- input_location = loc;
+ location_t loc = fn_start;
/* This will be our new outer scope. */
tree update_body
@@ -4450,7 +4449,7 @@ cp_coroutine_transform::wrap_original_function_body ()
/* If the coroutine has a frame that needs to be freed, this will be set by
the ramp. */
- var = coro_build_artificial_var (fn_start, coro_frame_needs_free_id,
+ var = coro_build_artificial_var (loc, coro_frame_needs_free_id,
boolean_type_node, orig_fn_decl, NULL_TREE);
DECL_CHAIN (var) = var_list;
var_list = var;
@@ -4462,7 +4461,7 @@ cp_coroutine_transform::wrap_original_function_body ()
tree ueh
= coro_build_promise_expression (orig_fn_decl, promise,
coro_unhandled_exception_identifier,
- fn_start, NULL, /*musthave=*/true);
+ loc, NULL, /*musthave=*/true);
/* Create and initialize the initial-await-resume-called variable per
[dcl.fct.def.coroutine] / 5.3. */
tree i_a_r_c
@@ -4524,9 +4523,9 @@ cp_coroutine_transform::wrap_original_function_body ()
tree ueh_meth
= lookup_promise_method (orig_fn_decl,
coro_unhandled_exception_identifier,
- fn_start, /*musthave=*/false);
+ loc, /*musthave=*/false);
if (!ueh_meth || ueh_meth == error_mark_node)
- warning_at (fn_start, 0, "no member named %qE in %qT",
+ warning_at (loc, 0, "no member named %qE in %qT",
coro_unhandled_exception_identifier,
get_coroutine_promise_type (orig_fn_decl));
}
@@ -4539,6 +4538,10 @@ cp_coroutine_transform::wrap_original_function_body ()
add_stmt (return_void);
}
+ /* We are now doing actions associated with the end of the function, so
+ point to the closing brace. */
+ input_location = loc = fn_end;
+
/* co_return branches to the final_suspend label, so declare that now. */
fs_label
= create_named_label_with_ctx (loc, "final.suspend", NULL_TREE);
@@ -4550,7 +4553,7 @@ cp_coroutine_transform::wrap_original_function_body ()
zero_resume = build2_loc (loc, MODIFY_EXPR, act_des_fn_ptr_type,
resume_fn_ptr, zero_resume);
finish_expr_stmt (zero_resume);
- finish_expr_stmt (build_init_or_final_await (fn_start, true));
+ finish_expr_stmt (build_init_or_final_await (loc, true));
BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body));
BIND_EXPR_VARS (update_body) = nreverse (var_list);
BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body);
@@ -5207,9 +5210,10 @@ cp_coroutine_transform::cp_coroutine_transform (tree
_orig_fn, bool _inl)
}
/* We don't have the locus of the opening brace - it's filled in later (and
- there doesn't really seem to be any easy way to get at it).
- The closing brace is assumed to be input_location. */
+ there doesn't really seem to be any easy way to get at it). */
fn_start = DECL_SOURCE_LOCATION (orig_fn_decl);
+ /* The closing brace is assumed to be input_location. */
+ fn_end = input_location;
/* Build types we need. */
tree fr_name = get_fn_local_identifier (orig_fn_decl, "Frame");
diff --git a/gcc/cp/coroutines.h b/gcc/cp/coroutines.h
index 55caa6e61e3..cb5d5572733 100644
--- a/gcc/cp/coroutines.h
+++ b/gcc/cp/coroutines.h
@@ -102,6 +102,7 @@ private:
tree orig_fn_decl; /* The original function decl. */
tree orig_fn_body = NULL_TREE; /* The original function body. */
location_t fn_start = UNKNOWN_LOCATION;
+ location_t fn_end = UNKNOWN_LOCATION;
tree resumer = error_mark_node;
tree destroyer = error_mark_node;
tree coroutine_body = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C
b/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C
index 6a0878c1269..b2522311a49 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C
@@ -7,10 +7,10 @@
#include "coro1-ret-int-yield-int.h"
coro1
-my_coro () // { dg-error {no member named 'final_suspend' in} }
+my_coro ()
{
co_return 0;
-}
+} // { dg-error {no member named 'final_suspend' in} }
// check we have not messed up continuation of the compilation.
template <class... Args>
diff --git a/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C
b/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C
index c1869e0654c..93b6159216f 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C
@@ -13,7 +13,7 @@ bar0 () // { dg-error {no member named 'await_suspend' in
'coro1::suspend_always
co_yield 5; // { dg-error {no member named 'await_suspend' in
'coro1::suspend_always_prt'} }
co_await coro1::suspend_always_intprt(5); // { dg-error {no member named
'await_resume' in 'coro1::suspend_always_intprt'} }
co_return 0;
-}
+} // { dg-error {no member named 'await_suspend' in
'coro1::suspend_always_prt'} }
int main (int ac, char *av[]) {
struct coro1 x0 = bar0 ();
diff --git a/gcc/testsuite/g++.dg/coroutines/pr104051.C
b/gcc/testsuite/g++.dg/coroutines/pr104051.C
index f77a915af74..cd69877361d 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr104051.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr104051.C
@@ -24,7 +24,7 @@ template <typename T> struct task {
std::coroutine_handle<> await_suspend(std::coroutine_handle<>);
T await_resume();
};
-task<std::vector<int>> foo() { // { dg-error {awaitable type 'bool' is not a
structure} }
+task<std::vector<int>> foo() {
while ((co_await foo()).empty())
;
-}
+} // { dg-error {awaitable type 'bool' is not a structure} }
diff --git a/gcc/testsuite/g++.dg/coroutines/pr120273.C
b/gcc/testsuite/g++.dg/coroutines/pr120273.C
new file mode 100644
index 00000000000..19b9e51b9fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr120273.C
@@ -0,0 +1,58 @@
+// PR120273
+// { dg-additional-options "-Wno-literal-suffix" }
+namespace std {
+void declval();
+template < typename > struct invoke_result;
+template < typename _Fn > using invoke_result_t = invoke_result< _Fn >;
+template < typename _Derived, typename _Base >
+concept derived_from = __is_base_of(_Base, _Derived);
+template < typename, typename >
+concept convertible_to = requires { declval; };
+template < char... > int operator""ms();
+template < typename _Result, typename > struct coroutine_traits : _Result {};
+template < typename = void > struct coroutine_handle {
+ static coroutine_handle from_address(void *);
+ operator coroutine_handle<>();
+ void *address();
+};
+}
+
+using namespace std;
+
+template < class > using CoroutineHandle = coroutine_handle<>;
+
+template < class Callable >
+ requires(derived_from< invoke_result_t< Callable >, int >)
+Callable operator co_await(Callable);
+
+struct FinalSuspendProxy {
+ bool await_ready() noexcept;
+ void await_suspend(CoroutineHandle< void >) noexcept ;
+ void await_resume() noexcept;
+};
+
+struct Task {
+ struct Promise;
+ using promise_type = Promise;
+
+ struct Promise {
+ auto initial_suspend() { return FinalSuspendProxy(); }
+ auto final_suspend () noexcept { return FinalSuspendProxy(); }
+ void unhandled_exception () {}
+ Task get_return_object () { return {}; }
+ };
+} ;
+
+struct TestEventLoop {
+ struct Sleep {
+ Sleep(TestEventLoop, int);
+ bool await_ready();
+ void await_suspend(CoroutineHandle< void >);
+ void await_resume();
+ };
+ auto sleep(int tm) { return Sleep(*this, tm); }
+};
+
+Task test_body_11(TestEventLoop t) {
+ co_await t.sleep(5ms);
+}