@@ -12,7 +12,7 @@ use super::MoveDataParamEnv;
12
12
13
13
use crate :: util:: elaborate_drops:: DropFlagState ;
14
14
15
- use super :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
15
+ use super :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
16
16
use super :: { AnalysisDomain , BottomValue , GenKill , GenKillAnalysis } ;
17
17
18
18
use super :: drop_flag_effects_for_function_entry;
@@ -124,11 +124,23 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
124
124
tcx : TyCtxt < ' tcx > ,
125
125
body : & ' a Body < ' tcx > ,
126
126
mdpe : & ' a MoveDataParamEnv < ' tcx > ,
127
+
128
+ mark_inactive_variants_as_uninit : bool ,
127
129
}
128
130
129
131
impl < ' a , ' tcx > MaybeUninitializedPlaces < ' a , ' tcx > {
130
132
pub fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , mdpe : & ' a MoveDataParamEnv < ' tcx > ) -> Self {
131
- MaybeUninitializedPlaces { tcx, body, mdpe }
133
+ MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit : false }
134
+ }
135
+
136
+ /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
137
+ /// enum discriminant.
138
+ ///
139
+ /// This is correct in a vacuum but is not the default because it causes problems in the borrow
140
+ /// checker, where this information gets propagated along `FakeEdge`s.
141
+ pub fn mark_inactive_variants_as_uninit ( mut self ) -> Self {
142
+ self . mark_inactive_variants_as_uninit = true ;
143
+ self
132
144
}
133
145
}
134
146
@@ -350,27 +362,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
350
362
_adt : & ty:: AdtDef ,
351
363
variant : VariantIdx ,
352
364
) {
353
- let enum_mpi = match self . move_data ( ) . rev_lookup . find ( enum_place. as_ref ( ) ) {
354
- LookupResult :: Exact ( mpi) => mpi,
355
- LookupResult :: Parent ( _) => return ,
356
- } ;
357
-
358
- // Kill all move paths that correspond to variants other than this one
359
- let move_paths = & self . move_data ( ) . move_paths ;
360
- let enum_path = & move_paths[ enum_mpi] ;
361
- for ( mpi, variant_path) in enum_path. children ( move_paths) {
362
- trans. kill ( mpi) ;
363
- match variant_path. place . projection . last ( ) . unwrap ( ) {
364
- mir:: ProjectionElem :: Downcast ( _, idx) if * idx == variant => continue ,
365
- _ => drop_flag_effects:: on_all_children_bits (
366
- self . tcx ,
367
- self . body ,
368
- self . move_data ( ) ,
369
- mpi,
370
- |mpi| trans. kill ( mpi) ,
371
- ) ,
372
- }
373
- }
365
+ // Kill all move paths that correspond to variants we know to be inactive along this
366
+ // particular outgoing edge of a `SwitchInt`.
367
+ drop_flag_effects:: on_all_inactive_variants (
368
+ self . tcx ,
369
+ self . body ,
370
+ self . move_data ( ) ,
371
+ enum_place,
372
+ variant,
373
+ |mpi| trans. kill ( mpi) ,
374
+ ) ;
374
375
}
375
376
}
376
377
@@ -443,6 +444,30 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
443
444
} ,
444
445
) ;
445
446
}
447
+
448
+ fn discriminant_switch_effect (
449
+ & self ,
450
+ trans : & mut impl GenKill < Self :: Idx > ,
451
+ _block : mir:: BasicBlock ,
452
+ enum_place : mir:: Place < ' tcx > ,
453
+ _adt : & ty:: AdtDef ,
454
+ variant : VariantIdx ,
455
+ ) {
456
+ if !self . mark_inactive_variants_as_uninit {
457
+ return ;
458
+ }
459
+
460
+ // Mark all move paths that correspond to variants other than this one as maybe
461
+ // uninitialized (in reality, they are *definitely* uninitialized).
462
+ drop_flag_effects:: on_all_inactive_variants (
463
+ self . tcx ,
464
+ self . body ,
465
+ self . move_data ( ) ,
466
+ enum_place,
467
+ variant,
468
+ |mpi| trans. gen ( mpi) ,
469
+ ) ;
470
+ }
446
471
}
447
472
448
473
impl < ' a , ' tcx > AnalysisDomain < ' tcx > for DefinitelyInitializedPlaces < ' a , ' tcx > {
0 commit comments