@@ -12,7 +12,7 @@ use rustc_middle::mir::{
12
12
use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty } ;
13
13
use rustc_span:: source_map:: DesugaringKind ;
14
14
use rustc_span:: symbol:: sym;
15
- use rustc_span:: { Span , DUMMY_SP } ;
15
+ use rustc_span:: { MultiSpan , Span , DUMMY_SP } ;
16
16
use rustc_trait_selection:: infer:: InferCtxtExt ;
17
17
18
18
use crate :: dataflow:: drop_flag_effects;
@@ -66,7 +66,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
66
66
self . move_spans ( moved_place, location) . or_else ( || self . borrow_spans ( span, location) ) ;
67
67
let span = use_spans. args_or_use ( ) ;
68
68
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) ;
70
70
debug ! (
71
71
"report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}" ,
72
72
move_site_vec, use_spans
@@ -139,6 +139,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
139
139
self . describe_place_with_options ( moved_place, IncludingDowncast ( true ) ) ,
140
140
) ;
141
141
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
+
142
168
self . add_moved_or_invoked_closure_note ( location, used_place, & mut err) ;
143
169
144
170
let mut is_loop_move = false ;
@@ -219,7 +245,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
219
245
) ,
220
246
) ;
221
247
}
222
- if is_option_or_result {
248
+ if is_option_or_result && maybe_reinitialized_locations . is_empty ( ) {
223
249
err. span_suggestion_verbose (
224
250
fn_call_span. shrink_to_lo ( ) ,
225
251
"consider calling `.as_ref()` to borrow the type's contents" ,
@@ -260,19 +286,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
260
286
}
261
287
}
262
288
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
+ }
276
306
}
277
307
278
308
if let Some ( DesugaringKind :: ForLoop ( _) ) = move_span. desugaring_kind ( ) {
@@ -1465,7 +1495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1465
1495
err
1466
1496
}
1467
1497
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 > ) {
1469
1503
fn predecessor_locations (
1470
1504
body : & ' a mir:: Body < ' tcx > ,
1471
1505
location : Location ,
@@ -1488,6 +1522,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1488
1522
} ) ) ;
1489
1523
1490
1524
let mut visited = FxHashSet :: default ( ) ;
1525
+ let mut move_locations = FxHashSet :: default ( ) ;
1526
+ let mut reinits = vec ! [ ] ;
1491
1527
let mut result = vec ! [ ] ;
1492
1528
1493
1529
' dfs: while let Some ( ( location, is_back_edge) ) = stack. pop ( ) {
@@ -1529,6 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1529
1565
move_paths[ path] . place
1530
1566
) ;
1531
1567
result. push ( MoveSite { moi : * moi, traversed_back_edge : is_back_edge } ) ;
1568
+ move_locations. insert ( location) ;
1532
1569
1533
1570
// Strictly speaking, we could continue our DFS here. There may be
1534
1571
// other moves that can reach the point of error. But it is kind of
@@ -1565,6 +1602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1565
1602
} ,
1566
1603
) ;
1567
1604
if any_match {
1605
+ reinits. push ( location) ;
1568
1606
continue ' dfs;
1569
1607
}
1570
1608
@@ -1574,7 +1612,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1574
1612
} ) ) ;
1575
1613
}
1576
1614
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)
1578
1634
}
1579
1635
1580
1636
pub ( in crate :: borrow_check) fn report_illegal_mutation_of_borrowed (
0 commit comments