Skip to content

Commit e5ab1e4

Browse files
committed
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
1 parent f022a5a commit e5ab1e4

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

clang/lib/Sema/SemaStmt.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2764,9 +2764,11 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
27642764
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference)
27652765
<< NonReferenceType << NewReferenceType << VD->getSourceRange()
27662766
<< FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
2767-
} else {
2767+
} else if (!VariableType->isRValueReferenceType()) {
27682768
// The range always returns a copy, so a temporary is always created.
27692769
// Suggest removing the reference from the loop variable.
2770+
// If the type is a rvalue reference do not warn since that changes the
2771+
// semantic of the code.
27702772
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
27712773
<< VD << RangeInitType;
27722774
QualType NonReferenceType = VariableType.getNonReferenceType();

clang/test/SemaCXX/warn-range-loop-analysis.cpp

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,34 +84,46 @@ void test0() {
8484
void test1() {
8585
Container<int> A;
8686

87+
for (const int &&x : A) {}
88+
// No warning, rvalue-reference to the temporary
8789
for (const int &x : A) {}
8890
// expected-warning@-1 {{always a copy}}
8991
// expected-note@-2 {{'int'}}
9092
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
9193
for (const int x : A) {}
9294
// No warning, non-reference type indicates copy is made
95+
for (int&& x : A) {}
96+
// No warning, rvalue-reference to the temporary
9397
//for (int &x : A) {}
9498
// Binding error
9599
for (int x : A) {}
96100
// No warning, non-reference type indicates copy is made
97101

102+
for (const double &&x : A) {}
103+
// No warning, rvalue-reference to the temporary
98104
for (const double &x : A) {}
99105
// expected-warning@-1 {{always a copy}}
100106
// expected-note@-2 {{'double'}}
101107
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:""
102108
for (const double x : A) {}
103109
// No warning, non-reference type indicates copy is made
110+
for (double &&x : A) {}
111+
// No warning, rvalue-reference to the temporary
104112
//for (double &x : A) {}
105113
// Binding error
106114
for (double x : A) {}
107115
// No warning, non-reference type indicates copy is made
108116

117+
for (const Bar &&x : A) {}
118+
// No warning, rvalue-reference to the temporary
109119
for (const Bar &x : A) {}
110120
// expected-warning@-1 {{always a copy}}
111121
// expected-note@-2 {{'Bar'}}
112122
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
113123
for (const Bar x : A) {}
114124
// No warning, non-reference type indicates copy is made
125+
for (Bar &&x : A) {}
126+
// No warning, rvalue-reference to the temporary
115127
//for (Bar &x : A) {}
116128
// Binding error
117129
for (Bar x : A) {}
@@ -121,30 +133,50 @@ void test1() {
121133
void test2() {
122134
Container<int&> B;
123135

136+
//for (const int &&x : B) {}
137+
// Binding error
124138
for (const int &x : B) {}
125139
// No warning, this reference is not a temporary
126140
for (const int x : B) {}
127141
// No warning on POD copy
142+
//for (int &x : B) {}
143+
// Binding error
128144
for (int &x : B) {}
129145
// No warning
130146
for (int x : B) {}
131147
// No warning
132148

149+
for (const double &&x : B) {}
150+
// expected-warning@-1 {{resulting in a copy}}
151+
// expected-note-re@-2 {{'double'{{.*}}'const int &'}}
152+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:23}:""
133153
for (const double &x : B) {}
134154
// expected-warning@-1 {{resulting in a copy}}
135155
// expected-note-re@-2 {{'double'{{.*}}'const int &'}}
136156
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:""
137157
for (const double x : B) {}
158+
for (double &&x : B) {}
159+
// expected-warning@-1 {{resulting in a copy}}
160+
// expected-note-re@-2 {{'double'{{.*}}'const int &'}}
161+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:17}:""
138162
//for (double &x : B) {}
139163
// Binding error
140164
for (double x : B) {}
141165
// No warning
142166

167+
for (const Bar &&x : B) {}
168+
// expected-warning@-1 {{resulting in a copy}}
169+
// expected-note@-2 {{'Bar'}}
170+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
143171
for (const Bar &x : B) {}
144172
// expected-warning@-1 {{resulting in a copy}}
145173
// expected-note@-2 {{'Bar'}}
146174
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
147175
for (const Bar x : B) {}
176+
for (Bar &&x : B) {}
177+
// expected-warning@-1 {{resulting in a copy}}
178+
// expected-note@-2 {{'Bar'}}
179+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
148180
//for (Bar &x : B) {}
149181
// Binding error
150182
for (Bar x : B) {}
@@ -154,23 +186,31 @@ void test2() {
154186
void test3() {
155187
Container<Bar> C;
156188

189+
for (const Bar &&x : C) {}
190+
// No warning, rvalue-reference to the temporary
157191
for (const Bar &x : C) {}
158192
// expected-warning@-1 {{always a copy}}
159193
// expected-note@-2 {{'Bar'}}
160194
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
161195
for (const Bar x : C) {}
162196
// No warning, non-reference type indicates copy is made
197+
for (Bar &&x : C) {}
198+
// No warning, rvalue-reference to the temporary
163199
//for (Bar &x : C) {}
164200
// Binding error
165201
for (Bar x : C) {}
166202
// No warning, non-reference type indicates copy is made
167203

204+
for (const int &&x : C) {}
205+
// No warning, rvalue-reference to the temporary
168206
for (const int &x : C) {}
169207
// expected-warning@-1 {{always a copy}}
170208
// expected-note@-2 {{'int'}}
171209
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
172210
for (const int x : C) {}
173211
// No warning, copy made
212+
for (int &&x : C) {}
213+
// No warning, rvalue-reference to the temporary
174214
//for (int &x : C) {}
175215
// Binding error
176216
for (int x : C) {}
@@ -180,23 +220,35 @@ void test3() {
180220
void test4() {
181221
Container<Bar&> D;
182222

223+
//for (const Bar &&x : D) {}
224+
// Binding error
183225
for (const Bar &x : D) {}
184226
// No warning, this reference is not a temporary
185227
for (const Bar x : D) {}
186228
// expected-warning@-1 {{creates a copy}}
187229
// expected-note@-2 {{'const Bar &'}}
188230
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&"
231+
//for (Bar &&x : D) {}
232+
// Binding error
189233
for (Bar &x : D) {}
190234
// No warning
191235
for (Bar x : D) {}
192236
// No warning
193237

238+
for (const int &&x : D) {}
239+
// expected-warning@-1 {{resulting in a copy}}
240+
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
241+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
194242
for (const int &x : D) {}
195243
// expected-warning@-1 {{resulting in a copy}}
196244
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
197245
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
198246
for (const int x : D) {}
199247
// No warning
248+
for (int &&x : D) {}
249+
// expected-warning@-1 {{resulting in a copy}}
250+
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
251+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
200252
//for (int &x : D) {}
201253
// Binding error
202254
for (int x : D) {}
@@ -206,12 +258,16 @@ void test4() {
206258
void test5() {
207259
Container<Foo> E;
208260

261+
for (const Bar &&x : E) {}
262+
// No warning, rvalue-reference to the temporary
209263
for (const Bar &x : E) {}
210264
// expected-warning@-1 {{always a copy}}
211265
// expected-note@-2 {{'Bar'}}
212266
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
213267
for (const Bar x : E) {}
214268
// No warning, non-reference type indicates copy is made
269+
for (Bar &&x : E) {}
270+
// No warning, rvalue-reference to the temporary
215271
//for (Bar &x : E) {}
216272
// Binding error
217273
for (Bar x : E) {}
@@ -221,12 +277,20 @@ void test5() {
221277
void test6() {
222278
Container<Foo&> F;
223279

280+
for (const Bar &&x : F) {}
281+
// expected-warning@-1 {{resulting in a copy}}
282+
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
283+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
224284
for (const Bar &x : F) {}
225285
// expected-warning@-1 {{resulting in a copy}}
226286
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
227287
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
228288
for (const Bar x : F) {}
229289
// No warning.
290+
for (Bar &&x : F) {}
291+
// expected-warning@-1 {{resulting in a copy}}
292+
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
293+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
230294
//for (Bar &x : F) {}
231295
// Binding error
232296
for (Bar x : F) {}
@@ -236,56 +300,88 @@ void test6() {
236300
void test7() {
237301
double G[2];
238302

303+
//for (const double &&x : G) {}
304+
// Binding error
239305
for (const double &x : G) {}
240306
// No warning
241307
for (const double x : G) {}
242308
// No warning on POD copy
309+
//for (double &&x : G) {}
310+
// Binding error
243311
for (double &x : G) {}
244312
// No warning
245313
for (double x : G) {}
246314
// No warning
247315

316+
for (const int &&x : G) {}
317+
// expected-warning@-1 {{resulting in a copy}}
318+
// expected-note-re@-2 {{'int'{{.*}}'const double &'}}
319+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
248320
for (const int &x : G) {}
249321
// expected-warning@-1 {{resulting in a copy}}
250322
// expected-note-re@-2 {{'int'{{.*}}'const double &'}}
251323
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
252324
for (const int x : G) {}
253325
// No warning
326+
for (int &&x : G) {}
327+
// expected-warning@-1 {{resulting in a copy}}
328+
// expected-note-re@-2 {{'int'{{.*}}'const double &'}}
329+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
254330
//for (int &x : G) {}
255331
// Binding error
256332
for (int x : G) {}
257333
// No warning
258334

335+
for (const Bar &&x : G) {}
336+
// expected-warning@-1 {{resulting in a copy}}
337+
// expected-note-re@-2 {{'Bar'{{.*}}'const double &'}}
338+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
259339
for (const Bar &x : G) {}
260340
// expected-warning@-1 {{resulting in a copy}}
261341
// expected-note-re@-2 {{'Bar'{{.*}}'const double &'}}
262342
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
263343
for (const Bar x : G) {}
264344
// No warning
265-
//for (int &Bar : G) {}
345+
for (Bar &&x : G) {}
346+
// expected-warning@-1 {{resulting in a copy}}
347+
// expected-note-re@-2 {{'Bar'{{.*}}'const double &'}}
348+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
349+
//for (Bar &x : G) {}
266350
// Binding error
267-
for (int Bar : G) {}
351+
for (Bar x : G) {}
268352
// No warning
269353
}
270354

271355
void test8() {
272356
Foo H[2];
273357

358+
//for (const Foo &&x : H) {}
359+
// Binding error
274360
for (const Foo &x : H) {}
275361
// No warning
276362
for (const Foo x : H) {}
277363
// No warning on POD copy
364+
//for (Foo &&x : H) {}
365+
// Binding error
278366
for (Foo &x : H) {}
279367
// No warning
280368
for (Foo x : H) {}
281369
// No warning
282370

371+
for (const Bar &&x : H) {}
372+
// expected-warning@-1 {{resulting in a copy}}
373+
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
374+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
283375
for (const Bar &x : H) {}
284376
// expected-warning@-1 {{resulting in a copy}}
285377
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
286378
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
287379
for (const Bar x : H) {}
288380
// No warning
381+
for (Bar &&x: H) {}
382+
// expected-warning@-1 {{resulting in a copy}}
383+
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
384+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
289385
//for (Bar &x: H) {}
290386
// Binding error
291387
for (Bar x: H) {}
@@ -295,23 +391,35 @@ void test8() {
295391
void test9() {
296392
Bar I[2] = {1,2};
297393

394+
//for (const Bar &&x : I) {}
395+
// Binding error
298396
for (const Bar &x : I) {}
299397
// No warning
300398
for (const Bar x : I) {}
301399
// expected-warning@-1 {{creates a copy}}
302400
// expected-note@-2 {{'const Bar &'}}
303401
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&"
402+
//for (Bar &&x : I) {}
403+
// Binding error
304404
for (Bar &x : I) {}
305405
// No warning
306406
for (Bar x : I) {}
307407
// No warning
308408

409+
for (const int &&x : I) {}
410+
// expected-warning@-1 {{resulting in a copy}}
411+
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
412+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
309413
for (const int &x : I) {}
310414
// expected-warning@-1 {{resulting in a copy}}
311415
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
312416
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
313417
for (const int x : I) {}
314418
// No warning
419+
for (int &&x : I) {}
420+
// expected-warning@-1 {{resulting in a copy}}
421+
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
422+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:14}:""
315423
//for (int &x : I) {}
316424
// Binding error
317425
for (int x : I) {}

0 commit comments

Comments
 (0)