@@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
10
10
use crate :: ty:: print:: { FmtPrinter , Printer } ;
11
11
use crate :: ty:: visit:: TypeVisitableExt ;
12
12
use crate :: ty:: { self , List , Ty , TyCtxt } ;
13
- use crate :: ty:: { AdtDef , InstanceDef , UserTypeAnnotationIndex } ;
13
+ use crate :: ty:: { AdtDef , Instance , InstanceDef , UserTypeAnnotationIndex } ;
14
14
use crate :: ty:: { GenericArg , GenericArgsRef } ;
15
15
16
16
use rustc_data_structures:: captures:: Captures ;
@@ -29,6 +29,7 @@ pub use rustc_ast::Mutability;
29
29
use rustc_data_structures:: fx:: FxHashMap ;
30
30
use rustc_data_structures:: fx:: FxHashSet ;
31
31
use rustc_data_structures:: graph:: dominators:: Dominators ;
32
+ use rustc_index:: bit_set:: BitSet ;
32
33
use rustc_index:: { Idx , IndexSlice , IndexVec } ;
33
34
use rustc_serialize:: { Decodable , Encodable } ;
34
35
use rustc_span:: symbol:: Symbol ;
@@ -642,6 +643,73 @@ impl<'tcx> Body<'tcx> {
642
643
self . injection_phase . is_some ( )
643
644
}
644
645
646
+ /// Finds which basic blocks are actually reachable for a specific
647
+ /// monomorphization of this body.
648
+ ///
649
+ /// This is allowed to have false positives; just because this says a block
650
+ /// is reachable doesn't mean that's necessarily true. It's thus always
651
+ /// legal for this to return a filled set.
652
+ ///
653
+ /// Regardless, the [`BitSet::domain_size`] of the returned set will always
654
+ /// exactly match the number of blocks in the body so that `contains`
655
+ /// checks can be done without worrying about panicking.
656
+ ///
657
+ /// The main case this supports is filtering out `if <T as Trait>::CONST`
658
+ /// bodies that can't be removed in generic MIR, but *can* be removed once
659
+ /// the specific `T` is known.
660
+ ///
661
+ /// This is used in the monomorphization collector as well as in codegen.
662
+ pub fn reachable_blocks_in_mono (
663
+ & self ,
664
+ tcx : TyCtxt < ' tcx > ,
665
+ instance : Instance < ' tcx > ,
666
+ ) -> BitSet < BasicBlock > {
667
+ if instance. args . non_erasable_generics ( tcx, instance. def_id ( ) ) . next ( ) . is_none ( ) {
668
+ // If it's non-generic, then mir-opt const prop has already run, meaning it's
669
+ // probably not worth doing any further filtering. So call everything reachable.
670
+ return BitSet :: new_filled ( self . basic_blocks . len ( ) ) ;
671
+ }
672
+
673
+ let mut set = BitSet :: new_empty ( self . basic_blocks . len ( ) ) ;
674
+ self . reachable_blocks_in_mono_from ( tcx, instance, & mut set, START_BLOCK ) ;
675
+ set
676
+ }
677
+
678
+ fn reachable_blocks_in_mono_from (
679
+ & self ,
680
+ tcx : TyCtxt < ' tcx > ,
681
+ instance : Instance < ' tcx > ,
682
+ set : & mut BitSet < BasicBlock > ,
683
+ bb : BasicBlock ,
684
+ ) {
685
+ if !set. insert ( bb) {
686
+ return ;
687
+ }
688
+
689
+ let data = & self . basic_blocks [ bb] ;
690
+
691
+ if let TerminatorKind :: SwitchInt { discr : Operand :: Constant ( constant) , targets } =
692
+ & data. terminator ( ) . kind
693
+ {
694
+ let env = ty:: ParamEnv :: reveal_all ( ) ;
695
+ let mono_literal = instance. instantiate_mir_and_normalize_erasing_regions (
696
+ tcx,
697
+ env,
698
+ crate :: ty:: EarlyBinder :: bind ( constant. const_ ) ,
699
+ ) ;
700
+ if let Some ( bits) = mono_literal. try_eval_bits ( tcx, env) {
701
+ let target = targets. target_for_value ( bits) ;
702
+ return self . reachable_blocks_in_mono_from ( tcx, instance, set, target) ;
703
+ } else {
704
+ bug ! ( "Couldn't evaluate constant {:?} in mono {:?}" , constant, instance) ;
705
+ }
706
+ }
707
+
708
+ for target in data. terminator ( ) . successors ( ) {
709
+ self . reachable_blocks_in_mono_from ( tcx, instance, set, target) ;
710
+ }
711
+ }
712
+
645
713
/// For a `Location` in this scope, determine what the "caller location" at that point is. This
646
714
/// is interesting because of inlining: the `#[track_caller]` attribute of inlined functions
647
715
/// must be honored. Falls back to the `tracked_caller` value for `#[track_caller]` functions,
0 commit comments