@@ -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.
@@ -364,15 +415,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
364415 return None ;
365416 }
366417
367- discr. place ( ) . and_then ( |discr| {
368- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
369- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
370- enum_place,
371- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
372- index : 0 ,
373- } ,
374- )
375- } )
418+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
376419 }
377420
378421 fn apply_switch_int_edge_effect (
@@ -483,15 +526,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
483526 return None ;
484527 }
485528
486- discr. place ( ) . and_then ( |discr| {
487- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
488- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
489- enum_place,
490- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
491- index : 0 ,
492- } ,
493- )
494- } )
529+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
495530 }
496531
497532 fn apply_switch_int_edge_effect (
@@ -597,45 +632,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
597632 }
598633 }
599634}
600-
601- /// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
602- /// an enum discriminant.
603- ///
604- /// We expect such blocks to have a call to `discriminant` as their last statement like so:
605- ///
606- /// ```text
607- /// ...
608- /// _42 = discriminant(_1)
609- /// SwitchInt(_42, ..)
610- /// ```
611- ///
612- /// If the basic block matches this pattern, this function returns the place corresponding to the
613- /// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
614- fn switch_on_enum_discriminant < ' mir , ' tcx > (
615- tcx : TyCtxt < ' tcx > ,
616- body : & ' mir mir:: Body < ' tcx > ,
617- block : & ' mir mir:: BasicBlockData < ' tcx > ,
618- switch_on : mir:: Place < ' tcx > ,
619- ) -> Option < ( mir:: Place < ' tcx > , ty:: AdtDef < ' tcx > ) > {
620- for statement in block. statements . iter ( ) . rev ( ) {
621- match & statement. kind {
622- mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( discriminated) ) )
623- if * lhs == switch_on =>
624- {
625- match discriminated. ty ( body, tcx) . ty . kind ( ) {
626- ty:: Adt ( def, _) => return Some ( ( * discriminated, * def) ) ,
627-
628- // `Rvalue::Discriminant` is also used to get the active yield point for a
629- // coroutine, but we do not need edge-specific effects in that case. This may
630- // change in the future.
631- ty:: Coroutine ( ..) => return None ,
632-
633- t => bug ! ( "`discriminant` called on unexpected type {:?}" , t) ,
634- }
635- }
636- mir:: StatementKind :: Coverage ( _) => continue ,
637- _ => return None ,
638- }
639- }
640- None
641- }
0 commit comments