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() {};
43   MoveOnly(const MoveOnly&) = delete;
44   MoveOnly(MoveOnly&&) noexcept {};
45   ~MoveOnly() {};
46 };
47 
48 struct NoCopyNoMove {
49   NoCopyNoMove() = default;
50   NoCopyNoMove(const NoCopyNoMove &) = delete; // expected-note 4{{'NoCopyNoMove' has been explicitly marked deleted here}}
51 };
52 
53 template <typename T>
54 struct task {
55   struct promise_type {
56     auto initial_suspend() { return suspend_never{}; }
57     auto final_suspend() noexcept { return suspend_never{}; }
58     auto get_return_object() { return task{}; }
59     static void unhandled_exception() {}
60     void return_value(T &&value) {} // expected-note 4{{passing argument}}
61   };
62 };
63 
64 task<NoCopyNoMove> local2val() {
65   NoCopyNoMove value;
66   co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}}
67   // expected-error@-1 {{value reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
68 }
69 
70 task<NoCopyNoMove &> local2ref() {
71   NoCopyNoMove value;
72   co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}}
73 }
74 
75 // We need the move constructor for construction of the coroutine.
76 task<MoveOnly> param2val(MoveOnly value) {
77   co_return value;
78 }
79 
80 task<NoCopyNoMove> lvalue2val(NoCopyNoMove &value) {
81   co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
82 }
83 
84 task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) {
85   co_return value; // expected-error {{rvalue reference to type 'NoCopyNoMove' cannot bind to lvalue of type 'NoCopyNoMove'}}
86   // expected-error@-1 {{call to deleted constructor of 'NoCopyNoMove'}}
87 }
88 
89 task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) {
90   co_return value;
91 }
92 
93 task<NoCopyNoMove &> rvalue2ref(NoCopyNoMove &&value) {
94   co_return value; // expected-error {{call to deleted constructor of 'NoCopyNoMove'}}
95 }
96 
97 struct To {
98   operator MoveOnly() &&;
99 };
100 task<MoveOnly> conversion_operator() {
101   To t;
102   co_return t;
103 }
104 
105 struct Construct {
106   Construct(MoveOnly);
107 };
108 task<Construct> converting_constructor() {
109   MoveOnly w;
110   co_return w;
111 }
112 
113 struct Derived : MoveOnly {};
114 task<MoveOnly> derived2base() {
115   Derived result;
116   co_return result;
117 }
118 
119 struct RetThis {
120   task<RetThis> foo() && {
121     co_return *this; // expected-error {{rvalue reference to type 'RetThis' cannot bind to lvalue of type 'RetThis'}}
122   }
123 };
124 
125 template <typename, typename>
126 struct is_same { static constexpr bool value = false; };
127 
128 template <typename T>
129 struct is_same<T, T> { static constexpr bool value = true; };
130 
131 template <typename T>
132 struct generic_task {
133   struct promise_type {
134     auto initial_suspend() { return suspend_never{}; }
135     auto final_suspend() noexcept { return suspend_never{}; }
136     auto get_return_object() { return generic_task{}; }
137     static void unhandled_exception();
138     template <typename U>
139     void return_value(U &&value) {
140       static_assert(is_same<T, U>::value);
141     }
142   };
143 };
144 
145 generic_task<MoveOnly> param2template(MoveOnly value) {
146   co_return value; // We should deduce U = MoveOnly.
147 }
148 
149 generic_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) {
150   co_return value; // We should deduce U = NoCopyNoMove&.
151 }
152