https://gcc.gnu.org/g:98364636c194398d5dccb477e5405cb1d02a55f1

commit r14-11725-g98364636c194398d5dccb477e5405cb1d02a55f1
Author: Iain Sandoe <i...@sandoe.co.uk>
Date:   Sat Aug 17 15:47:58 2024 +0100

    c++, coroutines: Only allow void get_return_object if the ramp is void 
[PR100476].
    
    Require that the value returned by get_return_object is convertible to
    the ramp return.  This means that the only time we allow a void
    get_return_object, is when the ramp is also a void function.
    
    We diagnose this early to allow us to exit the ramp build if the return
    values are incompatible.
    
            PR c++/100476
    
    gcc/cp/ChangeLog:
    
            * coroutines.cc
            (cp_coroutine_transform::build_ramp_function): Remove special
            handling of void get_return_object expressions.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C:
            Adjust expected diagnostic.
            * g++.dg/coroutines/pr102489.C: Avoid void get_return_object.
            * g++.dg/coroutines/pr103868.C: Likewise.
            * g++.dg/coroutines/pr94879-folly-1.C: Likewise.
            * g++.dg/coroutines/pr94883-folly-2.C: Likewise.
            * g++.dg/coroutines/pr96749-2.C: Likewise.
    
    Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
    (cherry picked from commit a0b431033c307982123abbff752045cfe7eda47f)

Diff:
---
 gcc/cp/coroutines.cc                               | 49 ++++++++++------------
 .../coro-bad-gro-01-void-gro-non-class-coro.C      |  4 +-
 gcc/testsuite/g++.dg/coroutines/pr102489.C         |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr103868.C         |  2 +-
 gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C  |  3 +-
 gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C  | 39 ++++++++---------
 gcc/testsuite/g++.dg/coroutines/pr96749-2.C        |  2 +-
 7 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3774e5595a0d..a6cbe07d1a28 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4646,8 +4646,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
   /* Create the coro frame type, as far as it can be known at this stage.
      1. Types we already know.  */
 
-  tree fn_return_type = TREE_TYPE (TREE_TYPE (orig));
   tree promise_type = get_coroutine_promise_type (orig);
+  tree fn_return_type = TREE_TYPE (TREE_TYPE (orig));
+  bool void_ramp_p = VOID_TYPE_P (fn_return_type);
 
   /* 2. Types we need to define or look up.  */
 
@@ -4951,7 +4952,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
       tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, nullptr_node);
       cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
       finish_if_stmt_cond (cond, if_stmt);
-      if (VOID_TYPE_P (fn_return_type))
+      if (void_ramp_p)
        {
          /* Execute the get-return-object-on-alloc-fail call...  */
          finish_expr_stmt (grooaf);
@@ -5157,7 +5158,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
                                     coro_get_return_object_identifier,
                                     fn_start, NULL, /*musthave=*/true);
   /* Without a return object we haven't got much clue what's going on.  */
-  if (get_ro == error_mark_node)
+  if (!get_ro || get_ro == error_mark_node)
     {
       BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body);
       DECL_SAVED_TREE (orig) = newbody;
@@ -5165,10 +5166,20 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
       suppress_warning (orig, OPT_Wreturn_type);
       return false;
     }
+ 
+  /* Check for a bad get return object type.
+     [dcl.fct.def.coroutine] / 7 requires:
+     The expression promise.get_return_object() is used to initialize the
+     returned reference or prvalue result object ... */
+  tree gro_type = TREE_TYPE (get_ro);
+  if (VOID_TYPE_P (gro_type) && !void_ramp_p)
+    {
+      error_at (fn_start, "no viable conversion from %<void%> provided by"
+               " %<get_return_object%> to return type %qT", fn_return_type);
+      return false;
+    }
 
   tree gro_context_body = push_stmt_list ();
-  tree gro_type = TREE_TYPE (get_ro);
-  bool gro_is_void_p = VOID_TYPE_P (gro_type);
 
   tree gro = NULL_TREE;
   tree gro_bind_vars = NULL_TREE;
@@ -5177,8 +5188,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
   tree gro_cleanup_stmt = NULL_TREE;
   /* We have to sequence the call to get_return_object before initial
      suspend.  */
-  if (gro_is_void_p)
-    r = get_ro;
+  if (void_ramp_p)
+    {
+      gcc_checking_assert (VOID_TYPE_P (gro_type));
+      r = get_ro;
+    }
   else if (same_type_p (gro_type, fn_return_type))
     {
      /* [dcl.fct.def.coroutine] / 7
@@ -5264,28 +5278,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree 
*destroyer)
      for an object of the return type.  */
 
   if (same_type_p (gro_type, fn_return_type))
-    r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig);
-  else if (!gro_is_void_p)
+    r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig);
+  else
     /* check_return_expr will automatically return gro as an rvalue via
        treat_lvalue_as_rvalue_p.  */
     r = gro;
