|  | // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wloop-analysis -verify %s | 
|  | // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wrange-loop-analysis -verify %s | 
|  |  | 
|  | template <typename return_type> | 
|  | struct Iterator { | 
|  | return_type operator*(); | 
|  | Iterator operator++(); | 
|  | bool operator!=(const Iterator); | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | struct Container { | 
|  | typedef Iterator<T> I; | 
|  |  | 
|  | I begin(); | 
|  | I end(); | 
|  | }; | 
|  |  | 
|  | struct Foo {}; | 
|  | struct Bar { | 
|  | Bar(Foo); | 
|  | Bar(int); | 
|  | operator int(); | 
|  | }; | 
|  |  | 
|  | // Testing notes: | 
|  | // test0 checks that the full text of the warnings and notes is correct.  The | 
|  | //   rest of the tests checks a smaller portion of the text. | 
|  | // test1-6 are set in pairs, the odd numbers are the non-reference returning | 
|  | //   versions of the even numbers. | 
|  | // test7-9 use an array instead of a range object | 
|  | // tests use all four versions of the loop variable, const &T, const T, T&, and | 
|  | //   T.  Versions producing errors and are commented out. | 
|  | // | 
|  | // Conversion chart: | 
|  | //   double <=> int | 
|  | //   int    <=> Bar | 
|  | //   double  => Bar | 
|  | //   Foo     => Bar | 
|  | // | 
|  | // Conversions during tests: | 
|  | // test1-2 | 
|  | //   int => int | 
|  | //   int => double | 
|  | //   int => Bar | 
|  | // test3-4 | 
|  | //   Bar => Bar | 
|  | //   Bar => int | 
|  | // test5-6 | 
|  | //   Foo => Bar | 
|  | // test7 | 
|  | //   double => double | 
|  | //   double => int | 
|  | //   double => Bar | 
|  | // test8 | 
|  | //   Foo => Foo | 
|  | //   Foo => Bar | 
|  | // test9 | 
|  | //   Bar => Bar | 
|  | //   Bar => int | 
|  |  | 
|  | void test0() { | 
|  | Container<int> int_non_ref_container; | 
|  | Container<int&> int_container; | 
|  | Container<Bar&> bar_container; | 
|  |  | 
|  | for (const int &x : int_non_ref_container) {} | 
|  | // expected-warning@-1 {{loop variable 'x' is always a copy because the range of type 'Container<int>' does not return a reference}} | 
|  | // expected-note@-2 {{use non-reference type 'int'}} | 
|  |  | 
|  | for (const double &x : int_container) {} | 
|  | // expected-warning@-1 {{loop variable 'x' has type 'const double &' but is initialized with type 'int' resulting in a copy}} | 
|  | // expected-note@-2 {{use non-reference type 'double' to keep the copy or type 'const int &' to prevent copying}} | 
|  |  | 
|  | for (const Bar x : bar_container) {} | 
|  | // expected-warning@-1 {{loop variable 'x' of type 'const Bar' creates a copy from type 'const Bar'}} | 
|  | // expected-note@-2 {{use reference type 'const Bar &' to prevent copying}} | 
|  | } | 
|  |  | 
|  | void test1() { | 
|  | Container<int> A; | 
|  |  | 
|  | for (const int &x : A) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'int'}} | 
|  | for (const int x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | //for (int &x : A) {} | 
|  | // Binding error | 
|  | for (int x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  |  | 
|  | for (const double &x : A) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'double'}} | 
|  | for (const double x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | //for (double &x : A) {} | 
|  | // Binding error | 
|  | for (double x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  |  | 
|  | for (const Bar &x : A) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'Bar'}} | 
|  | for (const Bar x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | //for (Bar &x : A) {} | 
|  | // Binding error | 
|  | for (Bar x : A) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | } | 
|  |  | 
|  | void test2() { | 
|  | Container<int&> B; | 
|  |  | 
|  | for (const int &x : B) {} | 
|  | // No warning, this reference is not a temporary | 
|  | for (const int x : B) {} | 
|  | // No warning on POD copy | 
|  | for (int &x : B) {} | 
|  | // No warning | 
|  | for (int x : B) {} | 
|  | // No warning | 
|  |  | 
|  | for (const double &x : B) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'double'{{.*}}'const int &'}} | 
|  | for (const double x : B) {} | 
|  | //for (double &x : B) {} | 
|  | // Binding error | 
|  | for (double x : B) {} | 
|  | // No warning | 
|  |  | 
|  | for (const Bar &x : B) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note@-2 {{'Bar'}} | 
|  | for (const Bar x : B) {} | 
|  | //for (Bar &x : B) {} | 
|  | // Binding error | 
|  | for (Bar x : B) {} | 
|  | // No warning | 
|  | } | 
|  |  | 
|  | void test3() { | 
|  | Container<Bar> C; | 
|  |  | 
|  | for (const Bar &x : C) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'Bar'}} | 
|  | for (const Bar x : C) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | //for (Bar &x : C) {} | 
|  | // Binding error | 
|  | for (Bar x : C) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  |  | 
|  | for (const int &x : C) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'int'}} | 
|  | for (const int x : C) {} | 
|  | // No warning, copy made | 
|  | //for (int &x : C) {} | 
|  | // Binding error | 
|  | for (int x : C) {} | 
|  | // No warning, copy made | 
|  | } | 
|  |  | 
|  | void test4() { | 
|  | Container<Bar&> D; | 
|  |  | 
|  | for (const Bar &x : D) {} | 
|  | // No warning, this reference is not a temporary | 
|  | for (const Bar x : D) {} | 
|  | // expected-warning@-1 {{creates a copy}} | 
|  | // expected-note@-2 {{'const Bar &'}} | 
|  | for (Bar &x : D) {} | 
|  | // No warning | 
|  | for (Bar x : D) {} | 
|  | // No warning | 
|  |  | 
|  | for (const int &x : D) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} | 
|  | for (const int x : D) {} | 
|  | // No warning | 
|  | //for (int &x : D) {} | 
|  | // Binding error | 
|  | for (int x : D) {} | 
|  | // No warning | 
|  | } | 
|  |  | 
|  | void test5() { | 
|  | Container<Foo> E; | 
|  |  | 
|  | for (const Bar &x : E) {} | 
|  | // expected-warning@-1 {{always a copy}} | 
|  | // expected-note@-2 {{'Bar'}} | 
|  | for (const Bar x : E) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | //for (Bar &x : E) {} | 
|  | // Binding error | 
|  | for (Bar x : E) {} | 
|  | // No warning, non-reference type indicates copy is made | 
|  | } | 
|  |  | 
|  | void test6() { | 
|  | Container<Foo&> F; | 
|  |  | 
|  | for (const Bar &x : F) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} | 
|  | for (const Bar x : F) {} | 
|  | // No warning. | 
|  | //for (Bar &x : F) {} | 
|  | // Binding error | 
|  | for (Bar x : F) {} | 
|  | // No warning | 
|  | } | 
|  |  | 
|  | void test7() { | 
|  | double G[2]; | 
|  |  | 
|  | for (const double &x : G) {} | 
|  | // No warning | 
|  | for (const double x : G) {} | 
|  | // No warning on POD copy | 
|  | for (double &x : G) {} | 
|  | // No warning | 
|  | for (double x : G) {} | 
|  | // No warning | 
|  |  | 
|  | for (const int &x : G) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'int'{{.*}}'const double &'}} | 
|  | for (const int x : G) {} | 
|  | // No warning | 
|  | //for (int &x : G) {} | 
|  | // Binding error | 
|  | for (int x : G) {} | 
|  | // No warning | 
|  |  | 
|  | for (const Bar &x : G) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} | 
|  | for (const Bar x : G) {} | 
|  | // No warning | 
|  | //for (int &Bar : G) {} | 
|  | // Binding error | 
|  | for (int Bar : G) {} | 
|  | // No warning | 
|  | } | 
|  |  | 
|  | void test8() { | 
|  | Foo H[2]; | 
|  |  | 
|  | for (const Foo &x : H) {} | 
|  | // No warning | 
|  | for (const Foo x : H) {} | 
|  | // No warning on POD copy | 
|  | for (Foo &x : H) {} | 
|  | // No warning | 
|  | for (Foo x : H) {} | 
|  | // No warning | 
|  |  | 
|  | for (const Bar &x : H) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} | 
|  | for (const Bar x : H) {} | 
|  | // No warning | 
|  | //for (Bar &x: H) {} | 
|  | // Binding error | 
|  | for (Bar x: H) {} | 
|  | // No warning | 
|  | } | 
|  |  | 
|  | void test9() { | 
|  | Bar I[2] = {1,2}; | 
|  |  | 
|  | for (const Bar &x : I) {} | 
|  | // No warning | 
|  | for (const Bar x : I) {} | 
|  | // expected-warning@-1 {{creates a copy}} | 
|  | // expected-note@-2 {{'const Bar &'}} | 
|  | for (Bar &x : I) {} | 
|  | // No warning | 
|  | for (Bar x : I) {} | 
|  | // No warning | 
|  |  | 
|  | for (const int &x : I) {} | 
|  | // expected-warning@-1 {{resulting in a copy}} | 
|  | // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} | 
|  | for (const int x : I) {} | 
|  | // No warning | 
|  | //for (int &x : I) {} | 
|  | // Binding error | 
|  | for (int x : I) {} | 
|  | // No warning | 
|  | } |