https://gcc.gnu.org/g:3b95be7bd1882add4b1e22f6b70bc130cd465eca

commit r16-1534-g3b95be7bd1882add4b1e22f6b70bc130cd465eca
Author: Iain Sandoe <i...@sandoe.co.uk>
Date:   Tue Jun 3 13:07:27 2025 +0100

    c++, coroutines: Avoid UNKNOWN_LOCATION synthesizing code [PR120273].
    
    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.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/coroutines/pr120273.C: New test.
    
    Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>

Diff:
---
 gcc/cp/coroutines.cc                       | 15 ++++----
 gcc/testsuite/g++.dg/coroutines/pr120273.C | 58 ++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 4057a0762baf..17d0ee997903 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4313,8 +4313,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
@@ -4455,7 +4454,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;
@@ -4467,7 +4466,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
@@ -4529,9 +4528,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));
        }
@@ -4544,6 +4543,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);
diff --git a/gcc/testsuite/g++.dg/coroutines/pr120273.C 
b/gcc/testsuite/g++.dg/coroutines/pr120273.C
new file mode 100644
index 000000000000..19b9e51b9faf
--- /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);
+}

Reply via email to