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()64 task<NoCopyNoMove> local2val() {
65   NoCopyNoMove value;
66   co_return value; // expected-warning {{support for std::experimental::coroutine_traits will be removed}}
67 }
68 
local2ref()69 task<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)75 task<MoveOnly> param2val(MoveOnly value) {
76   co_return value;
77 }
78 
lvalue2val(NoCopyNoMove & value)79 task<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)83 task<NoCopyNoMove> rvalue2val(NoCopyNoMove &&value) {
84   co_return value;
85 }
86 
lvalue2ref(NoCopyNoMove & value)87 task<NoCopyNoMove &> lvalue2ref(NoCopyNoMove &value) {
88   co_return value;
89 }
90 
rvalue2ref(NoCopyNoMove && value)91 task<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()98 task<MoveOnly> conversion_operator() {
99   To t;
100   co_return t;
101 }
102 
103 struct Construct {
104   Construct(MoveOnly);
105 };
converting_constructor()106 task<Construct> converting_constructor() {
107   MoveOnly w;
108   co_return w;
109 }
110 
111 struct Derived : MoveOnly {};
derived2base()112 task<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)143 generic_task<MoveOnly> param2template(MoveOnly value) {
144   co_return value; // We should deduce U = MoveOnly.
145 }
146 
lvalue2template(NoCopyNoMove & value)147 generic_task<NoCopyNoMove &> lvalue2template(NoCopyNoMove &value) {
148   co_return value; // We should deduce U = NoCopyNoMove&.
149 }
150