1 // RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
2 // RUN:    -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
3 // RUN:    -fblocks
4 #include "Inputs/std-coroutine.h"
5 
6 using namespace std::experimental;
7 
8 
9 template <class Begin>
10 struct Awaiter {
11   bool await_ready();
12   void await_suspend(coroutine_handle<>);
13   Begin await_resume();
14 };
15 
16 template <class Iter> struct BeginTag { BeginTag() = delete; };
17 template <class Iter> struct IncTag { IncTag() = delete; };
18 
19 template <class Iter, bool Delete = false>
20 struct CoawaitTag { CoawaitTag() = delete; };
21 
22 template <class T>
23 struct Iter {
24   using value_type = T;
25   using reference = T &;
26   using pointer = T *;
27 
28   IncTag<Iter> operator++();
29   reference operator*();
30   pointer operator->();
31 };
32 template <class T> bool operator==(Iter<T>, Iter<T>);
33 template <class T> bool operator!=(Iter<T>, Iter<T>);
34 
35 template <class T>
36 struct Range {
37   BeginTag<Iter<T>> begin();
38   Iter<T> end();
39 };
40 
41 struct MyForLoopArrayAwaiter {
42   struct promise_type {
get_return_objectMyForLoopArrayAwaiter::promise_type43     MyForLoopArrayAwaiter get_return_object() { return {}; }
44     void return_void();
45     void unhandled_exception();
46     suspend_never initial_suspend();
47     suspend_never final_suspend();
48     template <class T>
49     Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
50   };
51 };
g()52 MyForLoopArrayAwaiter g() {
53   int arr[10] = {0};
54   for co_await(auto i : arr) {}
55   // expected-error@-1 {{call to deleted member function 'await_transform'}}
56   // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
57 }
58 
59 struct ForLoopAwaiterBadBeginTransform {
60   struct promise_type {
61     ForLoopAwaiterBadBeginTransform get_return_object();
62     void return_void();
63     void unhandled_exception();
64     suspend_never initial_suspend();
65     suspend_never final_suspend();
66 
67     template <class T>
68     Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
69 
70     template <class T>
71     CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
72   };
73 };
bad_begin()74 ForLoopAwaiterBadBeginTransform bad_begin() {
75   Range<int> R;
76   for co_await(auto i : R) {}
77   // expected-error@-1 {{call to deleted member function 'await_transform'}}
78   // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
79 }
80 template <class Dummy>
bad_begin_template(Dummy)81 ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
82   Range<Dummy> R;
83   for co_await(auto i : R) {}
84   // expected-error@-1 {{call to deleted member function 'await_transform'}}
85   // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
86 }
87 template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
88 
89 template <class Iter>
90 Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
91 // expected-note@-1 1+ {{explicitly deleted}}
92 
93 struct ForLoopAwaiterBadIncTransform {
94   struct promise_type {
95     ForLoopAwaiterBadIncTransform get_return_object();
96     void return_void();
97     void unhandled_exception();
98     suspend_never initial_suspend();
99     suspend_never final_suspend();
100 
101     template <class T>
102     Awaiter<T> await_transform(BeginTag<T> e);
103 
104     template <class T>
105     CoawaitTag<T, true> await_transform(IncTag<T>);
106   };
107 };
bad_inc_transform()108 ForLoopAwaiterBadIncTransform bad_inc_transform() {
109   Range<float> R;
110   for co_await(auto i : R) {}
111   // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
112   // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
113 }
114 
115 template <class Dummy>
bad_inc_transform_template(Dummy)116 ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
117   Range<Dummy> R;
118   for co_await(auto i : R) {}
119   // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
120   // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
121 }
122 template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
123 
124 // Ensure we mark and check the function as a coroutine even if it's
125 // never instantiated.
126 template <class T>
never_instant(T)127 constexpr void never_instant(T) {
128   static_assert(sizeof(T) != sizeof(T), "function should not be instantiated");
129   for co_await(auto i : foo(T{})) {}
130   // expected-error@-1 {{'co_await' cannot be used in a constexpr function}}
131 }
132 
133 namespace NS {
134 struct ForLoopAwaiterCoawaitLookup {
135   struct promise_type {
136     ForLoopAwaiterCoawaitLookup get_return_object();
137     void return_void();
138     void unhandled_exception();
139     suspend_never initial_suspend();
140     suspend_never final_suspend();
141     template <class T>
142     CoawaitTag<T, false> await_transform(BeginTag<T> e);
143     template <class T>
144     Awaiter<T> await_transform(IncTag<T>);
145   };
146 };
147 } // namespace NS
148 using NS::ForLoopAwaiterCoawaitLookup;
149 
150 template <class T>
test_coawait_lookup(T)151 ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
152   Range<T> R;
153   for co_await(auto i : R) {}
154   // expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag<Iter<int>, false>'}}
155 }
156 template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
157 
158 // FIXME: This test should fail as well since the newly declared operator co_await
159 // should not be found by lookup.
160 namespace NS2 {
161 template <class Iter>
162 Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
163 }
164 using NS2::operator co_await;
165 template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
166