forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			300 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
| // 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
 | |
| }
 |