@@ -131,12 +131,26 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> {
131
131
tcx : TyCtxt < ' tcx > ,
132
132
body : & ' a Body < ' tcx > ,
133
133
move_data : & ' a MoveData < ' tcx > ,
134
+ exclude_inactive_in_otherwise : bool ,
134
135
skip_unreachable_unwind : bool ,
135
136
}
136
137
137
138
impl < ' a , ' tcx > MaybeInitializedPlaces < ' a , ' tcx > {
138
139
pub fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , move_data : & ' a MoveData < ' tcx > ) -> Self {
139
- MaybeInitializedPlaces { tcx, body, move_data, skip_unreachable_unwind : false }
140
+ MaybeInitializedPlaces {
141
+ tcx,
142
+ body,
143
+ move_data,
144
+ exclude_inactive_in_otherwise : false ,
145
+ skip_unreachable_unwind : false ,
146
+ }
147
+ }
148
+
149
+ /// Ensures definitely inactive variants are excluded from the set of initialized places for
150
+ /// blocks reached through an `otherwise` edge.
151
+ pub fn exclude_inactive_in_otherwise ( mut self ) -> Self {
152
+ self . exclude_inactive_in_otherwise = true ;
153
+ self
140
154
}
141
155
142
156
pub fn skipping_unreachable_unwind ( mut self ) -> Self {
@@ -208,6 +222,7 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
208
222
move_data : & ' a MoveData < ' tcx > ,
209
223
210
224
mark_inactive_variants_as_uninit : bool ,
225
+ include_inactive_in_otherwise : bool ,
211
226
skip_unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
212
227
}
213
228
@@ -218,6 +233,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
218
233
body,
219
234
move_data,
220
235
mark_inactive_variants_as_uninit : false ,
236
+ include_inactive_in_otherwise : false ,
221
237
skip_unreachable_unwind : DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
222
238
}
223
239
}
@@ -232,6 +248,13 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
232
248
self
233
249
}
234
250
251
+ /// Ensures definitely inactive variants are included in the set of uninitialized places for
252
+ /// blocks reached through an `otherwise` edge.
253
+ pub fn include_inactive_in_otherwise ( mut self ) -> Self {
254
+ self . include_inactive_in_otherwise = true ;
255
+ self
256
+ }
257
+
235
258
pub fn skipping_unreachable_unwind (
236
259
mut self ,
237
260
unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
@@ -431,22 +454,47 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
431
454
data : & mut Self :: SwitchIntData ,
432
455
state : & mut Self :: Domain ,
433
456
value : SwitchTargetValue ,
434
- mut otherwise_state : Option < & mut Self :: Domain > ,
457
+ otherwise_state : Option < & mut Self :: Domain > ,
435
458
) {
436
459
if let SwitchTargetValue :: Normal ( value) = value {
437
460
// Kill all move paths that correspond to variants we know to be inactive along this
438
461
// particular outgoing edge of a `SwitchInt`.
439
- drop_flag_effects:: on_all_inactive_variants (
462
+ drop_flag_effects:: on_all_variants (
440
463
self . move_data ,
441
464
data. enum_place ,
442
465
data. next_discr ( value) ,
443
466
|mpi| state. kill ( mpi) ,
444
- move |mpi| {
445
- otherwise_state. as_mut ( ) . map ( |state| state. kill ( mpi) ) ;
446
- } ,
467
+ otherwise_state. map ( |state| |mpi| state. kill ( mpi) ) ,
447
468
) ;
448
469
}
449
470
}
471
+
472
+ fn apply_switch_int_edge_effect_for_targets (
473
+ & mut self ,
474
+ targets : & mir:: SwitchTargets ,
475
+ mut data : Self :: SwitchIntData ,
476
+ state : & mut Self :: Domain ,
477
+ mut propagate : impl FnMut ( mir:: BasicBlock , & Self :: Domain ) ,
478
+ ) {
479
+ let analyze_otherwise = self . exclude_inactive_in_otherwise
480
+ && ( 1 ..data. discriminants . len ( ) ) . contains ( & targets. all_values ( ) . len ( ) ) ;
481
+
482
+ let mut otherwise_state = if analyze_otherwise { Some ( state. clone ( ) ) } else { None } ;
483
+ let mut target_state = MaybeReachable :: Unreachable ;
484
+
485
+ for ( value, target) in targets. iter ( ) {
486
+ target_state. clone_from ( & state) ;
487
+ self . apply_switch_int_edge_effect (
488
+ & mut data,
489
+ & mut target_state,
490
+ SwitchTargetValue :: Normal ( value) ,
491
+ otherwise_state. as_mut ( ) ,
492
+ ) ;
493
+ propagate ( target, & target_state) ;
494
+ }
495
+
496
+ propagate ( targets. otherwise ( ) , otherwise_state. as_ref ( ) . unwrap_or ( state) ) ;
497
+ }
450
498
}
451
499
452
500
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
@@ -548,21 +596,46 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
548
596
data : & mut Self :: SwitchIntData ,
549
597
state : & mut Self :: Domain ,
550
598
value : SwitchTargetValue ,
551
- mut otherwise_state : Option < & mut Self :: Domain > ,
599
+ otherwise_state : Option < & mut Self :: Domain > ,
552
600
) {
553
601
if let SwitchTargetValue :: Normal ( value) = value {
554
602
// Mark all move paths that correspond to variants other than this one as maybe
555
603
// uninitialized (in reality, they are *definitely* uninitialized).
556
- drop_flag_effects:: on_all_inactive_variants (
604
+ drop_flag_effects:: on_all_variants (
557
605
self . move_data ,
558
606
data. enum_place ,
559
607
data. next_discr ( value) ,
560
608
|mpi| state. gen_ ( mpi) ,
561
- |mpi| {
562
- otherwise_state. as_mut ( ) . map ( |state| state. gen_ ( mpi) ) ;
563
- } ,
609
+ otherwise_state. map ( |state| |mpi| state. gen_ ( mpi) ) ,
610
+ ) ;
611
+ }
612
+ }
613
+
614
+ fn apply_switch_int_edge_effect_for_targets (
615
+ & mut self ,
616
+ targets : & mir:: SwitchTargets ,
617
+ mut data : Self :: SwitchIntData ,
618
+ state : & mut Self :: Domain ,
619
+ mut propagate : impl FnMut ( mir:: BasicBlock , & Self :: Domain ) ,
620
+ ) {
621
+ let analyze_otherwise = self . include_inactive_in_otherwise
622
+ && ( 1 ..data. discriminants . len ( ) ) . contains ( & targets. all_values ( ) . len ( ) ) ;
623
+
624
+ let mut otherwise_state = if analyze_otherwise { Some ( state. clone ( ) ) } else { None } ;
625
+ let mut target_state = MixedBitSet :: new_empty ( self . move_data ( ) . move_paths . len ( ) ) ;
626
+
627
+ for ( value, target) in targets. iter ( ) {
628
+ target_state. clone_from ( & state) ;
629
+ self . apply_switch_int_edge_effect (
630
+ & mut data,
631
+ & mut target_state,
632
+ SwitchTargetValue :: Normal ( value) ,
633
+ otherwise_state. as_mut ( ) ,
564
634
) ;
635
+ propagate ( target, & target_state) ;
565
636
}
637
+
638
+ propagate ( targets. otherwise ( ) , otherwise_state. as_ref ( ) . unwrap_or ( state) ) ;
566
639
}
567
640
}
568
641
0 commit comments