@@ -340,7 +340,7 @@ fn do_mir_borrowck<'tcx>(
340340 next_region_name : RefCell :: new ( 1 ) ,
341341 polonius_output : None ,
342342 errors,
343- to_skip : Default :: default ( ) ,
343+ replaces : Default :: default ( ) ,
344344 } ;
345345 promoted_mbcx. report_move_errors ( move_errors) ;
346346 errors = promoted_mbcx. errors ;
@@ -372,7 +372,7 @@ fn do_mir_borrowck<'tcx>(
372372 next_region_name : RefCell :: new ( 1 ) ,
373373 polonius_output,
374374 errors,
375- to_skip : Default :: default ( ) ,
375+ replaces : Default :: default ( ) ,
376376 } ;
377377
378378 // Compute and report region errors, if any.
@@ -556,7 +556,9 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
556556
557557 errors : error:: BorrowckErrors < ' tcx > ,
558558
559- to_skip : FxHashSet < Location > ,
559+ /// Record the places were a replace happens so that we can use the
560+ /// correct access depth in the assignment for better diagnostic
561+ replaces : FxHashSet < Location > ,
560562}
561563
562564// Check that:
@@ -581,9 +583,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
581583 match & stmt. kind {
582584 StatementKind :: Assign ( box ( lhs, rhs) ) => {
583585 self . consume_rvalue ( location, ( rhs, span) , flow_state) ;
584- if !self . to_skip . contains ( & location) {
585- self . mutate_place ( location, ( * lhs, span) , Shallow ( None ) , flow_state) ;
586- }
586+ // In case of a replace the drop access check is skipped for better diagnostic but we need
587+ // to use a stricter access depth here
588+ let access_depth = if self . replaces . contains ( & location) { AccessDepth :: Drop } else { Shallow ( None ) } ;
589+ self . mutate_place ( location, ( * lhs, span) , access_depth, flow_state) ;
587590 }
588591 StatementKind :: FakeRead ( box ( _, place) ) => {
589592 // Read for match doesn't access any memory and is used to
@@ -656,36 +659,28 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
656659 loc, term, place, span
657660 ) ;
658661
659- let next_statement = if * is_replace {
660- self . body ( )
661- . basic_blocks
662- . get ( * target)
663- . expect ( "MIR should be complete at this point" )
664- . statements
665- . first ( )
666- } else {
667- None
668- } ;
669-
670- match next_statement {
671- Some ( Statement { kind : StatementKind :: Assign ( _) , source_info : _ } ) => {
672- // this is a drop from a replace operation, for better diagnostic report
673- // here possible conflicts and mute the assign statement errors
674- self . to_skip . insert ( Location { block : * target, statement_index : 0 } ) ;
675- self . to_skip
676- . insert ( Location { block : unwind. unwrap ( ) , statement_index : 0 } ) ;
677- self . mutate_place ( loc, ( * place, span) , AccessDepth :: Deep , flow_state) ;
678- }
679- _ => {
680- self . access_place (
681- loc,
682- ( * place, span) ,
683- ( AccessDepth :: Drop , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
684- LocalMutationIsAllowed :: Yes ,
685- flow_state,
686- ) ;
662+ // In case of a replace, it's more user friendly to report a problem with the explicit
663+ // assignment than the implicit drop.
664+ // Simply skip this access and rely on the assignment to report any error.
665+ if * is_replace {
666+ // An assignment `x = ...` is usually a shallow access, but in the case of a replace
667+ // the drop could access internal references depending on the drop implementation.
668+ // Since we're skipping the drop access, we need to mark the access depth
669+ // of the assignment as AccessDepth::Drop.
670+ self . replaces . insert ( Location { block : * target, statement_index : 0 } ) ;
671+ if let Some ( unwind) = unwind {
672+ self . replaces . insert ( Location { block : * unwind, statement_index : 0 } ) ;
687673 }
674+ return ;
688675 }
676+
677+ self . access_place (
678+ loc,
679+ ( * place, span) ,
680+ ( AccessDepth :: Drop , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
681+ LocalMutationIsAllowed :: Yes ,
682+ flow_state,
683+ )
689684 }
690685 TerminatorKind :: Call {
691686 func,
0 commit comments