Add support for C++0x's range-based for loops, as specified by the C++11 draft standard (N3291).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129541 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
new file mode 100644
index 0000000..810f1de
--- /dev/null
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+namespace value_range_detail {
+  template<typename T>
+  class value_range_iter {
+    T t;
+  public:
+    value_range_iter(const T &t) : t(t) {}
+    T operator*() const { return t; }
+    bool operator!=(const value_range_iter &o) const { return t != o.t; }
+    value_range_iter &operator++() { ++t; return *this; }
+  };
+
+  template<typename T>
+  struct value_range {
+    value_range(const T &a, const T &b) : begin_(a), end_(b) {}
+    value_range_iter<T> begin_, end_;
+  };
+
+  template<typename T>
+  value_range_iter<T> begin(const value_range<T> &r) { return r.begin_; }
+  template<typename T>
+  value_range_iter<T> end(const value_range<T> &r) { return r.end_; }
+
+
+  struct end_t {};
+
+  template<typename T>
+  class value_range_step_iter {
+    T it, step;
+  public:
+    value_range_step_iter(const T &it, const T &step) : it(it), step(step) {}
+    T operator*() const { return it; }
+    bool operator!=(value_range_step_iter end) const { return it != end.it; }
+    value_range_step_iter &operator++() { it += step; return *this; }
+  };
+
+  template<typename T>
+  class value_range_step {
+    T it, step, end_;
+  public:
+    value_range_step(const T &it, const T &end, const T &step) :
+      it(it), end_(end), step(step) {}
+    typedef value_range_step_iter<T> iterator;
+    iterator begin() const { return iterator(it, step); }
+    iterator end() const { return iterator(end_, step); }
+  };
+}
+
+template<typename T>
+value_range_detail::value_range<T> range(const T &a, const T &b) { return value_range_detail::value_range<T>(a, b); }
+
+template<typename T>
+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); }
+
+
+namespace map_range {
+  template<typename T>
+  class vector {
+    T storage[100];
+    decltype(sizeof(char)) size;
+  public:
+    vector() : size() {}
+    void push_back(T t) { storage[size++] = t; }
+    T *begin() { return storage; }
+    T *end() { return storage + size; }
+  };
+
+  template<typename T> struct tuple_elem {
+    T t;
+    tuple_elem() {}
+    tuple_elem(T t) : t(t) {}
+  };
+  template<typename... A>
+  struct tuple : tuple_elem<A>... {
+    tuple() : tuple_elem<A>()... {}
+    tuple(A... a) : tuple_elem<A>(a)... {}
+    template<typename B> B &get() { return tuple_elem<B>::t; }
+  };
+
+  template<typename F, typename I>
+  class map_iter {
+    F f;
+    I i;
+  public:
+    map_iter(F f, I i) : f(f), i(i) {}
+    auto operator*() const -> decltype(f(*i)) { return f(*i); }
+    bool operator!=(const map_iter &o) const { return i != o.i; }
+    map_iter &operator++() { ++i; return *this; }
+  };
+
+  template<typename T>
+  struct iter_pair {
+    T begin_, end_;
+    iter_pair(T begin, T end) : begin_(begin), end_(end) {}
+  };
+  template<typename T> T begin(iter_pair<T> p) { return p.begin_; }
+  template<typename T> T end(iter_pair<T> p) { return p.end_; }
+
+  template<typename...> class mem_fun_impl;
+  template<typename R, typename T, typename... A>
+  class mem_fun_impl<R (T::*)(A...)> {
+    typedef R (T::*F)(A...);
+    F f;
+  public:
+    mem_fun_impl(F f) : f(f) {}
+    R operator()(T &t, A &&...a) const { return (t.*f)(static_cast<A&&>(a)...); }
+  };
+  template<typename F> mem_fun_impl<F> mem_fun(F f) { return mem_fun_impl<F>(f); }
+
+  template<typename F, typename T>
+  auto map(const F &f, T &t) -> iter_pair<map_iter<F, decltype(t.begin())>> {
+    typedef map_iter<F, decltype(t.begin())> iter;
+    return iter_pair<iter>(iter(f, t.begin()), iter(f, t.end()));
+  }
+}
+
+#define assert(b) if (!b) { return 1; }
+int main() {
+  int total = 0;
+
+  for (auto n : range(1, 5)) {
+    total += n;
+  }
+  assert(total == 10);
+
+  for (auto n : range(10, 100, 10)) {
+    total += n;
+  }
+  assert(total == 460);
+
+  map_range::vector<char> chars;
+  chars.push_back('a');
+  chars.push_back('b');
+  chars.push_back('c');
+  for (char c : chars) {
+    ++total;
+  }
+  assert(total == 463);
+
+  typedef map_range::tuple<int, double> T;
+  map_range::vector<T> pairs;
+  pairs.push_back(T(42, 12.9));
+  pairs.push_back(T(6, 4.2));
+  pairs.push_back(T(9, 1.1));
+  for (auto a : map(map_range::mem_fun(&T::get<int>), pairs)) {
+    total += a;
+  }
+  assert(total == 500);
+}
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
new file mode 100644
index 0000000..8cc71e5
--- /dev/null
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+struct S {
+  int *begin();
+  int *end();
+};
+
+struct T {
+};
+
+struct Range {};
+int begin(Range); // expected-note {{not viable}}
+int end(Range);
+
+namespace NS {
+  struct ADL {};
+  struct iter {
+    int operator*();
+    bool operator!=(iter);
+    void operator++();
+  };
+  iter begin(ADL); // expected-note {{not viable}}
+  iter end(ADL);
+
+  struct NoADL {};
+}
+NS::iter begin(NS::NoADL); // expected-note {{not viable}}
+NS::iter end(NS::NoADL);
+
+void f() {
+  int a[] = {1, 2, 3};
+  for (auto b : S()) {} // ok
+  for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+  for (auto b : a) {} // ok
+  for (int b : NS::ADL()) {} // ok
+  for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+}