@@ -40,6 +40,57 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
40
40
}
41
41
}
42
42
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
+
43
94
/// `MaybeInitializedPlaces` tracks all places that might be
44
95
/// initialized upon reaching a particular point in the control flow
45
96
/// for a function.
@@ -428,15 +479,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
428
479
return None ;
429
480
}
430
481
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)
440
483
}
441
484
442
485
fn apply_switch_int_edge_effect (
@@ -547,15 +590,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
547
590
return None ;
548
591
}
549
592
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)
559
594
}
560
595
561
596
fn apply_switch_int_edge_effect (
@@ -725,45 +760,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
725
760
}
726
761
}
727
762
}
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