https://gcc.gnu.org/g:217b7f655227a52e5fe26729baa09dc6083ed577

commit r16-961-g217b7f655227a52e5fe26729baa09dc6083ed577
Author: Iain Sandoe <i...@sandoe.co.uk>
Date:   Thu May 29 11:00:18 2025 +0100

    c++, coroutines: Fix identification of coroutine ramps [PR120453].
    
    The existing implementation, incorrectly, tried to use DECL_RAMP_FN
    in check_return_expr to determine if we are handling a ramp func.
    However, that query is only set for the resume/destroy functions.
    
    Replace the use of DECL_RAMP_FN with a new query.
    
            PR c++/120453
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (DECL_RAMP_P): New.
            * typeck.cc (check_return_expr): Use DECL_RAMP_P instead
            of DECL_RAMP_FN.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/coroutines/pr120453.C: New test.
    
    Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>

Diff:
---
 gcc/cp/cp-tree.h                           |  4 ++
 gcc/cp/typeck.cc                           |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr120453.C | 95 ++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 19c0b452d868..d9fc80b92e58 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5522,6 +5522,10 @@ decl_template_parm_check (const_tree t, const char *f, 
int l, const char *fn)
 #define DECL_RAMP_FN(NODE) \
   (coro_get_ramp_function (NODE))
 
+/* For a FUNCTION_DECL this is true if it is a coroutine ramp.  */
+#define DECL_RAMP_P(NODE) \
+  DECL_COROUTINE_P (NODE) && !DECL_RAMP_FN (NODE)
+
 /* True for an OMP_ATOMIC that has dependent parameters.  These are stored
    as an expr in operand 1, and integer_zero_node or clauses in operand 0.  */
 #define OMP_ATOMIC_DEPENDENT_P(NODE) \
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index af2cbaff8fdc..ac1eb397f011 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -11466,7 +11466,7 @@ check_return_expr (tree retval, bool *no_warning, bool 
*dangling)
       /* Don't check copy-initialization for NRV in a coroutine ramp; we
         implement this case as NRV, but it's specified as directly
         initializing the return value from get_return_object().  */
-      if (DECL_RAMP_FN (current_function_decl) && named_return_value_okay_p)
+      if (DECL_RAMP_P (current_function_decl) && named_return_value_okay_p)
        converted = true;
 
       /* First convert the value to the function's return type, then
diff --git a/gcc/testsuite/g++.dg/coroutines/pr120453.C 
b/gcc/testsuite/g++.dg/coroutines/pr120453.C
new file mode 100644
index 000000000000..2f2c4ece008b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr120453.C
@@ -0,0 +1,95 @@
+// PR120453 - reduced testcase amended to add a TaskBase move constructor
+// and a LazyTask destructor, to more closely match the original code.
+// { dg-additional-options "-w" }
+namespace std {
+template <typename> struct __coroutine_traits_impl;
+template <typename _Result>
+  requires requires { typename _Result; }
+struct __coroutine_traits_impl<_Result>;
+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();
+};
+struct suspend_never {
+  bool await_ready();
+  void await_suspend(coroutine_handle<>);
+  void await_resume();
+};
+} // namespace std
+
+namespace QCoro {
+namespace detail {
+template <typename T>
+concept has_await_methods = requires(T t) { t; };
+} // namespace detail
+
+template <typename T>
+concept Awaitable = detail::has_await_methods<T>;
+namespace detail {
+struct TaskFinalSuspend {
+  bool await_ready() noexcept;
+  template <typename Promise>
+  void await_suspend(std::coroutine_handle<Promise>) noexcept;
+  void await_resume() noexcept;
+};
+struct TaskPromiseBase {
+  std::suspend_never initial_suspend();
+  auto final_suspend() noexcept { return TaskFinalSuspend{}; }
+  template <Awaitable T> auto &&await_transform(T &&);
+};
+struct TaskPromise : TaskPromiseBase {
+  void unhandled_exception();
+};
+template <typename> struct TaskAwaiterBase {
+  bool await_ready();
+  void await_suspend(std::coroutine_handle<>);
+};
+template <typename, template <typename> class, typename> struct TaskBase {
+  TaskBase() = default;
+  TaskBase(TaskBase &&) = default;
+  void operator=(TaskBase &&);
+  auto operator co_await() const;
+  std::coroutine_handle<> mCoroutine;
+};
+} // namespace detail
+template <typename> struct Task : detail::TaskBase<int, Task, int> {};
+} // namespace QCoro
+
+namespace QCoro::detail {
+template <Awaitable T> auto &&TaskPromiseBase::await_transform(T &&awaitable) {
+  return awaitable;
+}
+
+template <typename T, template <typename> class TaskImpl, typename PromiseType>
+auto TaskBase<T, TaskImpl, PromiseType>::operator co_await() const {
+  class TaskAwaiter : public TaskAwaiterBase<PromiseType> {
+  public:
+    TaskAwaiter(std::coroutine_handle<>);
+    auto await_resume() {}
+  };
+  return TaskAwaiter{mCoroutine};
+}
+
+} // namespace QCoro::detail
+
+namespace QCoro {
+template <typename T> class LazyTask ;
+namespace detail {
+struct LazyTaskPromise : TaskPromise {
+  LazyTask<int> get_return_object();
+};
+} // namespace detail
+
+template <typename T> struct LazyTask : detail::TaskBase<int, LazyTask, int> {
+  typedef detail::LazyTaskPromise promise_type;
+  ~LazyTask();
+};
+
+auto coro = [] -> LazyTask<int>
+{
+  co_await [] -> Task<int> { return {}; }();
+};
+
+} // namespace QCoro

Reply via email to