@@ -20,6 +20,7 @@ use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
2020use rustc:: mir:: { Statement , StatementKind , Terminator , TerminatorKind } ;
2121use transform:: nll;
2222
23+ use rustc_data_structures:: fx:: FxHashSet ;
2324use rustc_data_structures:: indexed_set:: { self , IdxSetBuf } ;
2425use rustc_data_structures:: indexed_vec:: { Idx } ;
2526
@@ -136,6 +137,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
136137 node_id : id,
137138 move_data : & mdpe. move_data ,
138139 param_env : param_env,
140+ storage_drop_or_dead_error_reported : FxHashSet ( ) ,
139141 } ;
140142
141143 let mut state = InProgress :: new ( flow_borrows,
@@ -153,6 +155,10 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
153155 node_id : ast:: NodeId ,
154156 move_data : & ' cx MoveData < ' tcx > ,
155157 param_env : ParamEnv < ' gcx > ,
158+ /// This field keeps track of when storage drop or dead errors are reported
159+ /// in order to stop duplicate error reporting and identify the conditions required
160+ /// for a "temporary value dropped here while still borrowed" error. See #45360.
161+ storage_drop_or_dead_error_reported : FxHashSet < Local > ,
156162}
157163
158164// (forced to be `pub` due to its use as an associated type below.)
@@ -281,10 +287,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
281287 }
282288
283289 StatementKind :: StorageDead ( local) => {
284- self . access_lvalue ( ContextKind :: StorageDead . new ( location) ,
285- ( & Lvalue :: Local ( local) , span) ,
286- ( Shallow ( None ) , Write ( WriteKind :: StorageDead ) ) ,
287- flow_state) ;
290+ if self . storage_drop_or_dead_error_reported . insert ( local) {
291+ self . access_lvalue ( ContextKind :: StorageDead . new ( location) ,
292+ ( & Lvalue :: Local ( local) , span) ,
293+ ( Shallow ( None ) , Write ( WriteKind :: StorageDead ) ) ,
294+ flow_state) ;
295+ }
288296 }
289297 }
290298 }
@@ -604,12 +612,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
604612 let erased_ty = gcx. lift ( & self . tcx . erase_regions ( & ty) ) . unwrap ( ) ;
605613 let moves_by_default = erased_ty. moves_by_default ( gcx, self . param_env , DUMMY_SP ) ;
606614
607- if moves_by_default {
608- // move of lvalue: check if this is move of already borrowed path
609- self . access_lvalue ( context, lvalue_span, ( Deep , Write ( WriteKind :: Move ) ) , flow_state) ;
610- } else {
611- // copy of lvalue: check if this is "copy of frozen path" (FIXME: see check_loans.rs)
612- self . access_lvalue ( context, lvalue_span, ( Deep , Read ( ReadKind :: Copy ) ) , flow_state) ;
615+ // Check if error has already been reported to stop duplicate reporting.
616+ let has_storage_drop_or_dead_error_reported = match * lvalue {
617+ Lvalue :: Local ( local) => self . storage_drop_or_dead_error_reported . insert ( local) ,
618+ _ => false ,
619+ } ;
620+
621+ if !has_storage_drop_or_dead_error_reported {
622+ if moves_by_default {
623+ // move of lvalue: check if this is move of already borrowed path
624+ self . access_lvalue ( context, lvalue_span, ( Deep , Write ( WriteKind :: Move ) ) ,
625+ flow_state) ;
626+ } else {
627+ // copy of lvalue: check if this is "copy of frozen path"
628+ // (FIXME: see check_loans.rs)
629+ self . access_lvalue ( context, lvalue_span, ( Deep , Read ( ReadKind :: Copy ) ) ,
630+ flow_state) ;
631+ }
613632 }
614633
615634 // Finally, check if path was already moved.
0 commit comments