coroutines: Pass class reference to promise param preview [PR94682]
authorIain Sandoe <iain@sandoe.co.uk>
Wed, 22 Apr 2020 08:49:20 +0000 (09:49 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Wed, 22 Apr 2020 08:49:20 +0000 (09:49 +0100)
As reported in the PR, per [dcl.fct.def.coroutine]/4 we should
be passing a reference to the object to the promise parameter
preview, and we are currently passing a pointer (this).  Amend to
pass the reference.

gcc/cp/ChangeLog:

2020-04-22  Iain Sandoe  <iain@sandoe.co.uk>

PR c++/94682
* coroutines.cc (struct param_info): Add a field to note that
the param is 'this'.
(morph_fn_to_coro): Convert this to a reference before using it
in the promise parameter preview.

gcc/testsuite/ChangeLog:

2020-04-22  Iain Sandoe  <iain@sandoe.co.uk>

PR c++/94682
* g++.dg/coroutines/pr94682-preview-this.C: New test.

gcc/cp/ChangeLog
gcc/cp/coroutines.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/coroutines/pr94682-preview-this.C [new file with mode: 0644]

index 4b6691a77f0be7e88c8afb16394b937ac1c26301..cce017cf245e9803a42b61f6d1014811415ce1f6 100644 (file)
@@ -1,3 +1,11 @@
+2020-04-22 Iain Sandoe <iain@sandoe.co.uk>
+
+       PR c++/94682
+       * coroutines.cc (struct param_info): Add a field to note that
+       the param is 'this'.
+       (morph_fn_to_coro): Convert this to a reference before using it
+       in the promise parameter preview.
+
 2020-04-22  Jason Merrill  <jason@redhat.com>
 
        PR c++/94546
index 30676eba6c23f75042aa48070bbedb8c62db030f..b1d91f84cae042f8c8695596458133d7f69cf28f 100644 (file)
@@ -1760,14 +1760,15 @@ transform_await_wrapper (tree *stmt, int *do_subtree, void *d)
 
 struct param_info
 {
-  tree field_id;  /* The name of the copy in the coroutine frame.  */
+  tree field_id;     /* The name of the copy in the coroutine frame.  */
   vec<tree *> *body_uses; /* Worklist of uses, void if there are none.  */
-  tree frame_type; /* The type used to represent this parm in the frame.  */
-  tree orig_type;  /* The original type of the parm (not as passed).  */
-  bool by_ref;  /* Was passed by reference.  */
-  bool rv_ref;  /* Was an rvalue reference.  */
-  bool pt_ref;  /* Was a pointer to object.  */
+  tree frame_type;   /* The type used to represent this parm in the frame.  */
+  tree orig_type;    /* The original type of the parm (not as passed).  */
+  bool by_ref;       /* Was passed by reference.  */
+  bool rv_ref;       /* Was an rvalue reference.  */
+  bool pt_ref;       /* Was a pointer to object.  */
   bool trivial_dtor; /* The frame type has a trivial DTOR.  */
+  bool this_ptr;     /* Is 'this' */
 };
 
 struct local_var_info
@@ -3279,7 +3280,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
            }
          else
            parm.frame_type = actual_type;
-
+         parm.this_ptr = is_this_parameter (arg);
          parm.trivial_dtor = TYPE_HAS_TRIVIAL_DESTRUCTOR (parm.frame_type);
          tree pname = DECL_NAME (arg);
          char *buf = xasprintf ("__parm.%s", IDENTIFIER_POINTER (pname));
@@ -3617,8 +3618,21 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
                                              false, tf_warning_or_error);
 
          /* Add this to the promise CTOR arguments list, accounting for
-            refs.  */
-         if (parm.by_ref)
+            refs and this ptr.  */
+         if (parm.this_ptr)
+           {
+             /* We pass a reference to *this to the param preview.  */
+             tree tt = TREE_TYPE (arg);
+             gcc_checking_assert (POINTER_TYPE_P (tt));
+             tree ct = TREE_TYPE (tt);
+             tree this_ref = build1 (INDIRECT_REF, ct, arg);
+             tree rt = cp_build_reference_type (ct, false);
+             this_ref = convert_to_reference (rt, this_ref, CONV_STATIC,
+                                              LOOKUP_NORMAL , NULL_TREE,
+                                              tf_warning_or_error);
+             vec_safe_push (promise_args, this_ref);
+           }
+         else if (parm.by_ref)
            vec_safe_push (promise_args, fld_idx);
          else if (parm.rv_ref)
            vec_safe_push (promise_args, rvalue (fld_idx));
index 0689f202f646fdda29d3e1201cc83ed4bf3871ba..413014277c802e9d11415505efc511d0011581a0 100644 (file)
@@ -1,3 +1,8 @@
+2020-04-22 Iain Sandoe <iain@sandoe.co.uk>
+
+       PR c++/94682
+       * g++.dg/coroutines/promise-parm-preview-this.C: New test.
+
 2020-04-22  Christophe Lyon  <christophe.lyon@linaro.org>
 
        * lib/gcc-dg.exp (schedule-cleanups): Accept --save-temps.
diff --git a/gcc/testsuite/g++.dg/coroutines/pr94682-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr94682-preview-this.C
new file mode 100644 (file)
index 0000000..ca96f37
--- /dev/null
@@ -0,0 +1,27 @@
+#include "coro.h"
+
+struct promise;
+
+struct future
+{
+    using promise_type = promise;
+};
+
+struct promise
+{
+  template<typename Class>
+  promise(Class &,int) { static_assert(!std::is_pointer<Class>::value, ""); }
+
+  coro::suspend_never initial_suspend() { return {}; }
+  coro::suspend_never final_suspend() { return {}; }
+
+  future get_return_object() { return {}; }
+
+  void return_value(int) {}
+  void unhandled_exception() {}
+};
+
+struct bar
+{
+  future foo(int param) { co_return 0; }
+};
\ No newline at end of file