On 6/2/25 5:13 AM, Iain Sandoe wrote:
Tested on x86_64-darwin, OK for trunk?
thanks
Iain

--- 8< ---

Using lookup_template_class () directly on the coroutine_handle identifier
fails in the reported test because the using TYPE_DECL is found.

Hmm, this seems like a longstanding (since the implementation of namespaces in r19631) bug in lookup_template_class; if context is a namespace, I'd expect that to bypass any local declaration.

Fix this
by looking up the std::coroutine_handle template specifically and then
instantiating that.

        PR c++/120495

gcc/cp/ChangeLog:

        * coroutines.cc
        (instantiate_coro_handle_for_promise_type): Lookup the coroutine
        handle template specifically and then instantiate that.

gcc/testsuite/ChangeLog:

        * g++.dg/coroutines/pr120495.C: New test.

Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
---
  gcc/cp/coroutines.cc                       | 17 ++++---
  gcc/testsuite/g++.dg/coroutines/pr120495.C | 55 ++++++++++++++++++++++
  2 files changed, 66 insertions(+), 6 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120495.C

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 42f719ddde1..7ea1ad7c3aa 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -609,16 +609,21 @@ get_handle_type_from_address (location_t kw, tree 
handle_type)
  static tree
  instantiate_coro_handle_for_promise_type (location_t kw, tree promise_type)
  {
+  /* Look up the template.  */
+  tree handle_type = find_coro_handle_template_decl (kw);
+  if (!handle_type)
+    return NULL_TREE;
+
    /* So now build up a type list for the template, one entry, the promise.  */
    tree targ = make_tree_vec (1);
    TREE_VEC_ELT (targ, 0) = promise_type;
-  tree handle_type
-    = lookup_template_class (coro_handle_identifier, targ,
-                            /* in_decl=*/NULL_TREE,
-                            /* context=*/std_node,
-                            tf_warning_or_error);
- if (handle_type == error_mark_node)
+  /* Instantiate for the promise type.  */
+  handle_type
+    = lookup_template_class (handle_type, targ, /*in_decl*/NULL_TREE,
+                            /*context*/std_node, tf_warning_or_error);
+
+  if (!handle_type || handle_type == error_mark_node)
      {
        error_at (kw, "cannot instantiate a %<coroutine handle%> for"
                " promise type %qT", promise_type);
diff --git a/gcc/testsuite/g++.dg/coroutines/pr120495.C 
b/gcc/testsuite/g++.dg/coroutines/pr120495.C
new file mode 100644
index 00000000000..f59c34a8676
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr120495.C
@@ -0,0 +1,55 @@
+// { dg-additional-options "-fsyntax-only" }
+
+#include <coroutine>
+#include <exception>
+
+struct fire_and_forget {
+};
+
+template <typename... Args>
+struct std::coroutine_traits<fire_and_forget, Args...>
+{
+    struct promise_type
+    {
+        fire_and_forget get_return_object() const noexcept
+        {
+            return{};
+        }
+
+        void return_void() const noexcept
+        {
+        }
+
+        suspend_never initial_suspend() const noexcept
+        {
+            return{};
+        }
+
+        suspend_never final_suspend() const noexcept
+        {
+            return{};
+        }
+
+        void unhandled_exception() const noexcept
+        {
+            std::terminate();
+        }
+    };
+};
+
+struct foo
+{
+    fire_and_forget bar()
+    {
+        co_await std::suspend_always{ };
+    }
+
+private:
+    // The line below triggered the error.
+    using coroutine_handle = std::coroutine_handle<>;
+};
+
+int main()
+{
+    foo{}.bar();
+}

Reply via email to