@@ -16,7 +16,7 @@ use rustc_middle::ty::{
1616 fold:: { TypeFoldable , TypeVisitor } ,
1717 query:: Providers ,
1818 subst:: SubstsRef ,
19- Const , Ty , TyCtxt ,
19+ Const , InstanceDef , Ty , TyCtxt ,
2020} ;
2121use rustc_span:: symbol:: sym;
2222use std:: convert:: TryInto ;
@@ -27,21 +27,25 @@ pub fn provide(providers: &mut Providers) {
2727 providers. unused_generic_params = unused_generic_params;
2828}
2929
30- /// Determine which generic parameters are used by the function/method/closure represented by
31- /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
30+ /// Determine which generic parameters are used by the `instance`.
31+ ///
32+ /// Returns a bitset where bits representing unused parameters are set (`is_empty`
3233/// indicates all parameters are used).
33- fn unused_generic_params ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> FiniteBitSet < u32 > {
34- debug ! ( "unused_generic_params({:?})" , def_id) ;
34+ fn unused_generic_params < ' tcx > (
35+ tcx : TyCtxt < ' tcx > ,
36+ instance : InstanceDef < ' tcx > ,
37+ ) -> FiniteBitSet < u32 > {
38+ debug ! ( "unused_generic_params({:?})" , instance) ;
3539
40+ // If polymorphization disabled, then all parameters are used.
3641 if !tcx. sess . opts . debugging_opts . polymorphize {
37- // If polymorphization disabled, then all parameters are used.
3842 return FiniteBitSet :: new_empty ( ) ;
3943 }
4044
41- // Polymorphization results are stored in cross-crate metadata only when there are unused
42- // parameters, so assume that non-local items must have only used parameters (else this query
43- // would not be invoked, and the cross-crate metadata used instead).
44- if !def_id . is_local ( ) {
45+ // Exit early if this instance should not be polymorphized.
46+ let def_id = instance . def_id ( ) ;
47+ if ! should_polymorphize ( tcx , def_id , instance ) {
48+ debug ! ( "unused_generic_params: skipping" ) ;
4549 return FiniteBitSet :: new_empty ( ) ;
4650 }
4751
@@ -53,36 +57,24 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
5357 return FiniteBitSet :: new_empty ( ) ;
5458 }
5559
56- // Exit early when there is no MIR available.
57- let context = tcx. hir ( ) . body_const_context ( def_id. expect_local ( ) ) ;
58- match context {
59- Some ( ConstContext :: ConstFn ) | None if !tcx. is_mir_available ( def_id) => {
60- debug ! ( "unused_generic_params: (no mir available) def_id={:?}" , def_id) ;
61- return FiniteBitSet :: new_empty ( ) ;
62- }
63- Some ( _) if !tcx. is_ctfe_mir_available ( def_id) => {
64- debug ! ( "unused_generic_params: (no ctfe mir available) def_id={:?}" , def_id) ;
65- return FiniteBitSet :: new_empty ( ) ;
66- }
67- _ => { }
68- }
69-
7060 // Create a bitset with N rightmost ones for each parameter.
7161 let generics_count: u32 =
7262 generics. count ( ) . try_into ( ) . expect ( "more generic parameters than can fit into a `u32`" ) ;
7363 let mut unused_parameters = FiniteBitSet :: < u32 > :: new_empty ( ) ;
7464 unused_parameters. set_range ( 0 ..generics_count) ;
7565 debug ! ( "unused_generic_params: (start) unused_parameters={:?}" , unused_parameters) ;
66+
7667 mark_used_by_default_parameters ( tcx, def_id, generics, & mut unused_parameters) ;
7768 debug ! ( "unused_generic_params: (after default) unused_parameters={:?}" , unused_parameters) ;
7869
79- // Visit MIR and accumululate used generic parameters.
80- let body = match context {
70+ let body = match tcx. hir ( ) . body_const_context ( def_id. expect_local ( ) ) {
8171 // Const functions are actually called and should thus be considered for polymorphization
82- // via their runtime MIR
72+ // via their runtime MIR.
8373 Some ( ConstContext :: ConstFn ) | None => tcx. optimized_mir ( def_id) ,
8474 Some ( _) => tcx. mir_for_ctfe ( def_id) ,
8575 } ;
76+
77+ // Visit MIR and accumululate used generic parameters.
8678 let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters : & mut unused_parameters } ;
8779 vis. visit_body ( body) ;
8880 debug ! ( "unused_generic_params: (after visitor) unused_parameters={:?}" , unused_parameters) ;
@@ -98,6 +90,48 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
9890 unused_parameters
9991}
10092
93+ /// Returns `true` if the `InstanceDef` should be polymorphized.
94+ fn should_polymorphize < ' tcx > (
95+ tcx : TyCtxt < ' tcx > ,
96+ def_id : DefId ,
97+ instance : ty:: InstanceDef < ' tcx > ,
98+ ) -> bool {
99+ // If a instance's MIR body is not polymorphic then the modified substitutions that are derived
100+ // from polymorphization's result won't make any difference.
101+ if !instance. has_polymorphic_mir_body ( ) {
102+ return false ;
103+ }
104+
105+ // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
106+ if matches ! ( instance, ty:: InstanceDef :: Intrinsic ( ..) | ty:: InstanceDef :: Virtual ( ..) ) {
107+ return false ;
108+ }
109+
110+ // Polymorphization results are stored in cross-crate metadata only when there are unused
111+ // parameters, so assume that non-local items must have only used parameters (else this query
112+ // would not be invoked, and the cross-crate metadata used instead).
113+ if !def_id. is_local ( ) {
114+ return false ;
115+ }
116+
117+ // Foreign items don't have a body to analyze.
118+ if tcx. is_foreign_item ( def_id) {
119+ return false ;
120+ }
121+
122+ // Without available MIR, polymorphization has nothing to analyze.
123+ match tcx. hir ( ) . body_const_context ( def_id. expect_local ( ) ) {
124+ // FIXME(davidtwco): Disable polymorphization for any constant functions which, at the time
125+ // of writing, can result in an ICE from typeck in one test and a cycle error in another.
126+ Some ( _) => false ,
127+ None if !tcx. is_mir_available ( def_id) => {
128+ debug ! ( "should_polymorphize: (no mir available) def_id={:?}" , def_id) ;
129+ false
130+ }
131+ None => true ,
132+ }
133+ }
134+
101135/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
102136/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
103137/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
@@ -220,7 +254,9 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
220254 /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
221255 /// a closure, generator or constant).
222256 fn visit_child_body ( & mut self , def_id : DefId , substs : SubstsRef < ' tcx > ) {
223- let unused = self . tcx . unused_generic_params ( def_id) ;
257+ let unused = self
258+ . tcx
259+ . unused_generic_params ( ty:: InstanceDef :: Item ( ty:: WithOptConstParam :: unknown ( def_id) ) ) ;
224260 debug ! (
225261 "visit_child_body: unused_parameters={:?} unused={:?}" ,
226262 self . unused_parameters, unused
0 commit comments