[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