Index: lib/CodeGen/CGCoroutine.cpp =================================================================== --- lib/CodeGen/CGCoroutine.cpp +++ lib/CodeGen/CGCoroutine.cpp @@ -338,8 +338,11 @@ EmitStmt(S.getPromiseDeclStmt()); CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB); + // FIXME: Emit param moves and gro initialization. - // FIXME: Emit initial suspend and more before the body. + + CurCoro.Data->CurrentAwaitKind = AwaitKind::Init; + EmitStmt(S.getInitSuspendStmt()); CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal; EmitStmt(S.getBody()); @@ -349,7 +352,8 @@ const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0; if (CanFallthrough || HasCoreturns) { EmitBlock(FinalBB); - // FIXME: Emit final suspend. + CurCoro.Data->CurrentAwaitKind = AwaitKind::Final; + EmitStmt(S.getFinalSuspendStmt()); } } Index: test/CodeGenCoroutines/coro-await.cpp =================================================================== --- test/CodeGenCoroutines/coro-await.cpp +++ test/CodeGenCoroutines/coro-await.cpp @@ -21,6 +21,17 @@ } } +struct init_susp { + bool await_ready(); + void await_suspend(std::experimental::coroutine_handle<>); + void await_resume(); +}; +struct final_susp { + bool await_ready(); + void await_suspend(std::experimental::coroutine_handle<>); + void await_resume(); +}; + struct suspend_always { int stuff; bool await_ready(); @@ -32,8 +43,8 @@ struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend(); + init_susp initial_suspend(); + final_susp final_suspend(); void return_void(); }; }; @@ -42,6 +53,13 @@ extern "C" void f0() { // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( + // See if initial_suspend was issued: + // ---------------------------------- + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv( + // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp* + // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save( + // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false) + co_await suspend_always{}; // See if we need to suspend: // -------------------------- @@ -60,6 +78,7 @@ // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}} // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]]) // ------------------------- + // Generate a suspend point: // ------------------------- // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false) @@ -76,6 +95,13 @@ // -------------------------- // CHECK: [[READY_BB]]: // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]]) + + // See if final_suspend was issued: + // ---------------------------------- + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv( + // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp* + // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save( + // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true) } struct suspend_maybe { @@ -91,8 +117,8 @@ struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend(); + init_susp initial_suspend(); + final_susp final_suspend(); void return_void(); suspend_maybe yield_value(int); }; @@ -228,3 +254,21 @@ // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* % // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret % } + +// CHECK-LABEL: EndlessLoop( +extern "C" void EndlessLoop() { + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( + + // See if initial_suspend was issued: + // ---------------------------------- + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv( + // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp* + + for (;;) + co_await suspend_always{}; + + // Verify that final_suspend was NOT issued: + // ---------------------------------- + // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv( + // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp* +} Index: test/CodeGenCoroutines/coro-cleanup.cpp =================================================================== --- test/CodeGenCoroutines/coro-cleanup.cpp +++ test/CodeGenCoroutines/coro-cleanup.cpp @@ -6,10 +6,10 @@ template struct coroutine_handle { coroutine_handle() = default; - static coroutine_handle from_address(void *) { return {}; } + static coroutine_handle from_address(void *) noexcept; }; template <> struct coroutine_handle { - static coroutine_handle from_address(void *) { return {}; } + static coroutine_handle from_address(void *) noexcept; coroutine_handle() = default; template coroutine_handle(coroutine_handle) {} @@ -17,16 +17,16 @@ } struct suspend_always { - bool await_ready(); - void await_suspend(std::experimental::coroutine_handle<>); - void await_resume(); + bool await_ready() noexcept; + void await_suspend(std::experimental::coroutine_handle<>) noexcept; + void await_resume() noexcept; }; template <> struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend(); + suspend_always initial_suspend() noexcept; + suspend_always final_suspend() noexcept; void return_void(); promise_type(); ~promise_type(); @@ -46,6 +46,11 @@ // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev( // CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]] + // CHECK: [[DeallocPad]]: + // CHECK-NEXT: landingpad + // CHECK-NEXT: cleanup + // CHECK: br label %[[Dealloc:.+]] + Cleanup cleanup; may_throw(); @@ -54,11 +59,6 @@ // CHECK: invoke void @_Z9may_throwv( // CHECK-NEXT: to label %{{.+}} unwind label %[[PromDtorPad:.+]] - // CHECK: [[DeallocPad]]: - // CHECK-NEXT: landingpad - // CHECK-NEXT: cleanup - // CHECK: br label %[[Dealloc:.+]] - // CHECK: [[PromDtorPad]]: // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup