* [PATCH] coroutines: Pass lvalues to user-defined operator new [PR 100772].
@ 2021-11-05 15:49 Iain Sandoe
2021-11-05 21:55 ` Jason Merrill
0 siblings, 1 reply; 2+ messages in thread
From: Iain Sandoe @ 2021-11-05 15:49 UTC (permalink / raw)
To: gcc-patches
The wording of the standard has been clarified to be explicit that
the the parameters to any user-defined operator-new in the promise
class should be lvalues.
tested on x86_64 darwin, linux,
OK for master and backports?
thanks
Iain
Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
PR c++/100772
gcc/cp/ChangeLog:
* coroutines.cc (morph_fn_to_coro): Convert function parms
from reference before constructing any operator-new args
list.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/pr100772-a.C: New test.
* g++.dg/coroutines/pr100772-b.C: New test.
---
gcc/cp/coroutines.cc | 6 +-
gcc/testsuite/g++.dg/coroutines/pr100772-a.C | 77 ++++++++++++++++
gcc/testsuite/g++.dg/coroutines/pr100772-b.C | 93 ++++++++++++++++++++
3 files changed, 174 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr100772-a.C
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr100772-b.C
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 6db4b70f028..ab211201255 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4602,8 +4602,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
If the lookup finds an allocation function in the scope of the promise
type, overload resolution is performed on a function call created by
assembling an argument list. The first argument is the amount of space
- requested, and has type std::size_t. The succeeding arguments are
- those of the original function. */
+ requested, and has type std::size_t. The lvalues p1...pn are the
+ succeeding arguments.. */
vec<tree, va_gc> *args = make_tree_vector ();
vec_safe_push (args, resizeable); /* Space needed. */
@@ -4623,6 +4623,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tf_warning_or_error);
vec_safe_push (args, this_ref);
}
+ else if (parm_i->rv_ref || parm_i->pt_ref)
+ vec_safe_push (args, convert_from_reference (arg));
else
vec_safe_push (args, arg);
}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr100772-a.C b/gcc/testsuite/g++.dg/coroutines/pr100772-a.C
new file mode 100644
index 00000000000..a325d384fc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr100772-a.C
@@ -0,0 +1,77 @@
+// { dg-additional-options "-fsyntax-only " }
+#ifdef __clang__
+#include <experimental/coroutine>
+namespace std {
+ using namespace std::experimental;
+}
+#else
+#include <coroutine>
+#endif
+
+struct Task
+{
+ struct promise_type
+ {
+ void return_void() const noexcept {}
+
+ void* operator new(std::size_t, auto &&...args) noexcept
+ {
+ static_assert(sizeof...(args) > 0);
+ static_assert(sizeof...(args) == 2);
+
+ return nullptr;
+ }
+
+ void operator delete(void *, std::size_t) noexcept
+ {
+ }
+
+ static Task get_return_object_on_allocation_failure() noexcept
+ {
+ return {};
+ }
+
+ Task get_return_object() noexcept
+ {
+ return Task{ *this };
+ }
+
+ std::suspend_always initial_suspend() noexcept
+ {
+ return {};
+ }
+
+ std::suspend_always final_suspend() noexcept
+ {
+ return {};
+ }
+
+ void unhandled_exception() noexcept {}
+ };
+
+ using promise_handle = std::coroutine_handle<promise_type>;
+
+ Task() = default;
+ Task(promise_type & promise) noexcept
+ : m_handle{ promise_handle::from_promise(promise) }
+ {}
+
+ ~Task()
+ {
+ if (m_handle.address()) { m_handle.destroy(); }
+ }
+
+ promise_handle m_handle{};
+};
+
+
+Task Foo(auto && ... args) noexcept
+{
+ co_return;
+}
+
+int main()
+{
+ int v;
+ Foo(v, 2134);
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr100772-b.C b/gcc/testsuite/g++.dg/coroutines/pr100772-b.C
new file mode 100644
index 00000000000..6cdf8d1e529
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr100772-b.C
@@ -0,0 +1,93 @@
+#ifdef __clang__
+#include <experimental/coroutine>
+namespace std {
+ using namespace std::experimental;
+}
+#else
+#include <coroutine>
+#endif
+#include <cstdio>
+#include <typeinfo>
+#include <cxxabi.h> // needed for abi::__cxa_demangle
+#include <memory>
+
+std::shared_ptr<char> cppDemangle(const char *abiName)
+{
+ int status;
+ char *ret = abi::__cxa_demangle(abiName, 0, 0, &status);
+
+ /* NOTE: must free() the returned char when done with it! */
+ std::shared_ptr<char> retval;
+ retval.reset( (char *)ret, [](char *mem) { if (mem) free((void*)mem); } );
+ return retval;
+}
+
+template <typename T>
+struct Id{};
+struct Task
+{
+ struct promise_type
+ {
+ void return_void() const noexcept {}
+
+ static void is_int (std::string x) {
+ if (x != "Id<int>")
+ abort() ;
+ }
+ template <typename ... Args>
+ void* operator new(std::size_t len, Args ...args) noexcept
+ {
+ (is_int (cppDemangle(typeid(Id<Args>).name()).get()), ...);
+ (std::puts (cppDemangle(typeid(Id<Args>).name()).get()), ...);
+ return nullptr;
+ }
+
+ static Task get_return_object_on_allocation_failure() noexcept
+ {
+ return {};
+ }
+
+ Task get_return_object() noexcept
+ {
+ return Task{ *this };
+ }
+
+ std::suspend_always initial_suspend() noexcept
+ {
+ return {};
+ }
+
+ std::suspend_always final_suspend() noexcept
+ {
+ return {};
+ }
+
+ void unhandled_exception() noexcept {}
+ };
+
+ using promise_handle = std::coroutine_handle<promise_type>;
+
+ Task() = default;
+ Task(promise_type & promise) noexcept
+ : m_handle{ promise_handle::from_promise(promise) }
+ {}
+
+ ~Task()
+ {
+ if (m_handle.address()) { m_handle.destroy(); }
+ }
+
+ promise_handle m_handle{};
+};
+
+
+Task Foo(auto && ... args) noexcept
+{
+ co_return;
+}
+
+int main()
+{
+ int v;
+ Foo(v, 2134);
+}
--
2.24.3 (Apple Git-128)
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] coroutines: Pass lvalues to user-defined operator new [PR 100772].
2021-11-05 15:49 [PATCH] coroutines: Pass lvalues to user-defined operator new [PR 100772] Iain Sandoe
@ 2021-11-05 21:55 ` Jason Merrill
0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2021-11-05 21:55 UTC (permalink / raw)
To: iain, gcc-patches
On 11/5/21 11:49, Iain Sandoe wrote:
> The wording of the standard has been clarified to be explicit that
> the the parameters to any user-defined operator-new in the promise
> class should be lvalues.
>
> tested on x86_64 darwin, linux,
> OK for master and backports?
> thanks
> Iain
>
> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
>
> PR c++/100772
>
> gcc/cp/ChangeLog:
>
> * coroutines.cc (morph_fn_to_coro): Convert function parms
> from reference before constructing any operator-new args
> list.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/coroutines/pr100772-a.C: New test.
> * g++.dg/coroutines/pr100772-b.C: New test.
> ---
> gcc/cp/coroutines.cc | 6 +-
> gcc/testsuite/g++.dg/coroutines/pr100772-a.C | 77 ++++++++++++++++
> gcc/testsuite/g++.dg/coroutines/pr100772-b.C | 93 ++++++++++++++++++++
> 3 files changed, 174 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/coroutines/pr100772-a.C
> create mode 100644 gcc/testsuite/g++.dg/coroutines/pr100772-b.C
>
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index 6db4b70f028..ab211201255 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -4602,8 +4602,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
> If the lookup finds an allocation function in the scope of the promise
> type, overload resolution is performed on a function call created by
> assembling an argument list. The first argument is the amount of space
> - requested, and has type std::size_t. The succeeding arguments are
> - those of the original function. */
> + requested, and has type std::size_t. The lvalues p1...pn are the
> + succeeding arguments.. */
> vec<tree, va_gc> *args = make_tree_vector ();
> vec_safe_push (args, resizeable); /* Space needed. */
>
> @@ -4623,6 +4623,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
> tf_warning_or_error);
> vec_safe_push (args, this_ref);
> }
> + else if (parm_i->rv_ref || parm_i->pt_ref)
> + vec_safe_push (args, convert_from_reference (arg));
Hmm, does this need to be conditional? convert_from_reference has no
effect on an expression that doesn't have reference type, it's used
unconditionally in lots of places.
OK either way.
> else
> vec_safe_push (args, arg);
> }
> diff --git a/gcc/testsuite/g++.dg/coroutines/pr100772-a.C b/gcc/testsuite/g++.dg/coroutines/pr100772-a.C
> new file mode 100644
> index 00000000000..a325d384fc3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/pr100772-a.C
> @@ -0,0 +1,77 @@
> +// { dg-additional-options "-fsyntax-only " }
> +#ifdef __clang__
> +#include <experimental/coroutine>
> +namespace std {
> + using namespace std::experimental;
> +}
> +#else
> +#include <coroutine>
> +#endif
> +
> +struct Task
> +{
> + struct promise_type
> + {
> + void return_void() const noexcept {}
> +
> + void* operator new(std::size_t, auto &&...args) noexcept
> + {
> + static_assert(sizeof...(args) > 0);
> + static_assert(sizeof...(args) == 2);
> +
> + return nullptr;
> + }
> +
> + void operator delete(void *, std::size_t) noexcept
> + {
> + }
> +
> + static Task get_return_object_on_allocation_failure() noexcept
> + {
> + return {};
> + }
> +
> + Task get_return_object() noexcept
> + {
> + return Task{ *this };
> + }
> +
> + std::suspend_always initial_suspend() noexcept
> + {
> + return {};
> + }
> +
> + std::suspend_always final_suspend() noexcept
> + {
> + return {};
> + }
> +
> + void unhandled_exception() noexcept {}
> + };
> +
> + using promise_handle = std::coroutine_handle<promise_type>;
> +
> + Task() = default;
> + Task(promise_type & promise) noexcept
> + : m_handle{ promise_handle::from_promise(promise) }
> + {}
> +
> + ~Task()
> + {
> + if (m_handle.address()) { m_handle.destroy(); }
> + }
> +
> + promise_handle m_handle{};
> +};
> +
> +
> +Task Foo(auto && ... args) noexcept
> +{
> + co_return;
> +}
> +
> +int main()
> +{
> + int v;
> + Foo(v, 2134);
> +}
> diff --git a/gcc/testsuite/g++.dg/coroutines/pr100772-b.C b/gcc/testsuite/g++.dg/coroutines/pr100772-b.C
> new file mode 100644
> index 00000000000..6cdf8d1e529
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/coroutines/pr100772-b.C
> @@ -0,0 +1,93 @@
> +#ifdef __clang__
> +#include <experimental/coroutine>
> +namespace std {
> + using namespace std::experimental;
> +}
> +#else
> +#include <coroutine>
> +#endif
> +#include <cstdio>
> +#include <typeinfo>
> +#include <cxxabi.h> // needed for abi::__cxa_demangle
> +#include <memory>
> +
> +std::shared_ptr<char> cppDemangle(const char *abiName)
> +{
> + int status;
> + char *ret = abi::__cxa_demangle(abiName, 0, 0, &status);
> +
> + /* NOTE: must free() the returned char when done with it! */
> + std::shared_ptr<char> retval;
> + retval.reset( (char *)ret, [](char *mem) { if (mem) free((void*)mem); } );
> + return retval;
> +}
> +
> +template <typename T>
> +struct Id{};
> +struct Task
> +{
> + struct promise_type
> + {
> + void return_void() const noexcept {}
> +
> + static void is_int (std::string x) {
> + if (x != "Id<int>")
> + abort() ;
> + }
> + template <typename ... Args>
> + void* operator new(std::size_t len, Args ...args) noexcept
> + {
> + (is_int (cppDemangle(typeid(Id<Args>).name()).get()), ...);
> + (std::puts (cppDemangle(typeid(Id<Args>).name()).get()), ...);
> + return nullptr;
> + }
> +
> + static Task get_return_object_on_allocation_failure() noexcept
> + {
> + return {};
> + }
> +
> + Task get_return_object() noexcept
> + {
> + return Task{ *this };
> + }
> +
> + std::suspend_always initial_suspend() noexcept
> + {
> + return {};
> + }
> +
> + std::suspend_always final_suspend() noexcept
> + {
> + return {};
> + }
> +
> + void unhandled_exception() noexcept {}
> + };
> +
> + using promise_handle = std::coroutine_handle<promise_type>;
> +
> + Task() = default;
> + Task(promise_type & promise) noexcept
> + : m_handle{ promise_handle::from_promise(promise) }
> + {}
> +
> + ~Task()
> + {
> + if (m_handle.address()) { m_handle.destroy(); }
> + }
> +
> + promise_handle m_handle{};
> +};
> +
> +
> +Task Foo(auto && ... args) noexcept
> +{
> + co_return;
> +}
> +
> +int main()
> +{
> + int v;
> + Foo(v, 2134);
> +}
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-11-05 21:55 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-05 15:49 [PATCH] coroutines: Pass lvalues to user-defined operator new [PR 100772] Iain Sandoe
2021-11-05 21:55 ` Jason Merrill
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).