@@ -11,7 +11,7 @@ use super::MoveDataParamEnv;
1111
1212use crate :: util:: elaborate_drops:: DropFlagState ;
1313
14- use super :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
14+ use super :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
1515use super :: { lattice, AnalysisDomain , GenKill , GenKillAnalysis } ;
1616
1717use super :: drop_flag_effects_for_function_entry;
@@ -362,40 +362,17 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
362362 return ;
363363 }
364364
365- let enum_ = discr. place ( ) . and_then ( |discr| {
366- switch_on_enum_discriminant ( self . tcx , & self . body , & self . body [ block] , discr)
367- } ) ;
368-
369- let ( enum_place, enum_def) = match enum_ {
370- Some ( x) => x,
371- None => return ,
372- } ;
373-
374- let mut discriminants = enum_def. discriminants ( self . tcx ) ;
375- edge_effects. apply ( |trans, edge| {
376- let value = match edge. value {
377- Some ( x) => x,
378- None => return ,
379- } ;
380-
381- // MIR building adds discriminants to the `values` array in the same order as they
382- // are yielded by `AdtDef::discriminants`. We rely on this to match each
383- // discriminant in `values` to its corresponding variant in linear time.
384- let ( variant, _) = discriminants
385- . find ( |& ( _, discr) | discr. val == value)
386- . expect ( "Order of `AdtDef::discriminants` differed from `SwitchInt::values`" ) ;
387-
388- // Kill all move paths that correspond to variants we know to be inactive along this
389- // particular outgoing edge of a `SwitchInt`.
390- drop_flag_effects:: on_all_inactive_variants (
391- self . tcx ,
392- self . body ,
393- self . move_data ( ) ,
394- enum_place,
395- variant,
396- |mpi| trans. kill ( mpi) ,
397- ) ;
398- } ) ;
365+ // Kill all move paths that correspond to variants we know to be inactive along a
366+ // particular outgoing edge of a `SwitchInt`.
367+ enum_discriminant_switch_inactive_variant_effects (
368+ self . tcx ,
369+ self . body ,
370+ self . move_data ( ) ,
371+ block,
372+ discr,
373+ edge_effects,
374+ |trans, mpi| trans. kill ( mpi) ,
375+ ) ;
399376 }
400377}
401378
@@ -481,40 +458,17 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
481458 return ;
482459 }
483460
484- let enum_ = discr. place ( ) . and_then ( |discr| {
485- switch_on_enum_discriminant ( self . tcx , & self . body , & self . body [ block] , discr)
486- } ) ;
487-
488- let ( enum_place, enum_def) = match enum_ {
489- Some ( x) => x,
490- None => return ,
491- } ;
492-
493- let mut discriminants = enum_def. discriminants ( self . tcx ) ;
494- edge_effects. apply ( |trans, edge| {
495- let value = match edge. value {
496- Some ( x) => x,
497- None => return ,
498- } ;
499-
500- // MIR building adds discriminants to the `values` array in the same order as they
501- // are yielded by `AdtDef::discriminants`. We rely on this to match each
502- // discriminant in `values` to its corresponding variant in linear time.
503- let ( variant, _) = discriminants
504- . find ( |& ( _, discr) | discr. val == value)
505- . expect ( "Order of `AdtDef::discriminants` differed from `SwitchInt::values`" ) ;
506-
507- // Mark all move paths that correspond to variants other than this one as maybe
508- // uninitialized (in reality, they are *definitely* uninitialized).
509- drop_flag_effects:: on_all_inactive_variants (
510- self . tcx ,
511- self . body ,
512- self . move_data ( ) ,
513- enum_place,
514- variant,
515- |mpi| trans. gen ( mpi) ,
516- ) ;
517- } ) ;
461+ // Mark all move paths that correspond to variants that are inactive along a given edge as
462+ // maybe uninitialized (in reality, they are *definitely* uninitialized).
463+ enum_discriminant_switch_inactive_variant_effects (
464+ self . tcx ,
465+ self . body ,
466+ self . move_data ( ) ,
467+ block,
468+ discr,
469+ edge_effects,
470+ |trans, mpi| trans. gen ( mpi) ,
471+ ) ;
518472 }
519473}
520474
@@ -715,3 +669,82 @@ fn switch_on_enum_discriminant(
715669 _ => None ,
716670 }
717671}
672+
673+ fn enum_discriminant_switch_inactive_variant_effects < D > (
674+ tcx : TyCtxt < ' tcx > ,
675+ body : & mir:: Body < ' tcx > ,
676+ move_data : & MoveData < ' tcx > ,
677+ block : mir:: BasicBlock ,
678+ discr : & mir:: Operand < ' tcx > ,
679+ edge_effects : & mut impl SwitchIntEdgeEffects < D > ,
680+ mut on_uninitialized_variant : impl FnMut ( & mut D , MovePathIndex ) ,
681+ ) {
682+ let enum_ =
683+ discr. place ( ) . and_then ( |discr| switch_on_enum_discriminant ( tcx, body, & body[ block] , discr) ) ;
684+
685+ let ( enum_place, enum_def) = match enum_ {
686+ Some ( x) => x,
687+ None => return ,
688+ } ;
689+
690+ let enum_mpi = match move_data. rev_lookup . find ( enum_place. as_ref ( ) ) {
691+ LookupResult :: Exact ( mpi) => mpi,
692+ LookupResult :: Parent ( _) => return ,
693+ } ;
694+
695+ let enum_path = & move_data. move_paths [ enum_mpi] ;
696+ let mut discriminants = enum_def. discriminants ( tcx) ;
697+
698+ // `MovePathIndex`s for those variants with their own outgoing edge. These
699+ // get marked as uninitialized along the "otherwise" edge.
700+ let mut variant_mpis_with_edge = vec ! [ ] ;
701+
702+ edge_effects. apply ( |trans, edge| {
703+ if let Some ( value) = edge. value {
704+ // MIR building adds discriminants to the `values` array in the same order as they
705+ // are yielded by `AdtDef::discriminants`. We rely on this to match each
706+ // discriminant in `values` to its corresponding variant in linear time.
707+ let ( active_variant, _) = discriminants
708+ . find ( |& ( _, discr) | discr. val == value)
709+ . expect ( "Order of `AdtDef::discriminants` differed from `SwitchInt::values`" ) ;
710+
711+ for ( variant_mpi, variant_path) in enum_path. children ( & move_data. move_paths ) {
712+ // Because of the way we build the `MoveData` tree, each child should have exactly one more
713+ // projection than `enum_place`. This additional projection must be a downcast since the
714+ // base is an enum.
715+ let ( downcast, base_proj) = variant_path. place . projection . split_last ( ) . unwrap ( ) ;
716+ assert_eq ! ( enum_place. projection. len( ) , base_proj. len( ) ) ;
717+
718+ let variant_idx = match * downcast {
719+ mir:: ProjectionElem :: Downcast ( _, idx) => idx,
720+ _ => unreachable ! ( ) ,
721+ } ;
722+
723+ if variant_idx == active_variant {
724+ // If this is the move path for the variant that is active along this edge
725+ // of the `SwitchInt` terminator, remember that it is not active as part of
726+ // the "otherwise" edge.
727+ variant_mpis_with_edge. push ( variant_mpi) ;
728+ } else {
729+ // Otherwise, it is the move path for an *inactive* variant. Mark it and
730+ // all of its descendants as uninitialzied.
731+ drop_flag_effects:: on_all_children_bits (
732+ tcx,
733+ body,
734+ move_data,
735+ variant_mpi,
736+ |mpi| on_uninitialized_variant ( trans, mpi) ,
737+ ) ;
738+ }
739+ }
740+ } else {
741+ // We're on the otherwise branch. All variants that we visited above are known to be
742+ // uninitialized.
743+ for & variant_mpi in & variant_mpis_with_edge {
744+ drop_flag_effects:: on_all_children_bits ( tcx, body, move_data, variant_mpi, |mpi| {
745+ on_uninitialized_variant ( trans, mpi)
746+ } ) ;
747+ }
748+ }
749+ } ) ;
750+ }
0 commit comments