diff options
author | Mark de Wever <koraq@xs4all.nl> | 2020-01-01 17:23:20 +0100 |
---|---|---|
committer | Mark de Wever <koraq@xs4all.nl> | 2020-01-01 20:02:18 +0100 |
commit | e5ab1e49f958cd8388bab617819ba78167e557d3 (patch) | |
tree | 72294366f36eede9f7c75016c636bac63b44805a | |
parent | f022a5a792fd39a4c33f49583d24d96c70177066 (diff) | |
download | bcm5719-llvm-e5ab1e49f958cd8388bab617819ba78167e557d3.tar.gz bcm5719-llvm-e5ab1e49f958cd8388bab617819ba78167e557d3.zip |
Improve Wrange-loop-analyses for rvalue reference
The Wrange-loop-analyses warns if a copy is made. Suppress this warning when
a temporary is bound to a rvalue reference.
While fixing this issue also found a copy-paste error in test6, which is also
fixed.
Differential Revision: https://reviews.llvm.org/D71806
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 4 | ||||
-rw-r--r-- | clang/test/SemaCXX/warn-range-loop-analysis.cpp | 112 |
2 files changed, 113 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 959adbf1c35..1e7cc503d8c 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2764,9 +2764,11 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference) << NonReferenceType << NewReferenceType << VD->getSourceRange() << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc()); - } else { + } else if (!VariableType->isRValueReferenceType()) { // The range always returns a copy, so a temporary is always created. // Suggest removing the reference from the loop variable. + // If the type is a rvalue reference do not warn since that changes the + // semantic of the code. SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy) << VD << RangeInitType; QualType NonReferenceType = VariableType.getNonReferenceType(); diff --git a/clang/test/SemaCXX/warn-range-loop-analysis.cpp b/clang/test/SemaCXX/warn-range-loop-analysis.cpp index a4db9e7b681..21c57479936 100644 --- a/clang/test/SemaCXX/warn-range-loop-analysis.cpp +++ b/clang/test/SemaCXX/warn-range-loop-analysis.cpp @@ -84,34 +84,46 @@ void test0() { void test1() { Container<int> A; + for (const int &&x : A) {} + // No warning, rvalue-reference to the temporary for (const int &x : A) {} // expected-warning@-1 {{always a copy}} // 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 {{always a copy}} // 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 {{always a copy}} // 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) {} @@ -121,30 +133,50 @@ void test1() { void test2() { Container<int&> 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 {{resulting in a copy}} + // expected-note-re@-2 {{'double'{{.*}}'const int &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:23}:"" for (const double &x : B) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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 {{resulting in a copy}} + // expected-note@-2 {{'Bar'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : B) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // expected-note@-2 {{'Bar'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" //for (Bar &x : B) {} // Binding error for (Bar x : B) {} @@ -154,23 +186,31 @@ void test2() { void test3() { Container<Bar> C; + for (const Bar &&x : C) {} + // No warning, rvalue-reference to the temporary for (const Bar &x : C) {} // expected-warning@-1 {{always a copy}} // 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 {{always a copy}} // 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) {} @@ -180,23 +220,35 @@ void test3() { void test4() { Container<Bar&> 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 {{resulting in a copy}} + // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : D) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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) {} @@ -206,12 +258,16 @@ void test4() { void test5() { Container<Foo> E; + for (const Bar &&x : E) {} + // No warning, rvalue-reference to the temporary for (const Bar &x : E) {} // expected-warning@-1 {{always a copy}} // 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) {} @@ -221,12 +277,20 @@ void test5() { void test6() { Container<Foo&> F; + for (const Bar &&x : F) {} + // expected-warning@-1 {{resulting in a copy}} + // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : F) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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) {} @@ -236,56 +300,88 @@ void test6() { 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 {{resulting in a copy}} + // expected-note-re@-2 {{'int'{{.*}}'const double &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : G) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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 {{resulting in a copy}} + // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : G) {} // expected-warning@-1 {{resulting in a copy}} // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:"" for (const Bar x : G) {} // No warning - //for (int &Bar : G) {} + for (Bar &&x : G) {} + // expected-warning@-1 {{resulting in a copy}} + // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:"" + //for (Bar &x : G) {} // Binding error - for (int Bar : G) {} + 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 {{resulting in a copy}} + // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const Bar &x : H) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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) {} @@ -295,23 +391,35 @@ void test8() { 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 {{resulting in a copy}} + // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:"" for (const int &x : I) {} // expected-warning@-1 {{resulting in a copy}} // 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 {{resulting in a copy}} + // 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) {} |