@@ -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 :: Retag ( _, _)
713738 | StatementKind :: StorageLive ( _)
@@ -746,7 +771,12 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
746771 continue ;
747772 } ;
748773 let source_info = body. local_decls [ place. local ] . source_info ;
749- let access = Access { kind, live : live. contains ( index) , is_direct : true } ;
774+ let access = Access {
775+ kind,
776+ location : Location :: START ,
777+ live : live. contains ( index) ,
778+ is_direct : true ,
779+ } ;
750780 assignments[ index] . insert ( source_info, access) ;
751781 }
752782 }
@@ -1099,31 +1129,34 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10991129 continue ;
11001130 }
11011131
1102- let mut next_direct_assign = None ;
1132+ let mut next_direct_assignments : Vec < ( Span , Location ) > = Vec :: new ( ) ;
11031133 let mut dead_statements = Vec :: with_capacity ( statements. len ( ) ) ;
11041134
1105- for ( source_info, Access { live, kind, is_direct } ) in statements. into_iter ( ) {
1106- let overwrite = match ( kind, is_direct, next_direct_assign) {
1107- ( AccessKind :: Assign , true , Some ( overwrite_span) ) => {
1108- Some ( errors:: UnusedAssignOverwrite {
1135+ for ( source_info, Access { live, kind, is_direct, location } ) in statements. into_iter ( )
1136+ {
1137+ let direct_assignment = kind == AccessKind :: Assign && is_direct;
1138+ let should_report = !live && ( is_direct || !is_maybe_drop_guard) ;
1139+
1140+ let overwrite = if should_report && direct_assignment {
1141+ next_direct_assignments
1142+ . iter ( )
1143+ . rfind ( |( _, overwrite_location) | {
1144+ location. is_predecessor_of ( * overwrite_location, self . body )
1145+ } )
1146+ . map ( |& ( overwrite_span, _) | errors:: UnusedAssignOverwrite {
11091147 assigned_span : source_info. span ,
11101148 overwrite_span,
11111149 name,
11121150 } )
1113- }
1114- _ => None ,
1151+ } else {
1152+ None
11151153 } ;
11161154
1117- if kind == AccessKind :: Assign && is_direct {
1118- next_direct_assign = Some ( source_info. span ) ;
1155+ if direct_assignment {
1156+ next_direct_assignments . push ( ( source_info. span , location ) ) ;
11191157 }
11201158
1121- if live {
1122- continue ;
1123- }
1124- // If this place was dropped and has non-trivial drop,
1125- // skip reporting field assignments.
1126- if !is_direct && is_maybe_drop_guard {
1159+ if !should_report {
11271160 continue ;
11281161 }
11291162 dead_statements. push ( ( source_info, kind, is_direct, overwrite) ) ;
0 commit comments