@@ -12,6 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
12
12
use rustc_middle:: mir:: {
13
13
self , traversal,
14
14
visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor as _} ,
15
+ Mutability ,
15
16
} ;
16
17
use rustc_middle:: ty:: { self , fold:: TypeVisitor , Ty } ;
17
18
use rustc_mir:: dataflow:: { Analysis , AnalysisDomain , GenKill , GenKillAnalysis , ResultsCursor } ;
@@ -87,13 +88,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
87
88
88
89
let mir = cx. tcx . optimized_mir ( def_id. to_def_id ( ) ) ;
89
90
91
+ let possible_borrowed = {
92
+ let mut vis = PossibleBorrowedVisitor :: new ( mir) ;
93
+ vis. visit_body ( mir) ;
94
+ vis. into_map ( cx)
95
+ } ;
90
96
let maybe_storage_live_result = MaybeStorageLive
91
97
. into_engine ( cx. tcx , mir)
92
98
. pass_name ( "redundant_clone" )
93
99
. iterate_to_fixpoint ( )
94
100
. into_results_cursor ( mir) ;
95
101
let mut possible_borrower = {
96
- let mut vis = PossibleBorrowerVisitor :: new ( cx, mir) ;
102
+ let mut vis = PossibleBorrowerVisitor :: new ( cx, mir, possible_borrowed ) ;
97
103
vis. visit_body ( mir) ;
98
104
vis. into_map ( cx, maybe_storage_live_result)
99
105
} ;
@@ -509,14 +515,20 @@ struct PossibleBorrowerVisitor<'a, 'tcx> {
509
515
possible_borrower : TransitiveRelation < mir:: Local > ,
510
516
body : & ' a mir:: Body < ' tcx > ,
511
517
cx : & ' a LateContext < ' tcx > ,
518
+ possible_borrowed : FxHashMap < mir:: Local , HybridBitSet < mir:: Local > > ,
512
519
}
513
520
514
521
impl < ' a , ' tcx > PossibleBorrowerVisitor < ' a , ' tcx > {
515
- fn new ( cx : & ' a LateContext < ' tcx > , body : & ' a mir:: Body < ' tcx > ) -> Self {
522
+ fn new (
523
+ cx : & ' a LateContext < ' tcx > ,
524
+ body : & ' a mir:: Body < ' tcx > ,
525
+ possible_borrowed : FxHashMap < mir:: Local , HybridBitSet < mir:: Local > > ,
526
+ ) -> Self {
516
527
Self {
517
528
possible_borrower : TransitiveRelation :: default ( ) ,
518
529
cx,
519
530
body,
531
+ possible_borrowed,
520
532
}
521
533
}
522
534
@@ -585,21 +597,109 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
585
597
..
586
598
} = & terminator. kind
587
599
{
600
+ // TODO add doc
588
601
// If the call returns something with lifetimes,
589
602
// let's conservatively assume the returned value contains lifetime of all the arguments.
590
603
// For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
591
- if ContainsRegion . visit_ty ( self . body . local_decls [ * dest ] . ty ) . is_continue ( ) {
592
- return ;
593
- }
604
+
605
+ let mut immutable_borrowers = vec ! [ ] ;
606
+ let mut mutable_borrowers = vec ! [ ] ;
594
607
595
608
for op in args {
596
609
match op {
597
610
mir:: Operand :: Copy ( p) | mir:: Operand :: Move ( p) => {
598
- self . possible_borrower . add ( p. local , * dest) ;
611
+ if let ty:: Ref ( _, _, Mutability :: Mut ) = self . body . local_decls [ p. local ] . ty . kind ( ) {
612
+ mutable_borrowers. push ( p. local ) ;
613
+ } else {
614
+ immutable_borrowers. push ( p. local ) ;
615
+ }
599
616
} ,
600
617
mir:: Operand :: Constant ( ..) => ( ) ,
601
618
}
602
619
}
620
+
621
+ let mut mutable_variables: Vec < mir:: Local > = mutable_borrowers
622
+ . iter ( )
623
+ // TODO why possible_borrowed not found?
624
+ . filter_map ( |r| self . possible_borrowed . get ( r) )
625
+ . flat_map ( |r| r. iter ( ) )
626
+ . collect ( ) ;
627
+
628
+ if ContainsRegion . visit_ty ( self . body . local_decls [ * dest] . ty ) . is_break ( ) {
629
+ mutable_variables. push ( * dest) ;
630
+ }
631
+
632
+ for y in mutable_variables {
633
+ for x in & immutable_borrowers {
634
+ self . possible_borrower . add ( * x, y) ;
635
+ }
636
+ for x in & mutable_borrowers {
637
+ self . possible_borrower . add ( * x, y) ;
638
+ }
639
+ }
640
+ }
641
+ }
642
+ }
643
+
644
+ /// Collect possible borrowed for every `&mut` local.
645
+ /// For exampel, `_1 = &mut _2` generate _1: {_2,...}
646
+ /// Known Problems: not sure all borrowed are tracked
647
+ struct PossibleBorrowedVisitor < ' a , ' tcx > {
648
+ possible_borrowed : TransitiveRelation < mir:: Local > ,
649
+ body : & ' a mir:: Body < ' tcx > ,
650
+ }
651
+
652
+ impl < ' a , ' tcx > PossibleBorrowedVisitor < ' a , ' tcx > {
653
+ fn new ( body : & ' a mir:: Body < ' tcx > ) -> Self {
654
+ Self {
655
+ possible_borrowed : TransitiveRelation :: default ( ) ,
656
+ body,
657
+ }
658
+ }
659
+
660
+ fn into_map ( self , cx : & LateContext < ' tcx > ) -> FxHashMap < mir:: Local , HybridBitSet < mir:: Local > > {
661
+ let mut map = FxHashMap :: default ( ) ;
662
+ for row in ( 1 ..self . body . local_decls . len ( ) ) . map ( mir:: Local :: from_usize) {
663
+ if is_copy ( cx, self . body . local_decls [ row] . ty ) {
664
+ continue ;
665
+ }
666
+
667
+ let borrowers = self . possible_borrowed . reachable_from ( & row) ;
668
+ if !borrowers. is_empty ( ) {
669
+ let mut bs = HybridBitSet :: new_empty ( self . body . local_decls . len ( ) ) ;
670
+ for & c in borrowers {
671
+ if c != mir:: Local :: from_usize ( 0 ) {
672
+ bs. insert ( c) ;
673
+ }
674
+ }
675
+
676
+ if !bs. is_empty ( ) {
677
+ map. insert ( row, bs) ;
678
+ }
679
+ }
680
+ }
681
+ map
682
+ }
683
+ }
684
+
685
+ impl < ' a , ' tcx > mir:: visit:: Visitor < ' tcx > for PossibleBorrowedVisitor < ' a , ' tcx > {
686
+ fn visit_assign ( & mut self , place : & mir:: Place < ' tcx > , rvalue : & mir:: Rvalue < ' _ > , _location : mir:: Location ) {
687
+ let lhs = place. local ;
688
+ match rvalue {
689
+ // Only consider `&mut`, which can modify origin place
690
+ mir:: Rvalue :: Ref ( _, rustc_middle:: mir:: BorrowKind :: Mut { .. } , borrowed) => {
691
+ self . possible_borrowed . add ( lhs, borrowed. local ) ;
692
+ } ,
693
+ // _2: &mut _;
694
+ // _3 = move _2
695
+ mir:: Rvalue :: Use ( mir:: Operand :: Move ( borrowed) ) =>{
696
+ self . possible_borrowed . add ( lhs, borrowed. local ) ;
697
+ }
698
+ // _3 = move _2 as &mut _;
699
+ mir:: Rvalue :: Cast ( _, mir:: Operand :: Move ( borrowed) , _) =>{
700
+ self . possible_borrowed . add ( lhs, borrowed. local ) ;
701
+ }
702
+ _ => { } ,
603
703
}
604
704
}
605
705
}
0 commit comments