@@ -4,55 +4,38 @@ use rustc_abi::VariantIdx;
44use rustc_index:: Idx ;
55use rustc_index:: bit_set:: { DenseBitSet , MixedBitSet } ;
66use rustc_middle:: bug;
7- use rustc_middle:: mir:: {
8- self , Body , CallReturnPlaces , Location , SwitchTargetValue , TerminatorEdges ,
9- } ;
10- use rustc_middle:: ty:: util:: Discr ;
7+ use rustc_middle:: mir:: { self , Body , CallReturnPlaces , Location , TerminatorEdges } ;
118use rustc_middle:: ty:: { self , TyCtxt } ;
129use smallvec:: SmallVec ;
1310use tracing:: { debug, instrument} ;
1411
1512use crate :: drop_flag_effects:: { DropFlagState , InactiveVariants } ;
1613use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
1714use crate :: {
18- Analysis , GenKill , MaybeReachable , drop_flag_effects, drop_flag_effects_for_function_entry,
19- drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
15+ Analysis , GenKill , MaybeReachable , SwitchTargetIndex , drop_flag_effects,
16+ drop_flag_effects_for_function_entry, drop_flag_effects_for_location, on_all_children_bits,
17+ on_lookup_result_bits,
2018} ;
2119
2220// Used by both `MaybeInitializedPlaces` and `MaybeUninitializedPlaces`.
2321pub struct MaybePlacesSwitchIntData < ' tcx > {
2422 enum_place : mir:: Place < ' tcx > ,
25- discriminants : Vec < ( VariantIdx , Discr < ' tcx > ) > ,
26- index : usize ,
27- }
2823
29- impl < ' 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-
36- // The discriminant order in the `SwitchInt` targets should match the order yielded by
37- // `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
38- // corresponding variant in linear time.
39- fn next_discr ( & mut self , value : u128 ) -> VariantIdx {
40- // An out-of-bounds abort will occur if the discriminant ordering isn't as described above.
41- loop {
42- let ( variant, discr) = self . discriminants [ self . index ] ;
43- self . index += 1 ;
44- if discr. val == value {
45- return variant;
46- }
47- }
48- }
24+ // Variant indices targeted by the SwitchInt. For example, if you have:
25+ // ```
26+ // enum E { A = 1, B = 3, C = 5, D = 7 }
27+ // ```
28+ // and a `SwitchInt(A -> bb1, C -> bb2, _ -> bb3)`, this vec will contain `[0, 2]` because
29+ // those are the variant indices for `A` and `C`.
30+ variants : SmallVec < [ VariantIdx ; 4 ] > ,
4931}
5032
5133impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
5234 fn new (
5335 tcx : TyCtxt < ' tcx > ,
5436 body : & Body < ' tcx > ,
5537 block : mir:: BasicBlock ,
38+ targets : & mir:: SwitchTargets ,
5639 discr : & mir:: Operand < ' tcx > ,
5740 ) -> Option < Self > {
5841 let Some ( discr) = discr. place ( ) else { return None } ;
@@ -76,11 +59,29 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
7659 {
7760 match enum_place. ty ( body, tcx) . ty . kind ( ) {
7861 ty:: Adt ( enum_def, _) => {
79- return Some ( MaybePlacesSwitchIntData {
80- enum_place,
81- discriminants : enum_def. discriminants ( tcx) . collect ( ) ,
82- index : 0 ,
83- } ) ;
62+ // The value of each discriminant, in AdtDef order.
63+ let discriminant_vals: SmallVec < [ u128 ; 4 ] > =
64+ enum_def. discriminants ( tcx) . map ( |( _, discr) | discr. val ) . collect ( ) ;
65+ let mut i = 0 ;
66+
67+ // For each value in the SwitchInt, find the VariantIdx for the variant
68+ // with that value. This works because `discriminant_vals` and
69+ // `targets.all_values()` are guaranteed to list variants in the same
70+ // order. (If that ever changes we will get out-of-bounds panics here.)
71+ let variants = targets
72+ . all_values ( )
73+ . iter ( )
74+ . map ( |value| {
75+ loop {
76+ if discriminant_vals[ i] == value. get ( ) {
77+ return VariantIdx :: new ( i) ;
78+ }
79+ i += 1 ;
80+ }
81+ } )
82+ . collect ( ) ;
83+
84+ return Some ( MaybePlacesSwitchIntData { enum_place, variants } ) ;
8485 }
8586
8687 // `Rvalue::Discriminant` is also used to get the active yield point for a
@@ -452,26 +453,28 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
452453 fn get_switch_int_data (
453454 & self ,
454455 block : mir:: BasicBlock ,
456+ targets : & mir:: SwitchTargets ,
455457 discr : & mir:: Operand < ' tcx > ,
456458 ) -> Option < Self :: SwitchIntData > {
457459 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
458460 return None ;
459461 }
460462
461- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
463+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, targets , discr)
462464 }
463465
464466 fn apply_switch_int_edge_effect (
465467 & self ,
466- data : & mut Self :: SwitchIntData ,
467468 state : & mut Self :: Domain ,
468- value : SwitchTargetValue ,
469- targets : & mir :: SwitchTargets ,
469+ data : & mut Self :: SwitchIntData ,
470+ target_idx : SwitchTargetIndex ,
470471 ) {
471- let inactive_variants = match value {
472- SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
473- SwitchTargetValue :: Otherwise if self . exclude_inactive_in_otherwise => {
474- InactiveVariants :: Inactives ( data. variants ( targets) )
472+ let inactive_variants = match target_idx {
473+ SwitchTargetIndex :: Normal ( target_idx) => {
474+ InactiveVariants :: Active ( data. variants [ target_idx] )
475+ }
476+ SwitchTargetIndex :: Otherwise if self . exclude_inactive_in_otherwise => {
477+ InactiveVariants :: Inactives ( data. variants . clone ( ) )
475478 }
476479 _ => return ,
477480 } ;
@@ -568,6 +571,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
568571 fn get_switch_int_data (
569572 & self ,
570573 block : mir:: BasicBlock ,
574+ targets : & mir:: SwitchTargets ,
571575 discr : & mir:: Operand < ' tcx > ,
572576 ) -> Option < Self :: SwitchIntData > {
573577 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
@@ -578,20 +582,21 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
578582 return None ;
579583 }
580584
581- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
585+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, targets , discr)
582586 }
583587
584588 fn apply_switch_int_edge_effect (
585589 & self ,
586- data : & mut Self :: SwitchIntData ,
587590 state : & mut Self :: Domain ,
588- value : SwitchTargetValue ,
589- targets : & mir :: SwitchTargets ,
591+ data : & mut Self :: SwitchIntData ,
592+ target_idx : SwitchTargetIndex ,
590593 ) {
591- let inactive_variants = match value {
592- SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
593- SwitchTargetValue :: Otherwise if self . include_inactive_in_otherwise => {
594- InactiveVariants :: Inactives ( data. variants ( targets) )
594+ let inactive_variants = match target_idx {
595+ SwitchTargetIndex :: Normal ( target_idx) => {
596+ InactiveVariants :: Active ( data. variants [ target_idx] )
597+ }
598+ SwitchTargetIndex :: Otherwise if self . include_inactive_in_otherwise => {
599+ InactiveVariants :: Inactives ( data. variants . clone ( ) )
595600 }
596601 _ => return ,
597602 } ;
0 commit comments