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/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
new file mode 100644
index 0000000..d930f97
--- /dev/null
+++ b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+void f() {
+  int b;
+  int arr[] = {1, 2, 3};
+
+  if (bool b = true) // expected-note 2{{previous definition}}
+    bool b; // expected-error {{redefinition}}
+  else
+    int b; // expected-error {{redefinition}}
+  while (bool b = true) // expected-note {{previous definition}}
+    int b; // expected-error {{redefinition}}
+  for (int c; // expected-note 2{{previous definition}}
+       bool c = true;) // expected-error {{redefinition}}
+    double c; // expected-error {{redefinition}}
+  switch (int n = 37 + 5) // expected-note {{previous definition}}
+    int n; // expected-error {{redefinition}}
+  for (int a : arr) // expected-note {{previous definition}}
+    int a = 0; // expected-error {{redefinition}}
+
+  if (bool b = true) { // expected-note 2{{previous definition}}
+    int b; // expected-error {{redefinition}}
+  } else {
+    int b; // expected-error {{redefinition}}
+  }
+  while (bool b = true) { // expected-note {{previous definition}}
+    int b; // expected-error {{redefinition}}
+  }
+  for (int c; // expected-note 2{{previous definition}}
+       bool c = true;) { // expected-error {{redefinition}}
+    double c; // expected-error {{redefinition}}
+  }
+  switch (int n = 37 + 5) { // expected-note {{previous definition}}
+    int n; // expected-error {{redefinition}}
+  }
+  for (int &a : arr) { // expected-note {{previous definition}}
+    int a = 0; // expected-error {{redefinition}}
+  }
+
+  if (bool b = true) {{ // expected-note {{previous definition}}
+    bool b;
+  }} else {
+    int b; // expected-error {{redefinition}}
+  }
+  if (bool b = true) { // expected-note {{previous definition}}
+    bool b; // expected-error {{redefinition}}
+  } else {{
+    int b;
+  }}
+  if (bool b = true) {{
+    bool b;
+  }} else {{
+    int b;
+  }}
+  while (bool b = true) {{
+    int b;
+  }}
+  for (int c; // expected-note {{previous definition}}
+       bool c = true; ) {{ // expected-error {{redefinition}}
+    double c;
+  }}
+  switch (int n = 37 + 5) {{
+    int n;
+  }}
+  for (int &a : arr) {{
+    int a = 0;
+  }}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
new file mode 100644
index 0000000..10184a0
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// FIXME: when clang supports alias-declarations.
+#if 0
+using X = struct { // ok
+};
+#endif
+
+class K {
+  virtual ~K();
+  // FIXME: the diagnostic here isn't very good
+  operator struct S {} (); // expected-error 2{{}}
+};
+
+void f() {
+  int arr[3] = {1,2,3};
+
+  for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
+  }
+
+  new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
+
+  // FIXME: the diagnostic here isn't very good
+  try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
+
+  (void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}
+
+  (void)dynamic_cast<struct W {}*>((K*)0); // expected-error {{'W' can not be defined in a type specifier}}
+  (void)static_cast<struct X {}*>(0); // expected-error {{'X' can not be defined in a type specifier}}
+  (void)reinterpret_cast<struct Y {}*>(0); // expected-error {{'Y' can not be defined in a type specifier}}
+  (void)const_cast<struct Z {}*>((const Z*)0); // expected-error {{'Z' can not be defined in a type specifier}}
+}
+
+void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}}
+}
+
+// FIXME: this currently gives a strange error because alignas is not recognised as a keyword yet.
+int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a parameter type}} expected-error {{expected function body}}
+
+int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}}
+int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}}
+
+namespace std { struct type_info; }
+const std::type_info &ti = typeid(struct Ti {}); // expected-error {{'Ti' can not be defined in a type specifier}}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
new file mode 100644
index 0000000..12acde1
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -0,0 +1,210 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+namespace std {
+  template<typename T>
+    auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 4{{ignored: substitution failure}}
+  template<typename T>
+    auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
+
+  template<typename T>
+    auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \
+                                                                              expected-note 4{{candidate template ignored: substitution failure [with T = }}
+  template<typename T>
+    auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
+
+  namespace inner {
+    // These should never be considered.
+    int begin(int);
+    int end(int);
+  }
+
+  using namespace inner;
+}
+
+struct A { // expected-note {{candidate constructor}}
+  A();
+  int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
+  int *end();
+};
+
+struct B {
+  B();
+  int *alt_begin();
+  int *alt_end();
+};
+
+void f(); // expected-note {{candidate}}
+void f(int); // expected-note {{candidate}}
+
+void g() {
+  for (int a : A())
+    A __begin;
+  for (char *a : A()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+  }
+  for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+  }
+  // FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
+  for (double a : f) { // expected-error {{address of overloaded function 'f' does not match required type '<overloaded function type>'}}
+  }
+  for (auto a : A()) {
+  }
+  for (auto a : B()) {
+  }
+  for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}}
+  }
+  // : is not a typo for :: here.
+  for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}}
+  }
+  for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}}
+  }
+
+  for (auto a : A())
+    for (auto b : A()) {
+      __range.begin(); // expected-error {{use of undeclared identifier '__range'}}
+      ++__begin; // expected-error {{use of undeclared identifier '__begin'}}
+      --__end; // expected-error {{use of undeclared identifier '__end'}}
+    }
+
+  for (char c : "test")
+    ;
+  for (auto a : f()) // expected-error {{cannot use type 'void' as a range}}
+    ;
+
+  extern int incomplete[];
+  for (auto a : incomplete) // expected-error {{cannot use incomplete type 'int []' as a range}}
+    ;
+  extern struct Incomplete also_incomplete[2]; // expected-note {{forward declaration}}
+  for (auto &a : also_incomplete) // expected-error {{cannot use incomplete type 'struct Incomplete [2]' as a range}}
+    ;
+
+  struct VoidBegin {
+    void begin(); // expected-note {{selected 'begin' function with iterator type 'void'}}
+    void end();
+  };
+  for (auto a : VoidBegin()) // expected-error {{cannot use type 'void' as an iterator}}
+    ;
+
+  struct null_t {
+    operator int*();
+  };
+  struct Differ {
+    int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
+    null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
+  };
+  for (auto a : Differ()) // expected-error {{'begin' and 'end' must return the same type (got 'int *' and 'null_t')}}
+    ;
+
+  for (void f() : "error") // expected-error {{for range declaration must declare a variable}}
+    ;
+
+  for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
+  for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
+  for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
+  // FIXME: when clang supports constexpr, this should be rejected.
+  for (constexpr int a : A()) {} // desired-error {{loop variable 'a' may not be declared 'constexpr'}}
+
+  struct NoBeginADL {
+    null_t alt_end();
+  };
+  struct NoEndADL {
+    null_t alt_begin();
+  };
+  for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
+  }
+  for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
+  }
+
+  struct NoBegin {
+    null_t end();
+  };
+  struct NoEnd {
+    null_t begin();
+  };
+  for (auto u : NoBegin()) { // expected-error {{range type 'NoBegin' has 'end' member but no 'begin' member}}
+  }
+  for (auto u : NoEnd()) { // expected-error {{range type 'NoEnd' has 'begin' member but no 'end' member}}
+  }
+
+  struct NoIncr {
+    void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
+    void *end();
+  };
+  for (auto u : NoIncr()) { // expected-error {{arithmetic on pointer to void type}}
+  }
+
+  struct NoNotEq {
+    NoNotEq begin(); // expected-note {{selected 'begin' function with iterator type 'NoNotEq'}}
+    NoNotEq end();
+    void operator++();
+  };
+  for (auto u : NoNotEq()) { // expected-error {{invalid operands to binary expression}}
+  }
+
+  struct NoCopy {
+    NoCopy();
+    NoCopy(const NoCopy &) = delete;
+    int *begin();
+    int *end();
+  };
+  for (int n : NoCopy()) { // ok
+  }
+
+  for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
+                        expected-note {{range has type 'int'}}
+  }
+
+  for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
+  }
+}
+
+template<typename T, typename U>
+void h(T t) {
+  for (U u : t) { // expected-error {{no viable conversion from 'A' to 'int'}}
+  }
+  for (auto u : t) {
+  }
+}
+
+template void h<A, int>(A);
+template void h<A(&)[4], A &>(A(&)[4]);
+template void h<A(&)[13], A>(A(&)[13]);
+template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
+
+template<typename T>
+void i(T t) {
+  for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
+                        expected-error {{member function 'begin' not viable}} \
+                        expected-note {{range has type}}
+  }
+}
+template void i<A[13]>(A*); // expected-note {{requested here}}
+template void i<const A>(const A); // expected-note {{requested here}}
+
+namespace NS {
+  class ADL {};
+  int *begin(ADL); // expected-note {{no known conversion from 'NS::NoADL' to 'NS::ADL'}}
+  int *end(ADL);
+
+  class NoADL {};
+}
+int *begin(NS::NoADL);
+int *end(NS::NoADL);
+
+struct VoidBeginADL {};
+void begin(VoidBeginADL); // expected-note {{selected 'begin' function with iterator type 'void'}}
+void end(VoidBeginADL);
+
+void j() {
+  for (auto u : NS::ADL()) {
+  }
+  for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+  }
+  for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
+  }
+}
+
+void example() {
+  int array[5] = { 1, 2, 3, 4, 5 };
+  for (int &x : array)
+    x *= 2;
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index a0b17ad..25338e3 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -205,6 +205,8 @@
     Types t; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
     for (Types *t = 0; ; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
     for (; Types *t = 0; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
+    T a[] = { T(), T(), T() };
+    for (Types t : a) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
     switch(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
     while(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
     if (Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
@@ -341,6 +343,8 @@
   // SizeOfPackExpr is uninteresting
 
   // FIXME: Objective-C expressions will need to go elsewhere
+
+  for (auto t : values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
 }
 
 // Test unexpanded parameter packs in partial specializations.
diff --git a/test/CodeGenCXX/for-range-temporaries.cpp b/test/CodeGenCXX/for-range-temporaries.cpp
new file mode 100644
index 0000000..285862f
--- /dev/null
+++ b/test/CodeGenCXX/for-range-temporaries.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -UDESUGAR %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -DDESUGAR %s | FileCheck %s
+
+struct A {
+  A();
+  A(const A &);
+  ~A();
+};
+
+struct B {
+  B();
+  B(const B &);
+  ~B();
+};
+
+struct C {
+  C(const B &);
+  C(const C &);
+  ~C();
+};
+
+struct E;
+struct D {
+  D(const C &);
+  D(const D &);
+  ~D();
+};
+E begin(D);
+E end(D);
+
+struct F;
+struct G;
+struct H;
+struct E {
+  E(const E &);
+  ~E();
+  F operator*();
+  G operator++();
+  H operator!=(const E &o);
+};
+
+struct I;
+struct F {
+  F(const F &);
+  ~F();
+  operator I();
+};
+
+struct G {
+  G(const G &);
+  ~G();
+  operator bool();
+};
+
+struct H {
+  H(const H &);
+  ~H();
+  operator bool();
+};
+
+struct I {
+  I(const I &);
+  ~I();
+};
+
+void body(const I &);
+
+void for_temps() {
+  A a;
+#ifdef DESUGAR
+  {
+    auto && __range = D(B());
+    for (auto __begin = begin(__range), __end = end(__range);
+         __begin != __end; ++__begin) {
+      I i = *__begin;
+      body(i);
+    }
+  }
+#else
+  for (I i : D(B())) {
+    body(i);
+  }
+#endif
+}
+
+// CHECK: define void @_Z9for_tempsv()
+// CHECK: call void @_ZN1AC1Ev(
+// CHECK: call void @_ZN1BC1Ev(
+// CHECK: call void @_ZN1CC1ERK1B(
+// CHECK: call void @_ZN1DC1ERK1C(
+// CHECK: call void @_ZN1CD1Ev(
+// CHECK: call void @_ZN1BD1Ev(
+// CHECK: call void @_ZN1DC1ERKS_(
+// CHECK: call void @_Z5begin1D(
+// CHECK: call void @_ZN1DD1Ev(
+// CHECK: call void @_ZN1DC1ERKS_(
+// CHECK: call void @_Z3end1D(
+// CHECK: call void @_ZN1DD1Ev(
+// CHECK: br label %[[COND:.*]]
+
+// CHECK: [[COND]]:
+// CHECK: call void @_ZN1EneERKS_(
+// CHECK: %[[CMP:.*]] = call zeroext i1 @_ZN1HcvbEv(
+// CHECK: call void @_ZN1HD1Ev(
+// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+// CHECK: [[CLEANUP]]:
+// CHECK: call void @_ZN1ED1Ev(
+// CHECK: call void @_ZN1ED1Ev(
+// In for-range:
+// call void @_ZN1DD1Ev(
+// CHECK: br label %[[END:.*]]
+
+// CHECK: [[BODY]]:
+// CHECK: call void @_ZN1EdeEv(
+// CHECK: call void @_ZN1Fcv1IEv(
+// CHECK: call void @_ZN1FD1Ev(
+// CHECK: call void @_Z4bodyRK1I(
+// CHECK: call void @_ZN1ID1Ev(
+// CHECK: br label %[[INC:.*]]
+
+// CHECK: [[INC]]:
+// CHECK: call void @_ZN1EppEv(
+// CHECK: call void @_ZN1GD1Ev(
+// CHECK: br label %[[COND]]
+
+// CHECK: [[END]]:
+// In desugared version:
+// call void @_ZN1DD1Ev(
+// CHECK: call void @_ZN1AD1Ev(
+// CHECK: ret void
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
new file mode 100644
index 0000000..94b614f
--- /dev/null
+++ b/test/CodeGenCXX/for-range.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+  A();
+  A(const A&);
+  ~A();
+};
+
+struct B {
+  B();
+  B(const B&);
+  ~B();
+};
+
+struct C {
+  C();
+  C(const C&);
+  ~C();
+};
+
+struct D {
+  D();
+  D(const D&);
+  ~D();
+
+  B *begin();
+  B *end();
+};
+
+namespace std {
+  B *begin(C&);
+  B *end(C&);
+}
+
+extern B array[5];
+
+// CHECK: define void @_Z9for_arrayv(
+void for_array() {
+  // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+  A a;
+  for (B b : array) {
+    // CHECK-NOT: 5begin
+    // CHECK-NOT: 3end
+    // CHECK: getelementptr {{.*}}, i32 0
+    // CHECK: getelementptr {{.*}}, i64 5
+    // CHECK: br label %[[COND:.*]]
+
+    // CHECK: [[COND]]:
+    // CHECK: %[[CMP:.*]] = icmp ne
+    // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
+
+    // CHECK: [[BODY]]:
+    // CHECK: call void @_ZN1BC1ERKS_(
+    // CHECK: call void @_ZN1BD1Ev(
+    // CHECK: br label %[[INC:.*]]
+
+    // CHECK: [[INC]]:
+    // CHECK: getelementptr {{.*}} i32 1
+    // CHECK: br label %[[COND]]
+  }
+  // CHECK: [[END]]:
+  // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z9for_rangev(
+void for_range() {
+  // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+  A a;
+  for (B b : C()) {
+    // CHECK: call void @_ZN1CC1Ev(
+    // CHECK: = call %struct.A* @_ZSt5beginR1C(
+    // CHECK: = call %struct.A* @_ZSt3endR1C(
+    // CHECK: br label %[[COND:.*]]
+
+    // CHECK: [[COND]]:
+    // CHECK: %[[CMP:.*]] = icmp ne
+    // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+    // CHECK: [[CLEANUP]]:
+    // CHECK: call void @_ZN1CD1Ev(
+    // CHECK: br label %[[END:.*]]
+
+    // CHECK: [[BODY]]:
+    // CHECK: call void @_ZN1BC1ERKS_(
+    // CHECK: call void @_ZN1BD1Ev(
+    // CHECK: br label %[[INC:.*]]
+
+    // CHECK: [[INC]]:
+    // CHECK: getelementptr {{.*}} i32 1
+    // CHECK: br label %[[COND]]
+  }
+  // CHECK: [[END]]:
+  // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z16for_member_rangev(
+void for_member_range() {
+  // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+  A a;
+  for (B b : D()) {
+    // CHECK: call void @_ZN1DC1Ev(
+    // CHECK: = call %struct.A* @_ZN1D5beginEv(
+    // CHECK: = call %struct.A* @_ZN1D3endEv(
+    // CHECK: br label %[[COND:.*]]
+
+    // CHECK: [[COND]]:
+    // CHECK: %[[CMP:.*]] = icmp ne
+    // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+    // CHECK: [[CLEANUP]]:
+    // CHECK: call void @_ZN1DD1Ev(
+    // CHECK: br label %[[END:.*]]
+
+    // CHECK: [[BODY]]:
+    // CHECK: call void @_ZN1BC1ERKS_(
+    // CHECK: call void @_ZN1BD1Ev(
+    // CHECK: br label %[[INC:.*]]
+
+    // CHECK: [[INC]]:
+    // CHECK: getelementptr {{.*}} i32 1
+    // CHECK: br label %[[COND]]
+  }
+  // CHECK: [[END]]:
+  // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+  // CHECK: ret void
+}
diff --git a/test/PCH/cxx-for-range.cpp b/test/PCH/cxx-for-range.cpp
new file mode 100644
index 0000000..5854917
--- /dev/null
+++ b/test/PCH/cxx-for-range.cpp
@@ -0,0 +1,19 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
+// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s 
+
+void h() {
+  f();
+
+  g<int>();
+
+  char a[3] = { 0, 1, 2 };
+  for (auto w : a)
+    for (auto x : S())
+      for (auto y : T())
+        for (auto z : U())
+          ;
+}
diff --git a/test/PCH/cxx-for-range.h b/test/PCH/cxx-for-range.h
new file mode 100644
index 0000000..f15c7e7
--- /dev/null
+++ b/test/PCH/cxx-for-range.h
@@ -0,0 +1,35 @@
+// Header for PCH test cxx-for-range.cpp
+
+struct S {
+  int *begin();
+  int *end();
+};
+
+struct T { };
+char *begin(T);
+char *end(T);
+
+struct U { };
+namespace std {
+  char *begin(U);
+  char *end(U);
+}
+
+void f() {
+  char a[3] = { 0, 1, 2 };
+  for (auto w : a)
+    for (auto x : S())
+      for (auto y : T())
+        for (auto z : U())
+          ;
+}
+
+template<typename A>
+void g() {
+  A a[3] = { 0, 1, 2 };
+  for (auto &v : a)
+    for (auto x : S())
+      for (auto y : T())
+        for (auto z : U())
+          ;
+}
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}}
+}