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();
+}