@@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
1010use crate :: ty:: print:: { FmtPrinter , Printer } ;
1111use crate :: ty:: visit:: TypeVisitableExt ;
1212use crate :: ty:: { self , List , Ty , TyCtxt } ;
13- use crate :: ty:: { AdtDef , InstanceDef , UserTypeAnnotationIndex } ;
13+ use crate :: ty:: { AdtDef , Instance , InstanceDef , UserTypeAnnotationIndex } ;
1414use crate :: ty:: { GenericArg , GenericArgsRef } ;
1515
1616use rustc_data_structures:: captures:: Captures ;
@@ -29,6 +29,7 @@ pub use rustc_ast::Mutability;
2929use rustc_data_structures:: fx:: FxHashMap ;
3030use rustc_data_structures:: fx:: FxHashSet ;
3131use rustc_data_structures:: graph:: dominators:: Dominators ;
32+ use rustc_index:: bit_set:: BitSet ;
3233use rustc_index:: { Idx , IndexSlice , IndexVec } ;
3334use rustc_serialize:: { Decodable , Encodable } ;
3435use rustc_span:: symbol:: Symbol ;
@@ -642,6 +643,73 @@ impl<'tcx> Body<'tcx> {
642643 self . injection_phase . is_some ( )
643644 }
644645
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+
645713 /// For a `Location` in this scope, determine what the "caller location" at that point is. This
646714 /// is interesting because of inlining: the `#[track_caller]` attribute of inlined functions
647715 /// must be honored. Falls back to the `tracked_caller` value for `#[track_caller]` functions,
0 commit comments