4
4
5
5
use rustc_index:: bit_set:: BitSet ;
6
6
use rustc_index:: vec:: Idx ;
7
+ use rustc_middle:: mir:: visit:: { MirVisitable , Visitor } ;
7
8
use rustc_middle:: mir:: { self , Body , Location } ;
8
9
use rustc_middle:: ty:: { self , TyCtxt } ;
9
10
10
- use crate :: drop_flag_effects;
11
11
use crate :: drop_flag_effects_for_function_entry;
12
12
use crate :: drop_flag_effects_for_location;
13
13
use crate :: elaborate_drops:: DropFlagState ;
14
14
use crate :: framework:: SwitchIntEdgeEffects ;
15
- use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
15
+ use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
16
16
use crate :: on_lookup_result_bits;
17
17
use crate :: MoveDataParamEnv ;
18
+ use crate :: { drop_flag_effects, on_all_children_bits} ;
18
19
use crate :: { lattice, AnalysisDomain , GenKill , GenKillAnalysis } ;
19
20
20
21
mod borrowed_locals;
@@ -307,22 +308,45 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
307
308
fn statement_effect (
308
309
& self ,
309
310
trans : & mut impl GenKill < Self :: Idx > ,
310
- _statement : & mir:: Statement < ' tcx > ,
311
+ statement : & mir:: Statement < ' tcx > ,
311
312
location : Location ,
312
313
) {
313
314
drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
314
315
Self :: update_bits ( trans, path, s)
316
+ } ) ;
317
+
318
+ if !self . tcx . sess . opts . debugging_opts . precise_enum_drop_elaboration {
319
+ return ;
320
+ }
321
+
322
+ // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
323
+ for_each_mut_borrow ( statement, location, |place| {
324
+ let LookupResult :: Exact ( mpi) = self . move_data ( ) . rev_lookup . find ( place. as_ref ( ) ) else { return } ;
325
+ on_all_children_bits ( self . tcx , self . body , self . move_data ( ) , mpi, |child| {
326
+ trans. gen ( child) ;
327
+ } )
315
328
} )
316
329
}
317
330
318
331
fn terminator_effect (
319
332
& self ,
320
333
trans : & mut impl GenKill < Self :: Idx > ,
321
- _terminator : & mir:: Terminator < ' tcx > ,
334
+ terminator : & mir:: Terminator < ' tcx > ,
322
335
location : Location ,
323
336
) {
324
337
drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
325
338
Self :: update_bits ( trans, path, s)
339
+ } ) ;
340
+
341
+ if !self . tcx . sess . opts . debugging_opts . precise_enum_drop_elaboration {
342
+ return ;
343
+ }
344
+
345
+ for_each_mut_borrow ( terminator, location, |place| {
346
+ let LookupResult :: Exact ( mpi) = self . move_data ( ) . rev_lookup . find ( place. as_ref ( ) ) else { return } ;
347
+ on_all_children_bits ( self . tcx , self . body , self . move_data ( ) , mpi, |child| {
348
+ trans. gen ( child) ;
349
+ } )
326
350
} )
327
351
}
328
352
@@ -427,7 +451,10 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
427
451
) {
428
452
drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
429
453
Self :: update_bits ( trans, path, s)
430
- } )
454
+ } ) ;
455
+
456
+ // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
457
+ // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
431
458
}
432
459
433
460
fn terminator_effect (
@@ -438,7 +465,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
438
465
) {
439
466
drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
440
467
Self :: update_bits ( trans, path, s)
441
- } )
468
+ } ) ;
442
469
}
443
470
444
471
fn call_return_effect (
@@ -704,3 +731,37 @@ fn switch_on_enum_discriminant(
704
731
_ => None ,
705
732
}
706
733
}
734
+
735
+ struct OnMutBorrow < F > ( F ) ;
736
+
737
+ impl < F > Visitor < ' _ > for OnMutBorrow < F >
738
+ where
739
+ F : FnMut ( & mir:: Place < ' _ > ) ,
740
+ {
741
+ fn visit_rvalue ( & mut self , rvalue : & mir:: Rvalue < ' _ > , location : Location ) {
742
+ // FIXME: Does `&raw const foo` allow mutation? See #90413.
743
+ match rvalue {
744
+ mir:: Rvalue :: Ref ( _, mir:: BorrowKind :: Mut { .. } , place)
745
+ | mir:: Rvalue :: AddressOf ( _, place) => ( self . 0 ) ( place) ,
746
+
747
+ _ => { }
748
+ }
749
+
750
+ self . super_rvalue ( rvalue, location)
751
+ }
752
+ }
753
+
754
+ /// Calls `f` for each mutable borrow or raw reference in the program.
755
+ ///
756
+ /// This DOES NOT call `f` for a shared borrow of a type with interior mutability. That's okay for
757
+ /// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but
758
+ /// other analyses will likely need to check for `!Freeze`.
759
+ fn for_each_mut_borrow < ' tcx > (
760
+ mir : & impl MirVisitable < ' tcx > ,
761
+ location : Location ,
762
+ f : impl FnMut ( & mir:: Place < ' _ > ) ,
763
+ ) {
764
+ let mut vis = OnMutBorrow ( f) ;
765
+
766
+ mir. apply ( location, & mut vis) ;
767
+ }
0 commit comments