Skip to content

Commit d547eda

Browse files
Merge pull request #734 from andreasfertig/fixIssue728
Fixed #728: Added missing `__coro_gro` declaration.
2 parents 924c6be + 8996701 commit d547eda

File tree

3 files changed

+210
-0
lines changed

3 files changed

+210
-0
lines changed

CoroutinesCodeGenerator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ void CoroutinesCodeGenerator::InsertCoroutine(const FunctionDecl& fd, const Coro
643643
mOutputFormatHelper.AppendNewLine();
644644
mOutputFormatHelper.AppendNewLine();
645645

646+
InsertArg(stmt->getResultDecl());
646647
InsertArg(stmt->getReturnStmt());
647648

648649
mOutputFormatHelper.AppendSemiNewLine();

tests/Issue728.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// cmdline:-std=c++20
2+
// cmdlineinsights:-edu-show-coroutine-transformation
3+
4+
#include <cstdio>
5+
#include <iostream>
6+
#include <coroutine>
7+
struct P {
8+
std::suspend_always initial_suspend()
9+
{
10+
return {};
11+
}
12+
void return_void() const noexcept
13+
{
14+
std::cout<<"return_void()\n";
15+
}
16+
std::coroutine_handle<> get_return_object()
17+
{
18+
return std::coroutine_handle<P>::from_promise(*this);
19+
};
20+
void unhandled_exception() { throw; }
21+
std::suspend_never final_suspend() noexcept
22+
{
23+
return {};
24+
}
25+
};
26+
struct R {
27+
R(
28+
std::coroutine_handle<> d) noexcept
29+
: data(d)
30+
{
31+
}
32+
std::coroutine_handle<> data;
33+
using promise_type = P;
34+
};
35+
R funcA(){
36+
co_await std::suspend_never{};
37+
}
38+
int main()
39+
{
40+
funcA().data.resume();
41+
return 0;
42+
}

tests/Issue728.expect

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*************************************************************************************
2+
* NOTE: The coroutine transformation you've enabled is a hand coded transformation! *
3+
* Most of it is _not_ present in the AST. What you see is an approximation. *
4+
*************************************************************************************/
5+
#include <cstdio>
6+
#include <iostream>
7+
#include <coroutine>
8+
struct P
9+
{
10+
inline std::suspend_always initial_suspend()
11+
{
12+
return {};
13+
}
14+
15+
inline void return_void() const noexcept
16+
{
17+
std::operator<<(std::cout, "return_void()\n");
18+
}
19+
20+
inline std::coroutine_handle<void> get_return_object()
21+
{
22+
return std::coroutine_handle<P>::from_promise(*this).operator std::coroutine_handle<void>();
23+
}
24+
25+
inline void unhandled_exception()
26+
{
27+
throw ;
28+
}
29+
30+
inline std::suspend_never final_suspend() noexcept
31+
{
32+
return {};
33+
}
34+
35+
// inline constexpr P() noexcept = default;
36+
};
37+
38+
39+
struct R
40+
{
41+
inline R(std::coroutine_handle<void> d) noexcept
42+
: data{std::coroutine_handle<void>(d)}
43+
{
44+
}
45+
46+
std::coroutine_handle<void> data;
47+
using promise_type = P;
48+
};
49+
50+
51+
struct __funcAFrame
52+
{
53+
void (*resume_fn)(__funcAFrame *);
54+
void (*destroy_fn)(__funcAFrame *);
55+
std::__coroutine_traits_sfinae<R>::promise_type __promise;
56+
int __suspend_index;
57+
bool __initial_await_suspend_called;
58+
std::suspend_always __suspend_35_3;
59+
std::suspend_never __suspend_36_12;
60+
std::suspend_never __suspend_35_3_1;
61+
};
62+
63+
R funcA()
64+
{
65+
/* Allocate the frame including the promise */
66+
/* Note: The actual parameter new is __builtin_coro_size */
67+
__funcAFrame * __f = reinterpret_cast<__funcAFrame *>(operator new(sizeof(__funcAFrame)));
68+
__f->__suspend_index = 0;
69+
__f->__initial_await_suspend_called = false;
70+
71+
/* Construct the promise. */
72+
new (&__f->__promise)std::__coroutine_traits_sfinae<R>::promise_type{};
73+
74+
/* Forward declare the resume and destroy function. */
75+
void __funcAResume(__funcAFrame * __f);
76+
void __funcADestroy(__funcAFrame * __f);
77+
78+
/* Assign the resume and destroy function pointers. */
79+
__f->resume_fn = &__funcAResume;
80+
__f->destroy_fn = &__funcADestroy;
81+
82+
/* Call the made up function with the coroutine body for initial suspend.
83+
This function will be called subsequently by coroutine_handle<>::resume()
84+
which calls __builtin_coro_resume(__handle_) */
85+
__funcAResume(__f);
86+
87+
88+
std::coroutine_handle<void> __coro_gro = __f->__promise.get_return_object();
89+
return R(std::coroutine_handle<void>(static_cast<std::coroutine_handle<void> &&>(__coro_gro)));
90+
}
91+
92+
/* This function invoked by coroutine_handle<>::resume() */
93+
void __funcAResume(__funcAFrame * __f)
94+
{
95+
try
96+
{
97+
/* Create a switch to get to the correct resume point */
98+
switch(__f->__suspend_index) {
99+
case 0: break;
100+
case 1: goto __resume_funcA_1;
101+
case 2: goto __resume_funcA_2;
102+
case 3: goto __resume_funcA_3;
103+
}
104+
105+
/* co_await Issue728.cpp:35 */
106+
__f->__suspend_35_3 = __f->__promise.initial_suspend();
107+
if(!__f->__suspend_35_3.await_ready()) {
108+
__f->__suspend_35_3.await_suspend(std::coroutine_handle<P>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
109+
__f->__suspend_index = 1;
110+
__f->__initial_await_suspend_called = true;
111+
return;
112+
}
113+
114+
__resume_funcA_1:
115+
__f->__suspend_35_3.await_resume();
116+
117+
/* co_await Issue728.cpp:36 */
118+
__f->__suspend_36_12 = std::suspend_never{};
119+
if(!__f->__suspend_36_12.await_ready()) {
120+
__f->__suspend_36_12.await_suspend(std::coroutine_handle<P>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
121+
__f->__suspend_index = 2;
122+
return;
123+
}
124+
125+
__resume_funcA_2:
126+
__f->__suspend_36_12.await_resume();
127+
/* co_return Issue728.cpp:35 */
128+
__f->__promise.return_void()/* implicit */;
129+
goto __final_suspend;
130+
} catch(...) {
131+
if(!__f->__initial_await_suspend_called) {
132+
throw ;
133+
}
134+
135+
__f->__promise.unhandled_exception();
136+
}
137+
138+
__final_suspend:
139+
140+
/* co_await Issue728.cpp:35 */
141+
__f->__suspend_35_3_1 = __f->__promise.final_suspend();
142+
if(!__f->__suspend_35_3_1.await_ready()) {
143+
__f->__suspend_35_3_1.await_suspend(std::coroutine_handle<P>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
144+
__f->__suspend_index = 3;
145+
return;
146+
}
147+
148+
__resume_funcA_3:
149+
__f->destroy_fn(__f);
150+
}
151+
152+
/* This function invoked by coroutine_handle<>::destroy() */
153+
void __funcADestroy(__funcAFrame * __f)
154+
{
155+
/* destroy all variables with dtors */
156+
__f->~__funcAFrame();
157+
/* Deallocating the coroutine frame */
158+
/* Note: The actual argument to delete is __builtin_coro_frame with the promise as parameter */
159+
operator delete(static_cast<void *>(__f), sizeof(__funcAFrame));
160+
}
161+
162+
163+
int main()
164+
{
165+
static_cast<const std::coroutine_handle<void> &&>(funcA().data).resume();
166+
return 0;
167+
}

0 commit comments

Comments
 (0)