44
55use rustc_index:: bit_set:: BitSet ;
66use rustc_index:: vec:: Idx ;
7+ use rustc_middle:: mir:: visit:: { MirVisitable , Visitor } ;
78use rustc_middle:: mir:: { self , Body , Location } ;
89use rustc_middle:: ty:: { self , TyCtxt } ;
910
10- use crate :: drop_flag_effects;
1111use crate :: drop_flag_effects_for_function_entry;
1212use crate :: drop_flag_effects_for_location;
1313use crate :: elaborate_drops:: DropFlagState ;
1414use crate :: framework:: SwitchIntEdgeEffects ;
15- use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
15+ use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
1616use crate :: on_lookup_result_bits;
1717use crate :: MoveDataParamEnv ;
18+ use crate :: { drop_flag_effects, on_all_children_bits} ;
1819use crate :: { lattice, AnalysisDomain , GenKill , GenKillAnalysis } ;
1920
2021mod borrowed_locals;
@@ -307,22 +308,45 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
307308 fn statement_effect (
308309 & self ,
309310 trans : & mut impl GenKill < Self :: Idx > ,
310- _statement : & mir:: Statement < ' tcx > ,
311+ statement : & mir:: Statement < ' tcx > ,
311312 location : Location ,
312313 ) {
313314 drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
314315 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+ } )
315328 } )
316329 }
317330
318331 fn terminator_effect (
319332 & self ,
320333 trans : & mut impl GenKill < Self :: Idx > ,
321- _terminator : & mir:: Terminator < ' tcx > ,
334+ terminator : & mir:: Terminator < ' tcx > ,
322335 location : Location ,
323336 ) {
324337 drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
325338 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+ } )
326350 } )
327351 }
328352
@@ -427,7 +451,10 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
427451 ) {
428452 drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
429453 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.
431458 }
432459
433460 fn terminator_effect (
@@ -438,7 +465,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
438465 ) {
439466 drop_flag_effects_for_location ( self . tcx , self . body , self . mdpe , location, |path, s| {
440467 Self :: update_bits ( trans, path, s)
441- } )
468+ } ) ;
442469 }
443470
444471 fn call_return_effect (
@@ -704,3 +731,37 @@ fn switch_on_enum_discriminant(
704731 _ => None ,
705732 }
706733}
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