@@ -12,7 +12,7 @@ use super::MoveDataParamEnv;
1212
1313use crate :: util:: elaborate_drops:: DropFlagState ;
1414
15- use super :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
15+ use super :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
1616use super :: { AnalysisDomain , BottomValue , GenKill , GenKillAnalysis } ;
1717
1818use super :: drop_flag_effects_for_function_entry;
@@ -124,11 +124,23 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
124124 tcx : TyCtxt < ' tcx > ,
125125 body : & ' a Body < ' tcx > ,
126126 mdpe : & ' a MoveDataParamEnv < ' tcx > ,
127+
128+ mark_inactive_variants_as_uninit : bool ,
127129}
128130
129131impl < ' a , ' tcx > MaybeUninitializedPlaces < ' a , ' tcx > {
130132 pub fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , mdpe : & ' a MoveDataParamEnv < ' tcx > ) -> Self {
131- MaybeUninitializedPlaces { tcx, body, mdpe }
133+ MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit : false }
134+ }
135+
136+ /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
137+ /// enum discriminant.
138+ ///
139+ /// This is correct in a vacuum but is not the default because it causes problems in the borrow
140+ /// checker, where this information gets propagated along `FakeEdge`s.
141+ pub fn mark_inactive_variants_as_uninit ( mut self ) -> Self {
142+ self . mark_inactive_variants_as_uninit = true ;
143+ self
132144 }
133145}
134146
@@ -350,27 +362,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
350362 _adt : & ty:: AdtDef ,
351363 variant : VariantIdx ,
352364 ) {
353- let enum_mpi = match self . move_data ( ) . rev_lookup . find ( enum_place. as_ref ( ) ) {
354- LookupResult :: Exact ( mpi) => mpi,
355- LookupResult :: Parent ( _) => return ,
356- } ;
357-
358- // Kill all move paths that correspond to variants other than this one
359- let move_paths = & self . move_data ( ) . move_paths ;
360- let enum_path = & move_paths[ enum_mpi] ;
361- for ( mpi, variant_path) in enum_path. children ( move_paths) {
362- trans. kill ( mpi) ;
363- match variant_path. place . projection . last ( ) . unwrap ( ) {
364- mir:: ProjectionElem :: Downcast ( _, idx) if * idx == variant => continue ,
365- _ => drop_flag_effects:: on_all_children_bits (
366- self . tcx ,
367- self . body ,
368- self . move_data ( ) ,
369- mpi,
370- |mpi| trans. kill ( mpi) ,
371- ) ,
372- }
373- }
365+ // Kill all move paths that correspond to variants we know to be inactive along this
366+ // particular outgoing edge of a `SwitchInt`.
367+ drop_flag_effects:: on_all_inactive_variants (
368+ self . tcx ,
369+ self . body ,
370+ self . move_data ( ) ,
371+ enum_place,
372+ variant,
373+ |mpi| trans. kill ( mpi) ,
374+ ) ;
374375 }
375376}
376377
@@ -443,6 +444,30 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
443444 } ,
444445 ) ;
445446 }
447+
448+ fn discriminant_switch_effect (
449+ & self ,
450+ trans : & mut impl GenKill < Self :: Idx > ,
451+ _block : mir:: BasicBlock ,
452+ enum_place : mir:: Place < ' tcx > ,
453+ _adt : & ty:: AdtDef ,
454+ variant : VariantIdx ,
455+ ) {
456+ if !self . mark_inactive_variants_as_uninit {
457+ return ;
458+ }
459+
460+ // Mark all move paths that correspond to variants other than this one as maybe
461+ // uninitialized (in reality, they are *definitely* uninitialized).
462+ drop_flag_effects:: on_all_inactive_variants (
463+ self . tcx ,
464+ self . body ,
465+ self . move_data ( ) ,
466+ enum_place,
467+ variant,
468+ |mpi| trans. gen ( mpi) ,
469+ ) ;
470+ }
446471}
447472
448473impl < ' a , ' tcx > AnalysisDomain < ' tcx > for DefinitelyInitializedPlaces < ' a , ' tcx > {
0 commit comments