@@ -9,9 +9,10 @@ use rustc_middle::mir::{
99} ;
1010use rustc_middle:: ty:: util:: Discr ;
1111use rustc_middle:: ty:: { self , TyCtxt } ;
12+ use smallvec:: SmallVec ;
1213use tracing:: { debug, instrument} ;
1314
14- use crate :: drop_flag_effects:: DropFlagState ;
15+ use crate :: drop_flag_effects:: { DropFlagState , InactiveVariants } ;
1516use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
1617use crate :: {
1718 Analysis , GenKill , MaybeReachable , drop_flag_effects, drop_flag_effects_for_function_entry,
@@ -26,6 +27,12 @@ pub struct MaybePlacesSwitchIntData<'tcx> {
2627}
2728
2829impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
30+ /// Creates a `SmallVec` mapping each target in `targets` to its `VariantIdx`.
31+ fn variants ( & mut self , targets : & mir:: SwitchTargets ) -> SmallVec < [ VariantIdx ; 4 ] > {
32+ self . index = 0 ;
33+ targets. all_values ( ) . iter ( ) . map ( |value| self . next_discr ( value. get ( ) ) ) . collect ( )
34+ }
35+
2936 // The discriminant order in the `SwitchInt` targets should match the order yielded by
3037 // `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
3138 // corresponding variant in linear time.
@@ -131,12 +138,26 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> {
131138 tcx : TyCtxt < ' tcx > ,
132139 body : & ' a Body < ' tcx > ,
133140 move_data : & ' a MoveData < ' tcx > ,
141+ exclude_inactive_in_otherwise : bool ,
134142 skip_unreachable_unwind : bool ,
135143}
136144
137145impl < ' a , ' tcx > MaybeInitializedPlaces < ' a , ' tcx > {
138146 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 }
147+ MaybeInitializedPlaces {
148+ tcx,
149+ body,
150+ move_data,
151+ exclude_inactive_in_otherwise : false ,
152+ skip_unreachable_unwind : false ,
153+ }
154+ }
155+
156+ /// Ensures definitely inactive variants are excluded from the set of initialized places for
157+ /// blocks reached through an `otherwise` edge.
158+ pub fn exclude_inactive_in_otherwise ( mut self ) -> Self {
159+ self . exclude_inactive_in_otherwise = true ;
160+ self
140161 }
141162
142163 pub fn skipping_unreachable_unwind ( mut self ) -> Self {
@@ -208,6 +229,7 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
208229 move_data : & ' a MoveData < ' tcx > ,
209230
210231 mark_inactive_variants_as_uninit : bool ,
232+ include_inactive_in_otherwise : bool ,
211233 skip_unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
212234}
213235
@@ -218,6 +240,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
218240 body,
219241 move_data,
220242 mark_inactive_variants_as_uninit : false ,
243+ include_inactive_in_otherwise : false ,
221244 skip_unreachable_unwind : DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
222245 }
223246 }
@@ -232,6 +255,13 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
232255 self
233256 }
234257
258+ /// Ensures definitely inactive variants are included in the set of uninitialized places for
259+ /// blocks reached through an `otherwise` edge.
260+ pub fn include_inactive_in_otherwise ( mut self ) -> Self {
261+ self . include_inactive_in_otherwise = true ;
262+ self
263+ }
264+
235265 pub fn skipping_unreachable_unwind (
236266 mut self ,
237267 unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
@@ -431,17 +461,24 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
431461 data : & mut Self :: SwitchIntData ,
432462 state : & mut Self :: Domain ,
433463 value : SwitchTargetValue ,
464+ targets : & mir:: SwitchTargets ,
434465 ) {
435- if let SwitchTargetValue :: Normal ( value) = value {
436- // Kill all move paths that correspond to variants we know to be inactive along this
437- // particular outgoing edge of a `SwitchInt`.
438- drop_flag_effects:: on_all_inactive_variants (
439- self . move_data ,
440- data. enum_place ,
441- data. next_discr ( value) ,
442- |mpi| state. kill ( mpi) ,
443- ) ;
444- }
466+ let inactive_variants = match value {
467+ SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
468+ SwitchTargetValue :: Otherwise if self . exclude_inactive_in_otherwise => {
469+ InactiveVariants :: Inactives ( data. variants ( targets) )
470+ }
471+ _ => return ,
472+ } ;
473+
474+ // Kill all move paths that correspond to variants we know to be inactive along this
475+ // particular outgoing edge of a `SwitchInt`.
476+ drop_flag_effects:: on_all_inactive_variants (
477+ self . move_data ,
478+ data. enum_place ,
479+ & inactive_variants,
480+ |mpi| state. kill ( mpi) ,
481+ ) ;
445482 }
446483}
447484
@@ -544,17 +581,24 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
544581 data : & mut Self :: SwitchIntData ,
545582 state : & mut Self :: Domain ,
546583 value : SwitchTargetValue ,
584+ targets : & mir:: SwitchTargets ,
547585 ) {
548- if let SwitchTargetValue :: Normal ( value) = value {
549- // Mark all move paths that correspond to variants other than this one as maybe
550- // uninitialized (in reality, they are *definitely* uninitialized).
551- drop_flag_effects:: on_all_inactive_variants (
552- self . move_data ,
553- data. enum_place ,
554- data. next_discr ( value) ,
555- |mpi| state. gen_ ( mpi) ,
556- ) ;
557- }
586+ let inactive_variants = match value {
587+ SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
588+ SwitchTargetValue :: Otherwise if self . include_inactive_in_otherwise => {
589+ InactiveVariants :: Inactives ( data. variants ( targets) )
590+ }
591+ _ => return ,
592+ } ;
593+
594+ // Mark all move paths that correspond to variants other than this one as maybe
595+ // uninitialized (in reality, they are *definitely* uninitialized).
596+ drop_flag_effects:: on_all_inactive_variants (
597+ self . move_data ,
598+ data. enum_place ,
599+ & inactive_variants,
600+ |mpi| state. gen_ ( mpi) ,
601+ ) ;
558602 }
559603}
560604
0 commit comments