@@ -12,7 +12,7 @@ use rustc_middle::mir::{
1212use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty } ;
1313use rustc_span:: source_map:: DesugaringKind ;
1414use rustc_span:: symbol:: sym;
15- use rustc_span:: { Span , DUMMY_SP } ;
15+ use rustc_span:: { MultiSpan , Span , DUMMY_SP } ;
1616use rustc_trait_selection:: infer:: InferCtxtExt ;
1717
1818use crate :: dataflow:: drop_flag_effects;
@@ -66,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
6666 self . move_spans ( moved_place, location) . or_else ( || self . borrow_spans ( span, location) ) ;
6767 let span = use_spans. args_or_use ( ) ;
6868
69- let move_site_vec = self . get_moved_indexes ( location, mpi) ;
69+ let ( move_site_vec, maybe_reinitialized_locations ) = self . get_moved_indexes ( location, mpi) ;
7070 debug ! (
7171 "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}" ,
7272 move_site_vec, use_spans
@@ -139,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
139139 self . describe_place_with_options ( moved_place, IncludingDowncast ( true ) ) ,
140140 ) ;
141141
142+ let reinit_spans = maybe_reinitialized_locations
143+ . iter ( )
144+ . take ( 3 )
145+ . map ( |loc| {
146+ self . move_spans ( self . move_data . move_paths [ mpi] . place . as_ref ( ) , * loc)
147+ . args_or_use ( )
148+ } )
149+ . collect :: < Vec < Span > > ( ) ;
150+ let reinits = maybe_reinitialized_locations. len ( ) ;
151+ if reinits == 1 {
152+ err. span_label ( reinit_spans[ 0 ] , "this reinitialization might get skipped" ) ;
153+ } else if reinits > 1 {
154+ err. span_note (
155+ MultiSpan :: from_spans ( reinit_spans) ,
156+ & if reinits <= 3 {
157+ format ! ( "these {} reinitializations might get skipped" , reinits)
158+ } else {
159+ format ! (
160+ "these 3 reinitializations and {} other{} might get skipped" ,
161+ reinits - 3 ,
162+ if reinits == 4 { "" } else { "s" }
163+ )
164+ } ,
165+ ) ;
166+ }
167+
142168 self . add_moved_or_invoked_closure_note ( location, used_place, & mut err) ;
143169
144170 let mut is_loop_move = false ;
@@ -219,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
219245 ) ,
220246 ) ;
221247 }
222- if is_option_or_result {
248+ if is_option_or_result && maybe_reinitialized_locations . is_empty ( ) {
223249 err. span_suggestion_verbose (
224250 fn_call_span. shrink_to_lo ( ) ,
225251 "consider calling `.as_ref()` to borrow the type's contents" ,
@@ -260,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
260286 }
261287 }
262288
263- if let UseSpans :: PatUse ( span) = move_spans {
264- err. span_suggestion_verbose (
265- span. shrink_to_lo ( ) ,
266- & format ! (
267- "borrow this field in the pattern to avoid moving {}" ,
268- self . describe_place( moved_place. as_ref( ) )
269- . map( |n| format!( "`{}`" , n) )
270- . unwrap_or_else( || "the value" . to_string( ) )
271- ) ,
272- "ref " . to_string ( ) ,
273- Applicability :: MachineApplicable ,
274- ) ;
275- in_pattern = true ;
289+ if let ( UseSpans :: PatUse ( span) , [ ] ) =
290+ ( move_spans, & maybe_reinitialized_locations[ ..] )
291+ {
292+ if maybe_reinitialized_locations. is_empty ( ) {
293+ err. span_suggestion_verbose (
294+ span. shrink_to_lo ( ) ,
295+ & format ! (
296+ "borrow this field in the pattern to avoid moving {}" ,
297+ self . describe_place( moved_place. as_ref( ) )
298+ . map( |n| format!( "`{}`" , n) )
299+ . unwrap_or_else( || "the value" . to_string( ) )
300+ ) ,
301+ "ref " . to_string ( ) ,
302+ Applicability :: MachineApplicable ,
303+ ) ;
304+ in_pattern = true ;
305+ }
276306 }
277307
278308 if let Some ( DesugaringKind :: ForLoop ( _) ) = move_span. desugaring_kind ( ) {
@@ -1465,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14651495 err
14661496 }
14671497
1468- fn get_moved_indexes ( & mut self , location : Location , mpi : MovePathIndex ) -> Vec < MoveSite > {
1498+ fn get_moved_indexes (
1499+ & mut self ,
1500+ location : Location ,
1501+ mpi : MovePathIndex ,
1502+ ) -> ( Vec < MoveSite > , Vec < Location > ) {
14691503 fn predecessor_locations (
14701504 body : & ' a mir:: Body < ' tcx > ,
14711505 location : Location ,
@@ -1488,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14881522 } ) ) ;
14891523
14901524 let mut visited = FxHashSet :: default ( ) ;
1525+ let mut move_locations = FxHashSet :: default ( ) ;
1526+ let mut reinits = vec ! [ ] ;
14911527 let mut result = vec ! [ ] ;
14921528
14931529 ' dfs: while let Some ( ( location, is_back_edge) ) = stack. pop ( ) {
@@ -1529,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15291565 move_paths[ path] . place
15301566 ) ;
15311567 result. push ( MoveSite { moi : * moi, traversed_back_edge : is_back_edge } ) ;
1568+ move_locations. insert ( location) ;
15321569
15331570 // Strictly speaking, we could continue our DFS here. There may be
15341571 // other moves that can reach the point of error. But it is kind of
@@ -1565,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15651602 } ,
15661603 ) ;
15671604 if any_match {
1605+ reinits. push ( location) ;
15681606 continue ' dfs;
15691607 }
15701608
@@ -1574,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15741612 } ) ) ;
15751613 }
15761614
1577- result
1615+ // Check if we can reach these reinits from a move location.
1616+ let reinits_reachable = reinits
1617+ . into_iter ( )
1618+ . filter ( |reinit| {
1619+ let mut visited = FxHashSet :: default ( ) ;
1620+ let mut stack = vec ! [ * reinit] ;
1621+ while let Some ( location) = stack. pop ( ) {
1622+ if !visited. insert ( location) {
1623+ continue ;
1624+ }
1625+ if move_locations. contains ( & location) {
1626+ return true ;
1627+ }
1628+ stack. extend ( predecessor_locations ( self . body , location) ) ;
1629+ }
1630+ false
1631+ } )
1632+ . collect :: < Vec < Location > > ( ) ;
1633+ ( result, reinits_reachable)
15781634 }
15791635
15801636 pub ( in crate :: borrow_check) fn report_illegal_mutation_of_borrowed (
0 commit comments