public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Iain Sandoe <iains.gcc@gmail.com>
To: gcc-patches@gcc.gnu.org
Cc: jason@redhat.com
Subject: [PATCH] coroutines: Accept 'extern "C"' coroutines.
Date: Sat, 10 Dec 2022 11:37:44 +0000	[thread overview]
Message-ID: <20221210113744.38708-1-iain@sandoe.co.uk> (raw)

This came up in discussion and was relatively easy to 'fix' although it remains
to be seen whether it was really intended.  Tested on x86_64-darwin21. 
OK for trunk?
Iain

--- >8 ---

As of now the standard does not appear to forbid this, and clang accepts.
The use-cases are somewhat unclear (question placed with the designers) but
implemented here for sake of compatibility.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

gcc/cp/ChangeLog:

	* coroutines.cc (coro_build_actor_or_destroy_function): Accept
	coroutines that are 'extern "C"' and build unmangled names for
	the actor and destroy functions.

gcc/testsuite/ChangeLog:

	* g++.dg/coroutines/torture/extern-c-coroutine.C: New test.
---
 gcc/cp/coroutines.cc                          | 12 +++
 .../coroutines/torture/extern-c-coroutine.C   | 89 +++++++++++++++++++
 2 files changed, 101 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/extern-c-coroutine.C

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3f23317a315..c1a0d6c2283 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "gcc-rich-location.h"
 #include "hash-map.h"
+#include "cgraph.h"
 
 static bool coro_promise_type_found_p (tree, location_t);
 
@@ -4060,6 +4061,17 @@ coro_build_actor_or_destroy_function (tree orig, tree fn_type,
       else
 	info->destroy_decl = fn;
     }
+  /* If the function is extern "C" the mangler will not be called.  */
+  if (DECL_EXTERN_C_P (orig))
+    {
+      /* clone_function_name () picks up the name from DECL_ASSEMBLER_NAME
+	 which is not yet set here.  */
+      SET_DECL_ASSEMBLER_NAME (fn, DECL_NAME (orig));
+      if (actor_p)
+	SET_DECL_ASSEMBLER_NAME (fn, clone_function_name (fn, "actor"));
+      else
+	SET_DECL_ASSEMBLER_NAME (fn, clone_function_name (fn, "destroy"));
+    }
   return fn;
 }
 
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/extern-c-coroutine.C b/gcc/testsuite/g++.dg/coroutines/torture/extern-c-coroutine.C
new file mode 100644
index 00000000000..c178a80ee4b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/extern-c-coroutine.C
@@ -0,0 +1,89 @@
+#include <coroutine>
+#include <cstdio>
+
+#ifndef OUTPUT
+#  define PRINT(X)
+#  define PRINTF(X,...)
+#else
+#  define PRINT(X) puts(X)
+#  define PRINTF printf
+#endif
+
+struct future {
+  struct promise_type;
+  using handle_type = std::coroutine_handle<future::promise_type>;
+  handle_type handle;
+  future () : handle(0) {}
+  future (handle_type _handle)
+    : handle(_handle) {
+        PRINT("Created future object from handle");
+  }
+  future (const future &) = delete; // no copying
+  future (future &&s) : handle(s.handle) {
+	s.handle = nullptr;
+	PRINT("future mv ctor ");
+  }
+  future &operator = (future &&s) {
+	handle = s.handle;
+	s.handle = nullptr;
+	PRINT("future op=  ");
+	return *this;
+  }
+  ~future() {
+        PRINT("Destroyed future");
+        if ( handle )
+          handle.destroy();
+  }
+
+  struct promise_type {
+    void return_value (int v) {
+      PRINTF ("return_value (%d)\n", v);
+      vv = v;
+    }
+
+    std::suspend_always initial_suspend() noexcept { return {}; }
+    std::suspend_always final_suspend() noexcept { return {}; }
+    void unhandled_exception() {}
+    auto get_return_object() {return handle_type::from_promise (*this);}
+    
+    int get_value () { return vv; }
+  private:
+    int vv;
+  };
+  bool await_ready() { return false; }
+  void await_suspend(std::coroutine_handle<>) {}
+  void await_resume() {}
+};
+
+extern "C" future
+test () {
+  co_return 22;
+}
+
+extern "C" future
+f () noexcept
+{
+  PRINT ("future: about to return");
+  co_return 42;
+}
+
+int main ()
+{
+  PRINT ("main: create future");
+  future x = f ();
+  PRINT ("main: got future - resuming");
+  if (x.handle.done())
+    __builtin_abort ();
+  x.handle.resume();
+  PRINT ("main: after resume");
+  int y = x.handle.promise().get_value();
+  if ( y != 42 )
+    __builtin_abort ();
+  if (!x.handle.done())
+    {
+      PRINT ("main: apparently not done...");
+      __builtin_abort ();
+    }
+  PRINT ("main: returning");
+  return 0;
+}
-- 
2.37.1 (Apple Git-137.1)


             reply	other threads:[~2022-12-10 11:37 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-10 11:37 Iain Sandoe [this message]
2022-12-17 13:40 ` [PATCH v2] " Iain Sandoe
2022-12-19 15:54   ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221210113744.38708-1-iain@sandoe.co.uk \
    --to=iains.gcc@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=iain@sandoe.co.uk \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).