xref: /llvm-project/clang/test/SemaCXX/coro-return-type-and-wrapper.cpp (revision 667e58a72e0d81abe0ab3500b5d5563b6a598e7f)
1 // RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-c++23-lambda-attributes
2 #include "Inputs/std-coroutine.h"
3 
4 using std::suspend_always;
5 using std::suspend_never;
6 
7 
8 namespace std {
9   struct nothrow_t {};
10   constexpr nothrow_t nothrow = {};
11 }
12 
13 using SizeT = decltype(sizeof(int));
14 
15 void* operator new(SizeT __sz, const std::nothrow_t&) noexcept;
16 
17 template <typename T> struct [[clang::coro_return_type]] Gen {
18   struct promise_type {
get_return_objectGen::promise_type19     Gen<T> get_return_object() {
20       return {};
21     }
get_return_object_on_allocation_failureGen::promise_type22     static Gen<T> get_return_object_on_allocation_failure() {
23       return {};
24     }
25     suspend_always initial_suspend();
26     suspend_always final_suspend() noexcept;
27     void unhandled_exception();
28     void return_value(T t);
29 
30     template <typename U>
await_transformGen::promise_type31     auto await_transform(const Gen<U> &) {
32       struct awaitable {
33         bool await_ready() noexcept { return false; }
34         void await_suspend(std::coroutine_handle<>) noexcept {}
35         U await_resume() noexcept { return {}; }
36       };
37       return awaitable{};
38     }
39   };
40 };
41 
42 Gen<int> foo_coro(int b);
foo_coro(int b)43 Gen<int> foo_coro(int b) { co_return b; }
44 
marked_wrapper1(int b)45 [[clang::coro_wrapper]] Gen<int> marked_wrapper1(int b) { return foo_coro(b); }
46 
47 // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
non_marked_wrapper(int b)48 Gen<int> non_marked_wrapper(int b) { return foo_coro(b); }
49 
50 namespace using_decl {
51 template <typename T> using Co = Gen<T>;
52 
marked_wrapper1(int b)53 [[clang::coro_wrapper]] Co<int> marked_wrapper1(int b) { return foo_coro(b); }
54 
55 // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
non_marked_wrapper(int b)56 Co<int> non_marked_wrapper(int b) { return foo_coro(b); }
57 } // namespace using_decl
58 
59 namespace lambdas {
60 
foo()61 void foo() {
62   auto coro_lambda = []() -> Gen<int> {
63     co_return 1;
64   };
65   // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
66   auto not_allowed_wrapper = []() -> Gen<int> {
67     return foo_coro(1);
68   };
69   auto allowed_wrapper = [] [[clang::coro_wrapper]] () -> Gen<int> {
70     return foo_coro(1);
71   };
72 }
73 
coro_containing_lambda()74 Gen<int> coro_containing_lambda() {
75   // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
76   auto wrapper_lambda = []() -> Gen<int> {
77     return foo_coro(1);
78   };
79   co_return co_await wrapper_lambda();
80 }
81 } // namespace lambdas
82 
83 namespace std_function {
84 namespace std {
85 template <typename> class function;
86 
87 template <typename ReturnValue, typename... Args>
88 class function<ReturnValue(Args...)> {
89 public:
operator =(T)90   template <typename T> function &operator=(T) {}
function(T)91   template <typename T> function(T) {}
92   // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
operator ()(Args...args) const93   ReturnValue operator()(Args... args) const {
94     return callable_->Invoke(args...);  // expected-note {{in instantiation of member}}
95   }
96 
97 private:
98   class Callable {
99   public:
100     // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
Invoke(Args...) const101     ReturnValue Invoke(Args...) const { return {}; }
102   };
103   Callable* callable_;
104 };
105 } // namespace std
106 
use_std_function()107 void use_std_function() {
108   std::function<int(bool)> foo = [](bool b) { return b ? 1 : 2; };
109   // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
110   std::function<Gen<int>(bool)> test1 = [](bool b) {
111     return foo_coro(b);
112   };
113   std::function<Gen<int>(bool)> test2 = [](bool) -> Gen<int> {
114     co_return 1;
115   };
116   std::function<Gen<int>(bool)> test3 = foo_coro;
117 
118   foo(true);   // Fine.
119   test1(true); // expected-note 2 {{in instantiation of member}}
120   test2(true);
121   test3(true);
122 }
123 } // namespace std_function
124 
125 // different_promise_type
126 class [[clang::coro_return_type]] Task{};
127 struct my_promise_type {
get_return_objectmy_promise_type128   Task get_return_object() {
129     return {};
130   }
131   suspend_always initial_suspend();
132   suspend_always final_suspend() noexcept;
133   void unhandled_exception();
134 };
135 namespace std {
136 template<> class coroutine_traits<Task, int> {
137     using promise_type = my_promise_type;
138 };
139 } // namespace std
140 // expected-error@+1 {{neither a coroutine nor a coroutine wrapper}}
foo(int)141 Task foo(int) { return Task{}; }
142