[Bug c++/95822] New: [coroutines] compiler internal error with local object with noexcept false destructor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95822 Bug ID: 95822 Summary: [coroutines] compiler internal error with local object with noexcept false destructor Product: gcc Version: 10.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- It seems that when a coroutine contains a local object whose destructor is marked as noexcept(false), gcc reaches an unexpected state and aborts. When compiling the following code with gcc10.1.0 (-std=c++20 -fcoroutines), I get a compiler internal error: > internal compiler error: in gimplify_var_or_parm_decl, at gimplify.c:2830 Making the destructor noexcept fixes the error. I got the error when using boost log within a couroutine. It uses a record_pump whose destructor is not noexcept. I managed to reproduce with godbolt (both gcc10.1 and gcc trunk give me the assertion) https://godbolt.org/z/6JtKsU #include struct task { struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_void() {} task get_return_object() { return task{}; } void unhandled_exception() noexcept {} }; ~task() noexcept {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; struct Error { ~Error() noexcept(false) {} }; task g(); task f() { Error error; co_await g(); }
[Bug c++/95823] New: [coroutines] compiler internal error in captures_temporary,
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95823 Bug ID: 95823 Summary: [coroutines] compiler internal error in captures_temporary, Product: gcc Version: 10.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- I get a compiler internal error when passing a value to a coroutine that is retrieved through two inderections within smart pointers (I don't get the error with raw pointers, that's the smallest piece of code I was able to produce). > internal compiler error: in captures_temporary, at cp/coroutines.cc:2717 It can be easily worked around by making a local variable containing the value. Of course the code would crash in runtime as the pointers are not initialized, but I get the same error when initializing them. I managed to reproduce with godbolt (both gcc10.1 and gcc trunk give me the assertion) https://godbolt.org/z/XarC_M #include #include struct task { struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_void() {} task get_return_object() { return task{}; } void unhandled_exception() noexcept {} }; ~task() noexcept {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; struct Id { std::unique_ptr value; }; task g(int); task f() { std::unique_ptr id; co_await g(*id->value); }
[Bug c++/95824] New: [coroutines] compiler crash
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95824 Bug ID: 95824 Summary: [coroutines] compiler crash Product: gcc Version: 10.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- The following code sample makes the gcc 10.1.0 compiler crash with segmentation fault (compiled with -std=c++20 -fcoroutines). Gcc trunk generates an assertion > internal compiler error: tree check: expected function_type or method_type, > have pointer_type in captures_temporary, at cp/coroutines.cc:2690 That's the smallest piece of code I was able to reproduce on gcc 10.1.0 (removing the virtual from the makeId method or removing the virtual inheritance from the exception fixes the issue). On gcc trunk the exception and base classes are not necessary to generate the assertion. I initially got this issue when invoking a virtual method to get a feed a parameter to a coroutine, with boost::archive::archive_exception included, which virtually inherits from std::exception. I managed to reproduce with godbolt https://godbolt.org/z/tBmRxJ #include struct task { struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_void() {} task get_return_object() { return task{}; } void unhandled_exception() noexcept {} }; ~task() noexcept {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; struct base { virtual ~base() = default; }; class exception : public virtual base {}; struct factory { virtual ~factory() = default; virtual int makeId() const; }; task g(int); task f(factory& factory) { co_await g(factory.makeId()); }
[Bug c++/101144] New: Coroutine compiler error
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101144 Bug ID: 101144 Summary: Coroutine compiler error Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- Hello, When trying to await the following coroutine, I get a compiler internal error > internal compiler error: in build_special_member_call, at cp/call.c:10157 See it on godbolt: https://godbolt.org/z/f178vEqc9 #include #include #include struct task { struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_void() {} task get_return_object() { return task{}; } void unhandled_exception() noexcept {} }; ~task() noexcept {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; task f(const std::vector&) { co_return; } task g() { co_await f({"2", "3"}); }
[Bug c++/101149] New: Coroutine compiler error with ternary operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101149 Bug ID: 101149 Summary: Coroutine compiler error with ternary operator Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- Hello, I'm getting a compiler error when trying to use co_await expression in a ternary operator: > internal compiler error: in expand_expr_real_1, at expr.c:10285 See on godbolt https://godbolt.org/z/Wfva333cc #include #include #include struct task { struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_value(int) {} task get_return_object() { return task{}; } void unhandled_exception() noexcept {} }; ~task() noexcept {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} int await_resume() noexcept { return 1; } }; task f(int) { co_return 1; } task g(bool b) { auto result = b ? co_await f(1) : 2; }
[Bug c++/99576] [coroutines] destructor of a temporary called too early within co_await expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99576 --- Comment #4 from Victor Burckel --- I'm also seeing the same behavior, destructor of lambda captures seems to get called twice https://godbolt.org/z/zxnhM3x47
[Bug c++/98401] Temporaries passed to co_await sometimes cause an extraneous call to destructor at incorrect address
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98401 Victor Burckel changed: What|Removed |Added CC||victor.burckel at gmail dot com --- Comment #4 from Victor Burckel --- I'm also seeing the same behavior, destructor of lambda captures seems to get called twice https://godbolt.org/z/zxnhM3x47
[Bug c++/101243] New: Coroutine lambda capture is destroyed twice
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101243 Bug ID: 101243 Summary: Coroutine lambda capture is destroyed twice Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- In a corourtine expecting a std::function parameter, passing a temporary lambda with a capture results in the capture being destroyed twice: See it on gldbolt, gcc vs clang outputs https://godbolt.org/z/jx9Yh5cqM #include #include #include #ifdef __clang__ namespace std::experimental { using std::coroutine_handle; using std::coroutine_traits; } // namespace std::experimental #endif struct task { struct promise_type; using handle_type = std::coroutine_handle; struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_void() noexcept {} task get_return_object() noexcept { return task{handle_type::from_promise(*this)}; } void unhandled_exception() noexcept {} }; task(handle_type h) : h{h} {} ~task() { if (h) { fmt::print("destroying coroutine\n"); h.destroy(); fmt::print("coroutine destroyed\n"); } } bool await_ready() const noexcept { return false; } bool await_suspend(std::coroutine_handle<>) noexcept { h.resume(); return true; } void await_resume() noexcept {} void resume() { h.resume(); } handle_type h; }; struct S { S() { fmt::print("S::S()\n"); } S(const S&) { fmt::print("S::S(const S&)\n"); } S(S&&) { fmt::print("S::S(S&&)\n"); } ~S() { fmt::print("S::~S()\n"); } }; task g(std::function) { fmt::print("in g()\n"); co_return; } task f() { fmt::print("calling g()\n"); co_await g([s=S{}] {}); fmt::print("g called\n"); } int main() { auto task = f(); fmt::print("resuming f\n"); task.resume(); fmt::print("resuming f\n"); task.resume(); } Gcc outputs: resuming f calling g() S::S() S::S(S&&) in g() resuming f destroying coroutine S::~S() coroutine destroyed S::~S() S::~S() g called destroying coroutine coroutine destroyed While clang outputs: resuming f calling g() S::S() S::S(S&&) in g() resuming f destroying coroutine S::~S() coroutine destroyed S::~S() g called destroying coroutine coroutine destroyed
[Bug c++/101243] Coroutine lambda capture is destroyed twice
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101243 --- Comment #1 from Victor Burckel --- May be similar to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99576 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98401
[Bug c++/101244] New: Wrong path in coroutine returning ternary
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101244 Bug ID: 101244 Summary: Wrong path in coroutine returning ternary Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: victor.burckel at gmail dot com Target Milestone: --- In a coroutine returning a ternary expression with co_await, the co_await part seems to be evaluated whatever the result of the condition: See it on godbolt, I added a check of coro.done in the resume operation to avoid a crash in the clang part as the coroutine is voluntarily resumed one extra time https://godbolt.org/z/vzGKoP8d3 #include #include #include #ifdef __clang__ namespace std::experimental { using std::coroutine_handle; using std::coroutine_traits; } // namespace std::experimental #endif struct task { struct promise_type; using handle_type = std::coroutine_handle; struct promise_type { auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_value(int v) noexcept { value = v; } task get_return_object() noexcept { return task{handle_type::from_promise(*this)}; } void unhandled_exception() noexcept {} int value{}; }; task(handle_type h) : h{h} {} ~task() { if (h) { fmt::print("destroying coroutine\n"); h.destroy(); fmt::print("coroutine destroyed\n"); } } bool await_ready() const noexcept { return false; } bool await_suspend(std::coroutine_handle<>) noexcept { h.resume(); return true; } int await_resume() noexcept { return h.promise().value; } void resume() { if (!h.done()) h.resume(); } handle_type h; }; struct S { S() { fmt::print("S::S()\n"); } S(const S&) { fmt::print("S::S(const S&)\n"); } S(S&&) { fmt::print("S::S(S&&)\n"); } ~S() { fmt::print("S::~S()\n"); } }; task g(S) { fmt::print("in g()\n"); co_return 1; } task f(bool b) { fmt::print("calling g()\n"); co_return b ? co_await g(S{}) : 2; } int main() { auto task = f(false); fmt::print("resuming f\n"); task.resume(); fmt::print("resuming f\n"); task.resume(); } Gcc outputs resuming f calling g() S::S() S::S(S&&) in g() resuming f destroying coroutine S::~S() coroutine destroyed S::~S() destroying coroutine coroutine destroyed While clang outputs resuming f calling g() resuming f destroying coroutine coroutine destroyed
[Bug c++/101244] Wrong path in coroutine returning ternary
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101244 --- Comment #1 from Victor Burckel --- If ternary is not put in the co_return part but split into assignement return, the compiler crashes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101149