@@ -40,6 +40,8 @@ enum CaptureKind {
4040struct Access {
4141 /// Describe the current access.
4242 kind : AccessKind ,
43+ /// MIR location where this access happens.
44+ location : Location ,
4345 /// Is the accessed place is live at the current statement?
4446 /// When we encounter multiple statements at the same location, we only increase the liveness,
4547 /// in order to avoid false positives.
@@ -648,26 +650,30 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
648650 & checked_places. places ,
649651 ) ;
650652
651- let mut check_place =
652- |place : Place < ' tcx > , kind, source_info : SourceInfo , live : & DenseBitSet < PlaceIndex > | {
653- if let Some ( ( index, extra_projections) ) = checked_places. get ( place. as_ref ( ) ) {
654- if !is_indirect ( extra_projections) {
655- let is_direct = extra_projections. is_empty ( ) ;
656- match assignments[ index] . entry ( source_info) {
657- IndexEntry :: Vacant ( v) => {
658- let access = Access { kind, live : live. contains ( index) , is_direct } ;
659- v. insert ( access) ;
660- }
661- IndexEntry :: Occupied ( mut o) => {
662- // There were already a sighting. Mark this statement as live if it
663- // was, to avoid false positives.
664- o. get_mut ( ) . live |= live. contains ( index) ;
665- o. get_mut ( ) . is_direct &= is_direct;
666- }
653+ let mut check_place = |place : Place < ' tcx > ,
654+ kind,
655+ source_info : SourceInfo ,
656+ location : Location ,
657+ live : & DenseBitSet < PlaceIndex > | {
658+ if let Some ( ( index, extra_projections) ) = checked_places. get ( place. as_ref ( ) ) {
659+ if !is_indirect ( extra_projections) {
660+ let is_direct = extra_projections. is_empty ( ) ;
661+ match assignments[ index] . entry ( source_info) {
662+ IndexEntry :: Vacant ( v) => {
663+ let access =
664+ Access { kind, location, live : live. contains ( index) , is_direct } ;
665+ v. insert ( access) ;
666+ }
667+ IndexEntry :: Occupied ( mut o) => {
668+ // There were already a sighting. Mark this statement as live if it
669+ // was, to avoid false positives.
670+ o. get_mut ( ) . live |= live. contains ( index) ;
671+ o. get_mut ( ) . is_direct &= is_direct;
667672 }
668673 }
669674 }
670- } ;
675+ }
676+ } ;
671677
672678 let mut record_drop = |place : Place < ' tcx > | {
673679 if let Some ( ( index, & [ ] ) ) = checked_places. get ( place. as_ref ( ) ) {
@@ -684,7 +690,13 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
684690 match & terminator. kind {
685691 TerminatorKind :: Call { destination : place, .. }
686692 | TerminatorKind :: Yield { resume_arg : place, .. } => {
687- check_place ( * place, AccessKind :: Assign , terminator. source_info , live) ;
693+ check_place (
694+ * place,
695+ AccessKind :: Assign ,
696+ terminator. source_info ,
697+ body. terminator_loc ( bb) ,
698+ live,
699+ ) ;
688700 record_drop ( * place)
689701 }
690702 TerminatorKind :: Drop { place, .. } => record_drop ( * place) ,
@@ -693,21 +705,34 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
693705 if let InlineAsmOperand :: Out { place : Some ( place) , .. }
694706 | InlineAsmOperand :: InOut { out_place : Some ( place) , .. } = operand
695707 {
696- check_place ( * place, AccessKind :: Assign , terminator. source_info , live) ;
708+ check_place (
709+ * place,
710+ AccessKind :: Assign ,
711+ terminator. source_info ,
712+ body. terminator_loc ( bb) ,
713+ live,
714+ ) ;
697715 }
698716 }
699717 }
700718 _ => { }
701719 }
702720
703721 for ( statement_index, statement) in bb_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
704- cursor. seek_before_primary_effect ( Location { block : bb, statement_index } ) ;
722+ let location = Location { block : bb, statement_index } ;
723+ cursor. seek_before_primary_effect ( location) ;
705724 let live = cursor. get ( ) ;
706725 ever_live. union ( live) ;
707726 match & statement. kind {
708727 StatementKind :: Assign ( box ( place, _) )
709728 | StatementKind :: SetDiscriminant { box place, .. } => {
710- check_place ( * place, AccessKind :: Assign , statement. source_info , live) ;
729+ check_place (
730+ * place,
731+ AccessKind :: Assign ,
732+ statement. source_info ,
733+ location,
734+ live,
735+ ) ;
711736 }
712737 StatementKind :: StorageLive ( _)
713738 | StatementKind :: StorageDead ( _)
@@ -745,7 +770,12 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
745770 continue ;
746771 } ;
747772 let source_info = body. local_decls [ place. local ] . source_info ;
748- let access = Access { kind, live : live. contains ( index) , is_direct : true } ;
773+ let access = Access {
774+ kind,
775+ location : Location :: START ,
776+ live : live. contains ( index) ,
777+ is_direct : true ,
778+ } ;
749779 assignments[ index] . insert ( source_info, access) ;
750780 }
751781 }
@@ -1098,23 +1128,34 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10981128 continue ;
10991129 }
11001130
1101- let mut next_direct_assign = None ;
1131+ let mut next_direct_assignments : Vec < ( Span , Location ) > = Vec :: new ( ) ;
11021132 let mut dead_statements = Vec :: with_capacity ( statements. len ( ) ) ;
11031133
1104- for ( source_info, Access { live, kind, is_direct } ) in statements. into_iter ( ) {
1105- let overwrite = match ( kind, is_direct, next_direct_assign) {
1106- ( AccessKind :: Assign , true , Some ( overwrite_span) ) => {
1107- Some ( errors:: UnusedAssignOverwrite {
1134+ for ( source_info, Access { live, kind, is_direct, location } ) in statements. into_iter ( )
1135+ {
1136+ let overwrite = if kind == AccessKind :: Assign && is_direct {
1137+ next_direct_assignments
1138+ . iter ( )
1139+ . filter ( |( _, overwrite_location) | {
1140+ location. is_predecessor_of ( * overwrite_location, self . body )
1141+ } )
1142+ // MIR traversal order is not always source-nearest for assignments such
1143+ // as compound assignment operations.
1144+ . min_by_key ( |( overwrite_span, _) | {
1145+ let is_source_successor = source_info. span . lo ( ) <= overwrite_span. lo ( ) ;
1146+ ( !is_source_successor, overwrite_span. lo ( ) )
1147+ } )
1148+ . map ( |& ( overwrite_span, _) | errors:: UnusedAssignOverwrite {
11081149 assigned_span : source_info. span ,
11091150 overwrite_span,
11101151 name,
11111152 } )
1112- }
1113- _ => None ,
1153+ } else {
1154+ None
11141155 } ;
11151156
11161157 if kind == AccessKind :: Assign && is_direct {
1117- next_direct_assign = Some ( source_info. span ) ;
1158+ next_direct_assignments . push ( ( source_info. span , location ) ) ;
11181159 }
11191160
11201161 if live {
0 commit comments