1 | // This file contains references to sections of the Coroutines TS, which can be |
2 | // found at http://wg21.link/coroutines. |
3 | |
4 | // RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result |
5 | |
6 | void no_coroutine_traits_bad_arg_await() { |
7 | co_await a; // expected-error {{include <experimental/coroutine>}} |
8 | // expected-error@-1 {{use of undeclared identifier 'a'}} |
9 | } |
10 | |
11 | void no_coroutine_traits_bad_arg_yield() { |
12 | co_yield a; // expected-error {{include <experimental/coroutine>}} |
13 | // expected-error@-1 {{use of undeclared identifier 'a'}} |
14 | } |
15 | |
16 | |
17 | void no_coroutine_traits_bad_arg_return() { |
18 | co_return a; // expected-error {{include <experimental/coroutine>}} |
19 | // expected-error@-1 {{use of undeclared identifier 'a'}} |
20 | } |
21 | |
22 | void no_coroutine_traits() { |
23 | co_await 4; // expected-error {{std::experimental::coroutine_traits type was not found; include <experimental/coroutine>}} |
24 | } |
25 | |
26 | namespace std { |
27 | namespace experimental { |
28 | |
29 | template <class... Args> |
30 | struct void_t_imp { |
31 | using type = void; |
32 | }; |
33 | template <class... Args> |
34 | using void_t = typename void_t_imp<Args...>::type; |
35 | |
36 | template <class T, class = void> |
37 | struct traits_sfinae_base {}; |
38 | |
39 | template <class T> |
40 | struct traits_sfinae_base<T, void_t<typename T::promise_type>> { |
41 | using promise_type = typename T::promise_type; |
42 | }; |
43 | |
44 | template <class Ret, class... Args> |
45 | struct coroutine_traits : public traits_sfinae_base<Ret> {}; |
46 | }} // namespace std::experimental |
47 | |
48 | template<typename Promise> struct coro {}; |
49 | template <typename Promise, typename... Ps> |
50 | struct std::experimental::coroutine_traits<coro<Promise>, Ps...> { |
51 | using promise_type = Promise; |
52 | }; |
53 | |
54 | struct awaitable { |
55 | bool await_ready(); |
56 | template <typename F> void await_suspend(F); |
57 | void await_resume(); |
58 | } a; |
59 | |
60 | struct suspend_always { |
61 | bool await_ready() { return false; } |
62 | template <typename F> void await_suspend(F); |
63 | void await_resume() {} |
64 | }; |
65 | |
66 | struct suspend_never { |
67 | bool await_ready() { return true; } |
68 | template <typename F> void await_suspend(F); |
69 | void await_resume() {} |
70 | }; |
71 | |
72 | struct auto_await_suspend { |
73 | bool await_ready(); |
74 | template <typename F> auto await_suspend(F) {} |
75 | void await_resume(); |
76 | }; |
77 | |
78 | struct DummyVoidTag {}; |
79 | DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}} |
80 | co_await a; |
81 | } |
82 | |
83 | template <typename... T> |
84 | struct std::experimental::coroutine_traits<int, T...> {}; |
85 | |
86 | int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}} |
87 | co_await a; |
88 | } |
89 | |
90 | template <> |
91 | struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; }; |
92 | double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}} |
93 | co_await a; |
94 | } |
95 | |
96 | template <> |
97 | struct std::experimental::coroutine_traits<double, int> { |
98 | struct promise_type {}; |
99 | }; |
100 | double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}} |
101 | co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}} |
102 | } |
103 | |
104 | struct promise; // expected-note {{forward declaration}} |
105 | struct promise_void; |
106 | struct void_tag {}; |
107 | template <typename... T> |
108 | struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; }; |
109 | template <typename... T> |
110 | struct std::experimental::coroutine_traits<void, void_tag, T...> |
111 | { using promise_type = promise_void; }; |
112 | |
113 | // FIXME: This diagnostic is terrible. |
114 | void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<void>::promise_type' (aka 'promise') is an incomplete type}} |
115 | co_await a; |
116 | } |
117 | |
118 | struct yielded_thing { const char *p; short a, b; }; |
119 | |
120 | struct not_awaitable {}; |
121 | |
122 | struct promise { |
123 | void get_return_object(); |
124 | suspend_always initial_suspend(); |
125 | suspend_always final_suspend(); |
126 | awaitable yield_value(int); // expected-note 2{{candidate}} |
127 | awaitable yield_value(yielded_thing); // expected-note 2{{candidate}} |
128 | not_awaitable yield_value(void()); // expected-note 2{{candidate}} |
129 | void return_value(int); // expected-note 2{{here}} |
130 | void unhandled_exception(); |
131 | }; |
132 | |
133 | struct promise_void { |
134 | void get_return_object(); |
135 | suspend_always initial_suspend(); |
136 | suspend_always final_suspend(); |
137 | void return_void(); |
138 | void unhandled_exception(); |
139 | }; |
140 | |
141 | void no_coroutine_handle() { // expected-error {{std::experimental::coroutine_handle type was not found; include <experimental/coroutine> before defining a coroutine}} |
142 | //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} |
143 | co_return 5; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
144 | } |
145 | |
146 | namespace std { |
147 | namespace experimental { |
148 | template <class PromiseType = void> |
149 | struct coroutine_handle { |
150 | static coroutine_handle from_address(void *); |
151 | }; |
152 | template <> |
153 | struct coroutine_handle<void> { |
154 | template <class PromiseType> |
155 | coroutine_handle(coroutine_handle<PromiseType>); |
156 | static coroutine_handle from_address(void *); |
157 | }; |
158 | }} // namespace std::experimental |
159 | |
160 | void yield() { |
161 | co_yield 0; |
162 | co_yield {"foo", 1, 2}; |
163 | co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{implicit conversion}} expected-warning {{braces around scalar}} |
164 | co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} |
165 | co_yield {"foo"}; |
166 | co_yield "foo"; // expected-error {{no matching}} |
167 | co_yield 1.0; |
168 | co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}} |
169 | } |
170 | |
171 | void check_auto_await_suspend() { |
172 | co_await auto_await_suspend{}; // Should compile successfully. |
173 | } |
174 | |
175 | void coreturn(int n) { |
176 | co_await a; |
177 | if (n == 0) |
178 | co_return 3; |
179 | if (n == 1) |
180 | co_return {4}; // expected-warning {{braces around scalar initializer}} |
181 | if (n == 2) |
182 | co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}} |
183 | co_return 42; |
184 | } |
185 | |
186 | template <class T> |
187 | void co_await_non_dependent_arg(T) { |
188 | co_await a; |
189 | } |
190 | template void co_await_non_dependent_arg(int); |
191 | |
192 | void mixed_yield() { |
193 | co_yield 0; // expected-note {{use of 'co_yield'}} |
194 | return; // expected-error {{not allowed in coroutine}} |
195 | } |
196 | |
197 | void mixed_yield_invalid() { |
198 | co_yield blah; // expected-error {{use of undeclared identifier}} |
199 | // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} |
200 | return; // expected-error {{return statement not allowed in coroutine}} |
201 | } |
202 | |
203 | template <class T> |
204 | void mixed_yield_template(T) { |
205 | co_yield blah; // expected-error {{use of undeclared identifier}} |
206 | // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} |
207 | return; // expected-error {{return statement not allowed in coroutine}} |
208 | } |
209 | |
210 | template <class T> |
211 | void mixed_yield_template2(T) { |
212 | co_yield 42; |
213 | // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} |
214 | return; // expected-error {{return statement not allowed in coroutine}} |
215 | } |
216 | |
217 | template <class T> |
218 | void mixed_yield_template3(T v) { |
219 | co_yield blah(v); |
220 | // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} |
221 | return; // expected-error {{return statement not allowed in coroutine}} |
222 | } |
223 | |
224 | void mixed_await() { |
225 | co_await a; // expected-note {{use of 'co_await'}} |
226 | return; // expected-error {{not allowed in coroutine}} |
227 | } |
228 | |
229 | void mixed_await_invalid() { |
230 | co_await 42; // expected-error {{'int' is not a structure or union}} |
231 | // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} |
232 | return; // expected-error {{not allowed in coroutine}} |
233 | } |
234 | |
235 | template <class T> |
236 | void mixed_await_template(T) { |
237 | co_await 42; |
238 | // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} |
239 | return; // expected-error {{not allowed in coroutine}} |
240 | } |
241 | |
242 | template <class T> |
243 | void mixed_await_template2(T v) { |
244 | co_await v; // expected-error {{'long' is not a structure or union}} |
245 | // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} |
246 | return; // expected-error {{not allowed in coroutine}} |
247 | } |
248 | template void mixed_await_template2(long); // expected-note {{requested here}} |
249 | |
250 | void only_coreturn(void_tag) { |
251 | co_return; // OK |
252 | } |
253 | |
254 | void mixed_coreturn(void_tag, bool b) { |
255 | if (b) |
256 | co_return; // expected-note {{use of 'co_return'}} |
257 | else |
258 | return; // expected-error {{not allowed in coroutine}} |
259 | } |
260 | |
261 | void mixed_coreturn_invalid(bool b) { |
262 | if (b) |
263 | co_return; // expected-note {{use of 'co_return'}} |
264 | // expected-error@-1 {{no member named 'return_void' in 'promise'}} |
265 | else |
266 | return; // expected-error {{not allowed in coroutine}} |
267 | } |
268 | |
269 | template <class T> |
270 | void mixed_coreturn_template(void_tag, bool b, T v) { |
271 | if (b) |
272 | co_return v; // expected-note {{use of 'co_return'}} |
273 | // expected-error@-1 {{no member named 'return_value' in 'promise_void'}} |
274 | else |
275 | return; // expected-error {{not allowed in coroutine}} |
276 | } |
277 | template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{requested here}} |
278 | |
279 | template <class T> |
280 | void mixed_coreturn_template2(bool b, T) { |
281 | if (b) |
282 | co_return v; // expected-note {{use of 'co_return'}} |
283 | // expected-error@-1 {{use of undeclared identifier 'v'}} |
284 | else |
285 | return; // expected-error {{not allowed in coroutine}} |
286 | } |
287 | |
288 | struct CtorDtor { |
289 | CtorDtor() { |
290 | co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}} |
291 | } |
292 | CtorDtor(awaitable a) { |
293 | // The spec doesn't say this is ill-formed, but it must be. |
294 | co_await a; // expected-error {{'co_await' cannot be used in a constructor}} |
295 | } |
296 | ~CtorDtor() { |
297 | co_return 0; // expected-error {{'co_return' cannot be used in a destructor}} |
298 | } |
299 | // FIXME: The spec says this is ill-formed. |
300 | void operator=(CtorDtor&) { |
301 | co_yield 0; // expected-error {{'co_yield' cannot be used in a copy assignment operator}} |
302 | } |
303 | void operator=(CtorDtor const &) { |
304 | co_yield 0; // expected-error {{'co_yield' cannot be used in a copy assignment operator}} |
305 | } |
306 | void operator=(CtorDtor &&) { |
307 | co_await a; // expected-error {{'co_await' cannot be used in a move assignment operator}} |
308 | } |
309 | void operator=(CtorDtor const &&) { |
310 | co_await a; // expected-error {{'co_await' cannot be used in a move assignment operator}} |
311 | } |
312 | void operator=(int) { |
313 | co_await a; // OK. Not a special member |
314 | } |
315 | }; |
316 | |
317 | namespace std { class type_info; } |
318 | |
319 | void unevaluated() { |
320 | decltype(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} |
321 | // expected-warning@-1 {{declaration does not declare anything}} |
322 | sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} |
323 | // expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}} |
324 | typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} |
325 | // expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}} |
326 | // expected-warning@-2 {{expression result unused}} |
327 | decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}} |
328 | // expected-warning@-1 {{declaration does not declare anything}} |
329 | sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}} |
330 | // expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}} |
331 | typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}} |
332 | // expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}} |
333 | // expected-warning@-2 {{expression result unused}} |
334 | } |
335 | |
336 | // [expr.await]p2: "An await-expression shall not appear in a default argument." |
337 | // FIXME: A better diagnostic would explicitly state that default arguments are |
338 | // not allowed. A user may not understand that this is "outside a function." |
339 | void default_argument(int arg = co_await 0) {} // expected-error {{'co_await' cannot be used outside a function}} |
340 | |
341 | void await_in_catch_coroutine() { |
342 | try { |
343 | } catch (...) { // FIXME: Emit a note diagnostic pointing out the try handler on this line. |
344 | []() -> void { co_await a; }(); // OK |
345 | co_await a; // expected-error {{'co_await' cannot be used in the handler of a try block}} |
346 | } |
347 | } |
348 | |
349 | void await_nested_in_catch_coroutine() { |
350 | try { |
351 | } catch (...) { // FIXME: Emit a note diagnostic pointing out the try handler on this line. |
352 | try { |
353 | co_await a; // expected-error {{'co_await' cannot be used in the handler of a try block}} |
354 | []() -> void { co_await a; }(); // OK |
355 | } catch (...) { |
356 | co_return 123; |
357 | } |
358 | } |
359 | } |
360 | |
361 | void await_in_lambda_in_catch_coroutine() { |
362 | try { |
363 | } catch (...) { |
364 | []() -> void { co_await a; }(); // OK |
365 | } |
366 | } |
367 | |
368 | void yield_in_catch_coroutine() { |
369 | try { |
370 | } catch (...) { |
371 | co_yield 1; // expected-error {{'co_yield' cannot be used in the handler of a try block}} |
372 | } |
373 | } |
374 | |
375 | void return_in_catch_coroutine() { |
376 | try { |
377 | } catch (...) { |
378 | co_return 123; // OK |
379 | } |
380 | } |
381 | |
382 | constexpr auto constexpr_deduced_return_coroutine() { |
383 | co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} |
384 | // expected-error@-1 {{'co_yield' cannot be used in a function with a deduced return type}} |
385 | } |
386 | |
387 | void varargs_coroutine(const char *, ...) { |
388 | co_await a; // expected-error {{'co_await' cannot be used in a varargs function}} |
389 | } |
390 | |
391 | auto deduced_return_coroutine() { |
392 | co_await a; // expected-error {{'co_await' cannot be used in a function with a deduced return type}} |
393 | } |
394 | |
395 | struct outer {}; |
396 | struct await_arg_1 {}; |
397 | struct await_arg_2 {}; |
398 | |
399 | namespace adl_ns { |
400 | struct coawait_arg_type {}; |
401 | awaitable operator co_await(coawait_arg_type); |
402 | } |
403 | |
404 | namespace dependent_operator_co_await_lookup { |
405 | template<typename T> void await_template(T t) { |
406 | // no unqualified lookup results |
407 | co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}} |
408 | // expected-error@-1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}} |
409 | }; |
410 | template void await_template(awaitable); |
411 | |
412 | struct indirectly_awaitable { indirectly_awaitable(outer); }; |
413 | awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}} |
414 | template void await_template(indirectly_awaitable); |
415 | |
416 | struct not_awaitable {}; |
417 | template void await_template(not_awaitable); // expected-note {{instantiation}} |
418 | |
419 | template<typename T> void await_template_2(T t) { |
420 | // one unqualified lookup result |
421 | co_await t; |
422 | }; |
423 | template void await_template(outer); // expected-note {{instantiation}} |
424 | template void await_template_2(outer); |
425 | |
426 | struct transform_awaitable {}; |
427 | struct transformed {}; |
428 | |
429 | struct transform_promise { |
430 | typedef transform_awaitable await_arg; |
431 | coro<transform_promise> get_return_object(); |
432 | transformed initial_suspend(); |
433 | ::adl_ns::coawait_arg_type final_suspend(); |
434 | transformed await_transform(transform_awaitable); |
435 | void unhandled_exception(); |
436 | void return_void(); |
437 | }; |
438 | template <class AwaitArg> |
439 | struct basic_promise { |
440 | typedef AwaitArg await_arg; |
441 | coro<basic_promise> get_return_object(); |
442 | awaitable initial_suspend(); |
443 | awaitable final_suspend(); |
444 | void unhandled_exception(); |
445 | void return_void(); |
446 | }; |
447 | |
448 | awaitable operator co_await(await_arg_1); |
449 | |
450 | template <typename T, typename U> |
451 | coro<T> await_template_3(U t) { |
452 | co_await t; |
453 | } |
454 | |
455 | template coro<basic_promise<await_arg_1>> await_template_3<basic_promise<await_arg_1>>(await_arg_1); |
456 | |
457 | template <class T, int I = 0> |
458 | struct dependent_member { |
459 | coro<T> mem_fn() const { |
460 | co_await typename T::await_arg{}; // expected-error {{call to function 'operator co_await'}}} |
461 | } |
462 | template <class U> |
463 | coro<T> dep_mem_fn(U t) { |
464 | co_await t; |
465 | } |
466 | }; |
467 | |
468 | template <> |
469 | struct dependent_member<long> { |
470 | // FIXME this diagnostic is terrible |
471 | coro<transform_promise> mem_fn() const { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}} |
472 | // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} |
473 | // expected-note@+1 {{function is a coroutine due to use of 'co_await' here}} |
474 | co_await transform_awaitable{}; |
475 | // expected-error@-1 {{no member named 'await_ready'}} |
476 | } |
477 | template <class R, class U> |
478 | coro<R> dep_mem_fn(U u) { co_await u; } |
479 | }; |
480 | |
481 | awaitable operator co_await(await_arg_2); // expected-note {{'operator co_await' should be declared prior to the call site}} |
482 | |
483 | template struct dependent_member<basic_promise<await_arg_1>, 0>; |
484 | template struct dependent_member<basic_promise<await_arg_2>, 0>; // expected-note {{in instantiation}} |
485 | |
486 | template <> |
487 | coro<transform_promise> |
488 | // FIXME this diagnostic is terrible |
489 | dependent_member<long>::dep_mem_fn<transform_promise>(int) { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}} |
490 | //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} |
491 | //expected-note@+1 {{function is a coroutine due to use of 'co_await' here}} |
492 | co_await transform_awaitable{}; |
493 | // expected-error@-1 {{no member named 'await_ready'}} |
494 | } |
495 | |
496 | void operator co_await(transform_awaitable) = delete; |
497 | awaitable operator co_await(transformed); |
498 | |
499 | template coro<transform_promise> |
500 | dependent_member<long>::dep_mem_fn<transform_promise>(transform_awaitable); |
501 | |
502 | template <> |
503 | coro<transform_promise> dependent_member<long>::dep_mem_fn<transform_promise>(long) { |
504 | co_await transform_awaitable{}; |
505 | } |
506 | |
507 | template <> |
508 | struct dependent_member<int> { |
509 | coro<transform_promise> mem_fn() const { |
510 | co_await transform_awaitable{}; |
511 | } |
512 | }; |
513 | |
514 | template coro<transform_promise> await_template_3<transform_promise>(transform_awaitable); |
515 | template struct dependent_member<transform_promise>; |
516 | template coro<transform_promise> dependent_member<transform_promise>::dep_mem_fn(transform_awaitable); |
517 | } |
518 | |
519 | struct yield_fn_tag {}; |
520 | template <> |
521 | struct std::experimental::coroutine_traits<void, yield_fn_tag> { |
522 | struct promise_type { |
523 | // FIXME: add an await_transform overload for functions |
524 | awaitable yield_value(int()); |
525 | void return_value(int()); |
526 | |
527 | suspend_never initial_suspend(); |
528 | suspend_never final_suspend(); |
529 | void get_return_object(); |
530 | void unhandled_exception(); |
531 | }; |
532 | }; |
533 | |
534 | namespace placeholder { |
535 | awaitable f(), f(int); // expected-note 4{{possible target}} |
536 | int g(), g(int); // expected-note 2{{candidate}} |
537 | void x() { |
538 | co_await f; // expected-error {{reference to overloaded function}} |
539 | } |
540 | void y() { |
541 | co_yield g; // expected-error {{no matching member function for call to 'yield_value'}} |
542 | } |
543 | void z() { |
544 | co_await a; |
545 | co_return g; // expected-error {{address of overloaded function 'g' does not match required type 'int'}} |
546 | } |
547 | |
548 | void x(yield_fn_tag) { |
549 | co_await f; // expected-error {{reference to overloaded function}} |
550 | } |
551 | void y(yield_fn_tag) { |
552 | co_yield g; |
553 | } |
554 | void z(yield_fn_tag) { |
555 | co_await a; |
556 | co_return g; |
557 | } |
558 | } |
559 | |
560 | struct bad_promise_1 { |
561 | suspend_always initial_suspend(); |
562 | suspend_always final_suspend(); |
563 | void unhandled_exception(); |
564 | void return_void(); |
565 | }; |
566 | coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}} |
567 | co_await a; |
568 | } |
569 | |
570 | struct bad_promise_2 { |
571 | coro<bad_promise_2> get_return_object(); |
572 | suspend_always final_suspend(); |
573 | void unhandled_exception(); |
574 | void return_void(); |
575 | }; |
576 | // FIXME: This shouldn't happen twice |
577 | coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}} |
578 | co_await a; |
579 | } |
580 | |
581 | struct bad_promise_3 { |
582 | coro<bad_promise_3> get_return_object(); |
583 | suspend_always initial_suspend(); |
584 | void unhandled_exception(); |
585 | void return_void(); |
586 | }; |
587 | coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}} |
588 | co_await a; |
589 | } |
590 | |
591 | struct bad_promise_4 { |
592 | coro<bad_promise_4> get_return_object(); |
593 | not_awaitable initial_suspend(); |
594 | suspend_always final_suspend(); |
595 | void return_void(); |
596 | }; |
597 | // FIXME: This diagnostic is terrible. |
598 | coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}} |
599 | // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} |
600 | co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}} |
601 | } |
602 | |
603 | struct bad_promise_5 { |
604 | coro<bad_promise_5> get_return_object(); |
605 | suspend_always initial_suspend(); |
606 | not_awaitable final_suspend(); |
607 | void return_void(); |
608 | }; |
609 | // FIXME: This diagnostic is terrible. |
610 | coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}} |
611 | // expected-note@-1 {{call to 'final_suspend' implicitly required by the final suspend point}} |
612 | co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}} |
613 | } |
614 | |
615 | struct bad_promise_6 { |
616 | coro<bad_promise_6> get_return_object(); |
617 | suspend_always initial_suspend(); |
618 | suspend_always final_suspend(); |
619 | void unhandled_exception(); |
620 | void return_void(); // expected-note 2 {{member 'return_void' first declared here}} |
621 | void return_value(int) const; // expected-note 2 {{member 'return_value' first declared here}} |
622 | void return_value(int); |
623 | }; |
624 | coro<bad_promise_6> bad_implicit_return() { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}} |
625 | co_await a; |
626 | } |
627 | |
628 | template <class T> |
629 | coro<T> bad_implicit_return_dependent(T) { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}} |
630 | co_await a; |
631 | } |
632 | template coro<bad_promise_6> bad_implicit_return_dependent(bad_promise_6); // expected-note {{in instantiation}} |
633 | |
634 | struct bad_promise_7 { // expected-note 2 {{defined here}} |
635 | coro<bad_promise_7> get_return_object(); |
636 | suspend_always initial_suspend(); |
637 | suspend_always final_suspend(); |
638 | void return_void(); |
639 | }; |
640 | coro<bad_promise_7> no_unhandled_exception() { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}} |
641 | co_await a; |
642 | } |
643 | |
644 | template <class T> |
645 | coro<T> no_unhandled_exception_dependent(T) { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}} |
646 | co_await a; |
647 | } |
648 | template coro<bad_promise_7> no_unhandled_exception_dependent(bad_promise_7); // expected-note {{in instantiation}} |
649 | |
650 | struct bad_promise_base { |
651 | private: |
652 | void return_void(); // expected-note 2 {{declared private here}} |
653 | }; |
654 | struct bad_promise_8 : bad_promise_base { |
655 | coro<bad_promise_8> get_return_object(); |
656 | suspend_always initial_suspend(); |
657 | suspend_always final_suspend(); |
658 | void unhandled_exception() __attribute__((unavailable)); // expected-note 2 {{marked unavailable here}} |
659 | void unhandled_exception() const; |
660 | void unhandled_exception(void *) const; |
661 | }; |
662 | coro<bad_promise_8> calls_unhandled_exception() { |
663 | // expected-error@-1 {{'unhandled_exception' is unavailable}} |
664 | // expected-error@-2 {{'return_void' is a private member}} |
665 | co_await a; |
666 | } |
667 | |
668 | template <class T> |
669 | coro<T> calls_unhandled_exception_dependent(T) { |
670 | // expected-error@-1 {{'unhandled_exception' is unavailable}} |
671 | // expected-error@-2 {{'return_void' is a private member}} |
672 | co_await a; |
673 | } |
674 | template coro<bad_promise_8> calls_unhandled_exception_dependent(bad_promise_8); // expected-note {{in instantiation}} |
675 | |
676 | struct bad_promise_9 { |
677 | coro<bad_promise_9> get_return_object(); |
678 | suspend_always initial_suspend(); |
679 | suspend_always final_suspend(); |
680 | void await_transform(void *); |
681 | awaitable await_transform(int) __attribute__((unavailable)); // expected-note {{explicitly marked unavailable}} |
682 | void return_void(); |
683 | void unhandled_exception(); |
684 | }; |
685 | coro<bad_promise_9> calls_await_transform() { |
686 | co_await 42; // expected-error {{'await_transform' is unavailable}} |
687 | } |
688 | |
689 | struct bad_promise_10 { |
690 | coro<bad_promise_10> get_return_object(); |
691 | suspend_always initial_suspend(); |
692 | suspend_always final_suspend(); |
693 | int await_transform; |
694 | void return_void(); |
695 | void unhandled_exception(); |
696 | }; |
697 | coro<bad_promise_10> bad_coawait() { |
698 | // FIXME this diagnostic is terrible |
699 | co_await 42; // expected-error {{called object type 'int' is not a function or function pointer}} |
700 | // expected-note@-1 {{call to 'await_transform' implicitly required by 'co_await' here}} |
701 | } |
702 | |
703 | struct call_operator { |
704 | template <class... Args> |
705 | awaitable operator()(Args...) const { return a; } |
706 | }; |
707 | void ret_void(); |
708 | struct good_promise_1 { |
709 | coro<good_promise_1> get_return_object(); |
710 | suspend_always initial_suspend(); |
711 | suspend_always final_suspend(); |
712 | void unhandled_exception(); |
713 | static const call_operator await_transform; |
714 | using Fn = void (*)(); |
715 | Fn return_void = ret_void; |
716 | }; |
717 | const call_operator good_promise_1::await_transform; |
718 | coro<good_promise_1> ok_static_coawait() { |
719 | // FIXME this diagnostic is terrible |
720 | co_await 42; |
721 | } |
722 | |
723 | template<> struct std::experimental::coroutine_traits<int, int, const char**> |
724 | { using promise_type = promise; }; |
725 | |
726 | int main(int, const char**) { |
727 | co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}} |
728 | } |
729 | |
730 | struct good_promise_2 { |
731 | float get_return_object(); |
732 | suspend_always initial_suspend(); |
733 | suspend_always final_suspend(); |
734 | void return_void(); |
735 | void unhandled_exception(); |
736 | }; |
737 | template<> struct std::experimental::coroutine_handle<good_promise_2> {}; |
738 | |
739 | template<> struct std::experimental::coroutine_traits<float> |
740 | { using promise_type = good_promise_2; }; |
741 | |
742 | float badly_specialized_coro_handle() { // expected-error {{std::experimental::coroutine_handle missing a member named 'from_address'}} |
743 | //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} |
744 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
745 | } |
746 | |
747 | namespace std { |
748 | struct nothrow_t {}; |
749 | constexpr nothrow_t nothrow = {}; |
750 | } |
751 | |
752 | using SizeT = decltype(sizeof(int)); |
753 | |
754 | void* operator new(SizeT __sz, const std::nothrow_t&) noexcept; |
755 | void operator delete(void* __p, const std::nothrow_t&) noexcept; |
756 | |
757 | |
758 | |
759 | struct promise_on_alloc_failure_tag {}; |
760 | |
761 | template<> |
762 | struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> { |
763 | struct promise_type { |
764 | int get_return_object() {} |
765 | suspend_always initial_suspend() { return {}; } |
766 | suspend_always final_suspend() { return {}; } |
767 | void return_void() {} |
768 | int get_return_object_on_allocation_failure(); // expected-error{{'promise_type': 'get_return_object_on_allocation_failure()' must be a static member function}} |
769 | void unhandled_exception(); |
770 | }; |
771 | }; |
772 | |
773 | extern "C" int f(promise_on_alloc_failure_tag) { |
774 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
775 | } |
776 | |
777 | struct bad_promise_11 { |
778 | coro<bad_promise_11> get_return_object(); |
779 | suspend_always initial_suspend(); |
780 | suspend_always final_suspend(); |
781 | void unhandled_exception(); |
782 | void return_void(); |
783 | |
784 | private: |
785 | static coro<bad_promise_11> get_return_object_on_allocation_failure(); // expected-note 2 {{declared private here}} |
786 | }; |
787 | coro<bad_promise_11> private_alloc_failure_handler() { |
788 | // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}} |
789 | co_return; // FIXME: Add a "declared coroutine here" note. |
790 | } |
791 | |
792 | template <class T> |
793 | coro<T> dependent_private_alloc_failure_handler(T) { |
794 | // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}} |
795 | co_return; // FIXME: Add a "declared coroutine here" note. |
796 | } |
797 | template coro<bad_promise_11> dependent_private_alloc_failure_handler(bad_promise_11); |
798 | // expected-note@-1 {{requested here}} |
799 | |
800 | struct bad_promise_12 { |
801 | coro<bad_promise_12> get_return_object(); |
802 | suspend_always initial_suspend(); |
803 | suspend_always final_suspend(); |
804 | void unhandled_exception(); |
805 | void return_void(); |
806 | static coro<bad_promise_12> get_return_object_on_allocation_failure(); |
807 | |
808 | static void* operator new(SizeT); |
809 | // expected-error@-1 2 {{'operator new' is required to have a non-throwing noexcept specification when the promise type declares 'get_return_object_on_allocation_failure()'}} |
810 | }; |
811 | coro<bad_promise_12> throwing_in_class_new() { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} |
812 | co_return; |
813 | } |
814 | |
815 | template <class T> |
816 | coro<T> dependent_throwing_in_class_new(T) { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} |
817 | co_return; |
818 | } |
819 | template coro<bad_promise_12> dependent_throwing_in_class_new(bad_promise_12); // expected-note {{requested here}} |
820 | |
821 | |
822 | struct good_promise_13 { |
823 | coro<good_promise_13> get_return_object(); |
824 | suspend_always initial_suspend(); |
825 | suspend_always final_suspend(); |
826 | void unhandled_exception(); |
827 | void return_void(); |
828 | static coro<good_promise_13> get_return_object_on_allocation_failure(); |
829 | }; |
830 | coro<good_promise_13> uses_nothrow_new() { |
831 | co_return; |
832 | } |
833 | |
834 | template <class T> |
835 | coro<T> dependent_uses_nothrow_new(T) { |
836 | co_return; |
837 | } |
838 | template coro<good_promise_13> dependent_uses_nothrow_new(good_promise_13); |
839 | |
840 | struct good_promise_custom_new_operator { |
841 | coro<good_promise_custom_new_operator> get_return_object(); |
842 | suspend_always initial_suspend(); |
843 | suspend_always final_suspend(); |
844 | void return_void(); |
845 | void unhandled_exception(); |
846 | void *operator new(SizeT, double, float, int); |
847 | }; |
848 | |
849 | coro<good_promise_custom_new_operator> |
850 | good_coroutine_calls_custom_new_operator(double, float, int) { |
851 | co_return; |
852 | } |
853 | |
854 | struct coroutine_nonstatic_member_struct; |
855 | |
856 | struct good_promise_nonstatic_member_custom_new_operator { |
857 | coro<good_promise_nonstatic_member_custom_new_operator> get_return_object(); |
858 | suspend_always initial_suspend(); |
859 | suspend_always final_suspend(); |
860 | void return_void(); |
861 | void unhandled_exception(); |
862 | void *operator new(SizeT, coroutine_nonstatic_member_struct &, double); |
863 | }; |
864 | |
865 | struct good_promise_noexcept_custom_new_operator { |
866 | static coro<good_promise_noexcept_custom_new_operator> get_return_object_on_allocation_failure(); |
867 | coro<good_promise_noexcept_custom_new_operator> get_return_object(); |
868 | suspend_always initial_suspend(); |
869 | suspend_always final_suspend(); |
870 | void return_void(); |
871 | void unhandled_exception(); |
872 | void *operator new(SizeT, double, float, int) noexcept; |
873 | }; |
874 | |
875 | coro<good_promise_noexcept_custom_new_operator> |
876 | good_coroutine_calls_noexcept_custom_new_operator(double, float, int) { |
877 | co_return; |
878 | } |
879 | |
880 | struct mismatch_gro_type_tag1 {}; |
881 | template<> |
882 | struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> { |
883 | struct promise_type { |
884 | void get_return_object() {} //expected-note {{member 'get_return_object' declared here}} |
885 | suspend_always initial_suspend() { return {}; } |
886 | suspend_always final_suspend() { return {}; } |
887 | void return_void() {} |
888 | void unhandled_exception(); |
889 | }; |
890 | }; |
891 | |
892 | extern "C" int f(mismatch_gro_type_tag1) { |
893 | // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} |
894 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
895 | } |
896 | |
897 | struct mismatch_gro_type_tag2 {}; |
898 | template<> |
899 | struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag2> { |
900 | struct promise_type { |
901 | void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}} |
902 | suspend_always initial_suspend() { return {}; } |
903 | suspend_always final_suspend() { return {}; } |
904 | void return_void() {} |
905 | void unhandled_exception(); |
906 | }; |
907 | }; |
908 | |
909 | extern "C" int f(mismatch_gro_type_tag2) { |
910 | // expected-error@-1 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} |
911 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
912 | } |
913 | |
914 | struct mismatch_gro_type_tag3 {}; |
915 | template<> |
916 | struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag3> { |
917 | struct promise_type { |
918 | int get_return_object() {} |
919 | static void get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared here}} |
920 | suspend_always initial_suspend() { return {}; } |
921 | suspend_always final_suspend() { return {}; } |
922 | void return_void() {} |
923 | void unhandled_exception(); |
924 | }; |
925 | }; |
926 | |
927 | extern "C" int f(mismatch_gro_type_tag3) { |
928 | // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} |
929 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
930 | } |
931 | |
932 | |
933 | struct mismatch_gro_type_tag4 {}; |
934 | template<> |
935 | struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag4> { |
936 | struct promise_type { |
937 | int get_return_object() {} |
938 | static char *get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared}} |
939 | suspend_always initial_suspend() { return {}; } |
940 | suspend_always final_suspend() { return {}; } |
941 | void return_void() {} |
942 | void unhandled_exception(); |
943 | }; |
944 | }; |
945 | |
946 | extern "C" int f(mismatch_gro_type_tag4) { |
947 | // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}} |
948 | co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} |
949 | } |
950 | |
951 | struct bad_promise_no_return_func { // expected-note {{'bad_promise_no_return_func' defined here}} |
952 | coro<bad_promise_no_return_func> get_return_object(); |
953 | suspend_always initial_suspend(); |
954 | suspend_always final_suspend(); |
955 | void unhandled_exception(); |
956 | }; |
957 | // FIXME: The PDTS currently specifies this as UB, technically forbidding a |
958 | // diagnostic. |
959 | coro<bad_promise_no_return_func> no_return_value_or_return_void() { |
960 | // expected-error@-1 {{'bad_promise_no_return_func' must declare either 'return_value' or 'return_void'}} |
961 | co_await a; |
962 | } |
963 | |
964 | struct bad_await_suspend_return { |
965 | bool await_ready(); |
966 | // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}} |
967 | char await_suspend(std::experimental::coroutine_handle<>); |
968 | void await_resume(); |
969 | }; |
970 | struct bad_await_ready_return { |
971 | // expected-note@+1 {{return type of 'await_ready' is required to be contextually convertible to 'bool'}} |
972 | void await_ready(); |
973 | bool await_suspend(std::experimental::coroutine_handle<>); |
974 | void await_resume(); |
975 | }; |
976 | struct await_ready_explicit_bool { |
977 | struct BoolT { |
978 | explicit operator bool() const; |
979 | }; |
980 | BoolT await_ready(); |
981 | void await_suspend(std::experimental::coroutine_handle<>); |
982 | void await_resume(); |
983 | }; |
984 | template <class SuspendTy> |
985 | struct await_suspend_type_test { |
986 | bool await_ready(); |
987 | // expected-error@+2 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &')}} |
988 | // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &&')}} |
989 | SuspendTy await_suspend(std::experimental::coroutine_handle<>); |
990 | void await_resume(); |
991 | }; |
992 | void test_bad_suspend() { |
993 | { |
994 | // FIXME: The actual error emitted here is terrible, and no number of notes can save it. |
995 | bad_await_ready_return a; |
996 | // expected-error@+1 {{value of type 'void' is not contextually convertible to 'bool'}} |
997 | co_await a; // expected-note {{call to 'await_ready' implicitly required by coroutine function here}} |
998 | } |
999 | { |
1000 | bad_await_suspend_return b; |
1001 | co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} |
1002 | } |
1003 | { |
1004 | await_ready_explicit_bool c; |
1005 | co_await c; // OK |
1006 | } |
1007 | { |
1008 | await_suspend_type_test<bool &&> a; |
1009 | await_suspend_type_test<bool &> b; |
1010 | await_suspend_type_test<const void> c; |
1011 | await_suspend_type_test<const volatile bool> d; |
1012 | co_await a; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} |
1013 | co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} |
1014 | co_await c; // OK |
1015 | co_await d; // OK |
1016 | } |
1017 | } |
1018 | |
1019 | template <int ID = 0> |
1020 | struct NoCopy { |
1021 | NoCopy(NoCopy const&) = delete; // expected-note 2 {{deleted here}} |
1022 | }; |
1023 | template <class T, class U> |
1024 | void test_dependent_param(T t, U) { |
1025 | // expected-error@-1 {{call to deleted constructor of 'NoCopy<0>'}} |
1026 | // expected-error@-2 {{call to deleted constructor of 'NoCopy<1>'}} |
1027 | ((void)t); |
1028 | co_return 42; |
1029 | } |
1030 | template void test_dependent_param(NoCopy<0>, NoCopy<1>); // expected-note {{requested here}} |
1031 | |
1032 | namespace CoroHandleMemberFunctionTest { |
1033 | struct CoroMemberTag {}; |
1034 | struct BadCoroMemberTag {}; |
1035 | |
1036 | template <class T, class U> |
1037 | constexpr bool IsSameV = false; |
1038 | template <class T> |
1039 | constexpr bool IsSameV<T, T> = true; |
1040 | |
1041 | template <class T> |
1042 | struct TypeTest { |
1043 | template <class U> |
1044 | static constexpr bool IsSame = IsSameV<T, U>; |
1045 | |
1046 | template <class... Args> |
1047 | static constexpr bool MatchesArgs = IsSameV<T, |
1048 | std::experimental::coroutine_traits<CoroMemberTag, Args...>>; |
1049 | }; |
1050 | |
1051 | template <class T> |
1052 | struct AwaitReturnsType { |
1053 | bool await_ready() const; |
1054 | void await_suspend(...) const; |
1055 | T await_resume() const; |
1056 | }; |
1057 | |
1058 | template <class... CoroTraitsArgs> |
1059 | struct CoroMemberPromise { |
1060 | using TraitsT = std::experimental::coroutine_traits<CoroTraitsArgs...>; |
1061 | using TypeTestT = TypeTest<TraitsT>; |
1062 | using AwaitTestT = AwaitReturnsType<TypeTestT>; |
1063 | |
1064 | CoroMemberTag get_return_object(); |
1065 | suspend_always initial_suspend(); |
1066 | suspend_always final_suspend(); |
1067 | |
1068 | AwaitTestT yield_value(int); |
1069 | |
1070 | void return_void(); |
1071 | void unhandled_exception(); |
1072 | }; |
1073 | |
1074 | } // namespace CoroHandleMemberFunctionTest |
1075 | |
1076 | template <class... Args> |
1077 | struct ::std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> { |
1078 | using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise<CoroHandleMemberFunctionTest::CoroMemberTag, Args...>; |
1079 | }; |
1080 | |
1081 | namespace CoroHandleMemberFunctionTest { |
1082 | struct TestType { |
1083 | |
1084 | CoroMemberTag test_qual() { |
1085 | auto TC = co_yield 0; |
1086 | static_assert(TC.MatchesArgs<TestType &>, ""); |
1087 | static_assert(!TC.MatchesArgs<TestType>, ""); |
1088 | static_assert(!TC.MatchesArgs<TestType *>, ""); |
1089 | } |
1090 | |
1091 | CoroMemberTag test_sanity(int *) const { |
1092 | auto TC = co_yield 0; |
1093 | static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}} |
1094 | static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}} |
1095 | static_assert(TC.MatchesArgs<const TestType &, int *>, ""); |
1096 | } |
1097 | |
1098 | CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { |
1099 | auto TC = co_yield 0; |
1100 | static_assert(TC.MatchesArgs<const TestType &, int *, const float &&, volatile void *volatile>, ""); |
1101 | } |
1102 | |
1103 | CoroMemberTag test_qual() const volatile { |
1104 | auto TC = co_yield 0; |
1105 | static_assert(TC.MatchesArgs<const volatile TestType &>, ""); |
1106 | } |
1107 | |
1108 | CoroMemberTag test_ref_qual() & { |
1109 | auto TC = co_yield 0; |
1110 | static_assert(TC.MatchesArgs<TestType &>, ""); |
1111 | } |
1112 | CoroMemberTag test_ref_qual() const & { |
1113 | auto TC = co_yield 0; |
1114 | static_assert(TC.MatchesArgs<TestType const &>, ""); |
1115 | } |
1116 | CoroMemberTag test_ref_qual() && { |
1117 | auto TC = co_yield 0; |
1118 | static_assert(TC.MatchesArgs<TestType &&>, ""); |
1119 | } |
1120 | CoroMemberTag test_ref_qual(const char *&) const volatile && { |
1121 | auto TC = co_yield 0; |
1122 | static_assert(TC.MatchesArgs<TestType const volatile &&, const char *&>, ""); |
1123 | } |
1124 | |
1125 | CoroMemberTag test_args(int) { |
1126 | auto TC = co_yield 0; |
1127 | static_assert(TC.MatchesArgs<TestType &, int>, ""); |
1128 | } |
1129 | CoroMemberTag test_args(int, long &, void *) const { |
1130 | auto TC = co_yield 0; |
1131 | static_assert(TC.MatchesArgs<TestType const &, int, long &, void *>, ""); |
1132 | } |
1133 | |
1134 | template <class... Args> |
1135 | CoroMemberTag test_member_template(Args...) const && { |
1136 | auto TC = co_yield 0; |
1137 | static_assert(TC.template MatchesArgs<TestType const &&, Args...>, ""); |
1138 | } |
1139 | |
1140 | static CoroMemberTag test_static() { |
1141 | auto TC = co_yield 0; |
1142 | static_assert(TC.MatchesArgs<>, ""); |
1143 | static_assert(!TC.MatchesArgs<TestType>, ""); |
1144 | static_assert(!TC.MatchesArgs<TestType &>, ""); |
1145 | static_assert(!TC.MatchesArgs<TestType *>, ""); |
1146 | } |
1147 | |
1148 | static CoroMemberTag test_static(volatile void *const, char &&) { |
1149 | auto TC = co_yield 0; |
1150 | static_assert(TC.MatchesArgs<volatile void *const, char &&>, ""); |
1151 | } |
1152 | |
1153 | template <class Dummy> |
1154 | static CoroMemberTag test_static_template(const char *volatile &, unsigned) { |
1155 | auto TC = co_yield 0; |
1156 | using TCT = decltype(TC); |
1157 | static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, ""); |
1158 | static_assert(!TCT::MatchesArgs<TestType &, const char *volatile &, unsigned>, ""); |
1159 | } |
1160 | |
1161 | BadCoroMemberTag test_diagnostics() { |
1162 | // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}} |
1163 | co_return; |
1164 | } |
1165 | BadCoroMemberTag test_diagnostics(int) const && { |
1166 | // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}} |
1167 | co_return; |
1168 | } |
1169 | |
1170 | static BadCoroMemberTag test_static_diagnostics(long *) { |
1171 | // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}} |
1172 | co_return; |
1173 | } |
1174 | }; |
1175 | |
1176 | template CoroMemberTag TestType::test_member_template(long, const char *) const &&; |
1177 | template CoroMemberTag TestType::test_static_template<void>(const char *volatile &, unsigned); |
1178 | |
1179 | template <class... Args> |
1180 | struct DepTestType { |
1181 | |
1182 | CoroMemberTag test_sanity(int *) const { |
1183 | auto TC = co_yield 0; |
1184 | static_assert(TC.template MatchesArgs<const DepTestType &>, ""); // expected-error {{static_assert failed}} |
1185 | static_assert(TC.template MatchesArgs<>, ""); // expected-error {{static_assert failed}} |
1186 | static_assert(TC.template MatchesArgs<const DepTestType &, int *>, ""); |
1187 | } |
1188 | |
1189 | CoroMemberTag test_qual() { |
1190 | auto TC = co_yield 0; |
1191 | static_assert(TC.template MatchesArgs<DepTestType &>, ""); |
1192 | static_assert(!TC.template MatchesArgs<DepTestType>, ""); |
1193 | static_assert(!TC.template MatchesArgs<DepTestType *>, ""); |
1194 | } |
1195 | |
1196 | CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { |
1197 | auto TC = co_yield 0; |
1198 | static_assert(TC.template MatchesArgs<const DepTestType &, int *, const float &&, volatile void *volatile>, ""); |
1199 | } |
1200 | |
1201 | CoroMemberTag test_qual() const volatile { |
1202 | auto TC = co_yield 0; |
1203 | static_assert(TC.template MatchesArgs<const volatile DepTestType &>, ""); |
1204 | } |
1205 | |
1206 | CoroMemberTag test_ref_qual() & { |
1207 | auto TC = co_yield 0; |
1208 | static_assert(TC.template MatchesArgs<DepTestType &>, ""); |
1209 | } |
1210 | CoroMemberTag test_ref_qual() const & { |
1211 | auto TC = co_yield 0; |
1212 | static_assert(TC.template MatchesArgs<DepTestType const &>, ""); |
1213 | } |
1214 | CoroMemberTag test_ref_qual() && { |
1215 | auto TC = co_yield 0; |
1216 | static_assert(TC.template MatchesArgs<DepTestType &&>, ""); |
1217 | } |
1218 | CoroMemberTag test_ref_qual(const char *&) const volatile && { |
1219 | auto TC = co_yield 0; |
1220 | static_assert(TC.template MatchesArgs<DepTestType const volatile &&, const char *&>, ""); |
1221 | } |
1222 | |
1223 | CoroMemberTag test_args(int) { |
1224 | auto TC = co_yield 0; |
1225 | static_assert(TC.template MatchesArgs<DepTestType &, int>, ""); |
1226 | } |
1227 | CoroMemberTag test_args(int, long &, void *) const { |
1228 | auto TC = co_yield 0; |
1229 | static_assert(TC.template MatchesArgs<DepTestType const &, int, long &, void *>, ""); |
1230 | } |
1231 | |
1232 | template <class... UArgs> |
1233 | CoroMemberTag test_member_template(UArgs...) const && { |
1234 | auto TC = co_yield 0; |
1235 | static_assert(TC.template MatchesArgs<DepTestType const &&, UArgs...>, ""); |
1236 | } |
1237 | |
1238 | static CoroMemberTag test_static() { |
1239 | auto TC = co_yield 0; |
1240 | using TCT = decltype(TC); |
1241 | static_assert(TCT::MatchesArgs<>, ""); |
1242 | static_assert(!TCT::MatchesArgs<DepTestType>, ""); |
1243 | static_assert(!TCT::MatchesArgs<DepTestType &>, ""); |
1244 | static_assert(!TCT::MatchesArgs<DepTestType *>, ""); |
1245 | |
1246 | // Ensure diagnostics are actually being generated here |
1247 | static_assert(TCT::MatchesArgs<int>, ""); // expected-error {{static_assert failed}} |
1248 | } |
1249 | |
1250 | static CoroMemberTag test_static(volatile void *const, char &&) { |
1251 | auto TC = co_yield 0; |
1252 | using TCT = decltype(TC); |
1253 | static_assert(TCT::MatchesArgs<volatile void *const, char &&>, ""); |
1254 | } |
1255 | |
1256 | template <class Dummy> |
1257 | static CoroMemberTag test_static_template(const char *volatile &, unsigned) { |
1258 | auto TC = co_yield 0; |
1259 | using TCT = decltype(TC); |
1260 | static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, ""); |
1261 | static_assert(!TCT::MatchesArgs<DepTestType &, const char *volatile &, unsigned>, ""); |
1262 | } |
1263 | }; |
1264 | |
1265 | template struct DepTestType<int>; // expected-note {{requested here}} |
1266 | template CoroMemberTag DepTestType<int>::test_member_template(long, const char *) const &&; |
1267 | |
1268 | template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned); |
1269 | |
1270 | struct bad_promise_deleted_constructor { |
1271 | // expected-note@+1 {{'bad_promise_deleted_constructor' has been explicitly marked deleted here}} |
1272 | bad_promise_deleted_constructor() = delete; |
1273 | coro<bad_promise_deleted_constructor> get_return_object(); |
1274 | suspend_always initial_suspend(); |
1275 | suspend_always final_suspend(); |
1276 | void return_void(); |
1277 | void unhandled_exception(); |
1278 | }; |
1279 | |
1280 | coro<bad_promise_deleted_constructor> |
1281 | bad_coroutine_calls_deleted_promise_constructor() { |
1282 | // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_deleted_constructor>>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}} |
1283 | co_return; |
1284 | } |
1285 | |
1286 | // Test that, when the promise type has a constructor whose signature matches |
1287 | // that of the coroutine function, that constructor is used. If no matching |
1288 | // constructor exists, the default constructor is used as a fallback. If no |
1289 | // matching constructors exist at all, an error is emitted. This is an |
1290 | // experimental feature that will be proposed for the Coroutines TS. |
1291 | |
1292 | struct good_promise_default_constructor { |
1293 | good_promise_default_constructor(double, float, int); |
1294 | good_promise_default_constructor() = default; |
1295 | coro<good_promise_default_constructor> get_return_object(); |
1296 | suspend_always initial_suspend(); |
1297 | suspend_always final_suspend(); |
1298 | void return_void(); |
1299 | void unhandled_exception(); |
1300 | }; |
1301 | |
1302 | coro<good_promise_default_constructor> |
1303 | good_coroutine_calls_default_constructor() { |
1304 | co_return; |
1305 | } |
1306 | |
1307 | struct some_class; |
1308 | |
1309 | struct good_promise_custom_constructor { |
1310 | good_promise_custom_constructor(some_class&, float, int); |
1311 | good_promise_custom_constructor(double, float, int); |
1312 | good_promise_custom_constructor() = delete; |
1313 | coro<good_promise_custom_constructor> get_return_object(); |
1314 | suspend_always initial_suspend(); |
1315 | suspend_always final_suspend(); |
1316 | void return_void(); |
1317 | void unhandled_exception(); |
1318 | }; |
1319 | |
1320 | coro<good_promise_custom_constructor> |
1321 | good_coroutine_calls_custom_constructor(double, float, int) { |
1322 | co_return; |
1323 | } |
1324 | |
1325 | struct some_class { |
1326 | coro<good_promise_custom_constructor> |
1327 | good_coroutine_calls_custom_constructor(float, int) { |
1328 | co_return; |
1329 | } |
1330 | coro<good_promise_custom_constructor> |
1331 | static good_coroutine_calls_custom_constructor(double, float, int) { |
1332 | co_return; |
1333 | } |
1334 | }; |
1335 | |
1336 | struct bad_promise_no_matching_constructor { |
1337 | bad_promise_no_matching_constructor(int, int, int); |
1338 | // expected-note@+1 2 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}} |
1339 | bad_promise_no_matching_constructor() = delete; |
1340 | coro<bad_promise_no_matching_constructor> get_return_object(); |
1341 | suspend_always initial_suspend(); |
1342 | suspend_always final_suspend(); |
1343 | void return_void(); |
1344 | void unhandled_exception(); |
1345 | }; |
1346 | |
1347 | coro<bad_promise_no_matching_constructor> |
1348 | bad_coroutine_calls_with_no_matching_constructor(int, int) { |
1349 | // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor>, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}} |
1350 | co_return; |
1351 | } |
1352 | |
1353 | struct some_class2 { |
1354 | coro<bad_promise_no_matching_constructor> |
1355 | bad_coroutine_calls_with_no_matching_constructor(int, int, int) { |
1356 | // expected-error@-1 {{call to deleted constructor}} |
1357 | co_return; |
1358 | } |
1359 | }; |
1360 | |
1361 | } // namespace CoroHandleMemberFunctionTest |
1362 | |
1363 | class awaitable_no_unused_warn { |
1364 | public: |
1365 | using handle_type = std::experimental::coroutine_handle<>; |
1366 | constexpr bool await_ready() { return false; } |
1367 | void await_suspend(handle_type) noexcept {} |
1368 | int await_resume() { return 1; } |
1369 | }; |
1370 | |
1371 | |
1372 | class awaitable_unused_warn { |
1373 | public: |
1374 | using handle_type = std::experimental::coroutine_handle<>; |
1375 | constexpr bool await_ready() { return false; } |
1376 | void await_suspend(handle_type) noexcept {} |
1377 | [[nodiscard]] |
1378 | int await_resume() { return 1; } |
1379 | }; |
1380 | |
1381 | template <class Await> |
1382 | struct check_warning_promise { |
1383 | coro<check_warning_promise> get_return_object(); |
1384 | Await initial_suspend(); |
1385 | Await final_suspend(); |
1386 | Await yield_value(int); |
1387 | void return_void(); |
1388 | void unhandled_exception(); |
1389 | }; |
1390 | |
1391 | |
1392 | coro<check_warning_promise<awaitable_no_unused_warn>> |
1393 | test_no_unused_warning() { |
1394 | co_await awaitable_no_unused_warn(); |
1395 | co_yield 42; |
1396 | } |
1397 | |
1398 | coro<check_warning_promise<awaitable_unused_warn>> |
1399 | test_unused_warning() { |
1400 | co_await awaitable_unused_warn(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} |
1401 | co_yield 42; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} |
1402 | } |
1403 | |
1404 | struct missing_await_ready { |
1405 | void await_suspend(std::experimental::coroutine_handle<>); |
1406 | void await_resume(); |
1407 | }; |
1408 | struct missing_await_suspend { |
1409 | bool await_ready(); |
1410 | void await_resume(); |
1411 | }; |
1412 | struct missing_await_resume { |
1413 | bool await_ready(); |
1414 | void await_suspend(std::experimental::coroutine_handle<>); |
1415 | }; |
1416 | |
1417 | void test_missing_awaitable_members() { |
1418 | co_await missing_await_ready{}; // expected-error {{no member named 'await_ready' in 'missing_await_ready'}} |
1419 | co_await missing_await_suspend{}; // expected-error {{no member named 'await_suspend' in 'missing_await_suspend'}} |
1420 | co_await missing_await_resume{}; // expected-error {{no member named 'await_resume' in 'missing_await_resume'}} |
1421 | } |
1422 | |