@@ -7,9 +7,7 @@ use rustc_middle::bug;
77use rustc_middle:: mir:: {
88 self , Body , CallReturnPlaces , Location , SwitchTargetValue , TerminatorEdges ,
99} ;
10- use rustc_middle:: ty:: util:: Discr ;
11- use rustc_middle:: ty:: { self , TyCtxt } ;
12- use smallvec:: SmallVec ;
10+ use rustc_middle:: ty:: { self , AdtDef , TyCtxt } ;
1311use tracing:: { debug, instrument} ;
1412
1513use crate :: drop_flag_effects:: { DropFlagState , InactiveVariants } ;
@@ -22,30 +20,25 @@ use crate::{
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 ,
23+ targets : Vec < ( VariantIdx , mir:: BasicBlock ) > ,
2724}
2825
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- }
26+ /// Maps values of targets in `SwitchTargets` to `(VariantIdx, BasicBlock).` Panics if the variants
27+ /// in `targets` aren't in the same order as `AdtDef::discriminants`.
28+ fn collect_switch_targets < ' tcx > (
29+ enum_def : AdtDef < ' tcx > ,
30+ targets : & mir:: SwitchTargets ,
31+ tcx : TyCtxt < ' tcx > ,
32+ ) -> Vec < ( VariantIdx , mir:: BasicBlock ) > {
33+ let mut discriminants = enum_def. discriminants ( tcx) ;
34+
35+ Vec :: from_iter ( targets. iter ( ) . map ( |( value, bb) | {
36+ let Some ( ( variant_idx, _) ) = discriminants. find ( |( _, discr) | discr. val == value) else {
37+ bug ! ( "ran out of discriminants before matching all switch targets" ) ;
38+ } ;
39+
40+ ( variant_idx, bb)
41+ } ) )
4942}
5043
5144impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
@@ -54,6 +47,7 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
5447 body : & Body < ' tcx > ,
5548 block : mir:: BasicBlock ,
5649 discr : & mir:: Operand < ' tcx > ,
50+ targets : & mir:: SwitchTargets ,
5751 ) -> Option < Self > {
5852 let Some ( discr) = discr. place ( ) else { return None } ;
5953
@@ -78,8 +72,7 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
7872 ty:: Adt ( enum_def, _) => {
7973 return Some ( MaybePlacesSwitchIntData {
8074 enum_place,
81- discriminants : enum_def. discriminants ( tcx) . collect ( ) ,
82- index : 0 ,
75+ targets : collect_switch_targets ( * enum_def, targets, tcx) ,
8376 } ) ;
8477 }
8578
@@ -451,25 +444,32 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
451444 & mut self ,
452445 block : mir:: BasicBlock ,
453446 discr : & mir:: Operand < ' tcx > ,
447+ targets : & mir:: SwitchTargets ,
454448 ) -> Option < Self :: SwitchIntData > {
455449 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
456450 return None ;
457451 }
458452
459- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
453+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr, targets)
454+ }
455+
456+ #[ inline]
457+ fn switch_int_target_variants < ' a > (
458+ data : & ' a Self :: SwitchIntData ,
459+ ) -> impl Iterator < Item = & ' a ( VariantIdx , mir:: BasicBlock ) > {
460+ data. targets . iter ( )
460461 }
461462
462463 fn apply_switch_int_edge_effect (
463464 & mut self ,
464- data : & mut Self :: SwitchIntData ,
465+ data : & Self :: SwitchIntData ,
465466 state : & mut Self :: Domain ,
466467 value : SwitchTargetValue ,
467- targets : & mir:: SwitchTargets ,
468468 ) {
469469 let inactive_variants = match value {
470- SwitchTargetValue :: Normal ( value ) => InactiveVariants :: Active ( data . next_discr ( value ) ) ,
470+ SwitchTargetValue :: Normal ( variant_idx ) => InactiveVariants :: Active ( variant_idx ) ,
471471 SwitchTargetValue :: Otherwise if self . exclude_inactive_in_otherwise => {
472- InactiveVariants :: Inactives ( data. variants ( targets) )
472+ InactiveVariants :: Inactives ( & data. targets )
473473 }
474474 _ => return ,
475475 } ;
@@ -567,6 +567,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
567567 & mut self ,
568568 block : mir:: BasicBlock ,
569569 discr : & mir:: Operand < ' tcx > ,
570+ targets : & mir:: SwitchTargets ,
570571 ) -> Option < Self :: SwitchIntData > {
571572 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
572573 return None ;
@@ -576,20 +577,26 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
576577 return None ;
577578 }
578579
579- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
580+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr, targets)
581+ }
582+
583+ #[ inline]
584+ fn switch_int_target_variants < ' a > (
585+ data : & ' a Self :: SwitchIntData ,
586+ ) -> impl Iterator < Item = & ' a ( VariantIdx , mir:: BasicBlock ) > {
587+ data. targets . iter ( )
580588 }
581589
582590 fn apply_switch_int_edge_effect (
583591 & mut self ,
584- data : & mut Self :: SwitchIntData ,
592+ data : & Self :: SwitchIntData ,
585593 state : & mut Self :: Domain ,
586594 value : SwitchTargetValue ,
587- targets : & mir:: SwitchTargets ,
588595 ) {
589596 let inactive_variants = match value {
590- SwitchTargetValue :: Normal ( value ) => InactiveVariants :: Active ( data . next_discr ( value ) ) ,
597+ SwitchTargetValue :: Normal ( variant_idx ) => InactiveVariants :: Active ( variant_idx ) ,
591598 SwitchTargetValue :: Otherwise if self . include_inactive_in_otherwise => {
592- InactiveVariants :: Inactives ( data. variants ( targets) )
599+ InactiveVariants :: Inactives ( & data. targets )
593600 }
594601 _ => return ,
595602 } ;
0 commit comments