xref: /llvm-project/clang/test/SemaCXX/for-range-examples.cpp (revision 5bb9c08d8895e9d5122411c8612521e9a84220b4)
1 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
2 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -fexperimental-new-constant-interpreter
3 
4 namespace value_range_detail {
5   template<typename T>
6   class value_range_iter {
7     T t;
8   public:
value_range_iter(const T & t)9     value_range_iter(const T &t) : t(t) {}
operator *() const10     T operator*() const { return t; }
operator !=(const value_range_iter & o) const11     bool operator!=(const value_range_iter &o) const { return t != o.t; }
operator ++()12     value_range_iter &operator++() { ++t; return *this; }
13   };
14 
15   template<typename T>
16   struct value_range {
value_rangevalue_range_detail::value_range17     value_range(const T &a, const T &b) : begin_(a), end_(b) {}
18     value_range_iter<T> begin_, end_;
19   };
20 
21   template<typename T>
begin(const value_range<T> & r)22   value_range_iter<T> begin(const value_range<T> &r) { return r.begin_; }
23   template<typename T>
end(const value_range<T> & r)24   value_range_iter<T> end(const value_range<T> &r) { return r.end_; }
25 
26 
27   struct end_t {};
28 
29   template<typename T>
30   class value_range_step_iter {
31     T it, step;
32   public:
value_range_step_iter(const T & it,const T & step)33     value_range_step_iter(const T &it, const T &step) : it(it), step(step) {}
operator *() const34     T operator*() const { return it; }
operator !=(value_range_step_iter end) const35     bool operator!=(value_range_step_iter end) const { return it != end.it; }
operator ++()36     value_range_step_iter &operator++() { it += step; return *this; }
37   };
38 
39   template<typename T>
40   class value_range_step {
41     T it, step, end_;
42   public:
value_range_step(const T & it,const T & end,const T & step)43     value_range_step(const T &it, const T &end, const T &step) :
44       it(it), end_(end), step(step) {}
45     typedef value_range_step_iter<T> iterator;
begin() const46     iterator begin() const { return iterator(it, step); }
end() const47     iterator end() const { return iterator(end_, step); }
48   };
49 }
50 
51 template<typename T>
range(const T & a,const T & b)52 value_range_detail::value_range<T> range(const T &a, const T &b) { return value_range_detail::value_range<T>(a, b); }
53 
54 template<typename T>
range(const T & a,const T & b,const T & step)55 value_range_detail::value_range_step<T> range(const T &a, const T &b, const T &step) { return value_range_detail::value_range_step<T>(a, b, step); }
56 
57 
58 namespace map_range {
59   template<typename T>
60   class vector {
61     T storage[100];
62     decltype(sizeof(char)) size;
63   public:
vector()64     vector() : size() {}
push_back(T t)65     void push_back(T t) { storage[size++] = t; }
begin()66     T *begin() { return storage; }
end()67     T *end() { return storage + size; }
68   };
69 
70   template<typename T> struct tuple_elem {
71     T t;
tuple_elemmap_range::tuple_elem72     tuple_elem() {}
tuple_elemmap_range::tuple_elem73     tuple_elem(T t) : t(t) {}
74   };
75   template<typename... A>
76   struct tuple : tuple_elem<A>... {
tuplemap_range::tuple77     tuple() : tuple_elem<A>()... {}
tuplemap_range::tuple78     tuple(A... a) : tuple_elem<A>(a)... {}
getmap_range::tuple79     template<typename B> B &get() { return tuple_elem<B>::t; }
80   };
81 
82   template<typename F, typename I>
83   class map_iter {
84     F f;
85     I i;
86   public:
map_iter(F f,I i)87     map_iter(F f, I i) : f(f), i(i) {}
operator *() const88     auto operator*() const -> decltype(f(*i)) { return f(*i); }
operator !=(const map_iter & o) const89     bool operator!=(const map_iter &o) const { return i != o.i; }
operator ++()90     map_iter &operator++() { ++i; return *this; }
91   };
92 
93   template<typename T>
94   struct iter_pair {
95     T begin_, end_;
iter_pairmap_range::iter_pair96     iter_pair(T begin, T end) : begin_(begin), end_(end) {}
97   };
begin(iter_pair<T> p)98   template<typename T> T begin(iter_pair<T> p) { return p.begin_; }
end(iter_pair<T> p)99   template<typename T> T end(iter_pair<T> p) { return p.end_; }
100 
101   template<typename...> class mem_fun_impl;
102   template<typename R, typename T, typename... A>
103   class mem_fun_impl<R (T::*)(A...)> {
104     typedef R (T::*F)(A...);
105     F f;
106   public:
mem_fun_impl(F f)107     mem_fun_impl(F f) : f(f) {}
operator ()(T & t,A &&...a) const108     R operator()(T &t, A &&...a) const { return (t.*f)(static_cast<A&&>(a)...); }
109   };
mem_fun(F f)110   template<typename F> mem_fun_impl<F> mem_fun(F f) { return mem_fun_impl<F>(f); }
111 
112   template<typename F, typename T>
map(const F & f,T & t)113   auto map(const F &f, T &t) -> iter_pair<map_iter<F, decltype(t.begin())>> {
114     typedef map_iter<F, decltype(t.begin())> iter;
115     return iter_pair<iter>(iter(f, t.begin()), iter(f, t.end()));
116   }
117 }
118 
119 #define assert(b) if (!(b)) { return 1; }
main()120 int main() {
121   int total = 0;
122 
123   for (auto n : range(1, 5)) {
124     total += n;
125   }
126   assert(total == 10);
127 
128   for (auto n : range(10, 100, 10)) {
129     total += n;
130   }
131   assert(total == 460);
132 
133   map_range::vector<char> chars;
134   chars.push_back('a');
135   chars.push_back('b');
136   chars.push_back('c');
137   for (char c : chars) {
138     ++total;
139   }
140   assert(total == 463);
141 
142   typedef map_range::tuple<int, double> T;
143   map_range::vector<T> pairs;
144   pairs.push_back(T(42, 12.9));
145   pairs.push_back(T(6, 4.2));
146   pairs.push_back(T(9, 1.1));
147   for (auto a : map(map_range::mem_fun(&T::get<int>), pairs)) {
148     total += a;
149   }
150   assert(total == 500);
151 }
152 
153 // PR11793
154 namespace test2 {
155   class A {
156     int xs[10]; // expected-note {{implicitly declared private here}}
157   };
test(A & a)158   void test(A &a) {
159     for (int x : a.xs) { } // expected-error {{'xs' is a private member of 'test2::A'}}
160   }
161 }
162 
163 namespace test3 {
164   // Make sure this doesn't crash
165   struct A {};
166   struct B { ~B(); operator bool(); };
167   struct C { B operator!=(const C&); C& operator++(); int operator*(); };
168   C begin(const A&);
169   C end(const A&);
f()170   template<typename T> void f() { for (auto a : A()) {} }
g()171   void g() { f<int>(); }
172 }
173 
174 namespace test4 {
f()175   void f() {
176     int y;
177 
178     // Make sure these don't crash. Better diagnostics would be nice.
179     for (: {1, 2, 3}) {} // expected-error {{expected expression}} expected-error {{expected ';'}}
180     for (1 : {1, 2, 3}) {} // expected-error {{must declare a variable}}
181     for (+x : {1, 2, 3}) {} // expected-error {{undeclared identifier}} expected-error {{expected ';'}}
182     for (+y : {1, 2, 3}) {} // expected-error {{must declare a variable}}
183   }
184 }
185 
186 namespace test5 {
187   // Test error-recovery.
f()188   void f() {
189     for (auto x : undeclared_identifier) // expected-error {{undeclared identifier}}
190       for (auto y : x->foo)
191         y->bar();
192     for (auto x : 123) // expected-error {{no viable 'begin'}}
193       x->foo();
194   }
195 }
196 
197 namespace test6 {
foo(int arr[])198   void foo(int arr[]) {  // expected-note {{declared here}}
199     for (auto i : arr) { }
200       // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'int[]' is treated as pointer type 'int *'}}
201   }
202 
203   struct vector {
begintest6::vector204     int *begin() { return 0; }
endtest6::vector205     int *end() { return 0; }
206   };
207 
foo(vector arr[])208   void foo(vector arr[]) {  // expected-note {{declared here}}
209     // Don't suggest to dereference arr.
210     for (auto i : arr) { }
211       // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'vector[]' is treated as pointer type 'vector *'}}
212   }
213 }
214 
215 namespace test7 {
f()216   void f() {
217     int arr[5], b;
218     for (a : arr) {} // expected-error {{requires type for loop variable}}
219     // FIXME: Give a different error in this case?
220     for (b : arr) {} // expected-error {{requires type for loop variable}}
221     for (arr : arr) {} // expected-error {{requires type for loop variable}}
222     for (c alignas(8) : arr) { // expected-error {{requires type for loop variable}}
223       static_assert(alignof(c) == 8, ""); // expected-warning {{extension}}
224     }
225     for (d alignas(1) : arr) {} // expected-error {{requested alignment is less than minimum}} expected-error {{requires type for loop variable}}
226     for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-error {{requires type for loop variable}}
227   }
228 }
229 
230 namespace pr18587 {
231   class Arg {};
232   struct Cont {
233     int *begin();
234     int *end();
235   };
AddAllArgs(Cont & x)236   void AddAllArgs(Cont &x) {
237     for (auto Arg: x) {
238     }
239   }
240 }
241 
242 namespace PR32933 {
243 // https://bugs.llvm.org/show_bug.cgi?id=32933
foo()244 void foo ()
245 {
246   int b = 1, a[b]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \
247                       expected-note {{read of non-const variable 'b' is not allowed in a constant expression}} \
248                       expected-note {{declared here}}
249   a[0] = 0;
250   [&] { for (int c : a) 0; } (); // expected-warning {{expression result unused}}
251 }
252 
253 
foo(int b)254 int foo(int b) { // expected-note {{declared here}}
255   int varr[b][(b+=8)]; // expected-warning 2{{variable length arrays in C++ are a Clang extension}} \
256                           expected-note {{function parameter 'b' with unknown value cannot be used in a constant expression}}
257   b = 15;
258   [&] {
259     int i = 0;
260     for (auto &c : varr)
261     {
262       c[0] = ++b;
263     }
264     [&] {
265       int i = 0;
266       for (auto &c : varr) {
267         int j = 0;
268         for(auto &c2 : c) {
269           ++j;
270         }
271         ++i;
272       }
273     }();
274   }();
275   return b;
276 }
277 }
278