I am writing a C++ coroutine for a UWP control using C++/WinRT:
winrt::fire_and_forget MyControl::DoSomething()
{
if (/* some condition */)
{
// Why does this work?!
return;
}
co_await winrt::resume_foreground(Dispatcher());
// Do some stuff
co_return;
}
This is compiling for me, but as far as I know, C++ coroutines do not allow plain return
statements. Is this a bug in the compiler?
(Interestingly, I cannot change the co_return
to return
; I get a compiler error. Is it that only return statements after a co_await
or co_yield
must be co_return
?)
Disclaimer: I work for Microsoft.
This seems to be a legacy implementation for MSVSC. MSVSC implemented coroutines before the standard was formally complete, so there are two implementations of async (/async
and /async:strict
). I seem to have the old, non–standard-compliant version turned on.
The standard is clear that you cannot use plain return
statements in coroutines (emphasis added):
Coroutines cannot use variadic arguments, plain return statements, or placeholder return types (auto or Concept). Constexpr functions, constructors, destructors, and the main function cannot be coroutines.
— https://en.cppreference.com/w/cpp/language/coroutines
You can verify that this is a legacy behavior with a simple example (view in Godbolt):
// ... boilerplate to make std::futures awaitable ...
// via https://stackoverflow.com/a/70406948/788168
std::future<int> compute_value()
{
if (rand() > 5)
{
// Shouldn't work:
return 5;
}
int result = co_await std::async([] { return 30; });
co_return result;
}
int main() {
compute_value();
}
With the x64 msvc v19.latest
compiler and the /std:c++20
flag, we get this error:
example.cpp
<source>(38): error C3773: Use of 'return' in this context is a non-conforming extension in C++20
<source>(38): note: Please use '/await' command-line option to enable relevant extensions
Compiler returned: 2
So, to answer the questions:
This is compiling for me, but as far as I know, C++ coroutines do not allow plain
return
statements. Is this a bug in the compiler?(Interestingly, I cannot change the
co_return
toreturn
; I get a compiler error. Is it that only return statements after aco_await
orco_yield
must beco_return
?)
It's not a bug in the compiler, it's just a non-standard implementation. If you use the standard implementation (with /async:strict
or /std:c++20
), that plain return
statement will not compile. Standards-compliant coroutines cannot use plain return statements, ever.