1// RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s
2
3struct awaitable {
4  bool await_ready();
5  void await_suspend(); // FIXME: coroutine_handle
6  void await_resume();
7} a;
8
9struct suspend_always {
10  bool await_ready() { return false; }
11  void await_suspend() {}
12  void await_resume() {}
13};
14
15struct suspend_never {
16  bool await_ready() { return true; }
17  void await_suspend() {}
18  void await_resume() {}
19};
20
21void no_coroutine_traits() {
22  co_await a; // expected-error {{need to include <coroutine>}}
23}
24
25namespace std {
26  template<typename ...T> struct coroutine_traits; // expected-note {{declared here}}
27};
28
29template<typename Promise> struct coro {};
30template<typename Promise, typename... Ps>
31struct std::coroutine_traits<coro<Promise>, Ps...> {
32  using promise_type = Promise;
33};
34
35void no_specialization() {
36  co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}}
37}
38
39template<typename ...T> struct std::coroutine_traits<int, T...> {};
40
41int no_promise_type() {
42  co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}}
43}
44
45template<> struct std::coroutine_traits<double, double> { typedef int promise_type; };
46double bad_promise_type(double) {
47  co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
48}
49
50template<> struct std::coroutine_traits<double, int> {
51  struct promise_type {};
52};
53double bad_promise_type_2(int) {
54  co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}}
55}
56
57struct promise; // expected-note 2{{forward declaration}}
58template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };
59
60  // FIXME: This diagnostic is terrible.
61void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
62  // FIXME: This diagnostic doesn't make any sense.
63  // expected-error@-2 {{incomplete definition of type 'promise'}}
64  co_await a;
65}
66
67struct yielded_thing { const char *p; short a, b; };
68
69struct not_awaitable {};
70
71struct promise {
72  void get_return_object();
73  suspend_always initial_suspend();
74  suspend_always final_suspend();
75  awaitable yield_value(int); // expected-note 2{{candidate}}
76  awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
77  not_awaitable yield_value(void()); // expected-note 2{{candidate}}
78  void return_void();
79  void return_value(int); // expected-note 2{{here}}
80};
81
82void yield() {
83  co_yield 0;
84  co_yield {"foo", 1, 2};
85  co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} expected-warning {{braces around scalar}}
86  co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}}
87  co_yield {"foo"};
88  co_yield "foo"; // expected-error {{no matching}}
89  co_yield 1.0;
90  co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
91}
92
93void coreturn(int n) {
94  co_await a;
95  if (n == 0)
96    co_return 3;
97  if (n == 1)
98    co_return {4};
99  if (n == 2)
100    co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}}
101  co_return;
102}
103
104void mixed_yield() {
105  co_yield 0; // expected-note {{use of 'co_yield'}}
106  return; // expected-error {{not allowed in coroutine}}
107}
108
109void mixed_await() {
110  co_await a; // expected-note {{use of 'co_await'}}
111  return; // expected-error {{not allowed in coroutine}}
112}
113
114void only_coreturn() {
115  co_return; // expected-warning {{'co_return' used in a function that uses neither 'co_await' nor 'co_yield'}}
116}
117
118void mixed_coreturn(bool b) {
119  if (b)
120    // expected-warning@+1 {{'co_return' used in a function that uses neither}}
121    co_return; // expected-note {{use of 'co_return'}}
122  else
123    return; // expected-error {{not allowed in coroutine}}
124}
125
126struct CtorDtor {
127  CtorDtor() {
128    co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
129  }
130  CtorDtor(awaitable a) {
131    // The spec doesn't say this is ill-formed, but it must be.
132    co_await a; // expected-error {{'co_await' cannot be used in a constructor}}
133  }
134  ~CtorDtor() {
135    co_return 0; // expected-error {{'co_return' cannot be used in a destructor}}
136  }
137  // FIXME: The spec says this is ill-formed.
138  void operator=(CtorDtor&) {
139    co_yield 0;
140  }
141};
142
143void unevaluated() {
144  decltype(co_await a); // expected-error {{cannot be used in an unevaluated context}}
145  sizeof(co_await a); // expected-error {{cannot be used in an unevaluated context}}
146  typeid(co_await a); // expected-error {{cannot be used in an unevaluated context}}
147  decltype(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
148  sizeof(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
149  typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
150}
151
152constexpr void constexpr_coroutine() {
153  co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
154}
155
156void varargs_coroutine(const char *, ...) {
157  co_await a; // expected-error {{'co_await' cannot be used in a varargs function}}
158}
159
160struct outer {};
161
162namespace dependent_operator_co_await_lookup {
163  template<typename T> void await_template(T t) {
164    // no unqualified lookup results
165    co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}}
166    // expected-error@-1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}}
167  };
168  template void await_template(awaitable);
169
170  struct indirectly_awaitable { indirectly_awaitable(outer); };
171  awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}}
172  template void await_template(indirectly_awaitable);
173
174  struct not_awaitable {};
175  template void await_template(not_awaitable); // expected-note {{instantiation}}
176
177  template<typename T> void await_template_2(T t) {
178    // one unqualified lookup result
179    co_await t;
180  };
181  template void await_template(outer); // expected-note {{instantiation}}
182  template void await_template_2(outer);
183}
184
185struct yield_fn_tag {};
186template<> struct std::coroutine_traits<void, yield_fn_tag> {
187  struct promise_type {
188    // FIXME: add an await_transform overload for functions
189    awaitable yield_value(int());
190    void return_value(int());
191
192    suspend_never initial_suspend();
193    suspend_never final_suspend();
194    void get_return_object();
195  };
196};
197
198namespace placeholder {
199  awaitable f(), f(int); // expected-note 4{{possible target}}
200  int g(), g(int); // expected-note 2{{candidate}}
201  void x() {
202    co_await f; // expected-error {{reference to overloaded function}}
203  }
204  void y() {
205    co_yield g; // expected-error {{no matching member function for call to 'yield_value'}}
206  }
207  void z() {
208    co_await a;
209    co_return g; // expected-error {{address of overloaded function 'g' does not match required type 'int'}}
210  }
211
212  void x(yield_fn_tag) {
213    co_await f; // expected-error {{reference to overloaded function}}
214  }
215  void y(yield_fn_tag) {
216    co_yield g;
217  }
218  void z(yield_fn_tag) {
219    co_await a;
220    co_return g;
221  }
222}
223
224struct bad_promise_1 {
225  suspend_always initial_suspend();
226  suspend_always final_suspend();
227};
228coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}}
229  co_await a;
230}
231
232struct bad_promise_2 {
233  coro<bad_promise_2> get_return_object();
234  // FIXME: We shouldn't offer a typo-correction here!
235  suspend_always final_suspend(); // expected-note {{here}}
236};
237coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}}
238  co_await a;
239}
240
241struct bad_promise_3 {
242  coro<bad_promise_3> get_return_object();
243  // FIXME: We shouldn't offer a typo-correction here!
244  suspend_always initial_suspend(); // expected-note {{here}}
245};
246coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
247  co_await a;
248}
249
250struct bad_promise_4 {
251  coro<bad_promise_4> get_return_object();
252  not_awaitable initial_suspend();
253  suspend_always final_suspend();
254};
255// FIXME: This diagnostic is terrible.
256coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
257  co_await a;
258}
259
260struct bad_promise_5 {
261  coro<bad_promise_5> get_return_object();
262  suspend_always initial_suspend();
263  not_awaitable final_suspend();
264};
265// FIXME: This diagnostic is terrible.
266coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
267  co_await a;
268}
269