@@ -185,7 +185,7 @@ use rustc_hir as hir;
185
185
use rustc_hir:: def_id:: { DefId , DefIdMap , LocalDefId , LOCAL_CRATE } ;
186
186
use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
187
187
use rustc_hir:: lang_items:: LangItem ;
188
- use rustc_index:: bit_set:: GrowableBitSet ;
188
+ use rustc_index:: bit_set:: { BitSet , GrowableBitSet } ;
189
189
use rustc_middle:: mir:: interpret:: { AllocId , ConstValue } ;
190
190
use rustc_middle:: mir:: interpret:: { ErrorHandled , GlobalAlloc , Scalar } ;
191
191
use rustc_middle:: mir:: mono:: { InstantiationMode , MonoItem } ;
@@ -608,6 +608,7 @@ struct MirNeighborCollector<'a, 'tcx> {
608
608
body : & ' a mir:: Body < ' tcx > ,
609
609
output : & ' a mut Vec < Spanned < MonoItem < ' tcx > > > ,
610
610
instance : Instance < ' tcx > ,
611
+ reachable_blocks : BitSet < mir:: BasicBlock > ,
611
612
}
612
613
613
614
impl < ' a , ' tcx > MirNeighborCollector < ' a , ' tcx > {
@@ -622,9 +623,95 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
622
623
value,
623
624
)
624
625
}
626
+
627
+ fn find_reachable_blocks ( & mut self , bb : mir:: BasicBlock ) {
628
+ if !self . reachable_blocks . insert ( bb) {
629
+ return ;
630
+ }
631
+
632
+ use mir:: TerminatorKind :: * ;
633
+ let data = & self . body . basic_blocks ( ) [ bb] ;
634
+ match data. terminator ( ) . kind {
635
+ Goto { target } => self . find_reachable_blocks ( target) ,
636
+ Resume | Abort | Return | Unreachable | GeneratorDrop => ( ) ,
637
+ Drop { place : _, target, unwind }
638
+ | DropAndReplace { place : _, value : _, target, unwind }
639
+ | Assert { cond : _, expected : _, msg : _, target, cleanup : unwind }
640
+ | Yield { value : _, resume : target, resume_arg : _, drop : unwind } => {
641
+ self . find_reachable_blocks ( target) ;
642
+ unwind. map ( |b| self . find_reachable_blocks ( b) ) ;
643
+ }
644
+ Call { func : _, args : _, destination, cleanup, from_hir_call : _, fn_span : _} => {
645
+ destination. map ( |( _, b) | self . find_reachable_blocks ( b) ) ;
646
+ cleanup. map ( |b| self . find_reachable_blocks ( b) ) ;
647
+ }
648
+ FalseEdge { .. } | FalseUnwind { .. } => {
649
+ bug ! ( "Expected false edges to already be gone when collecting neighbours for {:?}" , self . instance) ;
650
+ }
651
+ InlineAsm { template : _, operands : _, options : _, line_spans : _, destination} => {
652
+ destination. map ( |b| self . find_reachable_blocks ( b) ) ;
653
+ }
654
+ SwitchInt { ref discr, switch_ty, ref targets } => {
655
+ if let mir:: Operand :: Constant ( constant) = discr {
656
+ if let Some ( raw_value) = self . try_eval_constant_to_bits ( constant, switch_ty) {
657
+ // We know what this is going to be,
658
+ // so we can ignore all the other blocks.
659
+ for ( test_value, target) in targets. iter ( ) {
660
+ if test_value == raw_value {
661
+ return self . find_reachable_blocks ( target) ;
662
+ }
663
+ }
664
+
665
+ return self . find_reachable_blocks ( targets. otherwise ( ) ) ;
666
+ }
667
+ }
668
+
669
+ // If it's not a constant or we can't evaluate it,
670
+ // then we have to consider them all as reachable.
671
+ for & b in targets. all_targets ( ) {
672
+ self . find_reachable_blocks ( b)
673
+ }
674
+ }
675
+ }
676
+ }
677
+
678
+ fn try_eval_constant_to_bits ( & self , constant : & mir:: Constant < ' tcx > , ty : Ty < ' tcx > ) -> Option < u128 > {
679
+ let env = ty:: ParamEnv :: reveal_all ( ) ;
680
+ let ct = self . monomorphize ( constant. literal ) ;
681
+ let value = match ct {
682
+ mir:: ConstantKind :: Val ( value, _) => value,
683
+ mir:: ConstantKind :: Ty ( ct) => {
684
+ match ct. val {
685
+ ty:: ConstKind :: Unevaluated ( ct) => self
686
+ . tcx
687
+ . const_eval_resolve ( env, ct, None ) . ok ( ) ?,
688
+ ty:: ConstKind :: Value ( value) => value,
689
+ other => span_bug ! (
690
+ constant. span,
691
+ "encountered bad ConstKind after monomorphizing: {:?}" ,
692
+ other
693
+ ) ,
694
+ }
695
+ }
696
+ } ;
697
+ value. try_to_bits_for_ty ( self . tcx , env, ty)
698
+ }
625
699
}
626
700
627
701
impl < ' a , ' tcx > MirVisitor < ' tcx > for MirNeighborCollector < ' a , ' tcx > {
702
+ fn visit_body ( & mut self , body : & mir:: Body < ' tcx > ) {
703
+ self . find_reachable_blocks ( mir:: START_BLOCK ) ;
704
+ self . super_body ( body) ;
705
+ }
706
+
707
+ fn visit_basic_block_data ( & mut self , block : mir:: BasicBlock , data : & mir:: BasicBlockData < ' tcx > ) {
708
+ if self . reachable_blocks . contains ( block) {
709
+ self . super_basic_block_data ( block, data) ;
710
+ } else {
711
+ debug ! ( "skipping basic block {:?}" , block) ;
712
+ }
713
+ }
714
+
628
715
fn visit_rvalue ( & mut self , rvalue : & mir:: Rvalue < ' tcx > , location : Location ) {
629
716
debug ! ( "visiting rvalue {:?}" , * rvalue) ;
630
717
@@ -1395,7 +1482,16 @@ fn collect_neighbours<'tcx>(
1395
1482
debug ! ( "collect_neighbours: {:?}" , instance. def_id( ) ) ;
1396
1483
let body = tcx. instance_mir ( instance. def ) ;
1397
1484
1398
- MirNeighborCollector { tcx, body : & body, output, instance } . visit_body ( & body) ;
1485
+ let reachable_blocks =
1486
+ if instance. substs . is_noop ( ) {
1487
+ // If it's non-generic, then it's already filtered out
1488
+ // any blocks that are unreachable, so don't re-do the work.
1489
+ BitSet :: new_filled ( body. basic_blocks ( ) . len ( ) )
1490
+ } else {
1491
+ BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) )
1492
+ } ;
1493
+ let mut collector = MirNeighborCollector { tcx, body : & body, output, instance, reachable_blocks } ;
1494
+ collector. visit_body ( & body) ;
1399
1495
}
1400
1496
1401
1497
fn collect_const_value < ' tcx > (
0 commit comments