From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp002.apm-internet.net (smtp002.apm-internet.net [85.119.248.221]) by sourceware.org (Postfix) with ESMTPS id 06F9838618CC for ; Fri, 5 Mar 2021 17:03:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 06F9838618CC Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=sandoe.co.uk Authentication-Results: sourceware.org; spf=none smtp.mailfrom=iain@sandoe.co.uk Received: (qmail 29476 invoked from network); 5 Mar 2021 17:03:44 -0000 X-APM-Out-ID: 16149638242947 X-APM-Authkey: 257869/1(257869/1) 6 Received: from unknown (HELO ?192.168.1.212?) (81.138.1.83) by smtp002.apm-internet.net with SMTP; 5 Mar 2021 17:03:44 -0000 From: Iain Sandoe Message-Id: <1F35D481-B0C3-4159-A4E4-C1C539536392@sandoe.co.uk> Content-Type: multipart/mixed; boundary="Apple-Mail=_8812FCE9-BF9E-4A2F-8019-E179CA8A3CB7" Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) Subject: Re: [PATCH] coroutines : Do not accept throwing final await expressions [PR95616]. Date: Fri, 5 Mar 2021 17:03:43 +0000 In-Reply-To: Cc: GCC Patches To: Nathan Sidwell References: X-Mailer: Apple Mail (2.3273) X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, KAM_COUK, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 05 Mar 2021 17:03:49 -0000 --Apple-Mail=_8812FCE9-BF9E-4A2F-8019-E179CA8A3CB7 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=utf-8; delsp=yes; format=flowed Nathan Sidwell wrote: > On 3/4/21 2:54 PM, Iain Sandoe wrote: >> Hi, >> From the PR: >> The wording of [dcl.fct.def.coroutine]/15 states: >> * The expression co_await promise.final_suspend() shall not be >> potentially-throwing ([except.spec]). >> See http://eel.is/c++draft/dcl.fct.def.coroutine#15 >> and http://eel.is/c++draft/except.spec#6 >> ie. all of the following must be declared noexcept (if they form part of >> the await-expression): >> - promise_type::final_suspend() >> - finalSuspendObj.operator co_await() >> - finalSuspendAwaiter.await_ready() >> - finalSuspendAwaiter.await_suspend() >> - finalSuspendAwaiter.await_resume() >> - finalSuspedObj destructor >> - finalSuspendAwaiter destructor >> This implements the checks for these cases and rejects such code with >> a diagnostic. >> [ accepts invalid ] >> tested on x86_64-darwin, x86_64-linux-gnu, >> OK for master / 10.x? >> thanks >> Iain >> gcc/cp/ChangeLog: >> PR c++/95616 >> * coroutines.cc (coro_diagnose_throwing_fn): New helper. >> (coro_diagnose_throwing_final_aw_expr): New helper. >> (build_co_await): Diagnose throwing final await expression >> components. >> (build_init_or_final_await): Diagnose a throwing promise >> final_suspend() call. > > ok. Does this DTRT in the presence of -fno-exceptions? thanks for catching this… > (i.e. use of that flag means you don't have to decorate everything with noexcept) As discussed on IRC, I updated this to gate the diagnostics on flag_exceptions (and added three more tests to cover that circumstance). pushed to master, (for the record, updated version attached), thanks, Iain --Apple-Mail=_8812FCE9-BF9E-4A2F-8019-E179CA8A3CB7 Content-Disposition: attachment; filename=0001-coroutines-Do-not-accept-throwing-final-await-expres.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-coroutines-Do-not-accept-throwing-final-await-expres.patch" Content-Transfer-Encoding: quoted-printable =46rom=209ee91079fd5879cba046e452ab5593372166b2ab=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Iain=20Sandoe=20=0ADate:=20= Mon,=2015=20Feb=202021=2017:11:31=20+0000=0ASubject:=20[PATCH]=20= coroutines=20:=20Do=20not=20accept=20throwing=20final=20await=20= expressions=0A=20[PR95616].=0A=0A=46rom=20the=20PR:=0A=0AThe=20wording=20= of=20[dcl.fct.def.coroutine]/15=20states:=0A=20*=20The=20expression=20= co_await=20promise.final_suspend()=20shall=20not=20be=0A=20=20=20= potentially-throwing=20([except.spec]).=0A=0ASee=20= http://eel.is/c++draft/dcl.fct.def.coroutine#15=0Aand=20= http://eel.is/c++draft/except.spec#6=0A=0Aie.=20all=20of=20the=20= following=20must=20be=20declared=20noexcept=20(if=20they=20form=20part=20= of=20the=20await-expression):=0A-=20promise_type::final_suspend()=0A-=20= finalSuspendObj.operator=20co_await()=0A-=20= finalSuspendAwaiter.await_ready()=0A-=20= finalSuspendAwaiter.await_suspend()=0A-=20= finalSuspendAwaiter.await_resume()=0A-=20finalSuspedObj=20destructor=0A-=20= finalSuspendAwaiter=20destructor=0A=0AThis=20implements=20the=20checks=20= for=20these=20cases=20and=20rejects=20such=20code=20with=0Aa=20= diagnostic=20if=20exceptions=20are=20enabled.=0A=0Agcc/cp/ChangeLog:=0A=0A= =09PR=20c++/95616=0A=09*=20coroutines.cc=20(coro_diagnose_throwing_fn):=20= New=20helper.=0A=09(coro_diagnose_throwing_final_aw_expr):=20New=20= helper.=0A=09(build_co_await):=20Diagnose=20throwing=20final=20await=20= expression=0A=09components.=0A=09(build_init_or_final_await):=20Diagnose=20= a=20throwing=20promise=0A=09final_suspend()=20call.=0A=0A= gcc/testsuite/ChangeLog:=0A=0A=09PR=20c++/95616=0A=09*=20= g++.dg/coroutines/pr95616-0-no-exceptions.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-0.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-1-no-exceptions.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-1.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-2.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-3-no-exceptions.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-3.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-4.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-5.C:=20New=20test.=0A=09*=20= g++.dg/coroutines/pr95616-6.C:=20New=20test.=0A---=0A=20= gcc/cp/coroutines.cc=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=2085=20+++++++++++++++++++=0A=20= .../coroutines/pr95616-0-no-exceptions.C=20=20=20=20=20=20|=2050=20= +++++++++++=0A=20gcc/testsuite/g++.dg/coroutines/pr95616-0.C=20=20=20|=20= 51=20+++++++++++=0A=20.../coroutines/pr95616-1-no-exceptions.C=20=20=20=20= =20=20|=2051=20+++++++++++=0A=20= gcc/testsuite/g++.dg/coroutines/pr95616-1.C=20=20=20|=2051=20+++++++++++=0A= =20gcc/testsuite/g++.dg/coroutines/pr95616-2.C=20=20=20|=2051=20= +++++++++++=0A=20.../coroutines/pr95616-3-no-exceptions.C=20=20=20=20=20=20= |=2050=20+++++++++++=0A=20gcc/testsuite/g++.dg/coroutines/pr95616-3.C=20=20= =20|=2051=20+++++++++++=0A=20gcc/testsuite/g++.dg/coroutines/pr95616-4.C=20= =20=20|=2051=20+++++++++++=0A=20= gcc/testsuite/g++.dg/coroutines/pr95616-5.C=20=20=20|=2051=20+++++++++++=0A= =20gcc/testsuite/g++.dg/coroutines/pr95616-6.C=20=20=20|=2051=20= +++++++++++=0A=2011=20files=20changed,=20593=20insertions(+)=0A=20create=20= mode=20100644=20= gcc/testsuite/g++.dg/coroutines/pr95616-0-no-exceptions.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-0.C=0A=20create=20= mode=20100644=20= gcc/testsuite/g++.dg/coroutines/pr95616-1-no-exceptions.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-1.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-2.C=0A=20create=20= mode=20100644=20= gcc/testsuite/g++.dg/coroutines/pr95616-3-no-exceptions.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-3.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-4.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-5.C=0A=20create=20= mode=20100644=20gcc/testsuite/g++.dg/coroutines/pr95616-6.C=0A=0Adiff=20= --git=20a/gcc/cp/coroutines.cc=20b/gcc/cp/coroutines.cc=0Aindex=20= 3f88b077d08..ef50a5f5fa3=20100644=0A---=20a/gcc/cp/coroutines.cc=0A+++=20= b/gcc/cp/coroutines.cc=0A@@=20-793,6=20+793,43=20@@=20get_awaitable_var=20= (suspend_point_kind=20suspend_kind,=20tree=20v_type)=0A=20=20=20return=20= ret;=0A=20}=0A=20=0A+/*=20Helpers=20to=20diagnose=20missing=20noexcept=20= on=20final=20await=20expressions.=20=20*/=0A+=0A+static=20bool=0A= +coro_diagnose_throwing_fn=20(tree=20fndecl)=0A+{=0A+=20=20if=20= (!TYPE_NOTHROW_P=20(TREE_TYPE=20(fndecl)))=0A+=20=20=20=20{=0A+=20=20=20=20= =20=20location_t=20f_loc=20=3D=20cp_expr_loc_or_loc=20(fndecl,=0A+=09=09=09= =09=09=20=20=20=20=20DECL_SOURCE_LOCATION=20(fndecl));=0A+=20=20=20=20=20= =20error_at=20(f_loc,=20"the=20expression=20%qE=20is=20required=20to=20= be=20non-throwing",=0A+=09=09fndecl);=0A+=20=20=20=20=20=20inform=20= (f_loc,=20"must=20be=20declared=20with=20%");=0A+=20=20=20= =20=20=20return=20true;=0A+=20=20=20=20}=0A+=20=20return=20false;=0A+}=0A= +=0A+static=20bool=0A+coro_diagnose_throwing_final_aw_expr=20(tree=20= expr)=0A+{=0A+=20=20tree=20t=20=3D=20TARGET_EXPR_INITIAL=20(expr);=0A+=20= =20tree=20fn=20=3D=20NULL_TREE;=0A+=20=20if=20(TREE_CODE=20(t)=20=3D=3D=20= CALL_EXPR)=0A+=20=20=20=20fn=20=3D=20CALL_EXPR_FN(t);=0A+=20=20else=20if=20= (TREE_CODE=20(t)=20=3D=3D=20AGGR_INIT_EXPR)=0A+=20=20=20=20fn=20=3D=20= AGGR_INIT_EXPR_FN=20(t);=0A+=20=20else=20if=20(TREE_CODE=20(t)=20=3D=3D=20= CONSTRUCTOR)=0A+=20=20=20=20return=20false;=0A+=20=20else=0A+=20=20=20=20= {=0A+=20=20=20=20=20=20gcc_checking_assert=20(0=20&&=20"unhandled=20= expression=20type");=0A+=20=20=20=20=20=20return=20false;=0A+=20=20=20=20= }=0A+=20=20fn=20=3D=20TREE_OPERAND=20(fn,=200);=0A+=20=20return=20= coro_diagnose_throwing_fn=20(fn);=0A+}=0A+=0A=20/*=20=20This=20performs=20= [expr.await]=20bullet=203.3=20and=20validates=20the=20interface=20= obtained.=0A=20=20=20=20=20It=20is=20also=20used=20to=20build=20the=20= initial=20and=20final=20suspend=20points.=0A=20=0A@@=20-815,6=20+852,28=20= @@=20build_co_await=20(location_t=20loc,=20tree=20a,=20= suspend_point_kind=20suspend_kind)=0A=20=20=20=20=20=20=20/*=20If=20no=20= viable=20functions=20are=20found,=20o=20is=20a.=20=20*/=0A=20=20=20=20=20= =20=20if=20(!o=20||=20o=20=3D=3D=20error_mark_node)=0A=20=09o=20=3D=20a;=0A= +=20=20=20=20=20=20else=20if=20(flag_exceptions=20&&=20suspend_kind=20=3D=3D= =20FINAL_SUSPEND_POINT)=0A+=09{=0A+=09=20=20/*=20We=20found=20an=20= overload=20for=20co_await(),=20diagnose=20throwing=20cases.=20=20*/=0A+=09= =20=20if=20(TREE_CODE=20(o)=20=3D=3D=20TARGET_EXPR=0A+=09=20=20=20=20=20=20= &&=20coro_diagnose_throwing_final_aw_expr=20(o))=0A+=09=20=20=20=20= return=20error_mark_node;=0A+=0A+=09=20=20/*=20We=20now=20know=20that=20= the=20final=20suspend=20object=20is=20distinct=20from=20the=0A+=09=20=20=20= =20=20final=20awaiter,=20so=20check=20for=20a=20non-throwing=20DTOR=20= where=20needed.=20=20*/=0A+=09=20=20tree=20a_type=20=3D=20TREE_TYPE=20= (a);=0A+=09=20=20if=20(TYPE_HAS_NONTRIVIAL_DESTRUCTOR=20(a_type))=0A+=09=20= =20=20=20{=0A+=09=20=20=20=20=20=20tree=20dummy=0A+=09=09=3D=20= build_special_member_call=20(a,=20complete_dtor_identifier,=0A+=09=09=09=09= =09=20=20=20=20=20NULL,=20a_type,=20LOOKUP_NORMAL,=0A+=09=09=09=09=09=20=20= =20=20=20tf_none);=0A+=09=20=20=20=20=20=20dummy=20=3D=20dummy=20?=20= TREE_OPERAND=20(CALL_EXPR_FN=20(dummy),=200)=0A+=09=09=09=20=20=20=20:=20= NULL_TREE;=0A+=09=20=20=20=20=20=20if=20(dummy=20&&=20= coro_diagnose_throwing_fn=20(dummy))=0A+=09=09return=20error_mark_node;=0A= +=09=20=20=20=20}=0A+=09}=0A=20=20=20=20=20}=0A=20=20=20else=0A=20=20=20=20= =20o=20=3D=20a;=20/*=20This=20is=20most=20likely=20about=20to=20fail=20= anyway.=20=20*/=0A@@=20-958,6=20+1017,27=20@@=20build_co_await=20= (location_t=20loc,=20tree=20a,=20suspend_point_kind=20suspend_kind)=0A=20= =20=20if=20(!awrs_func=20||=20!awrs_call=20||=20awrs_call=20=3D=3D=20= error_mark_node)=0A=20=20=20=20=20return=20error_mark_node;=0A=20=0A+=20=20= if=20(flag_exceptions=20&&=20suspend_kind=20=3D=3D=20= FINAL_SUSPEND_POINT)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20if=20= (coro_diagnose_throwing_fn=20(awrd_func))=0A+=09return=20= error_mark_node;=0A+=20=20=20=20=20=20if=20(coro_diagnose_throwing_fn=20= (awsp_func))=0A+=09return=20error_mark_node;=0A+=20=20=20=20=20=20if=20= (coro_diagnose_throwing_fn=20(awrs_func))=0A+=09return=20= error_mark_node;=0A+=20=20=20=20=20=20if=20= (TYPE_HAS_NONTRIVIAL_DESTRUCTOR=20(o_type))=0A+=09{=0A+=09=20=20tree=20= dummy=0A+=09=20=20=20=20=3D=20build_special_member_call=20(e_proxy,=20= complete_dtor_identifier,=0A+=09=09=09=09=09=20NULL,=20o_type,=20= LOOKUP_NORMAL,=0A+=09=09=09=09=09=20tf_none);=0A+=09=20=20dummy=20=3D=20= dummy=20?=20TREE_OPERAND=20(CALL_EXPR_FN=20(dummy),=200)=0A+=09=09=09:=20= NULL_TREE;=0A+=09=20=20if=20(dummy=20&&=20coro_diagnose_throwing_fn=20= (dummy))=0A+=09=20=20=20=20return=20error_mark_node;=0A+=09}=0A+=20=20=20= =20}=0A+=0A=20=20=20/*=20We=20now=20have=20three=20call=20expressions,=20= in=20terms=20of=20the=20promise,=20handle=20and=0A=20=20=20=20=20=20'e'=20= proxies.=20=20Save=20them=20in=20the=20await=20expression=20for=20later=20= expansion.=20=20*/=0A=20=0A@@=20-2538,6=20+2618,11=20@@=20= build_init_or_final_await=20(location_t=20loc,=20bool=20is_final)=0A=20=20= =20=20=20=3D=20coro_build_promise_expression=20(current_function_decl,=20= NULL,=20suspend_alt,=0A=20=09=09=09=09=20=20=20=20=20loc,=20NULL,=20= /*musthave=3D*/true);=0A=20=0A+=20=20/*=20Check=20for=20noexcept=20on=20= the=20final_suspend=20call.=20=20*/=0A+=20=20if=20(flag_exceptions=20&&=20= is_final=20&&=20setup_call=20!=3D=20error_mark_node=0A+=20=20=20=20=20=20= &&=20coro_diagnose_throwing_final_aw_expr=20(setup_call))=0A+=20=20=20=20= return=20error_mark_node;=0A+=0A=20=20=20/*=20So=20build=20the=20= co_await=20for=20this=20*/=0A=20=20=20/*=20For=20initial/final=20= suspends=20the=20call=20is=20"a"=20per=20[expr.await]=203.2.=20=20*/=0A=20= =20=20return=20build_co_await=20(loc,=20setup_call,=20(is_final=20?=20= FINAL_SUSPEND_POINT=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-0-no-exceptions.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-0-no-exceptions.C=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..7ce811dc569=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-0-no-exceptions.C=0A@@=20-0,0=20= +1,50=20@@=0A+//=20=20{=20dg-additional-options=20"-fsyntax-only=20= -fno-exceptions"=20}=0A+=0A+#if=20__has_include()=0A+#include=20= =0A+#else=0A+#include=20=0A+namespace=20= std=20{=0A+=20=20using=20namespace=20std::experimental;=0A+}=0A+#endif=0A= +=0A+class=20promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20= int=20x;=0A+=20=20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(true)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(true)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20{=20return=20{3};=20}=20//=20NOTE:=20= not=20declared=20noexcept=0A+=0A+=20=20void=20return_void()=20noexcept=20= {}=0A+=20=20void=20unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A= +};=0A+=0A+//=20OK=20when=20exceptions=20are=20disabled=0A+task=20f()=20= {=20=20=0A+=20=20co_return;=0A+}=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-0.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-0.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..e500b6ea636=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-0.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(true)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(true)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20{=20return=20{3};=20}=20//=20NOTE:=20= not=20declared=20noexcept=0A+=20=20//=20{=20dg-error=20{the=20expression=20= 'task::promise_type::final_suspend'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+=0A+=20=20void=20= return_void()=20noexcept=20{}=0A+=20=20void=20unhandled_exception()=20= noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20should=20be=20= ill-formed=20since=20final_suspend()=20is=20potentially=20throwing.=0A= +task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-1-no-exceptions.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-1-no-exceptions.C=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..48981e6e51d=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-1-no-exceptions.C=0A@@=20-0,0=20= +1,51=20@@=0A+//=20=20{=20dg-additional-options=20"-fsyntax-only=20= -fno-exceptions"=20}=0A+=0A+#if=20__has_include()=0A+#include=20= =0A+#else=0A+#include=20=0A+namespace=20= std=20{=0A+=20=20using=20namespace=20std::experimental;=0A+}=0A+#endif=0A= +=0A+class=20promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20= int=20x;=0A+=20=20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(true)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(true)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20= noexcept(false)=20//=20NOTE:=20not=20declared=20noexcept=0A+=20=20=20{=20= =0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20{=0A= +=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20noexcept=20{=20return=20{3};=20}=0A+=0A= +=20=20void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20OK=20= when=20exceptions=20are=20disabled.=0A+task=20f()=20{=20=20=0A+=20=20= co_return;=0A+}=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-1.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-1.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..c3989804e6b=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-1.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(true)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(true)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20= noexcept(false)=20{=20=0A+=20=20//=20{=20dg-error=20{the=20expression=20= 'finalSuspendObj::operator=20co_await'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+=20=20=20=20= return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20{=0A+=20=20struct=20= promise_type=20{=0A+=20=20task=20get_return_object()=20noexcept=20{=20= return=20{};=20}=0A+=20=20std::suspend_never=20initial_suspend()=20= noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20finalSuspendObj=20= final_suspend()=20noexcept=20{=20return=20{3};=20}=0A+=0A+=20=20void=20= return_void()=20noexcept=20{}=0A+=20=20void=20unhandled_exception()=20= noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20should=20be=20= ill-formed=20since=20final_suspend()=20is=20potentially=20throwing.=0A= +task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-2.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-2.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..6ad251986ec=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-2.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(false)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(false)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(false)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(false)=20{}=20=0A+=20=20//=20{=20= dg-error=20{the=20expression=20'finalSuspendObj::~finalSuspendObj'=20is=20= required=20to=20be=20non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20= }=0A+=0A+=20=20finalSuspendAwaiter=20operator=20co_await()=20const=20&=20= noexcept(true)=20{=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A= +struct=20task=20{=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20= get_return_object()=20noexcept=20{=20return=20{};=20}=0A+=20=20= std::suspend_never=20initial_suspend()=20noexcept=20{=20return=20{};=20}=0A= +=20=20=0A+=20=20finalSuspendObj=20final_suspend()=20noexcept=20{=20= return=20{3};=20}=20//=20NOTE:=20not=20declared=20noexcept=0A+=0A+=20=20= void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20= should=20be=20ill-formed=20since=20final_suspend()=20is=20potentially=20= throwing.=0A+task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0Adiff=20= --git=20a/gcc/testsuite/g++.dg/coroutines/pr95616-3-no-exceptions.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-3-no-exceptions.C=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..1dcd426c608=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-3-no-exceptions.C=0A@@=20-0,0=20= +1,50=20@@=0A+//=20=20{=20dg-additional-options=20"-fsyntax-only=20= -fno-exceptions"=20}=0A+=0A+#if=20__has_include()=0A+#include=20= =0A+#else=0A+#include=20=0A+namespace=20= std=20{=0A+=20=20using=20namespace=20std::experimental;=0A+}=0A+#endif=0A= +=0A+class=20promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20= int=20x;=0A+=20=20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(false)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(false)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(false)=20{=20= return=20x;=20}=20=20//=20NOTE:=20not=20declared=20noexcept=0A+};=0A+=0A= +struct=20finalSuspendObj=20{=0A+=20=20int=20x;=0A+=20=20finalSuspendObj=20= ()=20:=20x(0)=20{=20}=0A+=20=20finalSuspendObj=20(int=20_x)=20:=20x(_x)=20= {=20}=0A+=20=20~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20noexcept=20{=20return=20{3};=20}=0A+=0A= +=20=20void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20OK=20= when=20exceptions=20are=20disabled=0A+task=20f()=20{=20=20=0A+=20=20= co_return;=0A+}=0Adiff=20--git=20= a/gcc/testsuite/g++.dg/coroutines/pr95616-3.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-3.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..7da1f6a9658=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-3.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(false)=20{=20return=20false;=20}=0A+=20=20= //=20{=20dg-error=20{the=20expression=20= 'finalSuspendAwaiter::await_ready'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+=20=20void=20= await_suspend(std::coroutine_handle<>)=20const=20noexcept(false)=20{=20}=0A= +=20=20int=20await_resume()=20const=20noexcept(false)=20{=20return=20x;=20= }=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20x;=0A+=20=20= finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20finalSuspendObj=20(int=20= _x)=20:=20x(_x)=20{=20}=0A+=20=20~finalSuspendObj=20()=20noexcept(true)=20= {}=20=0A+=0A+=20=20finalSuspendAwaiter=20operator=20co_await()=20const=20= &=20noexcept(true)=20{=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A= +=0A+struct=20task=20{=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20= get_return_object()=20noexcept=20{=20return=20{};=20}=0A+=20=20= std::suspend_never=20initial_suspend()=20noexcept=20{=20return=20{};=20}=0A= +=20=20=0A+=20=20finalSuspendObj=20final_suspend()=20noexcept=20{=20= return=20{3};=20}=0A+=0A+=20=20void=20return_void()=20noexcept=20{}=0A+=20= =20void=20unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A= +//=20This=20should=20be=20ill-formed=20since=20final_suspend()=20is=20= potentially=20throwing.=0A+task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0A= diff=20--git=20a/gcc/testsuite/g++.dg/coroutines/pr95616-4.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-4.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..ef6a160a5c4=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-4.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(false)=20= {=20}=0A+=20=20//=20{=20dg-error=20{the=20expression=20= 'finalSuspendAwaiter::await_suspend'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+=20=20int=20= await_resume()=20const=20noexcept(false)=20{=20return=20x;=20}=0A+};=0A+=0A= +struct=20finalSuspendObj=20{=0A+=20=20int=20x;=0A+=20=20finalSuspendObj=20= ()=20:=20x(0)=20{=20}=0A+=20=20finalSuspendObj=20(int=20_x)=20:=20x(_x)=20= {=20}=0A+=20=20~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20noexcept=20{=20return=20{3};=20}=0A+=0A= +=20=20void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20= should=20be=20ill-formed=20since=20final_suspend()=20is=20potentially=20= throwing.=0A+task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0Adiff=20= --git=20a/gcc/testsuite/g++.dg/coroutines/pr95616-5.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-5.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..930c1a7e6a1=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-5.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(false)=20{=20= return=20x;=20}=0A+=20=20//=20{=20dg-error=20{the=20expression=20= 'finalSuspendAwaiter::await_resume'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+};=0A+=0A= +struct=20finalSuspendObj=20{=0A+=20=20int=20x;=0A+=20=20finalSuspendObj=20= ()=20:=20x(0)=20{=20}=0A+=20=20finalSuspendObj=20(int=20_x)=20:=20x(_x)=20= {=20}=0A+=20=20~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20noexcept=20{=20return=20{3};=20}=0A+=0A= +=20=20void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20= should=20be=20ill-formed=20since=20final_suspend()=20is=20potentially=20= throwing.=0A+task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0Adiff=20= --git=20a/gcc/testsuite/g++.dg/coroutines/pr95616-6.C=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-6.C=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..e7481711c5e=0A---=20/dev/null=0A+++=20= b/gcc/testsuite/g++.dg/coroutines/pr95616-6.C=0A@@=20-0,0=20+1,51=20@@=0A= +//=20=20{=20dg-additional-options=20"-fsyntax-only"=20}=0A+=0A+#if=20= __has_include()=0A+#include=20=0A+#else=0A= +#include=20=0A+namespace=20std=20{=0A+=20=20= using=20namespace=20std::experimental;=0A+}=0A+#endif=0A+=0A+class=20= promise;=0A+=0A+struct=20finalSuspendAwaiter=20{=0A+=20=20int=20x;=0A+=20= =20finalSuspendAwaiter=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendAwaiter=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendAwaiter()=20noexcept(false)=20{=20}=0A+=20=20//=20{=20= dg-error=20{the=20expression=20= 'finalSuspendAwaiter::~finalSuspendAwaiter'=20is=20required=20to=20be=20= non-throwing}=20""=20{=20target=20*-*-*=20}=20.-1=20}=0A+=20=20bool=20= await_ready()=20const=20noexcept(true)=20{=20return=20false;=20}=0A+=20=20= void=20await_suspend(std::coroutine_handle<>)=20const=20noexcept(true)=20= {=20}=0A+=20=20int=20await_resume()=20const=20noexcept(true)=20{=20= return=20x;=20}=0A+};=0A+=0A+struct=20finalSuspendObj=20{=0A+=20=20int=20= x;=0A+=20=20finalSuspendObj=20()=20:=20x(0)=20{=20}=0A+=20=20= finalSuspendObj=20(int=20_x)=20:=20x(_x)=20{=20}=0A+=20=20= ~finalSuspendObj=20()=20noexcept(true)=20{}=20=0A+=0A+=20=20= finalSuspendAwaiter=20operator=20co_await()=20const=20&=20noexcept(true)=20= {=20=0A+=20=20=20=20return=20{x};=0A+=20=20}=0A+};=0A+=0A+struct=20task=20= {=0A+=20=20struct=20promise_type=20{=0A+=20=20task=20get_return_object()=20= noexcept=20{=20return=20{};=20}=0A+=20=20std::suspend_never=20= initial_suspend()=20noexcept=20{=20return=20{};=20}=0A+=20=20=0A+=20=20= finalSuspendObj=20final_suspend()=20noexcept=20{=20return=20{3};=20}=20=0A= +=0A+=20=20void=20return_void()=20noexcept=20{}=0A+=20=20void=20= unhandled_exception()=20noexcept=20{}=0A+=20=20};=0A+};=0A+=0A+//=20This=20= should=20be=20ill-formed=20since=20final_suspend()=20is=20potentially=20= throwing.=0A+task=20f()=20{=20=20=0A+=20=20co_return;=0A+}=0A--=20=0A= 2.24.1=0A=0A= --Apple-Mail=_8812FCE9-BF9E-4A2F-8019-E179CA8A3CB7 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii; delsp=yes; format=flowed --Apple-Mail=_8812FCE9-BF9E-4A2F-8019-E179CA8A3CB7--