@@ -182,15 +182,20 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
182
182
183
183
let clone_usage = if local == ret_local {
184
184
CloneUsage {
185
- cloned_used : false ,
185
+ cloned_use_loc : None . into ( ) ,
186
186
cloned_consume_or_mutate_loc : None ,
187
187
clone_consumed_or_mutated : true ,
188
188
}
189
189
} else {
190
190
let clone_usage = visit_clone_usage ( local, ret_local, mir, bb) ;
191
- if clone_usage. cloned_used && clone_usage. clone_consumed_or_mutated {
191
+ if clone_usage. cloned_use_loc . maybe_used ( ) && clone_usage. clone_consumed_or_mutated {
192
192
// cloned value is used, and the clone is modified or moved
193
193
continue ;
194
+ } else if let MirLocalUsage :: Used ( loc) = clone_usage. cloned_use_loc
195
+ && possible_borrower. local_is_alive_at ( ret_local, loc)
196
+ {
197
+ // cloned value is used, and the clone is alive.
198
+ continue ;
194
199
} else if let Some ( loc) = clone_usage. cloned_consume_or_mutate_loc
195
200
// cloned value is mutated, and the clone is alive.
196
201
&& possible_borrower. local_is_alive_at ( ret_local, loc)
@@ -227,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
227
232
228
233
span_lint_hir_and_then ( cx, REDUNDANT_CLONE , node, sugg_span, "redundant clone" , |diag| {
229
234
diag. span_suggestion ( sugg_span, "remove this" , "" , app) ;
230
- if clone_usage. cloned_used {
235
+ if clone_usage. cloned_use_loc . maybe_used ( ) {
231
236
diag. span_note ( span, "cloned value is neither consumed nor mutated" ) ;
232
237
} else {
233
238
diag. span_note (
@@ -328,10 +333,33 @@ fn base_local_and_movability<'tcx>(
328
333
( place. local , deref || field || slice)
329
334
}
330
335
331
- #[ derive( Default ) ]
336
+ #[ derive( Debug , Default ) ]
337
+ enum MirLocalUsage {
338
+ /// The local maybe used, but we are not sure how.
339
+ Unknown ,
340
+ /// The local is not used.
341
+ #[ default]
342
+ Unused ,
343
+ /// The local is used at a specific location.
344
+ Used ( mir:: Location ) ,
345
+ }
346
+
347
+ impl MirLocalUsage {
348
+ fn maybe_used ( & self ) -> bool {
349
+ matches ! ( self , MirLocalUsage :: Unknown | MirLocalUsage :: Used ( _) )
350
+ }
351
+ }
352
+
353
+ impl From < Option < mir:: Location > > for MirLocalUsage {
354
+ fn from ( loc : Option < mir:: Location > ) -> Self {
355
+ loc. map_or ( MirLocalUsage :: Unused , MirLocalUsage :: Used )
356
+ }
357
+ }
358
+
359
+ #[ derive( Debug , Default ) ]
332
360
struct CloneUsage {
333
- /// Whether the cloned value is used after the clone .
334
- cloned_used : bool ,
361
+ /// The first location where the cloned value is used, if any .
362
+ cloned_use_loc : MirLocalUsage ,
335
363
/// The first location where the cloned value is consumed or mutated, if any.
336
364
cloned_consume_or_mutate_loc : Option < mir:: Location > ,
337
365
/// Whether the clone value is mutated.
@@ -359,7 +387,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
359
387
. map ( |mut vec| ( vec. remove ( 0 ) , vec. remove ( 0 ) ) )
360
388
{
361
389
CloneUsage {
362
- cloned_used : ! cloned_use_locs. is_empty ( ) ,
390
+ cloned_use_loc : cloned_use_locs. first ( ) . copied ( ) . into ( ) ,
363
391
cloned_consume_or_mutate_loc : cloned_consume_or_mutate_locs. first ( ) . copied ( ) ,
364
392
// Consider non-temporary clones consumed.
365
393
// TODO: Actually check for mutation of non-temporaries.
@@ -368,7 +396,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
368
396
}
369
397
} else {
370
398
CloneUsage {
371
- cloned_used : true ,
399
+ cloned_use_loc : MirLocalUsage :: Unknown ,
372
400
cloned_consume_or_mutate_loc : None ,
373
401
clone_consumed_or_mutated : true ,
374
402
}
0 commit comments