Skip to content

Commit d35544d

Browse files
Surface error for plain return statement in coroutine earlier
1 parent 7088a5e commit d35544d

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
11201120

11211121
// [stmt.return.coroutine]p1:
11221122
// A coroutine shall not enclose a return statement ([stmt.return]).
1123-
if (Fn->FirstReturnLoc.isValid()) {
1123+
if (Fn->FirstReturnLoc.isValid() && Fn->FirstReturnLoc < Fn->FirstCoroutineStmtLoc) {
11241124
assert(Fn->FirstCoroutineStmtLoc.isValid() &&
11251125
"first coroutine location not set");
11261126
Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);

clang/lib/Sema/SemaStmt.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3747,6 +3747,16 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
37473747
Diag(ReturnLoc, diag::err_acc_branch_in_out_compute_construct)
37483748
<< /*return*/ 1 << /*out of */ 0);
37493749

3750+
// using plain return in a coroutine is not allowed.
3751+
FunctionScopeInfo *FSI = getCurFunction();
3752+
if (getLangOpts().Coroutines && FSI->isCoroutine()) {
3753+
assert(FSI->FirstCoroutineStmtLoc.isValid() &&
3754+
"first coroutine location not set");
3755+
Diag(ReturnLoc, diag::err_return_in_coroutine);
3756+
Diag(FSI->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
3757+
<< FSI->getFirstCoroutineStmtKeyword();
3758+
}
3759+
37503760
StmtResult R =
37513761
BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true);
37523762
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())

clang/test/SemaCXX/coroutines.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,15 @@ namespace std {
154154
template <class PromiseType = void>
155155
struct coroutine_handle {
156156
static coroutine_handle from_address(void *) noexcept;
157+
static coroutine_handle from_promise(PromiseType &promise);
157158
};
158159
template <>
159160
struct coroutine_handle<void> {
160161
template <class PromiseType>
161162
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
162163
static coroutine_handle from_address(void *) noexcept;
164+
template <class PromiseType>
165+
static coroutine_handle from_promise(PromiseType &promise);
163166
};
164167
} // namespace std
165168

@@ -291,6 +294,38 @@ void mixed_coreturn_template2(bool b, T) {
291294
return; // expected-error {{not allowed in coroutine}}
292295
}
293296

297+
struct promise_handle;
298+
299+
struct Handle : std::coroutine_handle<promise_handle> { // expected-note 2{{candidate constructor (the implicit copy constructor) not viable}}
300+
// expected-note@-1 2{{candidate constructor (the implicit move constructor) not viable}}
301+
using promise_type = promise_handle;
302+
};
303+
304+
struct promise_handle {
305+
Handle get_return_object() noexcept {
306+
{ return Handle(std::coroutine_handle<Handle::promise_type>::from_promise(*this)); }
307+
}
308+
suspend_never initial_suspend() const noexcept { return {}; }
309+
suspend_never final_suspend() const noexcept { return {}; }
310+
void return_void() const noexcept {}
311+
void unhandled_exception() const noexcept {}
312+
};
313+
314+
Handle mixed_return_value() {
315+
co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
316+
return 0; // expected-error {{return statement not allowed in coroutine}}
317+
// expected-error@-1 {{no viable conversion from returned value of type}}
318+
}
319+
320+
Handle mixed_return_value_return_first(bool b) {
321+
if (b) {
322+
return 0; // expected-error {{no viable conversion from returned value of type}}
323+
// expected-error@-1 {{return statement not allowed in coroutine}}
324+
}
325+
co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}}
326+
co_return 0; // expected-error {{no member named 'return_value' in 'promise_handle'}}
327+
}
328+
294329
struct CtorDtor {
295330
CtorDtor() {
296331
co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}

0 commit comments

Comments
 (0)