@@ -11,7 +11,7 @@ use super::MoveDataParamEnv;
11
11
12
12
use crate :: util:: elaborate_drops:: DropFlagState ;
13
13
14
- use super :: move_paths:: { HasMoveData , InitIndex , InitKind , MoveData , MovePathIndex } ;
14
+ use super :: move_paths:: { HasMoveData , InitIndex , InitKind , LookupResult , MoveData , MovePathIndex } ;
15
15
use super :: { lattice, AnalysisDomain , GenKill , GenKillAnalysis } ;
16
16
17
17
use super :: drop_flag_effects_for_function_entry;
@@ -362,40 +362,17 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
362
362
return ;
363
363
}
364
364
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
+ ) ;
399
376
}
400
377
}
401
378
@@ -481,40 +458,17 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
481
458
return ;
482
459
}
483
460
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
+ ) ;
518
472
}
519
473
}
520
474
@@ -715,3 +669,82 @@ fn switch_on_enum_discriminant(
715
669
_ => None ,
716
670
}
717
671
}
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