2
2
3
3
use crate :: MirPass ;
4
4
use rustc_data_structures:: fx:: FxHashSet ;
5
- use rustc_middle:: mir:: patch:: MirPatch ;
6
5
use rustc_middle:: mir:: {
7
- BasicBlock , BasicBlockData , BasicBlocks , Body , Local , Operand , Rvalue , StatementKind ,
8
- TerminatorKind ,
6
+ BasicBlockData , Body , Local , Operand , Rvalue , StatementKind , Terminator , TerminatorKind ,
9
7
} ;
10
8
use rustc_middle:: ty:: layout:: TyAndLayout ;
11
9
use rustc_middle:: ty:: { Ty , TyCtxt } ;
@@ -79,8 +77,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
79
77
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
80
78
trace ! ( "UninhabitedEnumBranching starting for {:?}" , body. source) ;
81
79
82
- let mut unreachable_targets = Vec :: new ( ) ;
83
- let mut patch = MirPatch :: new ( body) ;
80
+ let mut removable_switchs = Vec :: new ( ) ;
84
81
85
82
for ( bb, bb_data) in body. basic_blocks . iter_enumerated ( ) {
86
83
trace ! ( "processing block {:?}" , bb) ;
@@ -95,73 +92,46 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
95
92
tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) . and ( discriminant_ty) ,
96
93
) ;
97
94
98
- let mut allowed_variants = if let Ok ( layout) = layout {
95
+ let allowed_variants = if let Ok ( layout) = layout {
99
96
variant_discriminants ( & layout, discriminant_ty, tcx)
100
- } else if let Some ( variant_range) = discriminant_ty. variant_range ( tcx) {
101
- variant_range
102
- . map ( |variant| {
103
- discriminant_ty. discriminant_for_variant ( tcx, variant) . unwrap ( ) . val
104
- } )
105
- . collect ( )
106
97
} else {
107
98
continue ;
108
99
} ;
109
100
110
101
trace ! ( "allowed_variants = {:?}" , allowed_variants) ;
111
102
112
- unreachable_targets. clear ( ) ;
113
- let TerminatorKind :: SwitchInt { targets, discr } = & bb_data. terminator ( ) . kind else {
114
- bug ! ( )
115
- } ;
103
+ let terminator = bb_data. terminator ( ) ;
104
+ let TerminatorKind :: SwitchInt { targets, .. } = & terminator. kind else { bug ! ( ) } ;
116
105
106
+ let mut reachable_count = 0 ;
117
107
for ( index, ( val, _) ) in targets. iter ( ) . enumerate ( ) {
118
- if !allowed_variants. remove ( & val) {
119
- unreachable_targets. push ( index) ;
120
- }
121
- }
122
- let otherwise_is_empty_unreachable =
123
- body. basic_blocks [ targets. otherwise ( ) ] . is_empty_unreachable ( ) ;
124
- // After resolving https://github.com/llvm/llvm-project/issues/78578,
125
- // we can remove the limit on the number of successors.
126
- fn check_successors ( basic_blocks : & BasicBlocks < ' _ > , bb : BasicBlock ) -> bool {
127
- let mut successors = basic_blocks[ bb] . terminator ( ) . successors ( ) ;
128
- let Some ( first_successor) = successors. next ( ) else { return true } ;
129
- if successors. next ( ) . is_some ( ) {
130
- return true ;
108
+ if allowed_variants. contains ( & val) {
109
+ reachable_count += 1 ;
110
+ } else {
111
+ removable_switchs. push ( ( bb, index) ) ;
131
112
}
132
- if let TerminatorKind :: SwitchInt { .. } =
133
- & basic_blocks[ first_successor] . terminator ( ) . kind
134
- {
135
- return false ;
136
- } ;
137
- true
138
113
}
139
- let otherwise_is_last_variant = !otherwise_is_empty_unreachable
140
- && allowed_variants. len ( ) == 1
141
- && check_successors ( & body. basic_blocks , targets. otherwise ( ) ) ;
142
- let replace_otherwise_to_unreachable = otherwise_is_last_variant
143
- || !otherwise_is_empty_unreachable && allowed_variants. is_empty ( ) ;
144
114
145
- if unreachable_targets . is_empty ( ) && !replace_otherwise_to_unreachable {
146
- continue ;
115
+ if reachable_count == allowed_variants . len ( ) {
116
+ removable_switchs . push ( ( bb , targets . iter ( ) . count ( ) ) ) ;
147
117
}
118
+ }
148
119
149
- let unreachable_block = patch. unreachable_no_cleanup_block ( ) ;
150
- let mut targets = targets. clone ( ) ;
151
- if replace_otherwise_to_unreachable {
152
- if otherwise_is_last_variant {
153
- #[ allow( rustc:: potential_query_instability) ]
154
- let last_variant = * allowed_variants. iter ( ) . next ( ) . unwrap ( ) ;
155
- targets. add_target ( last_variant, targets. otherwise ( ) ) ;
156
- }
157
- unreachable_targets. push ( targets. iter ( ) . count ( ) ) ;
158
- }
159
- for index in unreachable_targets. iter ( ) {
160
- targets. all_targets_mut ( ) [ * index] = unreachable_block;
161
- }
162
- patch. patch_terminator ( bb, TerminatorKind :: SwitchInt { targets, discr : discr. clone ( ) } ) ;
120
+ if removable_switchs. is_empty ( ) {
121
+ return ;
163
122
}
164
123
165
- patch. apply ( body) ;
124
+ let new_block = BasicBlockData :: new ( Some ( Terminator {
125
+ source_info : body. basic_blocks [ removable_switchs[ 0 ] . 0 ] . terminator ( ) . source_info ,
126
+ kind : TerminatorKind :: Unreachable ,
127
+ } ) ) ;
128
+ let unreachable_block = body. basic_blocks . as_mut ( ) . push ( new_block) ;
129
+
130
+ for ( bb, index) in removable_switchs {
131
+ let bb = & mut body. basic_blocks . as_mut ( ) [ bb] ;
132
+ let terminator = bb. terminator_mut ( ) ;
133
+ let TerminatorKind :: SwitchInt { targets, .. } = & mut terminator. kind else { bug ! ( ) } ;
134
+ targets. all_targets_mut ( ) [ index] = unreachable_block;
135
+ }
166
136
}
167
137
}
0 commit comments