[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