Skip to content

Commit ca26dfe

Browse files
committed
Fixed #727: Consider throwing await_suspend.
1 parent 8a2454d commit ca26dfe

35 files changed

+956
-150
lines changed

CoroutinesCodeGenerator.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,9 +932,21 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt)
932932
StmtsContainer bodyStmts{};
933933
Expr* initializeInitialAwaitResume = nullptr;
934934

935-
auto addInitialAwaitSuspendCalled = [&] {
936-
bodyStmts.Add(bop);
935+
const bool canThrow{[&] {
936+
if(const auto* e = dyn_cast_or_null<ExprWithCleanups>(stmt->getSuspendExpr())) {
937+
if(const auto* ce = dyn_cast_or_null<CallExpr>(e->getSubExpr())) {
938+
if(const FunctionDecl* fd = ce->getDirectCallee()) {
939+
if(const FunctionProtoType* fpt = fd->getType()->getAs<FunctionProtoType>()) {
940+
return not fpt->isNothrow(/*ResultIfDependent=*/false);
941+
}
942+
}
943+
}
944+
}
945+
946+
return true;
947+
}()};
937948

949+
auto addInitialAwaitSuspendCalled = [&] {
938950
if(eState::InitialSuspend == mState) {
939951
mState = eState::Body;
940952
// https://timsong-cpp.github.io/cppwp/n4861/dcl.fct.def.coroutine#5.3
@@ -944,8 +956,24 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt)
944956
}
945957
};
946958

959+
auto insertTryCatchIfNecessary = [&](StmtsContainer& cont) {
960+
if(canThrow) {
961+
auto* tryBody = mkCompoundStmt(cont);
962+
963+
StmtsContainer catchBodyStmts{
964+
Assign(mASTData.mSuspendIndexAccess, mASTData.mSuspendIndexField, Int32(mSuspendsCount - 1)), Throw()};
965+
966+
cont.clear();
967+
cont.Add(Try(tryBody, Catch(catchBodyStmts)));
968+
}
969+
};
970+
947971
if(returnsVoid) {
972+
bodyStmts.Add(bop);
948973
bodyStmts.Add(stmt->getSuspendExpr());
974+
975+
insertTryCatchIfNecessary(bodyStmts);
976+
949977
addInitialAwaitSuspendCalled();
950978
bodyStmts.Add(Return());
951979

@@ -957,7 +985,10 @@ void CoroutinesCodeGenerator::InsertArg(const CoroutineSuspendExpr* stmt)
957985

958986
auto* ifSuspend = If(stmt->getSuspendExpr(), bodyStmts);
959987

960-
InsertArg(If(Not(stmt->getReadyExpr()), ifSuspend));
988+
StmtsContainer innerBodyStmts{bop, ifSuspend};
989+
insertTryCatchIfNecessary(innerBodyStmts);
990+
991+
InsertArg(If(Not(stmt->getReadyExpr()), innerBodyStmts));
961992
}
962993

