// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wall -Wrange-loop-bind-reference -Wno-unused -verify %s // 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 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wloop-analysis -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s template struct Iterator { return_type operator*(); Iterator operator++(); bool operator!=(const Iterator); }; template struct Container { typedef Iterator I; I begin(); I end(); }; struct Foo {}; struct Bar { // Small trivially copyable types do not show a warning when copied in a // range-based for loop. This size ensures the object is not considered // small. char s[128]; 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_non_ref_container; Container int_container; Container bar_container; for (const int &x : int_non_ref_container) {} // expected-warning@-1 {{loop variable 'x' binds to a temporary value produced by a range of type 'Container'}} // expected-note@-2 {{use non-reference type 'int'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const double &x : int_container) {} // expected-warning@-1 {{loop variable 'x' of type 'const double &' binds to a temporary constructed from type 'int &'}} // expected-note@-2 {{use non-reference type 'double' to make construction explicit or type 'const int &' to prevent copying}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:"" for (const Bar x : bar_container) {} // expected-warning@-1 {{loop variable 'x' creates a copy from type 'const Bar'}} // expected-note@-2 {{use reference type 'const Bar &' to prevent copying}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&" } void test1() { Container A; for (const int &&x : A) {} // No warning, rvalue-reference to the temporary for (const int &x : A) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'int'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const int x : A) {} // No warning, non-reference type indicates copy is made for (int&& x : A) {} // No warning, rvalue-reference to the temporary //for (int &x : A) {} // Binding error for (int x : A) {} // No warning, non-reference type indicates copy is made for (const double &&x : A) {} // No warning, rvalue-reference to the temporary for (const double &x : A) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'double'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:"" for (const double x : A) {} // No warning, non-reference type indicates copy is made for (double &&x : A) {} // No warning, rvalue-reference to the temporary //for (double &x : A) {} // Binding error for (double x : A) {} // No warning, non-reference type indicates copy is made for (const Bar &&x : A) {} // No warning, rvalue-reference to the temporary for (const Bar &x : A) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : A) {} // No warning, non-reference type indicates copy is made for (Bar &&x : A) {} // No warning, rvalue-reference to the temporary //for (Bar &x : A) {} // Binding error for (Bar x : A) {} // No warning, non-reference type indicates copy is made } void test2() { Container B; //for (const int &&x : B) {} // Binding error 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) {} // Binding error for (int &x : B) {} // No warning for (int x : B) {} // No warning for (const double &&x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'double'{{.*}}'const int &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:23}:"" for (const double &x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'double'{{.*}}'const int &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:"" for (const double x : B) {} for (double &&x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'double'{{.*}}'const int &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:17}:"" //for (double &x : B) {} // Binding error for (double x : B) {} // No warning for (const Bar &&x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : B) {} for (Bar &&x : B) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (Bar &x : B) {} // Binding error for (Bar x : B) {} // No warning } void test3() { Container C; for (const Bar &&x : C) {} // No warning, rvalue-reference to the temporary for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : C) {} // No warning, non-reference type indicates copy is made for (Bar &&x : C) {} // No warning, rvalue-reference to the temporary //for (Bar &x : C) {} // Binding error for (Bar x : C) {} // No warning, non-reference type indicates copy is made for (const int &&x : C) {} // No warning, rvalue-reference to the temporary for (const int &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'int'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const int x : C) {} // No warning, copy made for (int &&x : C) {} // No warning, rvalue-reference to the temporary //for (int &x : C) {} // Binding error for (int x : C) {} // No warning, copy made } void test4() { Container D; //for (const Bar &&x : D) {} // Binding error 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 &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&" //for (Bar &&x : D) {} // Binding error for (Bar &x : D) {} // No warning for (Bar x : D) {} // No warning for (const int &&x : D) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : D) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const int x : D) {} // No warning for (int &&x : D) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (int &x : D) {} // Binding error for (int x : D) {} // No warning } void test5() { Container E; for (const Bar &&x : E) {} // No warning, rvalue-reference to the temporary for (const Bar &x : E) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : E) {} // No warning, non-reference type indicates copy is made for (Bar &&x : E) {} // No warning, rvalue-reference to the temporary //for (Bar &x : E) {} // Binding error for (Bar x : E) {} // No warning, non-reference type indicates copy is made } void test6() { Container F; for (const Bar &&x : F) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : F) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : F) {} // No warning. for (Bar &&x : F) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (Bar &x : F) {} // Binding error for (Bar x : F) {} // No warning } void test7() { double G[2]; //for (const double &&x : G) {} // Binding error for (const double &x : G) {} // No warning for (const double x : G) {} // No warning on POD copy //for (double &&x : G) {} // Binding error for (double &x : G) {} // No warning for (double x : G) {} // No warning for (const int &&x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const int x : G) {} // No warning for (int &&x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (int &x : G) {} // Binding error for (int x : G) {} // No warning for (const Bar &&x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : G) {} // No warning for (Bar &&x : G) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (Bar &x : G) {} // Binding error for (Bar x : G) {} // No warning } void test8() { Foo H[2]; //for (const Foo &&x : H) {} // Binding error for (const Foo &x : H) {} // No warning for (const Foo x : H) {} // No warning on POD copy //for (Foo &&x : H) {} // Binding error for (Foo &x : H) {} // No warning for (Foo x : H) {} // No warning for (const Bar &&x : H) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : H) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : H) {} // No warning for (Bar &&x: H) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (Bar &x: H) {} // Binding error for (Bar x: H) {} // No warning } void test9() { Bar I[2] = {1,2}; //for (const Bar &&x : I) {} // Binding error for (const Bar &x : I) {} // No warning for (const Bar x : I) {} // expected-warning@-1 {{creates a copy}} // expected-note@-2 {{'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&" //for (Bar &&x : I) {} // Binding error for (Bar &x : I) {} // No warning for (Bar x : I) {} // No warning for (const int &&x : I) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : I) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const int x : I) {} // No warning for (int &&x : I) {} // expected-warning@-1 {{binds to a temporary constructed from}} // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (int &x : I) {} // Binding error for (int x : I) {} // No warning } void test10() { Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar& x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:"" for (const Bar & x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar&x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:" " } template void test_template_function() { // In a template instantiation the diagnostics should not be emitted for // loops with dependent types. Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" Container Dependent; for (const T &x : Dependent) {} } template void test_template_function(); template struct test_template_struct { static void static_member() { Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:"" Container Dependent; for (const T &x : Dependent) {} } void member() { Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:"" Container Dependent; for (const T &x : Dependent) {} } }; template struct test_template_struct; struct test_struct_with_templated_member { void member() { Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:"" } template void template_member() { Container C; for (const Bar &x : C) {} // expected-warning@-1 {{binds to a temporary value produced by a range}} // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:"" Container Dependent; for (const T &x : Dependent) {} } }; template void test_struct_with_templated_member::template_member(); #define TEST_MACRO \ void test_macro() { \ Container C; \ for (const Bar &x : C) {} \ } TEST_MACRO