@@ -40,6 +40,57 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
4040 }
4141}
4242
43+ impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
44+ fn new (
45+ tcx : TyCtxt < ' tcx > ,
46+ body : & Body < ' tcx > ,
47+ block : mir:: BasicBlock ,
48+ discr : & mir:: Operand < ' tcx > ,
49+ ) -> Option < Self > {
50+ let Some ( discr) = discr. place ( ) else { return None } ;
51+
52+ // Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt`
53+ // is an enum discriminant.
54+ //
55+ // We expect such blocks to have a call to `discriminant` as their last statement like so:
56+ // ```text
57+ // ...
58+ // _42 = discriminant(_1)
59+ // SwitchInt(_42, ..)
60+ // ```
61+ // If the basic block matches this pattern, this function gathers the place corresponding
62+ // to the enum (`_1` in the example above) as well as the discriminants.
63+ let block_data = & body[ block] ;
64+ for statement in block_data. statements . iter ( ) . rev ( ) {
65+ match statement. kind {
66+ mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( enum_place) ) )
67+ if lhs == discr =>
68+ {
69+ match enum_place. ty ( body, tcx) . ty . kind ( ) {
70+ ty:: Adt ( enum_def, _) => {
71+ return Some ( MaybePlacesSwitchIntData {
72+ enum_place,
73+ discriminants : enum_def. discriminants ( tcx) . collect ( ) ,
74+ index : 0 ,
75+ } ) ;
76+ }
77+
78+ // `Rvalue::Discriminant` is also used to get the active yield point for a
79+ // coroutine, but we do not need edge-specific effects in that case. This
80+ // may change in the future.
81+ ty:: Coroutine ( ..) => break ,
82+
83+ t => bug ! ( "`discriminant` called on unexpected type {:?}" , t) ,
84+ }
85+ }
86+ mir:: StatementKind :: Coverage ( _) => continue ,
87+ _ => break ,
88+ }
89+ }
90+ None
91+ }
92+ }
93+
4394/// `MaybeInitializedPlaces` tracks all places that might be
4495/// initialized upon reaching a particular point in the control flow
4596/// for a function.
@@ -428,15 +479,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
428479 return None ;
429480 }
430481
431- discr. place ( ) . and_then ( |discr| {
432- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
433- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
434- enum_place,
435- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
436- index : 0 ,
437- } ,
438- )
439- } )
482+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
440483 }
441484
442485 fn apply_switch_int_edge_effect (
@@ -547,15 +590,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
547590 return None ;
548591 }
549592
550- discr. place ( ) . and_then ( |discr| {
551- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
552- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
553- enum_place,
554- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
555- index : 0 ,
556- } ,
557- )
558- } )
593+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
559594 }
560595
561596 fn apply_switch_int_edge_effect (
@@ -725,45 +760,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
725760 }
726761 }
727762}
728-
729- /// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
730- /// an enum discriminant.
731- ///
732- /// We expect such blocks to have a call to `discriminant` as their last statement like so:
733- ///
734- /// ```text
735- /// ...
736- /// _42 = discriminant(_1)
737- /// SwitchInt(_42, ..)
738- /// ```
739- ///
740- /// If the basic block matches this pattern, this function returns the place corresponding to the
741- /// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
742- fn switch_on_enum_discriminant < ' mir , ' tcx > (
743- tcx : TyCtxt < ' tcx > ,
744- body : & ' mir mir:: Body < ' tcx > ,
745- block : & ' mir mir:: BasicBlockData < ' tcx > ,
746- switch_on : mir:: Place < ' tcx > ,
747- ) -> Option < ( mir:: Place < ' tcx > , ty:: AdtDef < ' tcx > ) > {
748- for statement in block. statements . iter ( ) . rev ( ) {
749- match & statement. kind {
750- mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( discriminated) ) )
751- if * lhs == switch_on =>
752- {
753- match discriminated. ty ( body, tcx) . ty . kind ( ) {
754- ty:: Adt ( def, _) => return Some ( ( * discriminated, * def) ) ,
755-
756- // `Rvalue::Discriminant` is also used to get the active yield point for a
757- // coroutine, but we do not need edge-specific effects in that case. This may
758- // change in the future.
759- ty:: Coroutine ( ..) => return None ,
760-
761- t => bug ! ( "`discriminant` called on unexpected type {:?}" , t) ,
762- }
763- }
764- mir:: StatementKind :: Coverage ( _) => continue ,
765- _ => return None ,
766- }
767- }
768- None
769- }
0 commit comments