@@ -9,9 +9,10 @@ use rustc_middle::mir::{
9
9
} ;
10
10
use rustc_middle:: ty:: util:: Discr ;
11
11
use rustc_middle:: ty:: { self , TyCtxt } ;
12
+ use smallvec:: SmallVec ;
12
13
use tracing:: { debug, instrument} ;
13
14
14
- use crate :: drop_flag_effects:: DropFlagState ;
15
+ use crate :: drop_flag_effects:: { DropFlagState , InactiveVariants } ;
15
16
use crate :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
16
17
use crate :: {
17
18
Analysis , GenKill , MaybeReachable , drop_flag_effects, drop_flag_effects_for_function_entry,
@@ -26,6 +27,12 @@ pub struct MaybePlacesSwitchIntData<'tcx> {
26
27
}
27
28
28
29
impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
30
+ /// Creates a `SmallVec` mapping each target in `targets` to its `VariantIdx`.
31
+ fn variants ( & mut self , targets : & mir:: SwitchTargets ) -> SmallVec < [ VariantIdx ; 4 ] > {
32
+ self . index = 0 ;
33
+ targets. all_values ( ) . iter ( ) . map ( |value| self . next_discr ( value. get ( ) ) ) . collect ( )
34
+ }
35
+
29
36
// The discriminant order in the `SwitchInt` targets should match the order yielded by
30
37
// `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
31
38
// corresponding variant in linear time.
@@ -131,12 +138,26 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> {
131
138
tcx : TyCtxt < ' tcx > ,
132
139
body : & ' a Body < ' tcx > ,
133
140
move_data : & ' a MoveData < ' tcx > ,
141
+ exclude_inactive_in_otherwise : bool ,
134
142
skip_unreachable_unwind : bool ,
135
143
}
136
144
137
145
impl < ' a , ' tcx > MaybeInitializedPlaces < ' a , ' tcx > {
138
146
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 }
147
+ MaybeInitializedPlaces {
148
+ tcx,
149
+ body,
150
+ move_data,
151
+ exclude_inactive_in_otherwise : false ,
152
+ skip_unreachable_unwind : false ,
153
+ }
154
+ }
155
+
156
+ /// Ensures definitely inactive variants are excluded from the set of initialized places for
157
+ /// blocks reached through an `otherwise` edge.
158
+ pub fn exclude_inactive_in_otherwise ( mut self ) -> Self {
159
+ self . exclude_inactive_in_otherwise = true ;
160
+ self
140
161
}
141
162
142
163
pub fn skipping_unreachable_unwind ( mut self ) -> Self {
@@ -208,6 +229,7 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
208
229
move_data : & ' a MoveData < ' tcx > ,
209
230
210
231
mark_inactive_variants_as_uninit : bool ,
232
+ include_inactive_in_otherwise : bool ,
211
233
skip_unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
212
234
}
213
235
@@ -218,6 +240,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
218
240
body,
219
241
move_data,
220
242
mark_inactive_variants_as_uninit : false ,
243
+ include_inactive_in_otherwise : false ,
221
244
skip_unreachable_unwind : DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
222
245
}
223
246
}
@@ -232,6 +255,13 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
232
255
self
233
256
}
234
257
258
+ /// Ensures definitely inactive variants are included in the set of uninitialized places for
259
+ /// blocks reached through an `otherwise` edge.
260
+ pub fn include_inactive_in_otherwise ( mut self ) -> Self {
261
+ self . include_inactive_in_otherwise = true ;
262
+ self
263
+ }
264
+
235
265
pub fn skipping_unreachable_unwind (
236
266
mut self ,
237
267
unreachable_unwind : DenseBitSet < mir:: BasicBlock > ,
@@ -431,17 +461,24 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
431
461
data : & mut Self :: SwitchIntData ,
432
462
state : & mut Self :: Domain ,
433
463
value : SwitchTargetValue ,
464
+ targets : & mir:: SwitchTargets ,
434
465
) {
435
- if let SwitchTargetValue :: Normal ( value) = value {
436
- // Kill all move paths that correspond to variants we know to be inactive along this
437
- // particular outgoing edge of a `SwitchInt`.
438
- drop_flag_effects:: on_all_inactive_variants (
439
- self . move_data ,
440
- data. enum_place ,
441
- data. next_discr ( value) ,
442
- |mpi| state. kill ( mpi) ,
443
- ) ;
444
- }
466
+ let inactive_variants = match value {
467
+ SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
468
+ SwitchTargetValue :: Otherwise if self . exclude_inactive_in_otherwise => {
469
+ InactiveVariants :: Inactives ( data. variants ( targets) )
470
+ }
471
+ _ => return ,
472
+ } ;
473
+
474
+ // Kill all move paths that correspond to variants we know to be inactive along this
475
+ // particular outgoing edge of a `SwitchInt`.
476
+ drop_flag_effects:: on_all_inactive_variants (
477
+ self . move_data ,
478
+ data. enum_place ,
479
+ & inactive_variants,
480
+ |mpi| state. kill ( mpi) ,
481
+ ) ;
445
482
}
446
483
}
447
484
@@ -544,17 +581,24 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
544
581
data : & mut Self :: SwitchIntData ,
545
582
state : & mut Self :: Domain ,
546
583
value : SwitchTargetValue ,
584
+ targets : & mir:: SwitchTargets ,
547
585
) {
548
- if let SwitchTargetValue :: Normal ( value) = value {
549
- // Mark all move paths that correspond to variants other than this one as maybe
550
- // uninitialized (in reality, they are *definitely* uninitialized).
551
- drop_flag_effects:: on_all_inactive_variants (
552
- self . move_data ,
553
- data. enum_place ,
554
- data. next_discr ( value) ,
555
- |mpi| state. gen_ ( mpi) ,
556
- ) ;
557
- }
586
+ let inactive_variants = match value {
587
+ SwitchTargetValue :: Normal ( value) => InactiveVariants :: Active ( data. next_discr ( value) ) ,
588
+ SwitchTargetValue :: Otherwise if self . include_inactive_in_otherwise => {
589
+ InactiveVariants :: Inactives ( data. variants ( targets) )
590
+ }
591
+ _ => return ,
592
+ } ;
593
+
594
+ // Mark all move paths that correspond to variants other than this one as maybe
595
+ // uninitialized (in reality, they are *definitely* uninitialized).
596
+ drop_flag_effects:: on_all_inactive_variants (
597
+ self . move_data ,
598
+ data. enum_place ,
599
+ & inactive_variants,
600
+ |mpi| state. gen_ ( mpi) ,
601
+ ) ;
558
602
}
559
603
}
560
604
0 commit comments