diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /test/SemaCXX/coroutines.cpp | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) | |
download | src-vendor/clang/clang-trunk-r338150.tar.gz src-vendor/clang/clang-trunk-r338150.zip |
Vendor import of clang trunk r338150:vendor/clang/clang-trunk-r338150
Diffstat (limited to 'test/SemaCXX/coroutines.cpp')
-rw-r--r-- | test/SemaCXX/coroutines.cpp | 217 |
1 files changed, 207 insertions, 10 deletions
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index 65e17abb11fe..d58cedf414f8 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions +// This file contains references to sections of the Coroutines TS, which can be +// found at http://wg21.link/coroutines. + +// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result void no_coroutine_traits_bad_arg_await() { co_await a; // expected-error {{include <experimental/coroutine>}} @@ -157,7 +160,7 @@ struct coroutine_handle<void> { void yield() { co_yield 0; co_yield {"foo", 1, 2}; - co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} expected-warning {{braces around scalar}} + co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{implicit conversion}} expected-warning {{braces around scalar}} co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} co_yield {"foo"}; co_yield "foo"; // expected-error {{no matching}} @@ -320,6 +323,11 @@ void unevaluated() { typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}} } +// [expr.await]p2: "An await-expression shall not appear in a default argument." +// FIXME: A better diagnostic would explicitly state that default arguments are +// not allowed. A user may not understand that this is "outside a function." +void default_argument(int arg = co_await 0) {} // expected-error {{'co_await' cannot be used outside a function}} + 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}} @@ -510,8 +518,7 @@ coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member struct bad_promise_2 { coro<bad_promise_2> get_return_object(); - // FIXME: We shouldn't offer a typo-correction here! - suspend_always final_suspend(); // expected-note {{here}} + suspend_always final_suspend(); void unhandled_exception(); void return_void(); }; @@ -522,8 +529,7 @@ coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member na struct bad_promise_3 { coro<bad_promise_3> get_return_object(); - // FIXME: We shouldn't offer a typo-correction here! - suspend_always initial_suspend(); // expected-note {{here}} + suspend_always initial_suspend(); void unhandled_exception(); void return_void(); }; @@ -781,6 +787,46 @@ coro<T> dependent_uses_nothrow_new(T) { } template coro<good_promise_13> dependent_uses_nothrow_new(good_promise_13); +struct good_promise_custom_new_operator { + coro<good_promise_custom_new_operator> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); + void *operator new(SizeT, double, float, int); +}; + +coro<good_promise_custom_new_operator> +good_coroutine_calls_custom_new_operator(double, float, int) { + co_return; +} + +struct coroutine_nonstatic_member_struct; + +struct good_promise_nonstatic_member_custom_new_operator { + coro<good_promise_nonstatic_member_custom_new_operator> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); + void *operator new(SizeT, coroutine_nonstatic_member_struct &, double); +}; + +struct good_promise_noexcept_custom_new_operator { + static coro<good_promise_noexcept_custom_new_operator> get_return_object_on_allocation_failure(); + coro<good_promise_noexcept_custom_new_operator> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); + void *operator new(SizeT, double, float, int) noexcept; +}; + +coro<good_promise_noexcept_custom_new_operator> +good_coroutine_calls_noexcept_custom_new_operator(double, float, int) { + co_return; +} + struct mismatch_gro_type_tag1 {}; template<> struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> { @@ -793,7 +839,7 @@ struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> { }; }; -extern "C" int f(mismatch_gro_type_tag1) { +extern "C" int f(mismatch_gro_type_tag1) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -810,7 +856,7 @@ struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag2> { }; }; -extern "C" int f(mismatch_gro_type_tag2) { +extern "C" int f(mismatch_gro_type_tag2) { // expected-error@-1 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -828,7 +874,7 @@ struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag3> { }; }; -extern "C" int f(mismatch_gro_type_tag3) { +extern "C" int f(mismatch_gro_type_tag3) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -847,7 +893,7 @@ struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag4> { }; }; -extern "C" int f(mismatch_gro_type_tag4) { +extern "C" int f(mismatch_gro_type_tag4) { // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}} co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} } @@ -1171,4 +1217,155 @@ template CoroMemberTag DepTestType<int>::test_member_template(long, const char * template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned); +struct bad_promise_deleted_constructor { + // expected-note@+1 {{'bad_promise_deleted_constructor' has been explicitly marked deleted here}} + bad_promise_deleted_constructor() = delete; + coro<bad_promise_deleted_constructor> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); +}; + +coro<bad_promise_deleted_constructor> +bad_coroutine_calls_deleted_promise_constructor() { + // 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')}} + co_return; +} + +// Test that, when the promise type has a constructor whose signature matches +// that of the coroutine function, that constructor is used. If no matching +// constructor exists, the default constructor is used as a fallback. If no +// matching constructors exist at all, an error is emitted. This is an +// experimental feature that will be proposed for the Coroutines TS. + +struct good_promise_default_constructor { + good_promise_default_constructor(double, float, int); + good_promise_default_constructor() = default; + coro<good_promise_default_constructor> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); +}; + +coro<good_promise_default_constructor> +good_coroutine_calls_default_constructor() { + co_return; +} + +struct some_class; + +struct good_promise_custom_constructor { + good_promise_custom_constructor(some_class&, float, int); + good_promise_custom_constructor(double, float, int); + good_promise_custom_constructor() = delete; + coro<good_promise_custom_constructor> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); +}; + +coro<good_promise_custom_constructor> +good_coroutine_calls_custom_constructor(double, float, int) { + co_return; +} + +struct some_class { + coro<good_promise_custom_constructor> + good_coroutine_calls_custom_constructor(float, int) { + co_return; + } + coro<good_promise_custom_constructor> + static good_coroutine_calls_custom_constructor(double, float, int) { + co_return; + } +}; + +struct bad_promise_no_matching_constructor { + bad_promise_no_matching_constructor(int, int, int); + // expected-note@+1 2 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}} + bad_promise_no_matching_constructor() = delete; + coro<bad_promise_no_matching_constructor> get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); +}; + +coro<bad_promise_no_matching_constructor> +bad_coroutine_calls_with_no_matching_constructor(int, int) { + // 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')}} + co_return; +} + +struct some_class2 { +coro<bad_promise_no_matching_constructor> +bad_coroutine_calls_with_no_matching_constructor(int, int, int) { + // expected-error@-1 {{call to deleted constructor}} + co_return; +} +}; + } // namespace CoroHandleMemberFunctionTest + +class awaitable_no_unused_warn { +public: + using handle_type = std::experimental::coroutine_handle<>; + constexpr bool await_ready() { return false; } + void await_suspend(handle_type) noexcept {} + int await_resume() { return 1; } +}; + + +class awaitable_unused_warn { +public: + using handle_type = std::experimental::coroutine_handle<>; + constexpr bool await_ready() { return false; } + void await_suspend(handle_type) noexcept {} + [[nodiscard]] + int await_resume() { return 1; } +}; + +template <class Await> +struct check_warning_promise { + coro<check_warning_promise> get_return_object(); + Await initial_suspend(); + Await final_suspend(); + Await yield_value(int); + void return_void(); + void unhandled_exception(); +}; + + +coro<check_warning_promise<awaitable_no_unused_warn>> +test_no_unused_warning() { + co_await awaitable_no_unused_warn(); + co_yield 42; +} + +coro<check_warning_promise<awaitable_unused_warn>> +test_unused_warning() { + co_await awaitable_unused_warn(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + co_yield 42; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} + +struct missing_await_ready { + void await_suspend(std::experimental::coroutine_handle<>); + void await_resume(); +}; +struct missing_await_suspend { + bool await_ready(); + void await_resume(); +}; +struct missing_await_resume { + bool await_ready(); + void await_suspend(std::experimental::coroutine_handle<>); +}; + +void test_missing_awaitable_members() { + co_await missing_await_ready{}; // expected-error {{no member named 'await_ready' in 'missing_await_ready'}} + co_await missing_await_suspend{}; // expected-error {{no member named 'await_suspend' in 'missing_await_suspend'}} + co_await missing_await_resume{}; // expected-error {{no member named 'await_resume' in 'missing_await_resume'}} +} |