{"id":26524,"date":"2020-09-14T16:30:26","date_gmt":"2020-09-14T16:30:26","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=26524"},"modified":"2020-09-14T18:15:30","modified_gmt":"2020-09-14T18:15:30","slug":"c-coroutines-in-visual-studio-2019-version-16-8","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/c-coroutines-in-visual-studio-2019-version-16-8\/","title":{"rendered":"C++ Coroutines in Visual Studio 2019 Version 16.8"},"content":{"rendered":"<p><em>Please see our <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/a-multitude-of-updates-in-visual-studio-2019-version-16-8-preview-3\/\">Visual Studio 2019 version 16.8 Preview 3 release notes<\/a> for more of our latest features.<\/em><\/p>\n<p>It&#8217;s been a long journey for coroutines in C++ and in MSVC. We announced an <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/asynchronous-programming-in-c-using-resumable-functions-and-await\/\">early preview<\/a> of resumable functions in 2013, followed up by the <code>\/await<\/code> switch and <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/resumable-functions-in-c\">initial C++ standardization proposals<\/a> in 2014, to <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/coroutines-in-visual-studio-2015-update-1\/\">proposal revisions<\/a> in 2015, and have continued tracking the Coroutines TS (Technical Specification) progress through Visual Studio 2017 and 2019. With the adoption of coroutines into the C++ standard in 2019, we are now pleased to announce feature completion of C++20 coroutines in Visual Studio 2019 version 16.8.<\/p>\n<h3>Standard vs. TS Coroutines<\/h3>\n<p>The coroutine support that ultimately made it through the standardization process and became part of C++20 is different from the early proposal drafts and from experimental coroutine support we&#8217;ve had in MSVC under the <code>\/await<\/code> switch. This led us to two important and contradictory goals in finishing the coroutine language support in 16.8:<\/p>\n<ol>\n<li>Provide an implementation of C++20 coroutines that strictly follows the standard, allowing users to write and consume portable code.<\/li>\n<li>Ensure existing users of experimental coroutines can painlessly upgrade to 16.8 without needing to change their code.<\/li>\n<\/ol>\n<p>As the proposal changed, we&#8217;ve added new support whenever possible without breaking existing code for early adopters of coroutines. This is of course not standard: It still accepts all the old keywords, names, and signatures, counter to goal 1. There are also a small number of behavior changes from the original versions we implemented under <code>\/await<\/code>, such as how a promise object is constructed. These could cause a program that previously compiled to fail to compile or behave differently at runtime.<\/p>\n<h4>Standard Mode &#8211; \/std:c++latest<\/h4>\n<p>Support for C++20 coroutines without legacy TS support is now enabled when using a compiler language version mode newer than C++17. For now, this is <code>\/std:c++latest<\/code> and will continue into numbered version switches after C++17 as these are added. When compiling with such a language switch and without <code>\/await<\/code> you get strict support for C++20 coroutines with library support in the <code>&lt;coroutine&gt;<\/code> header and defined in the <code>std<\/code> namespace. This mode will emit errors on non-standard code from earlier proposals, such as a bare <code>await<\/code> keywords or an <code>initial_suspend<\/code> function that returns <code>bool<\/code>, and only supports the standard behaviors when they differ from earlier implementations.<\/p>\n<h4>Extension Mode &#8211; \/await<\/h4>\n<p>Early adopters of coroutines can continue to compile their non-standard code with the <code>\/await<\/code> switch and any of the language version switches (including <code>\/std:c++latest<\/code>), and continue to use the experimental headers and namespace. We have added missing standard features and bug fixes in this mode as long as they don&#8217;t break compatibility.<\/p>\n<p>We recommend existing coroutine users move to standard coroutines as soon as possible, and new users should favor the standard mode over <code>\/await<\/code>.\u00a0 Support for the <code>\/await<\/code> switch will continue for existing users, but the future of coroutines is in the standard mode and new features will be implemented there. Excepting some corner cases migrating a project from <code>\/await<\/code> to C++20 is a straightforward process.<\/p>\n<h3>What&#8217;s New in 16.8<\/h3>\n<p>Version 16.8 introduces several new features and improvements in coroutines:<\/p>\n<ul>\n<li>Symmetric transfer<\/li>\n<li>No-op coroutines<\/li>\n<li>Coroutine promise constructor parameters<\/li>\n<li>Well-defined behavior for exceptions leaving a coroutine body<\/li>\n<li>Standard return object conversion behavior<\/li>\n<li>Improved debugging experience<\/li>\n<li>Common frame layout for improved compatibility with other vendors<\/li>\n<li>Numerous bug fixes<\/li>\n<\/ul>\n<p>Most of these changes are available only when building in standard mode, although no-op coroutines and most bug fixes have also been implemented under <code>\/await<\/code>. In the rest of this post we&#8217;ll take a closer look at some of these items and what&#8217;s next for coroutines in Visual Studio.<\/p>\n<h3>Symmetric transfer and no-op coroutines<\/h3>\n<p>These were the last two big missing pieces for C++20 coroutine support. With symmetric transfer a coroutine can indicate a coroutine handle for another coroutine to immediately resume when suspending. This is done by defining the <code>await_suspend<\/code> function of the coroutine promise with a return type of <code>coroutine_handle&lt;T&gt;<\/code>:<\/p>\n<pre style=\"padding-left: 40px;\">struct some_awaitable {\r\n  ...\r\n  std::coroutine_handle&lt;&gt; await_suspend(std::coroutine_handle&lt;promise_type&gt; h) noexcept {\r\n    \/\/ If the coroutine that is about to suspend (indicated by h) has a continuation\r\n    \/\/ coroutine handle, resume that coroutine instead of returning to the caller.\r\n    \/\/ Otherwise, return a no-op coroutine. The no-op coroutine does nothing, and will\r\n    \/\/ allow control to return to the caller.\r\n    return h.promise().continuation ? *continuation : std::noop_coroutine();\r\n  }\r\n};<\/pre>\n<p>In standard mode this suspend-and-resume operation works without introducing another frame onto the call stack. This allows an unlimited number of transfers between coroutines without risking a stack overflow.<\/p>\n<h3>Improved debugging experience<\/h3>\n<p>Version 16.8 introduces several new debugging features for working with coroutines. Some issues with stepping into and within coroutines have been fixed, especially with Just My Code. It&#8217;s also now possible to expand the frame pointer while within a coroutine. This exposes data like coroutine parameter values and members of the promise type (standard coroutines only). We&#8217;ve also changed the names of many compiler-generated symbols to work better with the debugger&#8217;s expression evaluation. These are now easier to use in an immediate or watch window, or as a conditional breakpoint.<\/p>\n<p><img decoding=\"async\" width=\"1128\" height=\"968\" class=\"wp-image-26525\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2020\/09\/conditional-breakpoints-and-frame-layout.png\" alt=\"Conditional breakpoints and frame layout \" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2020\/09\/conditional-breakpoints-and-frame-layout.png 1128w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2020\/09\/conditional-breakpoints-and-frame-layout-300x257.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2020\/09\/conditional-breakpoints-and-frame-layout-1024x879.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2020\/09\/conditional-breakpoints-and-frame-layout-768x659.png 768w\" sizes=\"(max-width: 1128px) 100vw, 1128px\" \/><\/p>\n<h3>Common frame layout<\/h3>\n<p>There is a new internal representation of a coroutine frame in standard C++20 mode. This exposes the parts of the frame that are important for working with a coroutine, such as how to resume or destroy it, in a way common across vendors. Coroutines produced in an object file or library produced by one vendor can then potentially be used by another. This doesn&#8217;t mean that the full frame layout is common across vendors or even guaranteed to be stable across compiler versions, but it does standardize (although unofficially) the interface between the standard library type <code>std::coroutine_handle<\/code> and the underlying coroutine frame object, and should help improve compatibility and flexibility when exposing or consuming a coroutine from a library. We&#8217;ve also introduced support for the same builtin functions used by Clang, allowing for better header-level compatibility.<\/p>\n<p>The level of coroutine support among different vendors currently varies, but is improving. As C++20 support rolls out widely across compilers we expect this to become more useful and important. We&#8217;re committed to providing a common, stable ABI for coroutines to make interfacing between different builds as seamless as possible.<\/p>\n<h3>What&#8217;s Next?<\/h3>\n<p>Coroutines in C++20 are a bit limited. The core language feature has been adopted, but there is no real coroutine support in the standard library. The good news is we expect to change relatively soon, with more extensive library support for coroutines in the next C++ language version.<\/p>\n<p>Our next steps for C++20 coroutines are in continued improvement of the debugging experience. One aspect of this is more natural stepping behavior, making it easier to trace through a coroutine execution as if it was a normal, synchronous function. We&#8217;re also looking at improved visualization of coroutine handles to easily see the state of a suspended coroutine.<\/p>\n<p>As always, feedback on this feature is welcome, and bug reports can be made on <a href=\"https:\/\/developercommunity.visualstudio.com\">Developer Community<\/a>. Happy co_awaiting!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Please see our Visual Studio 2019 version 16.8 Preview 3 release notes for more of our latest features. It&#8217;s been a long journey for coroutines in C++ and in MSVC. We announced an early preview of resumable functions in 2013, followed up by the \/await switch and initial C++ standardization proposals in 2014, to proposal [&hellip;]<\/p>\n","protected":false},"author":39398,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[270,1],"tags":[],"class_list":["post-26524","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcement","category-cplusplus"],"acf":[],"blog_post_summary":"<p>Please see our Visual Studio 2019 version 16.8 Preview 3 release notes for more of our latest features. It&#8217;s been a long journey for coroutines in C++ and in MSVC. We announced an early preview of resumable functions in 2013, followed up by the \/await switch and initial C++ standardization proposals in 2014, to proposal [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/26524","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/39398"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=26524"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/26524\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=26524"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=26524"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=26524"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}