forked from OSchip/llvm-project
[C++20] [Coroutines] Exit early if we found co_await appears in
unevaluated context Closes https://github.com/llvm/llvm-project/issues/58133 The direct cause for this issue is that the compilation process continues after it found it is in a invalid state. [expr.await]p2 says clearly that the co_await expressions are not allowed to appear in unevaluated context. So we can exit early in this case. It also reduces many redundant diagnostic messages (Such as 'expression with side effects has no effect in an unevaluated context').
This commit is contained in:
parent
bc5e969ca1
commit
b72a364bb5
|
@ -768,27 +768,34 @@ static bool isWithinCatchScope(Scope *S) {
|
|||
// function-body *outside of a handler* [...] A context within a function
|
||||
// where an await-expression can appear is called a suspension context of the
|
||||
// function."
|
||||
static void checkSuspensionContext(Sema &S, SourceLocation Loc,
|
||||
static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
|
||||
StringRef Keyword) {
|
||||
// First emphasis of [expr.await]p2: must be a potentially evaluated context.
|
||||
// That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
|
||||
// \c sizeof.
|
||||
if (S.isUnevaluatedContext())
|
||||
if (S.isUnevaluatedContext()) {
|
||||
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Second emphasis of [expr.await]p2: must be outside of an exception handler.
|
||||
if (isWithinCatchScope(S.getCurScope()))
|
||||
if (isWithinCatchScope(S.getCurScope())) {
|
||||
S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!checkSuspensionContext(*this, Loc, "co_await"))
|
||||
return ExprError();
|
||||
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
checkSuspensionContext(*this, Loc, "co_await");
|
||||
|
||||
if (E->hasPlaceholderType()) {
|
||||
ExprResult R = CheckPlaceholderExpr(E);
|
||||
if (R.isInvalid()) return ExprError();
|
||||
|
@ -905,13 +912,14 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
|
|||
}
|
||||
|
||||
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!checkSuspensionContext(*this, Loc, "co_yield"))
|
||||
return ExprError();
|
||||
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
checkSuspensionContext(*this, Loc, "co_yield");
|
||||
|
||||
// Build yield_value call.
|
||||
ExprResult Awaitable = buildPromiseCall(
|
||||
*this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
|
||||
|
|
|
@ -10,12 +10,14 @@ struct coroutine_traits { using promise_type = typename Ret::promise_type; };
|
|||
template <class Promise = void>
|
||||
struct coroutine_handle {
|
||||
static coroutine_handle from_address(void *) noexcept;
|
||||
constexpr void* address() const noexcept;
|
||||
};
|
||||
template <>
|
||||
struct coroutine_handle<void> {
|
||||
template <class PromiseType>
|
||||
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
|
||||
static coroutine_handle from_address(void *);
|
||||
constexpr void* address() const noexcept;
|
||||
};
|
||||
|
||||
struct suspend_always {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify
|
||||
#include "Inputs/std-coroutine.h"
|
||||
|
||||
struct MyTask{
|
||||
struct promise_type {
|
||||
MyTask get_return_object();
|
||||
std::suspend_always initial_suspend() { return {}; }
|
||||
|
||||
void unhandled_exception();
|
||||
void return_void();
|
||||
auto final_suspend() noexcept {
|
||||
struct Awaiter {
|
||||
bool await_ready() noexcept { return false; }
|
||||
std::coroutine_handle<promise_type> await_suspend(std::coroutine_handle<promise_type> h) noexcept;
|
||||
void await_resume() noexcept;
|
||||
};
|
||||
|
||||
return Awaiter{};
|
||||
}
|
||||
|
||||
// The coroutine to resume when we're done.
|
||||
std::coroutine_handle<promise_type> resume_when_done;
|
||||
};
|
||||
};
|
||||
|
||||
MyTask DoSomething() {
|
||||
static_assert(__is_same(void, decltype(co_await 0))); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
co_return;
|
||||
}
|
||||
|
||||
MyTask DoAnotherthing() {
|
||||
static_assert(__is_same(void, decltype(co_yield 0))); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
co_return;
|
||||
}
|
|
@ -334,21 +334,26 @@ class type_info;
|
|||
|
||||
void unevaluated() {
|
||||
decltype(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{declaration does not declare anything}}
|
||||
sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
|
||||
// expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}}
|
||||
typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}}
|
||||
// expected-warning@-2 {{expression result unused}}
|
||||
}
|
||||
|
||||
void unevaluated2() {
|
||||
sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
}
|
||||
|
||||
void unevaluated3() {
|
||||
typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
}
|
||||
|
||||
void unevaluated4() {
|
||||
decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{declaration does not declare anything}}
|
||||
sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
|
||||
// expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}}
|
||||
typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}}
|
||||
// expected-warning@-2 {{expression result unused}}
|
||||
}
|
||||
|
||||
void unevaluated5() {
|
||||
sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
}
|
||||
|
||||
void unevaluated6() {
|
||||
typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
}
|
||||
|
||||
// [expr.await]p2: "An await-expression shall not appear in a default argument."
|
||||
|
|
|
@ -323,21 +323,26 @@ namespace std { class type_info; }
|
|||
|
||||
void unevaluated() {
|
||||
decltype(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{declaration does not declare anything}}
|
||||
}
|
||||
|
||||
void unevaluated2() {
|
||||
sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
|
||||
// expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}}
|
||||
}
|
||||
|
||||
void unevaluated3() {
|
||||
typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}}
|
||||
// expected-warning@-2 {{expression result unused}}
|
||||
}
|
||||
|
||||
void unevaluated4() {
|
||||
decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{declaration does not declare anything}}
|
||||
}
|
||||
|
||||
void unevaluated5() {
|
||||
sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
|
||||
// expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}}
|
||||
}
|
||||
|
||||
void unevaluated6() {
|
||||
typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
|
||||
// expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}}
|
||||
// expected-warning@-2 {{expression result unused}}
|
||||
}
|
||||
|
||||
// [expr.await]p2: "An await-expression shall not appear in a default argument."
|
||||
|
|
Loading…
Reference in New Issue