[PATCH] c++/coroutines: correct passing *this to promise type
Patrick Palka
ppalka@redhat.com
Mon Jul 22 13:43:08 GMT 2024
Tested on x86_64-pc-linux-gnu, does this look OK for trunk
and perhaps backports?
-- >8 --
When passing *this to the promise type ctor (or operator new) (as
per [dcl.fct.def.coroutine]/4), we add an explicit cast to lvalue
reference, but that's unnecessary since *this is already an lvalue.
And it'd mean we'd have to call convert_from_reference afterwards to
lower the reference-yielding expression into an implicit dereference,
otherwise overload resolution gets confused when computing argument
conversions. So this patch removes the unnecessary reference cast when
passing *this to the promise ctor, and removes both the cast and
implicit deref when passing *this to operator new, for consistency.
PR c++/104981
PR c++/115550
gcc/cp/ChangeLog:
* coroutines.cc (morph_fn_to_coro): Remove unnecessary calls
to convert_to_reference and convert_from_reference for *this.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/pr104981-preview-this.C: New test.
* g++.dg/coroutines/pr115550-preview-this.C: New test.
---
gcc/cp/coroutines.cc | 10 +---
.../g++.dg/coroutines/pr104981-preview-this.C | 34 ++++++++++++++
.../g++.dg/coroutines/pr115550-preview-this.C | 47 +++++++++++++++++++
3 files changed, 82 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index f350fc33e9b..b8a53182c38 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4622,11 +4622,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
/* We pass a reference to *this to the allocator lookup. */
tree tt = TREE_TYPE (TREE_TYPE (arg));
tree this_ref = build1 (INDIRECT_REF, tt, arg);
- tt = cp_build_reference_type (tt, false);
- this_ref = convert_to_reference (tt, this_ref, CONV_STATIC,
- LOOKUP_NORMAL , NULL_TREE,
- tf_warning_or_error);
- vec_safe_push (args, convert_from_reference (this_ref));
+ vec_safe_push (args, this_ref);
}
else
vec_safe_push (args, convert_from_reference (arg));
@@ -4849,10 +4845,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
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.rv_ref)
diff --git a/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C
new file mode 100644
index 00000000000..81eb963db4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr104981-preview-this.C
@@ -0,0 +1,34 @@
+// PR c++/104981 - ICE from convert_to_base when passing *this to promise ctor
+
+#include <coroutine>
+
+class Base {};
+
+struct PromiseType;
+
+struct Result {
+ using promise_type = PromiseType;
+};
+
+struct PromiseType {
+ PromiseType(const Base& parser, auto&&...) {}
+
+ Result get_return_object() { return {}; }
+
+ static std::suspend_never initial_suspend() { return {}; }
+ static std::suspend_always final_suspend() noexcept { return {}; }
+ [[noreturn]] static void unhandled_exception() { throw; }
+
+ void return_value(int) {}
+};
+
+struct Derived : Base {
+ Result f() {
+ co_return 42;
+ }
+};
+
+int main() {
+ Derived d;
+ d.f();
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C b/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C
new file mode 100644
index 00000000000..f62c07096b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr115550-preview-this.C
@@ -0,0 +1,47 @@
+// PR c++/115550 - wrong deduction when passing *this to promise ctor template
+
+#include <coroutine>
+
+template <typename T> struct remove_reference { using type = T; };
+template <typename T> struct remove_reference<T&> { using type = T; };
+template <typename T> struct remove_reference<T&&> { using type = T; };
+template <typename T> using remove_reference_t = remove_reference<T>::type;
+
+template <typename, typename>
+struct is_same { static inline constexpr bool value = false; };
+template <typename T>
+struct is_same<T, T> { static inline constexpr bool value = true; };
+
+template <typename T, typename U>
+concept same_as = is_same<T, U>::value;
+
+struct coroutine
+{
+ struct promise_type
+ {
+ template <typename Arg>
+ explicit promise_type(Arg&&)
+ {
+ static_assert(same_as<
+ remove_reference_t<remove_reference_t<Arg>>,
+ remove_reference_t<Arg>
+ >);
+ }
+
+ coroutine get_return_object() { return {}; }
+
+ std::suspend_never initial_suspend() noexcept { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+
+ void return_void() {}
+ void unhandled_exception() {throw;}
+ };
+};
+
+struct x
+{
+ coroutine f()
+ {
+ co_return;
+ }
+};
--
2.46.0.rc0.106.g1c4a234a1c
More information about the Gcc-patches
mailing list