diff options
Diffstat (limited to 'test/SemaCXX/coroutines.cpp')
| -rw-r--r-- | test/SemaCXX/coroutines.cpp | 155 |
1 files changed, 132 insertions, 23 deletions
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index e82cb62f12d42..a22383cd566b5 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -1,4 +1,21 @@ -// RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s +// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s + +void no_coroutine_traits_bad_arg_await() { + co_await a; // expected-error {{include <experimental/coroutine>}} + // expected-error@-1 {{use of undeclared identifier 'a'}} +} + +void no_coroutine_traits_bad_arg_yield() { + co_yield a; // expected-error {{include <experimental/coroutine>}} + // expected-error@-1 {{use of undeclared identifier 'a'}} +} + + +void no_coroutine_traits_bad_arg_return() { + co_return a; // expected-error {{include <experimental/coroutine>}} + // expected-error@-1 {{use of undeclared identifier 'a'}} +} + struct awaitable { bool await_ready(); @@ -19,45 +36,64 @@ struct suspend_never { }; void no_coroutine_traits() { - co_await a; // expected-error {{need to include <coroutine>}} + co_await a; // expected-error {{need to include <experimental/coroutine>}} } namespace std { - template<typename ...T> struct coroutine_traits; // expected-note {{declared here}} -}; +namespace experimental { +template <typename... T> +struct coroutine_traits; // expected-note {{declared here}} +} +} template<typename Promise> struct coro {}; -template<typename Promise, typename... Ps> -struct std::coroutine_traits<coro<Promise>, Ps...> { +template <typename Promise, typename... Ps> +struct std::experimental::coroutine_traits<coro<Promise>, Ps...> { using promise_type = Promise; }; void no_specialization() { - co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}} + co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits<void>'}} } -template<typename ...T> struct std::coroutine_traits<int, T...> {}; +template <typename... T> +struct std::experimental::coroutine_traits<int, T...> {}; int no_promise_type() { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}} + co_await a; // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}} } -template<> struct std::coroutine_traits<double, double> { typedef int promise_type; }; +template <> +struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; }; double bad_promise_type(double) { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}} + co_await a; // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}} } -template<> struct std::coroutine_traits<double, int> { +template <> +struct std::experimental::coroutine_traits<double, int> { struct promise_type {}; }; double bad_promise_type_2(int) { - co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}} + co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}} } struct promise; // expected-note 2{{forward declaration}} -template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; }; +struct promise_void; +struct void_tag {}; +template <typename... T> +struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; }; +template <typename... T> +struct std::experimental::coroutine_traits<void, void_tag, T...> +{ using promise_type = promise_void; }; + +namespace std { +namespace experimental { +template <typename Promise = void> +struct coroutine_handle; +} +} - // FIXME: This diagnostic is terrible. +// FIXME: This diagnostic is terrible. void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}} // FIXME: This diagnostic doesn't make any sense. // expected-error@-2 {{incomplete definition of type 'promise'}} @@ -75,10 +111,16 @@ struct promise { awaitable yield_value(int); // expected-note 2{{candidate}} awaitable yield_value(yielded_thing); // expected-note 2{{candidate}} not_awaitable yield_value(void()); // expected-note 2{{candidate}} - void return_void(); void return_value(int); // expected-note 2{{here}} }; +struct promise_void { + void get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); +}; + void yield() { co_yield 0; co_yield {"foo", 1, 2}; @@ -95,10 +137,10 @@ void coreturn(int n) { if (n == 0) co_return 3; if (n == 1) - co_return {4}; + co_return {4}; // expected-warning {{braces around scalar initializer}} if (n == 2) co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}} - co_return; + co_return 42; } void mixed_yield() { @@ -111,11 +153,11 @@ void mixed_await() { return; // expected-error {{not allowed in coroutine}} } -void only_coreturn() { +void only_coreturn(void_tag) { co_return; // expected-warning {{'co_return' used in a function that uses neither 'co_await' nor 'co_yield'}} } -void mixed_coreturn(bool b) { +void mixed_coreturn(void_tag, bool b) { if (b) // expected-warning@+1 {{'co_return' used in a function that uses neither}} co_return; // expected-note {{use of 'co_return'}} @@ -136,7 +178,19 @@ struct CtorDtor { } // FIXME: The spec says this is ill-formed. void operator=(CtorDtor&) { - co_yield 0; + co_yield 0; // expected-error {{'co_yield' cannot be used in a copy assignment operator}} + } + void operator=(CtorDtor const &) { + co_yield 0; // expected-error {{'co_yield' cannot be used in a copy assignment operator}} + } + void operator=(CtorDtor &&) { + co_await a; // expected-error {{'co_await' cannot be used in a move assignment operator}} + } + void operator=(CtorDtor const &&) { + co_await a; // expected-error {{'co_await' cannot be used in a move assignment operator}} + } + void operator=(int) { + co_await a; // OK. Not a special member } }; @@ -149,14 +203,19 @@ void unevaluated() { typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}} } -constexpr void constexpr_coroutine() { +constexpr auto constexpr_deduced_return_coroutine() { co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} + // expected-error@-1 {{'co_yield' cannot be used in a function with a deduced return type}} } void varargs_coroutine(const char *, ...) { co_await a; // expected-error {{'co_await' cannot be used in a varargs function}} } +auto deduced_return_coroutine() { + co_await a; // expected-error {{'co_await' cannot be used in a function with a deduced return type}} +} + struct outer {}; namespace dependent_operator_co_await_lookup { @@ -183,7 +242,8 @@ namespace dependent_operator_co_await_lookup { } struct yield_fn_tag {}; -template<> struct std::coroutine_traits<void, yield_fn_tag> { +template <> +struct std::experimental::coroutine_traits<void, yield_fn_tag> { struct promise_type { // FIXME: add an await_transform overload for functions awaitable yield_value(int()); @@ -266,3 +326,52 @@ struct bad_promise_5 { coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}} co_await a; } + +struct bad_promise_6 { + coro<bad_promise_6> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void return_value(int) const; + void return_value(int); +}; +coro<bad_promise_6> bad_implicit_return() { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}} + co_await a; +} + +struct bad_promise_7 { + coro<bad_promise_7> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void set_exception(int *); +}; +coro<bad_promise_7> no_std_current_exc() { + // expected-error@-1 {{you need to include <exception> before defining a coroutine that implicitly uses 'set_exception'}} + co_await a; +} + +namespace std { +int *current_exception(); +} + +struct bad_promise_8 { + coro<bad_promise_8> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void set_exception(); // expected-note {{function not viable}} + void set_exception(int *) __attribute__((unavailable)); // expected-note {{explicitly made unavailable}} + void set_exception(void *); // expected-note {{candidate function}} +}; +coro<bad_promise_8> calls_set_exception() { + // expected-error@-1 {{call to unavailable member function 'set_exception'}} + co_await a; +} + +template<> struct std::experimental::coroutine_traits<int, int, const char**> +{ using promise_type = promise; }; + +int main(int, const char**) { + co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}} +} |
