You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The generated result with "Show coroutine transformation" enabled:
/************************************************************************************* * NOTE: The coroutine transformation you've enabled is a hand coded transformation! * * Most of it is _not_ present in the AST. What you see is an approximation. * *************************************************************************************/
#include<coroutine>
#include<iostream>
#include<cassert>
#include<exception>classFuture;
structPromise
{
using value_type = constchar *;
constchar * value;
inlineconstexprPromise() noexcept = default;
inline std::suspend_always initial_suspend()
{
return {};
}
inline std::suspend_always final_suspend() noexcept
{
return {};
}
inlinevoidunhandled_exception()
{
std::rethrow_exception(std::current_exception());
}
inline std::suspend_always yield_value(constchar * value)
{
this->value = std::move(value);
return {};
}
inlinevoidreturn_void()
{
this->value = nullptr;
}
Future get_return_object();
};
classFuture
{
public:using promise_type = Promise;
inlineexplicitFuture(std::coroutine_handle<Promise> handle)
: handle{std::coroutine_handle<Promise>(handle)}
{
}
inline~Future() noexcept
{
if(this->handle.operatorbool()) {
this->handle.destroy();
}
}
inline Promise::value_type next()
{
if(this->handle.operatorbool()) {
this->handle.resume();
returnthis->handle.promise().value;
} else {
return {};
}
}
private:
std::coroutine_handle<Promise> handle;
public:
};
Future Promise::get_return_object()
{
return Future{std::coroutine_handle<Promise>::from_promise(*this)};
}
struct__GeneratorFrame
{
void (*resume_fn)(__GeneratorFrame *);
void (*destroy_fn)(__GeneratorFrame *);
std::__coroutine_traits_impl<Future>::promise_type __promise;
int __suspend_index;
bool __initial_await_suspend_called;
std::suspend_always __suspend_62_8;
std::suspend_always __suspend_64_5;
std::suspend_always __suspend_65_5;
std::suspend_always __suspend_66_5;
std::suspend_always __suspend_62_8_1;
};
Future Generator()
{
/* Allocate the frame including the promise *//* Note: The actual parameter new is __builtin_coro_size */
__GeneratorFrame * __f = reinterpret_cast<__GeneratorFrame *>(operatornew(sizeof(__GeneratorFrame)));
__f->__suspend_index = 0;
__f->__initial_await_suspend_called = false;
/* Construct the promise. */new (&__f->__promise)std::__coroutine_traits_impl<Future>::promise_type{};
/* Forward declare the resume and destroy function. */void__GeneratorResume(__GeneratorFrame * __f);
void__GeneratorDestroy(__GeneratorFrame * __f);
/* Assign the resume and destroy function pointers. */
__f->resume_fn = &__GeneratorResume;
__f->destroy_fn = &__GeneratorDestroy;
/* Call the made up function with the coroutine body for initial suspend. This function will be called subsequently by coroutine_handle<>::resume() which calls __builtin_coro_resume(__handle_) */__GeneratorResume(__f);
return __f->__promise.get_return_object();
}
/* This function invoked by coroutine_handle<>::resume() */void__GeneratorResume(__GeneratorFrame * __f)
{
try
{
/* Create a switch to get to the correct resume point */switch(__f->__suspend_index) {
case0: break;
case1: goto __resume_Generator_1;
case2: goto __resume_Generator_2;
case3: goto __resume_Generator_3;
case4: goto __resume_Generator_4;
}
/* co_await insights.cpp:62 */
__f->__suspend_62_8 = __f->__promise.initial_suspend();
if(!__f->__suspend_62_8.await_ready()) {
__f->__suspend_62_8.await_suspend(std::coroutine_handle<Promise>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
__f->__suspend_index = 1;
__f->__initial_await_suspend_called = true;
return;
}
__resume_Generator_1:
__f->__suspend_62_8.await_resume();
/* co_yield insights.cpp:64 */
__f->__suspend_64_5 = __f->__promise.yield_value("Hello ");
if(!__f->__suspend_64_5.await_ready()) {
__f->__suspend_64_5.await_suspend(std::coroutine_handle<Promise>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
__f->__suspend_index = 2;
return;
}
__resume_Generator_2:
__f->__suspend_64_5.await_resume();
/* co_yield insights.cpp:65 */
__f->__suspend_65_5 = __f->__promise.yield_value("world");
if(!__f->__suspend_65_5.await_ready()) {
__f->__suspend_65_5.await_suspend(std::coroutine_handle<Promise>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
__f->__suspend_index = 3;
return;
}
__resume_Generator_3:
__f->__suspend_65_5.await_resume();
/* co_yield insights.cpp:66 */
__f->__suspend_66_5 = __f->__promise.yield_value("!");
if(!__f->__suspend_66_5.await_ready()) {
__f->__suspend_66_5.await_suspend(std::coroutine_handle<Promise>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
__f->__suspend_index = 4;
return;
}
__resume_Generator_4:
__f->__suspend_66_5.await_resume();
goto __final_suspend;
} catch(...) {
if(!__f->__initial_await_suspend_called) {
throw ;
}
__f->__promise.unhandled_exception();
}
__final_suspend:
/* co_await insights.cpp:62 */
__f->__suspend_62_8_1 = __f->__promise.final_suspend();
if(!__f->__suspend_62_8_1.await_ready()) {
__f->__suspend_62_8_1.await_suspend(std::coroutine_handle<Promise>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
return;
}
__f->destroy_fn(__f);
}
/* This function invoked by coroutine_handle<>::destroy() */void__GeneratorDestroy(__GeneratorFrame * __f)
{
/* destroy all variables with dtors */
__f->~__GeneratorFrame();
/* Deallocating the coroutine frame *//* Note: The actual argument to delete is __builtin_coro_frame with the promise as parameter */operatordelete(static_cast<void *>(__f));
}
intmain()
{
Future generator = Generator();
while(item) {
std::operator<<(std::cout, item);
}
std::cout.operator<<(std::endl);
return0;
}
Compiling this with
g++ -std=c++20 test.cpp
gives an error
test3.cpp: In function ‘int main()’:
test3.cpp:229:9: error: ‘item’ was not declared in this scope; did you mean ‘tm’?
229 | while(item) {
| ^~~~
| tm
but this incorrect handling of variable declaration in while loop parantheses doesn't seem to be related to the coroutines, so i created a separate issue with a more minimal example to reproduce this problem: #678
For now, i just manually replaced while(item) with the correct version while(const char *item = next()).
Then after compiling, instead of printing:
Hello world!
to the console, the generated program prints "Hello world!", but then it is stuck in an infinite loop printing the last result of co_yield (which is "!")
so the output is like this
Hello world!!!!!!!!!!!!!!!!!!!!!!!!!...
and continues to print "!" infinitely.
By comparing the generated assembly output of g++ with the cppinsights output, i have come up with the necessary changes to the program.
The expected behavior would be to generate a correct program that behaves similar to the program with the applied diff from above, i.e. it prints "Hello world!" and exits.
The text was updated successfully, but these errors were encountered:
I tried to transform the following simple program, which uses C++20 coroutines:
https://github.com/feabhas/coroutines-blog/blob/main/src/char_demo.cpp
Code:
The generated result with "Show coroutine transformation" enabled:
Compiling this with
gives an error
but this incorrect handling of variable declaration in while loop parantheses doesn't seem to be related to the coroutines, so i created a separate issue with a more minimal example to reproduce this problem: #678
For now, i just manually replaced
while(item)
with the correct versionwhile(const char *item = next())
.Then after compiling, instead of printing:
to the console, the generated program prints "Hello world!", but then it is stuck in an infinite loop printing the last result of co_yield (which is "!")
so the output is like this
and continues to print "!" infinitely.
By comparing the generated assembly output of g++ with the cppinsights output, i have come up with the necessary changes to the program.
The expected behavior would be to generate a correct program that behaves similar to the program with the applied diff from above, i.e. it prints "Hello world!" and exits.
The text was updated successfully, but these errors were encountered: