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}}
+}