[clang] [coroutines] Introduce [[clang::coro_return_type]] and [[clang::coro_wrapper]] (PR #71945)

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 17 05:16:16 PST 2023


================
@@ -0,0 +1,117 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra
+#include "Inputs/std-coroutine.h"
+
+using std::suspend_always;
+using std::suspend_never;
+
+
+template <typename T> struct [[clang::coro_return_type]] Gen {
+  struct promise_type {
+    Gen<T> get_return_object() {
+      return {};
+    }
+    suspend_always initial_suspend();
+    suspend_always final_suspend() noexcept;
+    void unhandled_exception();
+    void return_value(const T &t);
+
+    template <typename U>
+    auto await_transform(const Gen<U> &) {
+      struct awaitable {
+        bool await_ready() noexcept { return false; }
+        void await_suspend(std::coroutine_handle<>) noexcept {}
+        U await_resume() noexcept { return {}; }
+      };
+      return awaitable{};
+    }
+  };
+};
+
+Gen<int> foo_coro(int b);
+Gen<int> foo_coro(int b) { co_return b; }
+
+[[clang::coro_wrapper]] Gen<int> marked_wrapper1(int b) { return foo_coro(b); }
+
+// expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+Gen<int> non_marked_wrapper(int b) { return foo_coro(b); }
+
+namespace using_decl {
+template <typename T> using Co = Gen<T>;
+
+[[clang::coro_wrapper]] Co<int> marked_wrapper1(int b) { return foo_coro(b); }
+
+// expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+Co<int> non_marked_wrapper(int b) { return foo_coro(b); }
+} // namespace using_decl
+
+namespace lambdas {
+void foo() {
+  auto coro_lambda = []() -> Gen<int> {
+    co_return 1;
+  };
+  // expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+  auto wrapper_lambda = []() -> Gen<int> {
+    return foo_coro(1);
+  };
+}
+}
+
+namespace std_function {
+namespace std {
+template <typename> class function;
+
+template <typename ReturnValue, typename... Args>
+class function<ReturnValue(Args...)> {
+public:
+  template <typename T> function &operator=(T) {}
+  template <typename T> function(T) {}
+  // expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+  ReturnValue operator()(Args... args) const {
+    return callable_->Invoke(args...);  // expected-note {{in instantiation of member}}
+  }
+
+private:
+  class Callable {
+  public:
+    // expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+    ReturnValue Invoke(Args...) const { return {}; }
+  };
+  Callable* callable_;
+};
+} // namespace std
+
+void use_std_function() {
+  std::function<int(bool)> foo = [](bool b) { return b ? 1 : 2; };
+  // expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+  std::function<Gen<int>(bool)> test1 = [](bool b) {
+    return foo_coro(b);
+  };
+  std::function<Gen<int>(bool)> test2 = [](bool) -> Gen<int> {
+    co_return 1;
+  };
+  std::function<Gen<int>(bool)> test3 = foo_coro;
+
+  foo(true);   // Fine.
+  test1(true); // expected-note 2 {{in instantiation of member}}
+  test2(true);
+  test3(true);
+}
+} // namespace std_function
+
+// different_promise_type
+class [[clang::coro_return_type]] Task{};
+struct my_promise_type {
+  Task get_return_object() {
+    return {};
+  }
+  suspend_always initial_suspend();
+  suspend_always final_suspend() noexcept;
+  void unhandled_exception();
+};
+namespace std {
+template<> class coroutine_traits<Task, int> {
+    using promise_type = my_promise_type;
+};
+}
+// expected-error at +1 {{neither a coroutine nor a coroutine wrapper}}
+Task foo(int) { return Task{}; }
----------------
ilya-biryukov wrote:

NIT: add a newline at the end of the file

https://github.com/llvm/llvm-project/pull/71945


More information about the cfe-commits mailing list