@@ -131,12 +131,26 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> {
131131 tcx : TyCtxt < ' tcx > ,
132132 body : & ' a Body < ' tcx > ,
133133 move_data : & ' a MoveData < ' tcx > ,
134+ exclude_inactive_in_otherwise : bool ,
134135 skip_unreachable_unwind : bool ,
135136}
136137
137138impl < ' a , ' tcx > MaybeInitializedPlaces < ' a , ' tcx > {
138139 pub fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , move_data : & ' a MoveData < ' tcx > ) -> Self {
139- MaybeInitializedPlaces { tcx, body, move_data, skip_unreachable_unwind : false }
140+ MaybeInitializedPlaces {
141+ tcx,
142+ body,
143+ move_data,
144+ exclude_inactive_in_otherwise : false ,
145+ skip_unreachable_unwind : false ,
146+ }
147+ }
148+
149+ /// Ensures definitely inactive variants are excluded from the set of initialized places for
150+ /// blocks reached through an `otherwise` edge.
151+ pub fn exclude_inactive_in_otherwise ( mut self ) -> Self {
152+ self . exclude_inactive_in_otherwise = true ;
153+ self
140154 }
141155
142156 pub fn skipping_unreachable_unwind ( mut self ) -> Self {
@@ -208,6 +222,7 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
208222 move_data : & ' a MoveData < ' tcx > ,
209223
210224 mark_inactive_variants_as_uninit : bool ,
225+ include_inactive_in_otherwise : bool ,
211226 skip_unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
212227}
213228
@@ -218,6 +233,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
218233 body,
219234 move_data,
220235 mark_inactive_variants_as_uninit : false ,
236+ include_inactive_in_otherwise : false ,
221237 skip_unreachable_unwind : DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
222238 }
223239 }
@@ -232,6 +248,13 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
232248 self
233249 }
234250
251+ /// Ensures definitely inactive variants are included in the set of uninitialized places for
252+ /// blocks reached through an `otherwise` edge.
253+ pub fn include_inactive_in_otherwise ( mut self ) -> Self {
254+ self . include_inactive_in_otherwise = true ;
255+ self
256+ }
257+
235258 pub fn skipping_unreachable_unwind (
236259 mut self ,
237260 unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
@@ -431,22 +454,47 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
431454 data : & mut Self :: SwitchIntData ,
432455 state : & mut Self :: Domain ,
433456 value : SwitchTargetValue ,
434- mut otherwise_state : Option < & mut Self :: Domain > ,
457+ otherwise_state : Option < & mut Self :: Domain > ,
435458 ) {
436459 if let SwitchTargetValue :: Normal ( value) = value {
437460 // Kill all move paths that correspond to variants we know to be inactive along this
438461 // particular outgoing edge of a `SwitchInt`.
439- drop_flag_effects:: on_all_inactive_variants (
462+ drop_flag_effects:: on_all_variants (
440463 self . move_data ,
441464 data. enum_place ,
442465 data. next_discr ( value) ,
443466 |mpi| state. kill ( mpi) ,
444- move |mpi| {
445- otherwise_state. as_mut ( ) . map ( |state| state. kill ( mpi) ) ;
446- } ,
467+ otherwise_state. map ( |state| |mpi| state. kill ( mpi) ) ,
447468 ) ;
448469 }
449470 }
471+
472+ fn apply_switch_int_edge_effect_for_targets (
473+ & mut self ,
474+ targets : & mir:: SwitchTargets ,
475+ mut data : Self :: SwitchIntData ,
476+ state : & mut Self :: Domain ,
477+ mut propagate : impl FnMut ( mir:: BasicBlock , & Self :: Domain ) ,
478+ ) {
479+ let analyze_otherwise = self . exclude_inactive_in_otherwise
480+ && ( 1 ..data. discriminants . len ( ) ) . contains ( & targets. all_values ( ) . len ( ) ) ;
481+
482+ let mut otherwise_state = if analyze_otherwise { Some ( state. clone ( ) ) } else { None } ;
483+ let mut target_state = MaybeReachable :: Unreachable ;
484+
485+ for ( value, target) in targets. iter ( ) {
486+ target_state. clone_from ( & state) ;
487+ self . apply_switch_int_edge_effect (
488+ & mut data,
489+ & mut target_state,
490+ SwitchTargetValue :: Normal ( value) ,
491+ otherwise_state. as_mut ( ) ,
492+ ) ;
493+ propagate ( target, & target_state) ;
494+ }
495+
496+ propagate ( targets. otherwise ( ) , otherwise_state. as_ref ( ) . unwrap_or ( state) ) ;
497+ }
450498}
451499
452500/// There can be many more `MovePathIndex` than there are locals in a MIR body.
@@ -548,21 +596,46 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
548596 data : & mut Self :: SwitchIntData ,
549597 state : & mut Self :: Domain ,
550598 value : SwitchTargetValue ,
551- mut otherwise_state : Option < & mut Self :: Domain > ,
599+ otherwise_state : Option < & mut Self :: Domain > ,
552600 ) {
553601 if let SwitchTargetValue :: Normal ( value) = value {
554602 // Mark all move paths that correspond to variants other than this one as maybe
555603 // uninitialized (in reality, they are *definitely* uninitialized).
556- drop_flag_effects:: on_all_inactive_variants (
604+ drop_flag_effects:: on_all_variants (
557605 self . move_data ,
558606 data. enum_place ,
559607 data. next_discr ( value) ,
560608 |mpi| state. gen_ ( mpi) ,
561- |mpi| {
562- otherwise_state. as_mut ( ) . map ( |state| state. gen_ ( mpi) ) ;
563- } ,
609+ otherwise_state. map ( |state| |mpi| state. gen_ ( mpi) ) ,
610+ ) ;
611+ }
612+ }
613+
614+ fn apply_switch_int_edge_effect_for_targets (
615+ & mut self ,
616+ targets : & mir:: SwitchTargets ,
617+ mut data : Self :: SwitchIntData ,
618+ state : & mut Self :: Domain ,
619+ mut propagate : impl FnMut ( mir:: BasicBlock , & Self :: Domain ) ,
620+ ) {
621+ let analyze_otherwise = self . include_inactive_in_otherwise
622+ && ( 1 ..data. discriminants . len ( ) ) . contains ( & targets. all_values ( ) . len ( ) ) ;
623+
624+ let mut otherwise_state = if analyze_otherwise { Some ( state. clone ( ) ) } else { None } ;
625+ let mut target_state = MixedBitSet :: new_empty ( self . move_data ( ) . move_paths . len ( ) ) ;
626+
627+ for ( value, target) in targets. iter ( ) {
628+ target_state. clone_from ( & state) ;
629+ self . apply_switch_int_edge_effect (
630+ & mut data,
631+ & mut target_state,
632+ SwitchTargetValue :: Normal ( value) ,
633+ otherwise_state. as_mut ( ) ,
564634 ) ;
635+ propagate ( target, & target_state) ;
565636 }
637+
638+ propagate ( targets. otherwise ( ) , otherwise_state. as_ref ( ) . unwrap_or ( state) ) ;
566639 }
567640}
568641
0 commit comments