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 }
34 
35 struct suspend_never {
36   bool await_ready() noexcept;
37   void await_suspend(std::experimental::coroutine_handle<>) noexcept;
38   void await_resume() noexcept;
39 };
40 
41 struct MoveOnly {
42   MoveOnly() = default;
43   MoveOnly(const MoveOnly&) = delete;
44   MoveOnly(MoveOnly &&) = default;
45 };
46 
47 struct NoCopyNoMove {
48   NoCopyNoMove() = default;
49   NoCopyNoMove(const NoCopyNoMove &) = delete;
50 };
51 
52 template <typename T>
53 struct task {
54   struct promise_type {
initial_suspendtask::promise_type55     auto initial_suspend() { return suspend_never{}; }
final_suspendtask::promise_type56     auto final_suspend() noexcept { return suspend_never{}; }
get_return_objecttask::promise_type57     auto get_return_object() { return task{}; }
unhandled_exceptiontask::promise_type58     static void unhandled_exception() {}
return_valuetask::promise_type59     void return_value(T &&value) {} // expected-note 4{{passing argument}}
60   };
61 };
62 
local2val()63 task<NoCopyNoMove> local2val() {
64   NoCopyNoMove value;
65   co_return value;
66 }
67 
local2ref()68 task<NoCopyNoMove &> local2ref() {
69   NoCopyNoMove value;
70   co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
71 }
72 
73 // We need the move constructor for construction of the coroutine.
param2val(MoveOnly value)74 task<MoveOnly> param2val(MoveOnly value) {
75   co_return value;
76 }
77 
lvalue2val(NoCopyNoMove & value)78 task<NoCopyNoMove> lvalue2val(NoCopyNoMove &value) {
79   co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
80 }
81 
rvalue2val(NoCopyNoMove && value)82 task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) {
83   co_return value;
84 }
85 
lvalue2ref(NoCopyNoMove & value)86 task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) {
87   co_return value;
88 }
89 
rvalue2ref(NoCopyNoMove && value)90 task<NoCopyNoMove &> rvalue2ref(NoCopyNoMove &&value) {
91   co_return value; // expected-error {{non-const lvalue reference to type 'NoCopyNoMove' cannot bind to a temporary of type 'NoCopyNoMove'}}
92 }
93 
94 struct To {
95   operator MoveOnly() &&;
96 };
conversion_operator()97 task<MoveOnly> conversion_operator() {
98   To t;
99   co_return t;
100 }
101 
102 struct Construct {
103   Construct(MoveOnly);
104 };
converting_constructor()105 task<Construct> converting_constructor() {
106   MoveOnly w;
107   co_return w;
108 }
109 
110 struct Derived : MoveOnly {};
derived2base()111 task<MoveOnly> derived2base() {
112   Derived result;
113   co_return result;
114 }
115 
116 struct RetThis {
fooRetThis117   task<RetThis> foo() && {
118     co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}}
119   }
120 };
121 
122 template <typename, typename>
123 struct is_same { static constexpr bool value = false; };
124 
125 template <typename T>
126 struct is_same<T, T> { static constexpr bool value = true; };
127 
128 template <typename T>
129 struct generic_task {
130   struct promise_type {
initial_suspendgeneric_task::promise_type131     auto initial_suspend() { return suspend_never{}; }
final_suspendgeneric_task::promise_type132     auto final_suspend() noexcept { return suspend_never{}; }
get_return_objectgeneric_task::promise_type133     auto get_return_object() { return generic_task{}; }
134     static void unhandled_exception();
135     template <typename U>
return_valuegeneric_task::promise_type136     void return_value(U &&value) {
137       static_assert(is_same<T, U>::value);
138     }
139   };
140 };
141 
param2template(MoveOnly value)142 generic_task<MoveOnly> param2template(MoveOnly value) {
143   co_return value; // We should deduce U = MoveOnly.
144 }
145 
lvalue2template(NoCopyNoMove & value)146 generic_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) {
147   co_return value; // We should deduce U = NoCopyNoMove&.
148 }
149