1 // RUN: %clang_cc1 -verify -std=c++17 -fcoroutines-ts -fsyntax-only %s 2 3 namespace std::experimental { 4 template <class Promise = void> struct coroutine_handle { 5 coroutine_handle() = default; 6 static coroutine_handle from_address(void *) noexcept; 7 }; 8 9 template <> struct coroutine_handle<void> { 10 static coroutine_handle from_address(void *) noexcept; 11 coroutine_handle() = default; 12 template <class PromiseType> 13 coroutine_handle(coroutine_handle<PromiseType>) noexcept; 14 }; 15 16 template <class... Args> 17 struct void_t_imp { 18 using type = void; 19 }; 20 template <class... Args> 21 using void_t = typename void_t_imp<Args...>::type; 22 23 template <class T, class = void> 24 struct traits_sfinae_base {}; 25 26 template <class T> 27 struct traits_sfinae_base<T, void_t<typename T::promise_type>> { 28 using promise_type = typename T::promise_type; 29 }; 30 31 template <class Ret, class... Args> 32 struct coroutine_traits : public traits_sfinae_base<Ret> {}; 33 // expected-note@-1{{declared here}} 34 } // namespace std::experimental 35 36 struct suspend_never { 37 bool await_ready() noexcept; 38 void await_suspend(std::experimental::coroutine_handle<>) noexcept; 39 void await_resume() noexcept; 40 }; 41 42 struct MoveOnly { 43 MoveOnly() = default; 44 MoveOnly(const MoveOnly &) = delete; 45 MoveOnly(MoveOnly &&) = default; 46 }; 47 48 struct NoCopyNoMove { 49 NoCopyNoMove() = default; 50 NoCopyNoMove(const NoCopyNoMove &) = delete; 51 }; 52 53 template <typename T> 54 struct task { 55 struct promise_type { initial_suspendtask::promise_type56 auto initial_suspend() { return suspend_never{}; } final_suspendtask::promise_type57 auto final_suspend() noexcept { return suspend_never{}; } get_return_objecttask::promise_type58 auto get_return_object() { return task{}; } unhandled_exceptiontask::promise_type59 static void unhandled_exception() {} return_valuetask::promise_type60 void return_value(T &&value) {} // expected-note 4{{passing argument}} 61 }; 62 }; 63 local2val()64task<NoCopyNoMove> local2val() { 65 NoCopyNoMove value; 66 co_return value; // expected-warning {{support for std::experimental::coroutine_traits will be removed}} 67 } 68 local2ref()69task<NoCopyNoMove &> local2ref() { 70 NoCopyNoMove value; 71 co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}} 72 } 73 74 // We need the move constructor for construction of the coroutine. param2val(MoveOnly value)75task<MoveOnly> param2val(MoveOnly value) { 76 co_return value; 77 } 78 lvalue2val(NoCopyNoMove & value)79task<NoCopyNoMove> lvalue2val(NoCopyNoMove &value) { 80 co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}} 81 } 82 rvalue2val(NoCopyNoMove && value)83task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) { 84 co_return value; 85 } 86 lvalue2ref(NoCopyNoMove & value)87task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) { 88 co_return value; 89 } 90 rvalue2ref(NoCopyNoMove && value)91task<NoCopyNoMove &> rvalue2ref(NoCopyNoMove &&value) { 92 co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}} 93 } 94 95 struct To { 96 operator MoveOnly() &&; 97 }; conversion_operator()98task<MoveOnly> conversion_operator() { 99 To t; 100 co_return t; 101 } 102 103 struct Construct { 104 Construct(MoveOnly); 105 }; converting_constructor()106task<Construct> converting_constructor() { 107 MoveOnly w; 108 co_return w; 109 } 110 111 struct Derived : MoveOnly {}; derived2base()112task<MoveOnly> derived2base() { 113 Derived result; 114 co_return result; 115 } 116 117 struct RetThis { fooRetThis118 task<RetThis> foo() && { 119 co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}} 120 } 121 }; 122 123 template <typename, typename> 124 struct is_same { static constexpr bool value = false; }; 125 126 template <typename T> 127 struct is_same<T, T> { static constexpr bool value = true; }; 128 129 template <typename T> 130 struct generic_task { 131 struct promise_type { initial_suspendgeneric_task::promise_type132 auto initial_suspend() { return suspend_never{}; } final_suspendgeneric_task::promise_type133 auto final_suspend() noexcept { return suspend_never{}; } get_return_objectgeneric_task::promise_type134 auto get_return_object() { return generic_task{}; } 135 static void unhandled_exception(); 136 template <typename U> return_valuegeneric_task::promise_type137 void return_value(U &&value) { 138 static_assert(is_same<T, U>::value); 139 } 140 }; 141 }; 142 param2template(MoveOnly value)143generic_task<MoveOnly> param2template(MoveOnly value) { 144 co_return value; // We should deduce U = MoveOnly. 145 } 146 lvalue2template(NoCopyNoMove & value)147generic_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) { 148 co_return value; // We should deduce U = NoCopyNoMove&. 149 } 150