-  else if (CLASS_TYPE_P (fn_return_type))
-    {
-      /* For class type return objects, we can attempt to construct,
-        even if the gro is void. ??? Citation ??? c++/100476  */
-      r = build_special_member_call (NULL_TREE,
-                                    complete_ctor_identifier, NULL,
-                                    fn_return_type, LOOKUP_NORMAL,
-                                    tf_warning_or_error);
-      r = build_cplus_new (fn_return_type, r, tf_warning_or_error);
-    }
-  else
-    {
-      /* We can't initialize a non-class return value from void.  */
-      error_at (input_location, "cannot initialize a return object of type"
-               " %qT with an rvalue of type %<void%>", fn_return_type);
-      r = error_mark_node;
-    }
 
   finish_return_stmt (r);
 
diff --git 
a/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C 
b/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C
index 2671ce7ca289..a7e3f3d1ac7d 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C
@@ -27,11 +27,11 @@ struct std::coroutine_traits<R, HandleRef, T...> {
 };
 
 int
-my_coro (std::coroutine_handle<>& h)
+my_coro (std::coroutine_handle<>& h) // { dg-error {no viable conversion from 
'void' provided by 'get_return_object' to return type 'int'} }
 {
   PRINT ("coro1: about to return");
   co_return;
-} // { dg-error {cannot initialize a return object of type 'int' with an 
rvalue of type 'void'} }
+}
 
 int main ()
 {
diff --git a/gcc/testsuite/g++.dg/coroutines/pr102489.C 
b/gcc/testsuite/g++.dg/coroutines/pr102489.C
index 0ef06daa2112..15b85f4375b9 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr102489.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr102489.C
@@ -9,7 +9,7 @@ struct footask {
     std::suspend_never initial_suspend();
     std::suspend_never final_suspend() noexcept;
     void unhandled_exception();
-    void get_return_object();
+    footask get_return_object();
   };
   std::suspend_always foo;
   footask taskfun() { co_await foo; }
diff --git a/gcc/testsuite/g++.dg/coroutines/pr103868.C 
b/gcc/testsuite/g++.dg/coroutines/pr103868.C
index fd05769db3db..0ce40b699ced 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr103868.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr103868.C
@@ -116,7 +116,7 @@ struct awaitable_frame_base {
   template <typename T> auto await_transform(T a) { return a; }
 };
 template <> struct awaitable_frame<void> : awaitable_frame_base {
-  void get_return_object();
+  awaitable<void> get_return_object();
 };
 } // namespace detail
 } // namespace asio
diff --git a/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C 
b/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C
index 6e091526fe77..2d886fd387d3 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C
@@ -39,9 +39,10 @@ public:
   std::g initial_suspend();
   l final_suspend() noexcept;
 };
+class n;
 class m : public j {
 public:
-  void get_return_object();
+  n get_return_object();
   void unhandled_exception();
 };
 class n {
diff --git a/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C 
b/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C
index 98c5a7e3eeef..f12897e86909 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C
@@ -16,25 +16,7 @@ struct b {
   void await_resume();
 };
 } // namespace std
-
-template <typename d> auto ab(int ac, d ad) -> decltype(ad.e(ac));
-int f;
-class h {
-  class j {
-  public:
-    bool await_ready() noexcept;
-    void await_suspend(std::coroutine_handle<>) noexcept;
-    void await_resume() noexcept;
-  };
-
-public:
-  void get_return_object();
-  std::b initial_suspend();
-  j final_suspend() noexcept;
-  void unhandled_exception();
-  template <typename g> 
-    auto await_transform (g c) { return ab(f, c); }
-};
+class h;
 template <typename, typename = int> class k {
 public:
   using promise_type = h;
@@ -64,6 +46,25 @@ my_coro (k<aj, ak> am, ai) {
     ;
 }
 
+template <typename d> auto ab(int ac, d ad) -> decltype(ad.e(ac));
+int f;
+class h {
+  class j {
+  public:
+    bool await_ready() noexcept;
+    void await_suspend(std::coroutine_handle<>) noexcept;
+    void await_resume() noexcept;
+  };
+
+public:
+  k<int> get_return_object();
+  std::b initial_suspend();
+  j final_suspend() noexcept;
+  void unhandled_exception();
+  template <typename g> 
+    auto await_transform (g c) { return ab(f, c); }
+};
+
 void foo () {
   k<int> a;
   my_coro (a, [] {});
diff --git a/gcc/testsuite/g++.dg/coroutines/pr96749-2.C 
b/gcc/testsuite/g++.dg/coroutines/pr96749-2.C
index 43052b57dd9c..3d7645272915 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr96749-2.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr96749-2.C
@@ -27,7 +27,7 @@ struct Task {
        struct promise_type {
                auto initial_suspend() { return std::suspend_always{}; }
                auto final_suspend() noexcept { return std::suspend_always{}; }
-               void get_return_object() {}
+               Task get_return_object() ;
                void unhandled_exception() {}
        };
 };

Reply via email to