@@ -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
@@ -448,25 +441,32 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
448441 & mut self ,
449442 block : mir:: BasicBlock ,
450443 discr : & mir:: Operand < ' tcx > ,
444+ targets : & mir:: SwitchTargets ,
451445 ) -> Option < Self :: SwitchIntData > {
452446 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
453447 return None ;
454448 }
455449
456- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
450+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr, targets)
451+ }
452+
453+ #[ inline]
454+ fn switch_int_target_variants < ' a > (
455+ data : & ' a Self :: SwitchIntData ,
456+ ) -> impl Iterator < Item = & ' a ( VariantIdx , mir:: BasicBlock ) > {
457+ data. targets . iter ( )
457458 }
458459
459460 fn apply_switch_int_edge_effect (
460461 & mut self ,
461- data : & mut Self :: SwitchIntData ,
462+ data : & Self :: SwitchIntData ,
462463 state : & mut Self :: Domain ,
463464 value : SwitchTargetValue ,
464- targets : & mir:: SwitchTargets ,
465465 ) {
466466 let inactive_variants = match value {
467- SwitchTargetValue :: Normal ( value ) => InactiveVariants :: Active ( data . next_discr ( value ) ) ,
467+ SwitchTargetValue :: Normal ( variant_idx ) => InactiveVariants :: Active ( variant_idx ) ,
468468 SwitchTargetValue :: Otherwise if self . exclude_inactive_in_otherwise => {
469- InactiveVariants :: Inactives ( data. variants ( targets) )
469+ InactiveVariants :: Inactives ( & data. targets )
470470 }
471471 _ => return ,
472472 } ;
@@ -564,6 +564,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
564564 & mut self ,
565565 block : mir:: BasicBlock ,
566566 discr : & mir:: Operand < ' tcx > ,
567+ targets : & mir:: SwitchTargets ,
567568 ) -> Option < Self :: SwitchIntData > {
568569 if !self . tcx . sess . opts . unstable_opts . precise_enum_drop_elaboration {
569570 return None ;
@@ -573,20 +574,26 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
573574 return None ;
574575 }
575576
576- MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
577+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr, targets)
578+ }
579+
580+ #[ inline]
581+ fn switch_int_target_variants < ' a > (
582+ data : & ' a Self :: SwitchIntData ,
583+ ) -> impl Iterator < Item = & ' a ( VariantIdx , mir:: BasicBlock ) > {
584+ data. targets . iter ( )
577585 }
578586
579587 fn apply_switch_int_edge_effect (
580588 & mut self ,
581- data : & mut Self :: SwitchIntData ,
589+ data : & Self :: SwitchIntData ,
582590 state : & mut Self :: Domain ,
583591 value : SwitchTargetValue ,
584- targets : & mir:: SwitchTargets ,
585592 ) {
586593 let inactive_variants = match value {
587- SwitchTargetValue :: Normal ( value ) => InactiveVariants :: Active ( data . next_discr ( value ) ) ,
594+ SwitchTargetValue :: Normal ( variant_idx ) => InactiveVariants :: Active ( variant_idx ) ,
588595 SwitchTargetValue :: Otherwise if self . include_inactive_in_otherwise => {
589- InactiveVariants :: Inactives ( data. variants ( targets) )
596+ InactiveVariants :: Inactives ( & data. targets )
590597 }
591598 _ => return ,
592599 } ;
0 commit comments