11use clippy_utils:: diagnostics:: { span_lint_hir, span_lint_hir_and_then} ;
2+ use clippy_utils:: mir:: { visit_local_usage, LocalUsage } ;
23use clippy_utils:: source:: snippet_opt;
34use clippy_utils:: ty:: { has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth} ;
45use clippy_utils:: { fn_has_unsatisfiable_preds, match_def_path, paths} ;
@@ -7,10 +8,7 @@ use rustc_errors::Applicability;
78use rustc_hir:: intravisit:: FnKind ;
89use rustc_hir:: { def_id, Body , FnDecl , HirId } ;
910use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_middle:: mir:: {
11- self , traversal,
12- visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor as _} ,
13- } ;
11+ use rustc_middle:: mir:: { self , visit:: Visitor as _} ;
1412use rustc_middle:: ty:: { self , Ty } ;
1513use rustc_mir_dataflow:: Analysis ;
1614use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -381,86 +379,42 @@ struct CloneUsage {
381379 /// Whether the clone value is mutated.
382380 clone_consumed_or_mutated : bool ,
383381}
384- fn visit_clone_usage ( cloned : mir:: Local , clone : mir:: Local , mir : & mir:: Body < ' _ > , bb : mir:: BasicBlock ) -> CloneUsage {
385- struct V {
386- cloned : mir:: Local ,
387- clone : mir:: Local ,
388- result : CloneUsage ,
389- }
390- impl < ' tcx > mir:: visit:: Visitor < ' tcx > for V {
391- fn visit_basic_block_data ( & mut self , block : mir:: BasicBlock , data : & mir:: BasicBlockData < ' tcx > ) {
392- let statements = & data. statements ;
393- for ( statement_index, statement) in statements. iter ( ) . enumerate ( ) {
394- self . visit_statement ( statement, mir:: Location { block, statement_index } ) ;
395- }
396382
397- self . visit_terminator (
398- data. terminator ( ) ,
399- mir:: Location {
400- block,
401- statement_index : statements. len ( ) ,
402- } ,
403- ) ;
383+ fn visit_clone_usage ( cloned : mir:: Local , clone : mir:: Local , mir : & mir:: Body < ' _ > , bb : mir:: BasicBlock ) -> CloneUsage {
384+ if let Some (
385+ & [
386+ LocalUsage {
387+ local_use_loc : cloned_use_loc,
388+ local_consume_or_mutate_loc : cloned_consume_or_mutate_loc,
389+ } ,
390+ LocalUsage {
391+ local_use_loc : _,
392+ local_consume_or_mutate_loc : clone_consume_or_mutate_loc,
393+ } ,
394+ ] ,
395+ ) = visit_local_usage (
396+ & [ cloned, clone] ,
397+ mir,
398+ mir:: Location {
399+ block : bb,
400+ statement_index : mir. basic_blocks [ bb] . statements . len ( ) ,
401+ } ,
402+ )
403+ . as_deref ( )
404+ {
405+ CloneUsage {
406+ cloned_used : cloned_use_loc. is_some ( ) ,
407+ cloned_consume_or_mutate_loc,
408+ // Consider non-temporary clones consumed.
409+ // TODO: Actually check for mutation of non-temporaries.
410+ clone_consumed_or_mutated : mir. local_kind ( clone) != mir:: LocalKind :: Temp
411+ || clone_consume_or_mutate_loc. is_some ( ) ,
404412 }
405-
406- fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , ctx : PlaceContext , loc : mir:: Location ) {
407- let local = place. local ;
408-
409- if local == self . cloned
410- && !matches ! (
411- ctx,
412- PlaceContext :: MutatingUse ( MutatingUseContext :: Drop ) | PlaceContext :: NonUse ( _)
413- )
414- {
415- self . result . cloned_used = true ;
416- self . result . cloned_consume_or_mutate_loc = self . result . cloned_consume_or_mutate_loc . or_else ( || {
417- matches ! (
418- ctx,
419- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Move )
420- | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
421- )
422- . then ( || loc)
423- } ) ;
424- } else if local == self . clone {
425- match ctx {
426- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Move )
427- | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow ) => {
428- self . result . clone_consumed_or_mutated = true ;
429- } ,
430- _ => { } ,
431- }
432- }
413+ } else {
414+ CloneUsage {
415+ cloned_used : true ,
416+ cloned_consume_or_mutate_loc : None ,
417+ clone_consumed_or_mutated : true ,
433418 }
434419 }
435-
436- let init = CloneUsage {
437- cloned_used : false ,
438- cloned_consume_or_mutate_loc : None ,
439- // Consider non-temporary clones consumed.
440- // TODO: Actually check for mutation of non-temporaries.
441- clone_consumed_or_mutated : mir. local_kind ( clone) != mir:: LocalKind :: Temp ,
442- } ;
443- traversal:: ReversePostorder :: new ( mir, bb)
444- . skip ( 1 )
445- . fold ( init, |usage, ( tbb, tdata) | {
446- // Short-circuit
447- if ( usage. cloned_used && usage. clone_consumed_or_mutated ) ||
448- // Give up on loops
449- tdata. terminator ( ) . successors ( ) . any ( |s| s == bb)
450- {
451- return CloneUsage {
452- cloned_used : true ,
453- clone_consumed_or_mutated : true ,
454- ..usage
455- } ;
456- }
457-
458- let mut v = V {
459- cloned,
460- clone,
461- result : usage,
462- } ;
463- v. visit_basic_block_data ( tbb, tdata) ;
464- v. result
465- } )
466420}
0 commit comments