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