Clang Project

clang_source_code/test/SemaCXX/co_await-range-for.cpp
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
6using namespace std::experimental;
7
8
9template <class Begin>
10struct Awaiter {
11  bool await_ready();
12  void await_suspend(coroutine_handle<>);
13  Begin await_resume();
14};
15
16template <class Iter> struct BeginTag { BeginTag() = delete; };
17template <class Iter> struct IncTag { IncTag() = delete; };
18
19template <class Iter, bool Delete = false>
20struct CoawaitTag { CoawaitTag() = delete; };
21
22template <class T>
23struct 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};
32template <class T> bool operator==(Iter<T>, Iter<T>);
33template <class T> bool operator!=(Iter<T>, Iter<T>);
34
35template <class T>
36struct Range {
37  BeginTag<Iter<T>> begin();
38  Iter<T> end();
39};
40
41struct MyForLoopArrayAwaiter {
42  struct promise_type {
43    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};
52MyForLoopArrayAwaiter 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
59struct 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};
74ForLoopAwaiterBadBeginTransform 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}
80template <class Dummy>
81ForLoopAwaiterBadBeginTransform 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}
87template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
88
89template <class Iter>
90Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
91// expected-note@-1 1+ {{explicitly deleted}}
92
93struct 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};
108ForLoopAwaiterBadIncTransform 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
115template <class Dummy>
116ForLoopAwaiterBadIncTransform 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}
122template 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.
126template <class T>
127constexpr 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
133namespace NS {
134struct 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
148using NS::ForLoopAwaiterCoawaitLookup;
149
150template <class T>
151ForLoopAwaiterCoawaitLookup 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}
156template 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.
160namespace NS2 {
161template <class Iter>
162Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
163}
164using NS2::operator co_await;
165template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
166