From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id DB9C5385043F; Mon, 15 Feb 2021 14:00:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DB9C5385043F From: "iains at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/95615] [coroutines] Coroutine frame and promise is leaked if exception thrown from promise.initial_suspend() Date: Mon, 15 Feb 2021 14:00:07 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 10.1.1 X-Bugzilla-Keywords: wrong-code X-Bugzilla-Severity: normal X-Bugzilla-Who: iains at gcc dot gnu.org X-Bugzilla-Status: NEW X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: iains at gcc dot gnu.org X-Bugzilla-Target-Milestone: 10.3 X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Feb 2021 14:00:08 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D95615 --- Comment #3 from Iain Sandoe --- Actually, I don't think the example goes far enough. ISTM, [on exception in the places noted] that non-trivial DTORs for frame copies of parms should be run after the GRO and promise DTOR but before the frame is freed. Do you agree? (if so I have a patch for this now) So, I think the modified example below should print: Y () Y (const Y&) operator new() Y (const Y&) promise_type() get_return_object() task() ~task() ~promise_type() ~Y () operator delete ~Y () caught X ~Y () =3D=3D=3D=3D=3D=3D=3D but *both* [master] GCC and clang print: Y () Y (const Y&) operator new() Y (const Y&) promise_type() task() ~Y () ~task() ~Y () =3D=3D=3D=3D=3D=3D=3D #if __has_include() #include #else #include namespace std { using namespace std::experimental; } #endif #include struct X {}; int Y_live =3D 0; struct Y { Y () { std::puts("Y ()"); Y_live++; }=20 Y (const Y&) { std::puts("Y (const Y&)"); Y_live++; }=20 ~Y () { std::puts("~Y ()"); Y_live--; } }; struct task { struct promise_type { void* operator new(size_t sz) { std::puts("operator new()"); return ::operator new(sz); } void operator delete(void* p, size_t sz) { std::puts("operator delete"); return ::operator delete(p, sz); } promise_type() { std::puts("promise_type()"); // throw X{}; } ~promise_type() { std::puts("~promise_type()"); } struct awaiter { bool await_ready() { //throw X{}; return false; } void await_suspend(std::coroutine_handle<>) { //throw X{}; } void await_resume() { //throw X{}; } }; awaiter initial_suspend() { // throw X{}; return {}; } task get_return_object() { // throw X{}; return task{}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() noexcept {} void unhandled_exception() noexcept { std::puts("unhandled_exception()"); } }; task() { std::puts("task()"); } ~task() { std::puts("~task()"); } task(task&&) { std::puts("task(task&&)"); } }; task f(Y Val) { co_return; } int main() { Y Val; try { auto a =3D f(Val); } catch (X) { std::puts("caught X"); } } =3D=3D=3D=3D=