@@ -16,7 +16,7 @@ use rustc_middle::ty::{
16
16
fold:: { TypeFoldable , TypeVisitor } ,
17
17
query:: Providers ,
18
18
subst:: SubstsRef ,
19
- Const , Ty , TyCtxt ,
19
+ Const , InstanceDef , Ty , TyCtxt ,
20
20
} ;
21
21
use rustc_span:: symbol:: sym;
22
22
use std:: convert:: TryInto ;
@@ -27,21 +27,25 @@ pub fn provide(providers: &mut Providers) {
27
27
providers. unused_generic_params = unused_generic_params;
28
28
}
29
29
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`
32
33
/// 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) ;
35
39
40
+ // If polymorphization disabled, then all parameters are used.
36
41
if !tcx. sess . opts . debugging_opts . polymorphize {
37
- // If polymorphization disabled, then all parameters are used.
38
42
return FiniteBitSet :: new_empty ( ) ;
39
43
}
40
44
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" ) ;
45
49
return FiniteBitSet :: new_empty ( ) ;
46
50
}
47
51
@@ -53,36 +57,24 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
53
57
return FiniteBitSet :: new_empty ( ) ;
54
58
}
55
59
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
-
70
60
// Create a bitset with N rightmost ones for each parameter.
71
61
let generics_count: u32 =
72
62
generics. count ( ) . try_into ( ) . expect ( "more generic parameters than can fit into a `u32`" ) ;
73
63
let mut unused_parameters = FiniteBitSet :: < u32 > :: new_empty ( ) ;
74
64
unused_parameters. set_range ( 0 ..generics_count) ;
75
65
debug ! ( "unused_generic_params: (start) unused_parameters={:?}" , unused_parameters) ;
66
+
76
67
mark_used_by_default_parameters ( tcx, def_id, generics, & mut unused_parameters) ;
77
68
debug ! ( "unused_generic_params: (after default) unused_parameters={:?}" , unused_parameters) ;
78
69
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 ( ) ) {
81
71
// Const functions are actually called and should thus be considered for polymorphization
82
- // via their runtime MIR
72
+ // via their runtime MIR.
83
73
Some ( ConstContext :: ConstFn ) | None => tcx. optimized_mir ( def_id) ,
84
74
Some ( _) => tcx. mir_for_ctfe ( def_id) ,
85
75
} ;
76
+
77
+ // Visit MIR and accumululate used generic parameters.
86
78
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters : & mut unused_parameters } ;
87
79
vis. visit_body ( body) ;
88
80
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> {
98
90
unused_parameters
99
91
}
100
92
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
+
101
135
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
102
136
/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
103
137
/// 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> {
220
254
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
221
255
/// a closure, generator or constant).
222
256
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) ) ) ;
224
260
debug ! (
225
261
"visit_child_body: unused_parameters={:?} unused={:?}" ,
226
262
self . unused_parameters, unused
0 commit comments