963994
if(not returnsVoid and initializeInitialAwaitResume) {

tests/EduCoroutineAllocFailureTest.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ void __fun_intResume(__fun_intFrame * __f)
210210
/* co_await EduCoroutineAllocFailureTest.cpp:40 */
211211
__f->__suspend_40_14 = __f->__promise.initial_suspend();
212212
if(!__f->__suspend_40_14.await_ready()) {
213-
__f->__suspend_40_14.await_suspend(std::coroutine_handle<generator<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
214213
__f->__suspend_index = 1;
214+
__f->__suspend_40_14.await_suspend(std::coroutine_handle<generator<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
215215
__f->__initial_await_suspend_called = true;
216216
return;
217217
}
@@ -234,8 +234,8 @@ void __fun_intResume(__fun_intFrame * __f)
234234
/* co_await EduCoroutineAllocFailureTest.cpp:40 */
235235
__f->__suspend_40_14_1 = __f->__promise.final_suspend();
236236
if(!__f->__suspend_40_14_1.await_ready()) {
237-
__f->__suspend_40_14_1.await_suspend(std::coroutine_handle<generator<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
238237
__f->__suspend_index = 2;
238+
__f->__suspend_40_14_1.await_suspend(std::coroutine_handle<generator<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
239239
return;
240240
}
241241

tests/EduCoroutineBinaryExprTest.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ void __seqResume(__seqFrame * __f)
146146
/* co_await EduCoroutineBinaryExprTest.cpp:35 */
147147
__f->__suspend_35_11 = __f->__promise.initial_suspend();
148148
if(!__f->__suspend_35_11.await_ready()) {
149-
__f->__suspend_35_11.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
150149
__f->__suspend_index = 1;
150+
__f->__suspend_35_11.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
151151
__f->__initial_await_suspend_called = true;
152152
return;
153153
}
@@ -160,8 +160,8 @@ void __seqResume(__seqFrame * __f)
160160
/* co_yield EduCoroutineBinaryExprTest.cpp:42 */
161161
__f->__suspend_42_5 = __f->__promise.yield_value(__f->s.t);
162162
if(!__f->__suspend_42_5.await_ready()) {
163-
__f->__suspend_42_5.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
164163
__f->__suspend_index = 2;
164+
__f->__suspend_42_5.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
165165
return;
166166
}
167167

@@ -171,8 +171,8 @@ void __seqResume(__seqFrame * __f)
171171
/* co_yield EduCoroutineBinaryExprTest.cpp:43 */
172172
__f->__suspend_43_12 = __f->__promise.yield_value(__f->i);
173173
if(!__f->__suspend_43_12.await_ready()) {
174-
__f->__suspend_43_12.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
175174
__f->__suspend_index = 3;
175+
__f->__suspend_43_12.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
176176
return;
177177
}
178178

@@ -182,8 +182,8 @@ void __seqResume(__seqFrame * __f)
182182
/* co_yield EduCoroutineBinaryExprTest.cpp:44 */
183183
__f->__suspend_44_23 = __f->__promise.yield_value(__f->i);
184184
if(!__f->__suspend_44_23.await_ready()) {
185-
__f->__suspend_44_23.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
186185
__f->__suspend_index = 4;
186+
__f->__suspend_44_23.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
187187
return;
188188
}
189189

@@ -193,8 +193,8 @@ void __seqResume(__seqFrame * __f)
193193
/* co_yield EduCoroutineBinaryExprTest.cpp:45 */
194194
__f->__suspend_45_5 = __f->__promise.yield_value(__f->i + 1);
195195
if(!__f->__suspend_45_5.await_ready()) {
196-
__f->__suspend_45_5.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
197196
__f->__suspend_index = 5;
197+
__f->__suspend_45_5.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
198198
return;
199199
}
200200

@@ -216,8 +216,8 @@ void __seqResume(__seqFrame * __f)
216216
/* co_await EduCoroutineBinaryExprTest.cpp:35 */
217217
__f->__suspend_35_11_1 = __f->__promise.final_suspend();
218218
if(!__f->__suspend_35_11_1.await_ready()) {
219-
__f->__suspend_35_11_1.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
220219
__f->__suspend_index = 6;
220+
__f->__suspend_35_11_1.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
221221
return;
222222
}
223223

tests/EduCoroutineCaptureConstTest.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ void __seqResume(__seqFrame * __f)
137137
/* co_await EduCoroutineCaptureConstTest.cpp:35 */
138138
__f->__suspend_35_11 = __f->__promise.initial_suspend();
139139
if(!__f->__suspend_35_11.await_ready()) {
140-
__f->__suspend_35_11.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
141140
__f->__suspend_index = 1;
141+
__f->__suspend_35_11.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
142142
__f->__initial_await_suspend_called = true;
143143
return;
144144
}
@@ -162,8 +162,8 @@ void __seqResume(__seqFrame * __f)
162162
/* co_await EduCoroutineCaptureConstTest.cpp:35 */
163163
__f->__suspend_35_11_1 = __f->__promise.final_suspend();
164164
if(!__f->__suspend_35_11_1.await_ready()) {
165-
__f->__suspend_35_11_1.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
166165
__f->__suspend_index = 2;
166+
__f->__suspend_35_11_1.await_suspend(std::coroutine_handle<generator::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
167167
return;
168168
}
169169

tests/EduCoroutineCaptureThisTest.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ inline my_resumable coro(int x)
125125
/* co_await EduCoroutineCaptureThisTest.cpp:31 */
126126
__f->__suspend_31_16 = __f->__promise.initial_suspend();
127127
if(!__f->__suspend_31_16.await_ready()) {
128-
__f->__suspend_31_16.await_suspend(std::coroutine_handle<my_resumable::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
129128
__f->__suspend_index = 1;
129+
__f->__suspend_31_16.await_suspend(std::coroutine_handle<my_resumable::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
130130
__f->__initial_await_suspend_called = true;
131131
return;
132132
}
@@ -150,8 +150,8 @@ inline my_resumable coro(int x)
150150
/* co_await EduCoroutineCaptureThisTest.cpp:31 */
151151
__f->__suspend_31_16_1 = __f->__promise.final_suspend();
152152
if(!__f->__suspend_31_16_1.await_ready()) {
153-
__f->__suspend_31_16_1.await_suspend(std::coroutine_handle<my_resumable::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
154153
__f->__suspend_index = 2;
154+
__f->__suspend_31_16_1.await_suspend(std::coroutine_handle<my_resumable::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
155155
return;
156156
}
157157

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.tmp.cpp:167:3: error: unknown type name 'awaiter'
22
167 | awaiter __suspend_54_5;
33
| ^
4-
.tmp.cpp:250:10: warning: expression result unused [-Wunused-value]
5-
250 | __f->__suspend_56_14_res;
4+
.tmp.cpp:262:10: warning: expression result unused [-Wunused-value]
5+
262 | __f->__suspend_56_14_res;
66
| ~~~ ^~~~~~~~~~~~~~~~~~~
77
1 warning and 1 error generated.

tests/EduCoroutineCoAwaitOperatorTest.expect

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ void __gResume(__gFrame * __f)
215215
/* co_await EduCoroutineCoAwaitOperatorTest.cpp:51 */
216216
__f->__suspend_51_16 = __f->__promise.initial_suspend();
217217
if(!__f->__suspend_51_16.await_ready()) {
218-
__f->__suspend_51_16.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
219218
__f->__suspend_index = 1;
219+
__f->__suspend_51_16.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
220220
__f->__initial_await_suspend_called = true;
221221
return;
222222
}
@@ -228,8 +228,14 @@ void __gResume(__gFrame * __f)
228228
/* co_await EduCoroutineCoAwaitOperatorTest.cpp:54 */
229229
__f->__suspend_54_5 = operator co_await(std::operator""ms(10ULL));
230230
if(!__f->__suspend_54_5.await_ready()) {
231-
__f->__suspend_54_5.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
232-
__f->__suspend_index = 2;
231+
try
232+
{
233+
__f->__suspend_index = 2;
234+
__f->__suspend_54_5.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
235+
} catch(...) {
236+
__f->__suspend_index = 1;
237+
throw ;
238+
}
233239
return;
234240
}
235241

@@ -240,8 +246,14 @@ void __gResume(__gFrame * __f)
240246
/* co_await EduCoroutineCoAwaitOperatorTest.cpp:56 */
241247
__f->__suspend_56_14 = h();
242248
if(!__f->__suspend_56_14.await_ready()) {
243-
__f->__suspend_56_14.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
244-
__f->__suspend_index = 3;
249+
try
250+
{
251+
__f->__suspend_index = 3;
252+
__f->__suspend_56_14.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
253+
} catch(...) {
254+
__f->__suspend_index = 2;
255+
throw ;
256+
}
245257
return;
246258
}
247259

@@ -264,8 +276,8 @@ void __gResume(__gFrame * __f)
264276
/* co_await EduCoroutineCoAwaitOperatorTest.cpp:51 */
265277
__f->__suspend_51_16_1 = __f->__promise.final_suspend();
266278
if(!__f->__suspend_51_16_1.await_ready()) {
267-
__f->__suspend_51_16_1.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
268279
__f->__suspend_index = 4;
280+
__f->__suspend_51_16_1.await_suspend(std::coroutine_handle<my_future<int>::promise_type>::from_address(static_cast<void *>(__f)).operator std::coroutine_handle<void>());
269281
return;
270282
}
271283

tests/EduCoroutineCoreturnWithCoawaitTest.cerr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,38 @@
44
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
55
69 | inline generator(generator && rhs)
66
| ^
7-
.tmp.cpp:289:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
8-
289 | __f->__suspend_56_51 = simpleReturn(__f->v + 1);
7+
.tmp.cpp:295:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
8+
295 | __f->__suspend_56_51 = simpleReturn(__f->v + 1);
99
| ^
1010
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
1111
69 | inline generator(generator && rhs)
1212
| ^
13-
.tmp.cpp:414:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
14-
414 | __f->__suspend_60_24 = simpleReturn(__f->v);
13+
.tmp.cpp:426:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
14+
426 | __f->__suspend_60_24 = simpleReturn(__f->v);
1515
| ^
1616
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
1717
69 | inline generator(generator && rhs)
1818
| ^
19-
.tmp.cpp:425:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
20-
425 | __f->__suspend_60_51 = simpleReturn(__f->v + 1);
19+
.tmp.cpp:443:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
20+
443 | __f->__suspend_60_51 = simpleReturn(__f->v + 1);
2121
| ^
2222
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
2323
69 | inline generator(generator && rhs)
2424
| ^
25-
.tmp.cpp:436:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
26-
436 | __f->__suspend_60_80 = simpleReturn(__f->v + 2);
25+
.tmp.cpp:460:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
26+
460 | __f->__suspend_60_80 = simpleReturn(__f->v + 2);
2727
| ^
2828
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
2929
69 | inline generator(generator && rhs)
3030
| ^
31-
.tmp.cpp:558:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
32-
558 | __f->__suspend_67_24 = simpleReturn(__f->v);
31+
.tmp.cpp:588:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
32+
588 | __f->__suspend_67_24 = simpleReturn(__f->v);
3333
| ^
3434
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
3535
69 | inline generator(generator && rhs)
3636
| ^
37-
.tmp.cpp:569:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
38-
569 | __f->__suspend_67_51 = simpleReturn(__f->v + 1);
37+
.tmp.cpp:605:26: error: object of type 'generator' cannot be assigned because its copy assignment operator is implicitly deleted
38+
605 | __f->__suspend_67_51 = simpleReturn(__f->v + 1);
3939
| ^
4040
.tmp.cpp:69:10: note: copy assignment operator is implicitly deleted because 'generator' has a user-declared move constructor
4141
69 | inline generator(generator && rhs)

0 commit comments

Comments
 (0)