diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 22d859e77750..78ee1cac02ef 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7960,6 +7960,8 @@ def note_declared_coroutine_here : Note< "'%select{co_await|co_yield|co_return}0' here">; def err_coroutine_objc_method : Error< "Objective-C methods as coroutines are not yet supported">; +def err_coroutine_unevaluated_context : Error< + "'%0' cannot be used in an unevaluated context">; def err_coroutine_outside_function : Error< "'%0' cannot be used outside a function">; def err_coroutine_ctor_dtor : Error< diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 210f30e2a4ee..b4ba6e385b1e 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -99,10 +99,11 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, /// Check that this is a context in which a coroutine suspension can appear. static FunctionScopeInfo * checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { - // 'co_await' and 'co_yield' are permitted in unevaluated operands. - // FIXME: Not in 'noexcept'. - if (S.isUnevaluatedContext()) + // 'co_await' and 'co_yield' are not permitted in unevaluated operands. + if (S.isUnevaluatedContext()) { + S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; return nullptr; + } // Any other usage must be within a function. auto *FD = dyn_cast(S.CurContext); @@ -206,11 +207,12 @@ ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { } ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await"); + if (!Coroutine) + return ExprError(); if (E->getType()->isDependentType()) { Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E); - if (Coroutine) - Coroutine->CoroutineStmts.push_back(Res); + Coroutine->CoroutineStmts.push_back(Res); return Res; } @@ -230,8 +232,7 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1], RSS.Results[2]); - if (Coroutine) - Coroutine->CoroutineStmts.push_back(Res); + Coroutine->CoroutineStmts.push_back(Res); return Res; } @@ -244,11 +245,12 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { } ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield"); + if (!Coroutine) + return ExprError(); // FIXME: Build await_* calls. Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E); - if (Coroutine) - Coroutine->CoroutineStmts.push_back(Res); + Coroutine->CoroutineStmts.push_back(Res); return Res; } @@ -257,11 +259,12 @@ StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { } StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); + if (!Coroutine) + return StmtError(); // FIXME: Build return_* calls. Stmt *Res = new (Context) CoreturnStmt(Loc, E); - if (Coroutine) - Coroutine->CoroutineStmts.push_back(Res); + Coroutine->CoroutineStmts.push_back(Res); return Res; } diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp index c82302c3c070..6ca8d314f94d 100644 --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -78,8 +78,17 @@ struct CtorDtor { } }; -constexpr void constexpr_coroutine() { // expected-error {{never produces a constant expression}} - co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} expected-note {{subexpression}} +void unevaluated() { + decltype(co_await a); // expected-error {{cannot be used in an unevaluated context}} + sizeof(co_await a); // expected-error {{cannot be used in an unevaluated context}} + typeid(co_await a); // expected-error {{cannot be used in an unevaluated context}} + decltype(co_yield a); // expected-error {{cannot be used in an unevaluated context}} + sizeof(co_yield a); // expected-error {{cannot be used in an unevaluated context}} + typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}} +} + +constexpr void constexpr_coroutine() { + co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} } void varargs_coroutine(const char *, ...) {