diff --git a/CoroutinesCodeGenerator.cpp b/CoroutinesCodeGenerator.cpp index cebf5ff..390b34b 100644 --- a/CoroutinesCodeGenerator.cpp +++ b/CoroutinesCodeGenerator.cpp @@ -112,7 +112,6 @@ class CoroutineASTTransformer : public StmtVisitor CoroutineASTData& mASTData; Stmt* mStaged{}; bool mSkip{}; - bool mFinalSuspend{}; size_t& mSuspendsCount; llvm::DenseMap mVarNamePrefix{}; @@ -320,9 +319,7 @@ class CoroutineASTTransformer : public StmtVisitor void VisitCoawaitExpr(CoawaitExpr* stmt) { - if(not mFinalSuspend) { - ++mSuspendsCount; - } + ++mSuspendsCount; if(const bool returnsVoid{stmt->getResumeExpr()->getType()->isVoidType()}; returnsVoid) { Visit(stmt->getOperand()); @@ -391,13 +388,9 @@ class CoroutineASTTransformer : public StmtVisitor Visit(stmt->getReturnValueInit()); Visit(stmt->getExceptionHandler()); Visit(stmt->getReturnStmtOnAllocFailure()); - + Visit(stmt->getFallthroughHandler()); Visit(stmt->getInitSuspendStmt()); - - // final suspend point doesn't need a label - mFinalSuspend = true; Visit(stmt->getFinalSuspendStmt()); - mFinalSuspend = false; } void VisitStmt(Stmt* stmt) @@ -756,7 +749,10 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineBodyStmt* stmt) funcBodyStmts.Add(c); } - // InsertArg(stmt->getFallthroughHandler()); + if(const auto* coReturnVoid = dyn_cast_or_null(stmt->getFallthroughHandler())) { + coReturnVoid->dump(); + funcBodyStmts.Add(coReturnVoid); + } auto* gotoFinalSuspend = Goto(FINAL_SUSPEND_NAME); funcBodyStmts.Add(gotoFinalSuspend); @@ -939,16 +935,14 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt) Expr* initializeInitialAwaitResume = nullptr; auto addInitialAwaitSuspendCalled = [&] { - if(eState::FinalSuspend != mState) { - bodyStmts.Add(bop); - - if(eState::InitialSuspend == mState) { - mState = eState::Body; - // https://timsong-cpp.github.io/cppwp/n4861/dcl.fct.def.coroutine#5.3 - initializeInitialAwaitResume = - Assign(mASTData.mFrameAccessDeclRef, mASTData.mInitialAwaitResumeCalledField, Bool(true)); - bodyStmts.Add(initializeInitialAwaitResume); - } + bodyStmts.Add(bop); + + if(eState::InitialSuspend == mState) { + mState = eState::Body; + // https://timsong-cpp.github.io/cppwp/n4861/dcl.fct.def.coroutine#5.3 + initializeInitialAwaitResume = + Assign(mASTData.mFrameAccessDeclRef, mASTData.mInitialAwaitResumeCalledField, Bool(true)); + bodyStmts.Add(initializeInitialAwaitResume); } }; @@ -974,6 +968,9 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt) mOutputFormatHelper.AppendNewLine(); } + auto* suspendLabel = Label(BuildResumeLabelName(mSuspendsCount)); + InsertArg(suspendLabel); + if(eState::FinalSuspend == mState) { auto* memExpr = AccessMember(mASTData.mFrameAccessDeclRef, mASTData.mDestroyFnField, true); auto* callCoroFSM = Call(memExpr, {mASTData.mFrameAccessDeclRef}); @@ -981,9 +978,6 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt) return; } - auto* suspendLabel = Label(BuildResumeLabelName(mSuspendsCount)); - InsertArg(suspendLabel); - const auto* resumeExpr = stmt->getResumeExpr(); if(not resumeExpr->getType()->isVoidType()) { diff --git a/tests/EduCoroutineAllocFailureTest.expect b/tests/EduCoroutineAllocFailureTest.expect index 06506e2..8d1dc5e 100644 --- a/tests/EduCoroutineAllocFailureTest.expect +++ b/tests/EduCoroutineAllocFailureTest.expect @@ -204,6 +204,7 @@ void __fun_intResume(__fun_intFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_fun_int_1; + case 2: goto __resume_fun_int_2; } /* co_await EduCoroutineAllocFailureTest.cpp:40 */ @@ -234,9 +235,11 @@ void __fun_intResume(__fun_intFrame * __f) __f->__suspend_40_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_40_14_1.await_ready()) { __f->__suspend_40_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_fun_int_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineBinaryExprTest.expect b/tests/EduCoroutineBinaryExprTest.expect index b5c47c7..3b1bc2d 100644 --- a/tests/EduCoroutineBinaryExprTest.expect +++ b/tests/EduCoroutineBinaryExprTest.expect @@ -140,6 +140,7 @@ void __seqResume(__seqFrame * __f) case 3: goto __resume_seq_3; case 4: goto __resume_seq_4; case 5: goto __resume_seq_5; + case 6: goto __resume_seq_6; } /* co_await EduCoroutineBinaryExprTest.cpp:35 */ @@ -216,9 +217,11 @@ void __seqResume(__seqFrame * __f) __f->__suspend_35_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_35_11_1.await_ready()) { __f->__suspend_35_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 6; return; } + __resume_seq_6: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineCaptureConstTest.cerr b/tests/EduCoroutineCaptureConstTest.cerr index 198f56c..9e3c4d7 100644 --- a/tests/EduCoroutineCaptureConstTest.cerr +++ b/tests/EduCoroutineCaptureConstTest.cerr @@ -4,8 +4,8 @@ .tmp.cpp:82:15: note: non-static data member 'start' declared const here 82 | const int & start; | ~~~~~~~~~~~~^~~~~ -.tmp.cpp:147:12: error: no viable overloaded '=' - 147 | __f->s = {0, '\0'}; +.tmp.cpp:148:12: error: no viable overloaded '=' + 148 | __f->s = {0, '\0'}; | ~~~~~~ ^ ~~~~~~~~~ .tmp.cpp:84:10: note: candidate function (the implicit copy assignment operator) not viable: 'this' argument has type 'const S', but method is not marked const 84 | struct S diff --git a/tests/EduCoroutineCaptureConstTest.expect b/tests/EduCoroutineCaptureConstTest.expect index 3480528..209197b 100644 --- a/tests/EduCoroutineCaptureConstTest.expect +++ b/tests/EduCoroutineCaptureConstTest.expect @@ -131,6 +131,7 @@ void __seqResume(__seqFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_seq_1; + case 2: goto __resume_seq_2; } /* co_await EduCoroutineCaptureConstTest.cpp:35 */ @@ -162,9 +163,11 @@ void __seqResume(__seqFrame * __f) __f->__suspend_35_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_35_11_1.await_ready()) { __f->__suspend_35_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_seq_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineCaptureThisTest.expect b/tests/EduCoroutineCaptureThisTest.expect index 85c0c83..ed7cad7 100644 --- a/tests/EduCoroutineCaptureThisTest.expect +++ b/tests/EduCoroutineCaptureThisTest.expect @@ -119,6 +119,7 @@ inline my_resumable coro(int x) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_coro_1; + case 2: goto __resume_coro_2; } /* co_await EduCoroutineCaptureThisTest.cpp:31 */ @@ -150,9 +151,11 @@ inline my_resumable coro(int x) __f->__suspend_31_16_1 = __f->__promise.final_suspend(); if(!__f->__suspend_31_16_1.await_ready()) { __f->__suspend_31_16_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_coro_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineCoAwaitOperatorTest.cerr b/tests/EduCoroutineCoAwaitOperatorTest.cerr index c1f80d2..779a8de 100644 --- a/tests/EduCoroutineCoAwaitOperatorTest.cerr +++ b/tests/EduCoroutineCoAwaitOperatorTest.cerr @@ -1,7 +1,7 @@ .tmp.cpp:167:3: error: unknown type name 'awaiter' 167 | awaiter __suspend_54_5; | ^ -.tmp.cpp:249:10: warning: expression result unused [-Wunused-value] - 249 | __f->__suspend_56_14_res; +.tmp.cpp:250:10: warning: expression result unused [-Wunused-value] + 250 | __f->__suspend_56_14_res; | ~~~ ^~~~~~~~~~~~~~~~~~~ 1 warning and 1 error generated. diff --git a/tests/EduCoroutineCoAwaitOperatorTest.expect b/tests/EduCoroutineCoAwaitOperatorTest.expect index 455ad42..bbc6169 100644 --- a/tests/EduCoroutineCoAwaitOperatorTest.expect +++ b/tests/EduCoroutineCoAwaitOperatorTest.expect @@ -209,6 +209,7 @@ void __gResume(__gFrame * __f) case 1: goto __resume_g_1; case 2: goto __resume_g_2; case 3: goto __resume_g_3; + case 4: goto __resume_g_4; } /* co_await EduCoroutineCoAwaitOperatorTest.cpp:51 */ @@ -247,6 +248,8 @@ void __gResume(__gFrame * __f) __resume_g_3: __f->__suspend_56_14_res = __f->__suspend_56_14.await_resume(); __f->__suspend_56_14_res; + /* co_return EduCoroutineCoAwaitOperatorTest.cpp:51 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -262,9 +265,11 @@ void __gResume(__gFrame * __f) __f->__suspend_51_16_1 = __f->__promise.final_suspend(); if(!__f->__suspend_51_16_1.await_ready()) { __f->__suspend_51_16_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 4; return; } + __resume_g_4: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineCoreturnWithCoawaitTest.cerr b/tests/EduCoroutineCoreturnWithCoawaitTest.cerr index a6e31f1..15eccd0 100644 --- a/tests/EduCoroutineCoreturnWithCoawaitTest.cerr +++ b/tests/EduCoroutineCoreturnWithCoawaitTest.cerr @@ -1,41 +1,41 @@ -.tmp.cpp:274:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 274 | __f->__suspend_56_24 = simpleReturn(__f->v); +.tmp.cpp:278:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 278 | __f->__suspend_56_24 = simpleReturn(__f->v); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:285:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 285 | __f->__suspend_56_51 = simpleReturn(__f->v + 1); +.tmp.cpp:289:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 289 | __f->__suspend_56_51 = simpleReturn(__f->v + 1); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:407:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 407 | __f->__suspend_60_24 = simpleReturn(__f->v); +.tmp.cpp:414:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 414 | __f->__suspend_60_24 = simpleReturn(__f->v); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:418:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 418 | __f->__suspend_60_51 = simpleReturn(__f->v + 1); +.tmp.cpp:425:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 425 | __f->__suspend_60_51 = simpleReturn(__f->v + 1); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:429:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 429 | __f->__suspend_60_80 = simpleReturn(__f->v + 2); +.tmp.cpp:436:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 436 | __f->__suspend_60_80 = simpleReturn(__f->v + 2); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:548:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 548 | __f->__suspend_67_24 = simpleReturn(__f->v); +.tmp.cpp:558:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 558 | __f->__suspend_67_24 = simpleReturn(__f->v); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) | ^ -.tmp.cpp:559:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted - 559 | __f->__suspend_67_51 = simpleReturn(__f->v + 1); +.tmp.cpp:569:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted + 569 | __f->__suspend_67_51 = simpleReturn(__f->v + 1); | ^ .tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor 69 | inline generator(generator && rhs) diff --git a/tests/EduCoroutineCoreturnWithCoawaitTest.expect b/tests/EduCoroutineCoreturnWithCoawaitTest.expect index 72f945e..c02094b 100644 --- a/tests/EduCoroutineCoreturnWithCoawaitTest.expect +++ b/tests/EduCoroutineCoreturnWithCoawaitTest.expect @@ -148,6 +148,7 @@ void __simpleReturnResume(__simpleReturnFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_simpleReturn_1; + case 2: goto __resume_simpleReturn_2; } /* co_await EduCoroutineCoreturnWithCoawaitTest.cpp:50 */ @@ -178,9 +179,11 @@ void __simpleReturnResume(__simpleReturnFrame * __f) __f->__suspend_50_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_50_11_1.await_ready()) { __f->__suspend_50_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_simpleReturn_2: __f->destroy_fn(__f); } @@ -256,6 +259,7 @@ void __additionAwaitReturnResume(__additionAwaitReturnFrame * __f) case 1: goto __resume_additionAwaitReturn_1; case 2: goto __resume_additionAwaitReturn_2; case 3: goto __resume_additionAwaitReturn_3; + case 4: goto __resume_additionAwaitReturn_4; } /* co_await EduCoroutineCoreturnWithCoawaitTest.cpp:55 */ @@ -308,9 +312,11 @@ void __additionAwaitReturnResume(__additionAwaitReturnFrame * __f) __f->__suspend_55_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_55_11_1.await_ready()) { __f->__suspend_55_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 4; return; } + __resume_additionAwaitReturn_4: __f->destroy_fn(__f); } @@ -389,6 +395,7 @@ void __additionAwaitReturn2Resume(__additionAwaitReturn2Frame * __f) case 2: goto __resume_additionAwaitReturn2_2; case 3: goto __resume_additionAwaitReturn2_3; case 4: goto __resume_additionAwaitReturn2_4; + case 5: goto __resume_additionAwaitReturn2_5; } /* co_await EduCoroutineCoreturnWithCoawaitTest.cpp:59 */ @@ -452,9 +459,11 @@ void __additionAwaitReturn2Resume(__additionAwaitReturn2Frame * __f) __f->__suspend_59_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_59_11_1.await_ready()) { __f->__suspend_59_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 5; return; } + __resume_additionAwaitReturn2_5: __f->destroy_fn(__f); } @@ -530,6 +539,7 @@ void __additionAwaitReturnWithIntResume(__additionAwaitReturnWithIntFrame * __f) case 1: goto __resume_additionAwaitReturnWithInt_1; case 2: goto __resume_additionAwaitReturnWithInt_2; case 3: goto __resume_additionAwaitReturnWithInt_3; + case 4: goto __resume_additionAwaitReturnWithInt_4; } /* co_await EduCoroutineCoreturnWithCoawaitTest.cpp:63 */ @@ -582,9 +592,11 @@ void __additionAwaitReturnWithIntResume(__additionAwaitReturnWithIntFrame * __f) __f->__suspend_63_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_63_11_1.await_ready()) { __f->__suspend_63_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 4; return; } + __resume_additionAwaitReturnWithInt_4: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineCustomYieldTypeTest.expect b/tests/EduCoroutineCustomYieldTypeTest.expect index d21aead..0667fde 100644 --- a/tests/EduCoroutineCustomYieldTypeTest.expect +++ b/tests/EduCoroutineCustomYieldTypeTest.expect @@ -208,6 +208,7 @@ void __seqResume(__seqFrame * __f) case 0: break; case 1: goto __resume_seq_1; case 2: goto __resume_seq_2; + case 3: goto __resume_seq_3; } /* co_await EduCoroutineCustomYieldTypeTest.cpp:86 */ @@ -237,6 +238,8 @@ void __seqResume(__seqFrame * __f) __f->__suspend_88_14.await_resume(); } + /* co_return EduCoroutineCustomYieldTypeTest.cpp:86 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -252,9 +255,11 @@ void __seqResume(__seqFrame * __f) __f->__suspend_86_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_86_11_1.await_ready()) { __f->__suspend_86_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_seq_3: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineExprTest.expect b/tests/EduCoroutineExprTest.expect index bb24939..38c839b 100644 --- a/tests/EduCoroutineExprTest.expect +++ b/tests/EduCoroutineExprTest.expect @@ -281,6 +281,7 @@ void __get_randomResume(__get_randomFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_get_random_1; + case 2: goto __resume_get_random_2; } /* co_await EduCoroutineExprTest.cpp:77 */ @@ -312,9 +313,11 @@ void __get_randomResume(__get_randomFrame * __f) __f->__suspend_77_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_77_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_77_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 2; return; } + __resume_get_random_2: __f->destroy_fn(__f); } @@ -401,6 +404,7 @@ void __testVarDeclAndConditionalResume(__testVarDeclAndConditionalFrame * __f) case 5: goto __resume_testVarDeclAndConditional_5; case 6: goto __resume_testVarDeclAndConditional_6; case 7: goto __resume_testVarDeclAndConditional_7; + case 8: goto __resume_testVarDeclAndConditional_8; } /* co_await EduCoroutineExprTest.cpp:85 */ @@ -501,9 +505,11 @@ void __testVarDeclAndConditionalResume(__testVarDeclAndConditionalFrame * __f) __f->__suspend_85_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_85_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_85_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 8; return; } + __resume_testVarDeclAndConditional_8: __f->destroy_fn(__f); } @@ -581,6 +587,7 @@ void __testIfStmtResume(__testIfStmtFrame * __f) case 3: goto __resume_testIfStmt_3; case 4: goto __resume_testIfStmt_4; case 5: goto __resume_testIfStmt_5; + case 6: goto __resume_testIfStmt_6; } /* co_await EduCoroutineExprTest.cpp:96 */ @@ -663,9 +670,11 @@ void __testIfStmtResume(__testIfStmtFrame * __f) __f->__suspend_96_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_96_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_96_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 6; return; } + __resume_testIfStmt_6: __f->destroy_fn(__f); } @@ -732,6 +741,7 @@ void __testCallExprResume(__testCallExprFrame * __f) case 0: break; case 1: goto __resume_testCallExpr_1; case 2: goto __resume_testCallExpr_2; + case 3: goto __resume_testCallExpr_3; } /* co_await EduCoroutineExprTest.cpp:111 */ @@ -775,9 +785,11 @@ void __testCallExprResume(__testCallExprFrame * __f) __f->__suspend_111_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_111_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_111_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 3; return; } + __resume_testCallExpr_3: __f->destroy_fn(__f); } @@ -844,6 +856,7 @@ void __testSwitchResume(__testSwitchFrame * __f) case 0: break; case 1: goto __resume_testSwitch_1; case 2: goto __resume_testSwitch_2; + case 3: goto __resume_testSwitch_3; } /* co_await EduCoroutineExprTest.cpp:120 */ @@ -889,9 +902,11 @@ void __testSwitchResume(__testSwitchFrame * __f) __f->__suspend_120_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_120_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_120_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 3; return; } + __resume_testSwitch_3: __f->destroy_fn(__f); } @@ -959,6 +974,7 @@ void __testWhileResume(__testWhileFrame * __f) case 0: break; case 1: goto __resume_testWhile_1; case 2: goto __resume_testWhile_2; + case 3: goto __resume_testWhile_3; } /* co_await EduCoroutineExprTest.cpp:131 */ @@ -1005,9 +1021,11 @@ void __testWhileResume(__testWhileFrame * __f) __f->__suspend_131_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_131_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_131_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 3; return; } + __resume_testWhile_3: __f->destroy_fn(__f); } @@ -1075,6 +1093,7 @@ void __testDoWhileResume(__testDoWhileFrame * __f) case 0: break; case 1: goto __resume_testDoWhile_1; case 2: goto __resume_testDoWhile_2; + case 3: goto __resume_testDoWhile_3; } /* co_await EduCoroutineExprTest.cpp:142 */ @@ -1121,9 +1140,11 @@ void __testDoWhileResume(__testDoWhileFrame * __f) __f->__suspend_142_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_142_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_142_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 3; return; } + __resume_testDoWhile_3: __f->destroy_fn(__f); } @@ -1199,6 +1220,7 @@ void __testForLoopResume(__testForLoopFrame * __f) case 3: goto __resume_testForLoop_3; case 4: goto __resume_testForLoop_4; case 5: goto __resume_testForLoop_5; + case 6: goto __resume_testForLoop_6; } /* co_await EduCoroutineExprTest.cpp:154 */ @@ -1278,9 +1300,11 @@ void __testForLoopResume(__testForLoopFrame * __f) __f->__suspend_154_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_154_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_154_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 6; return; } + __resume_testForLoop_6: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineSimpleTest.expect b/tests/EduCoroutineSimpleTest.expect index 9cbdd67..5c8acf7 100644 --- a/tests/EduCoroutineSimpleTest.expect +++ b/tests/EduCoroutineSimpleTest.expect @@ -121,6 +121,7 @@ void __funResume(__funFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_fun_1; + case 2: goto __resume_fun_2; } /* co_await EduCoroutineSimpleTest.cpp:34 */ @@ -151,9 +152,11 @@ void __funResume(__funFrame * __f) __f->__suspend_34_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_34_11_1.await_ready()) { __f->__suspend_34_11_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_fun_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineStaticVarTest.expect b/tests/EduCoroutineStaticVarTest.expect index e3d49d1..a877f82 100644 --- a/tests/EduCoroutineStaticVarTest.expect +++ b/tests/EduCoroutineStaticVarTest.expect @@ -144,6 +144,7 @@ void __taskAResume(__taskAFrame * __f) case 0: break; case 1: goto __resume_taskA_1; case 2: goto __resume_taskA_2; + case 3: goto __resume_taskA_3; } /* co_await EduCoroutineStaticVarTest.cpp:58 */ @@ -171,6 +172,8 @@ void __taskAResume(__taskAFrame * __f) __f->__suspend_62_18.await_resume(); static std::basic_string, std::allocator > res = {std::operator""s("a is back doing work\n", 21UL)}; std::operator<<(std::cout, res); + /* co_return EduCoroutineStaticVarTest.cpp:58 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -186,9 +189,11 @@ void __taskAResume(__taskAFrame * __f) __f->__suspend_58_6_1 = __f->__promise.final_suspend(); if(!__f->__suspend_58_6_1.await_ready()) { __f->__suspend_58_6_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_taskA_3: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineSuspendNeverBoolTest.expect b/tests/EduCoroutineSuspendNeverBoolTest.expect index 57ae88c..bb1619c 100644 --- a/tests/EduCoroutineSuspendNeverBoolTest.expect +++ b/tests/EduCoroutineSuspendNeverBoolTest.expect @@ -211,6 +211,7 @@ void __fun_intResume(__fun_intFrame * __f) case 0: break; case 1: goto __resume_fun_int_1; case 2: goto __resume_fun_int_2; + case 3: goto __resume_fun_int_3; } /* co_await EduCoroutineSuspendNeverBoolTest.cpp:41 */ @@ -259,11 +260,13 @@ void __fun_intResume(__fun_intFrame * __f) __f->__suspend_41_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_41_14_1.await_ready()) { if(__f->__suspend_41_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle())) { + __f->__suspend_index = 3; return; } } + __resume_fun_int_3: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineSuspendNeverTest.expect b/tests/EduCoroutineSuspendNeverTest.expect index d65e895..736ecea 100644 --- a/tests/EduCoroutineSuspendNeverTest.expect +++ b/tests/EduCoroutineSuspendNeverTest.expect @@ -194,6 +194,7 @@ void __fun_intResume(__fun_intFrame * __f) case 0: break; case 1: goto __resume_fun_int_1; case 2: goto __resume_fun_int_2; + case 3: goto __resume_fun_int_3; } /* co_await EduCoroutineSuspendNeverTest.cpp:34 */ @@ -236,9 +237,11 @@ void __fun_intResume(__fun_intFrame * __f) __f->__suspend_34_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_34_14_1.await_ready()) { __f->__suspend_34_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_fun_int_3: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineTemplateGeneratorTest.expect b/tests/EduCoroutineTemplateGeneratorTest.expect index 4e4dd13..6ea5b48 100644 --- a/tests/EduCoroutineTemplateGeneratorTest.expect +++ b/tests/EduCoroutineTemplateGeneratorTest.expect @@ -189,6 +189,7 @@ void __fun_intResume(__fun_intFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_fun_int_1; + case 2: goto __resume_fun_int_2; } /* co_await EduCoroutineTemplateGeneratorTest.cpp:34 */ @@ -219,9 +220,11 @@ void __fun_intResume(__fun_intFrame * __f) __f->__suspend_34_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_34_14_1.await_ready()) { __f->__suspend_34_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_fun_int_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineVoidTest.expect b/tests/EduCoroutineVoidTest.expect index 5630358..f17f9a8 100644 --- a/tests/EduCoroutineVoidTest.expect +++ b/tests/EduCoroutineVoidTest.expect @@ -197,6 +197,7 @@ void __seq_intResume(__seq_intFrame * __f) case 0: break; case 1: goto __resume_seq_int_1; case 2: goto __resume_seq_int_2; + case 3: goto __resume_seq_int_3; } /* co_await EduCoroutineVoidTest.cpp:34 */ @@ -224,6 +225,8 @@ void __seq_intResume(__seq_intFrame * __f) __f->__suspend_36_5.await_resume(); } + /* co_return EduCoroutineVoidTest.cpp:34 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -239,9 +242,11 @@ void __seq_intResume(__seq_intFrame * __f) __f->__suspend_34_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_34_14_1.await_ready()) { __f->__suspend_34_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_seq_int_3: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineWithDtorTest.expect b/tests/EduCoroutineWithDtorTest.expect index bf51950..b8b4c8f 100644 --- a/tests/EduCoroutineWithDtorTest.expect +++ b/tests/EduCoroutineWithDtorTest.expect @@ -207,6 +207,7 @@ void __fun_TestResume(__fun_TestFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_fun_Test_1; + case 2: goto __resume_fun_Test_2; } /* co_await EduCoroutineWithDtorTest.cpp:43 */ @@ -237,9 +238,11 @@ void __fun_TestResume(__fun_TestFrame * __f) __f->__suspend_43_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_43_14_1.await_ready()) { __f->__suspend_43_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_fun_Test_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineWithExceptionHandlerTest.expect b/tests/EduCoroutineWithExceptionHandlerTest.expect index a3dd619..abab44c 100644 --- a/tests/EduCoroutineWithExceptionHandlerTest.expect +++ b/tests/EduCoroutineWithExceptionHandlerTest.expect @@ -205,6 +205,7 @@ void __fun_intResume(__fun_intFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_fun_int_1; + case 2: goto __resume_fun_int_2; } /* co_await EduCoroutineWithExceptionHandlerTest.cpp:41 */ @@ -235,9 +236,11 @@ void __fun_intResume(__fun_intFrame * __f) __f->__suspend_41_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_41_14_1.await_ready()) { __f->__suspend_41_14_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_fun_int_2: __f->destroy_fn(__f); } diff --git a/tests/EduCoroutineWithLambdaTest.cerr b/tests/EduCoroutineWithLambdaTest.cerr index 44b266d..9a14a09 100644 --- a/tests/EduCoroutineWithLambdaTest.cerr +++ b/tests/EduCoroutineWithLambdaTest.cerr @@ -4,8 +4,8 @@ .tmp.cpp:79:9: note: in instantiation of member function 'SyncAwait(std::suspend_always &&)::__lambda_45_24::operator()' requested here 79 | class __lambda_45_24 | ^ -.tmp.cpp:227:3: note: in instantiation of function template specialization 'SyncAwait' requested here - 227 | SyncAwait(std::suspend_always{}); +.tmp.cpp:232:3: note: in instantiation of function template specialization 'SyncAwait' requested here + 232 | SyncAwait(std::suspend_always{}); | ^ .tmp.cpp:76:25: note: 'a' declared here 76 | void SyncAwait(_AwrT && a) diff --git a/tests/EduCoroutineWithLambdaTest.expect b/tests/EduCoroutineWithLambdaTest.expect index 37b5888..d8a769e 100644 --- a/tests/EduCoroutineWithLambdaTest.expect +++ b/tests/EduCoroutineWithLambdaTest.expect @@ -150,6 +150,7 @@ inline generator operator()() const case 0: break; case 1: goto __resume_operator_45_43_1; case 2: goto __resume_operator_45_43_2; + case 3: goto __resume_operator_45_43_3; } /* co_await EduCoroutineWithLambdaTest.cpp:45 */ @@ -174,6 +175,8 @@ inline generator operator()() const __resume_operator_45_43_2: __f->__suspend_45_54.await_resume(); + /* co_return EduCoroutineWithLambdaTest.cpp:45 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -189,9 +192,11 @@ inline generator operator()() const __f->__suspend_45_24_1 = __f->__promise.final_suspend(); if(!__f->__suspend_45_24_1.await_ready()) { __f->__suspend_45_24_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_operator_45_43_3: __f->destroy_fn(__f); } diff --git a/tests/Issue518.expect b/tests/Issue518.expect index 1d218e6..6e8b474 100644 --- a/tests/Issue518.expect +++ b/tests/Issue518.expect @@ -285,6 +285,7 @@ void __get_randomResume(__get_randomFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_get_random_1; + case 2: goto __resume_get_random_2; } /* co_await Issue518.cpp:77 */ @@ -316,9 +317,11 @@ void __get_randomResume(__get_randomFrame * __f) __f->__suspend_77_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_77_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_77_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 2; return; } + __resume_get_random_2: __f->destroy_fn(__f); } @@ -390,6 +393,7 @@ void __testResume(__testFrame * __f) case 1: goto __resume_test_1; case 2: goto __resume_test_2; case 3: goto __resume_test_3; + case 4: goto __resume_test_4; } /* co_await Issue518.cpp:83 */ @@ -446,9 +450,11 @@ void __testResume(__testFrame * __f) __f->__suspend_83_11_1 = __f->__promise.final_suspend(); if(!__f->__suspend_83_11_1.await_ready()) { __builtin_coro_resume(__f->__suspend_83_11_1.await_suspend(std::coroutine_handle::promise_type>::from_address(static_cast(__f))).address()); + __f->__suspend_index = 4; return; } + __resume_test_4: __f->destroy_fn(__f); } diff --git a/tests/Issue526.expect b/tests/Issue526.expect index d740086..9d3ad37 100644 --- a/tests/Issue526.expect +++ b/tests/Issue526.expect @@ -71,6 +71,7 @@ static inline hello_world execute() case 0: break; case 1: goto __resume_execute_1; case 2: goto __resume_execute_2; + case 3: goto __resume_execute_3; } /* co_await Issue526.cpp:9 */ @@ -95,6 +96,8 @@ static inline hello_world execute() __resume_execute_2: __f->__suspend_9_51.await_resume(); + /* co_return Issue526.cpp:9 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -110,9 +113,11 @@ static inline hello_world execute() __f->__suspend_9_30_1 = __f->__promise.final_suspend(); if(!__f->__suspend_9_30_1.await_ready()) { __f->__suspend_9_30_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_execute_3: __f->destroy_fn(__f); } diff --git a/tests/Issue536.expect b/tests/Issue536.expect index 56dfc7f..6863767 100644 --- a/tests/Issue536.expect +++ b/tests/Issue536.expect @@ -129,6 +129,7 @@ void __coroResume(__coroFrame * __f) switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_coro_1; + case 2: goto __resume_coro_2; } /* co_await Issue536.cpp:37 */ @@ -144,6 +145,8 @@ void __coroResume(__coroFrame * __f) __f->__suspend_37_14.await_resume(); /* co_return Issue536.cpp:38 */ __f->__promise.return_void(); + /* co_return Issue536.cpp:37 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -159,9 +162,11 @@ void __coroResume(__coroFrame * __f) __f->__suspend_37_14_1 = __f->__promise.final_suspend(); if(!__f->__suspend_37_14_1.await_ready()) { __f->__suspend_37_14_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_coro_2: __f->destroy_fn(__f); } diff --git a/tests/Issue536_2.expect b/tests/Issue536_2.expect index 0f87eee..df76dbc 100644 --- a/tests/Issue536_2.expect +++ b/tests/Issue536_2.expect @@ -118,6 +118,7 @@ inline my_resumable coro(int x) const switch(__f->__suspend_index) { case 0: break; case 1: goto __resume_coro_1; + case 2: goto __resume_coro_2; } /* co_await Issue536_2.cpp:29 */ @@ -133,6 +134,8 @@ inline my_resumable coro(int x) const __f->__suspend_29_16.await_resume(); /* co_return Issue536_2.cpp:30 */ __f->__promise.return_void(); + /* co_return Issue536_2.cpp:29 */ + __f->__promise.return_void(); goto __final_suspend; } catch(...) { if(!__f->__initial_await_suspend_called) { @@ -148,9 +151,11 @@ inline my_resumable coro(int x) const __f->__suspend_29_16_1 = __f->__promise.final_suspend(); if(!__f->__suspend_29_16_1.await_ready()) { __f->__suspend_29_16_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 2; return; } + __resume_coro_2: __f->destroy_fn(__f); } diff --git a/tests/Issue628.expect b/tests/Issue628.expect index b56d0c7..63d9398 100644 --- a/tests/Issue628.expect +++ b/tests/Issue628.expect @@ -150,6 +150,7 @@ void __fooResume(__fooFrame * __f) case 0: break; case 1: goto __resume_foo_1; case 2: goto __resume_foo_2; + case 3: goto __resume_foo_3; } /* co_await Issue628.cpp:46 */ @@ -194,9 +195,11 @@ void __fooResume(__fooFrame * __f) __f->__suspend_46_6_1 = __f->__promise.final_suspend(); if(!__f->__suspend_46_6_1.await_ready()) { __f->__suspend_46_6_1.await_suspend(std::coroutine_handle::from_address(static_cast(__f)).operator std::coroutine_handle()); + __f->__suspend_index = 3; return; } + __resume_foo_3: __f->destroy_fn(__f); } diff --git a/tests/Issue679.cpp b/tests/Issue679.cpp new file mode 100644 index 0000000..ed0b1c9 --- /dev/null +++ b/tests/Issue679.cpp @@ -0,0 +1,81 @@ +// cmdline:-std=c++20 +// cmdlineinsights:-edu-show-coroutine-transformation + +#include +#include +#include +#include + +class Future; + +struct Promise +{ + using value_type = const char*; + const char* value{}; + + Promise() = default; + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() { std::rethrow_exception(std::current_exception()); } + + std::suspend_always yield_value(const char* value) { + this->value = std::move(value); + return {}; + } + + void return_void() { + this->value = nullptr; + } + + Future get_return_object(); +}; + +class Future +{ +public: + using promise_type = Promise; + + explicit Future(std::coroutine_handle handle) + : handle (handle) + {} + + ~Future() { + if (handle) { handle.destroy(); } + } + + Promise::value_type next() { + if (handle) { + handle.resume(); + return handle.promise().value; + } + else { + return {}; + } + } + +private: + std::coroutine_handle handle{}; +}; + +Future Promise::get_return_object() +{ + return Future{ std::coroutine_handle::from_promise(*this) }; +} + +Future Generator() +{ + co_yield "Hello "; + co_yield "world"; + co_yield "!"; +} + +int main() +{ + auto generator = Generator(); + while (const char* item = generator.next()) { + std::cout << item; + } + std::cout << std::endl; + + return 0; +}