[clang] b72a364 - [C++20] [Coroutines] Exit early if we found co_await appears in
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 9 00:01:36 PDT 2022
Author: Chuanqi Xu
Date: 2022-10-09T14:59:27+08:00
New Revision: b72a364bb5ccc4ad50f3e28b6706db86987d961b
URL: https://github.com/llvm/llvm-project/commit/b72a364bb5ccc4ad50f3e28b6706db86987d961b
DIFF: https://github.com/llvm/llvm-project/commit/b72a364bb5ccc4ad50f3e28b6706db86987d961b.diff
LOG: [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').
Added:
clang/test/SemaCXX/coroutine-decltype.cpp
Modified:
clang/lib/Sema/SemaCoroutine.cpp
clang/test/SemaCXX/Inputs/std-coroutine.h
clang/test/SemaCXX/coroutines-exp-namespace.cpp
clang/test/SemaCXX/coroutines.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index d39dac79fb5de..46065b10156f8 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -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);
diff --git a/clang/test/SemaCXX/Inputs/std-coroutine.h b/clang/test/SemaCXX/Inputs/std-coroutine.h
index 9809cd7cde7d8..832ae7746f68b 100644
--- a/clang/test/SemaCXX/Inputs/std-coroutine.h
+++ b/clang/test/SemaCXX/Inputs/std-coroutine.h
@@ -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 {
diff --git a/clang/test/SemaCXX/coroutine-decltype.cpp b/clang/test/SemaCXX/coroutine-decltype.cpp
new file mode 100644
index 0000000000000..7cbe6688d4155
--- /dev/null
+++ b/clang/test/SemaCXX/coroutine-decltype.cpp
@@ -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;
+}
diff --git a/clang/test/SemaCXX/coroutines-exp-namespace.cpp b/clang/test/SemaCXX/coroutines-exp-namespace.cpp
index 48f0dd0126345..09eca2be744bf 100644
--- a/clang/test/SemaCXX/coroutines-exp-namespace.cpp
+++ b/clang/test/SemaCXX/coroutines-exp-namespace.cpp
@@ -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 at -1 {{declaration does not declare anything}}
- sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}}
- // expected-error at -1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
- // expected-warning at -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 at -1 {{expression with side effects has no effect in an unevaluated context}}
- // expected-warning at -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 at -1 {{declaration does not declare anything}}
- sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
- // expected-error at -1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
- // expected-warning at -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 at -1 {{expression with side effects has no effect in an unevaluated context}}
- // expected-warning at -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."
diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp
index b646810809a06..7f16c1ef45f1a 100644
--- a/clang/test/SemaCXX/coroutines.cpp
+++ b/clang/test/SemaCXX/coroutines.cpp
@@ -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 at -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 at -1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
- // expected-warning at -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 at -1 {{expression with side effects has no effect in an unevaluated context}}
- // expected-warning at -2 {{expression result unused}}
+}
+
+void unevaluated4() {
decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}}
- // expected-warning at -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 at -1 {{invalid application of 'sizeof' to an incomplete type 'void'}}
- // expected-warning at -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 at -1 {{expression with side effects has no effect in an unevaluated context}}
- // expected-warning at -2 {{expression result unused}}
}
// [expr.await]p2: "An await-expression shall not appear in a default argument."
More information about the cfe-commits
mailing list