@@ -69,8 +69,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
69
69
70
70
// Visit MIR and accumululate used generic parameters.
71
71
let body = tcx. optimized_mir ( def_id) ;
72
- let mut vis =
73
- UsedGenericParametersVisitor { tcx, def_id, unused_parameters : & mut unused_parameters } ;
72
+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters : & mut unused_parameters } ;
74
73
vis. visit_body ( body) ;
75
74
debug ! ( "unused_generic_params: (after visitor) unused_parameters={:?}" , unused_parameters) ;
76
75
@@ -120,45 +119,101 @@ fn mark_used_by_predicates<'tcx>(
120
119
def_id : DefId ,
121
120
unused_parameters : & mut FiniteBitSet < u32 > ,
122
121
) {
123
- let def_id = tcx. closure_base_def_id ( def_id) ;
124
-
125
- let is_self_ty_used = |unused_parameters : & mut FiniteBitSet < u32 > , self_ty : Ty < ' tcx > | {
126
- debug ! ( "unused_generic_params: self_ty={:?}" , self_ty) ;
127
- if let ty:: Param ( param) = self_ty. kind {
128
- !unused_parameters. contains ( param. index ) . unwrap_or ( false )
129
- } else {
130
- false
131
- }
122
+ let is_ty_used = |unused_parameters : & FiniteBitSet < u32 > , ty : Ty < ' tcx > | -> bool {
123
+ let mut vis = IsUsedGenericParams { unused_parameters } ;
124
+ ty. visit_with ( & mut vis)
132
125
} ;
133
126
134
127
let mark_ty = |unused_parameters : & mut FiniteBitSet < u32 > , ty : Ty < ' tcx > | {
135
- let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters } ;
128
+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters } ;
136
129
ty. visit_with ( & mut vis) ;
137
130
} ;
138
131
132
+ let def_id = tcx. closure_base_def_id ( def_id) ;
139
133
let predicates = tcx. explicit_predicates_of ( def_id) ;
140
- debug ! ( "mark_parameters_used_in_predicates: predicates_of={:?}" , predicates) ;
141
- for ( predicate, _) in predicates. predicates {
142
- match predicate. skip_binders ( ) {
143
- ty:: PredicateAtom :: Trait ( predicate, ..) => {
144
- let trait_ref = predicate. trait_ref ;
145
- if is_self_ty_used ( unused_parameters, trait_ref. self_ty ( ) ) {
134
+ debug ! ( "mark_used_by_predicates: predicates_of={:?}" , predicates) ;
135
+
136
+ let mut current_unused_parameters = FiniteBitSet :: new_empty ( ) ;
137
+ // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
138
+ // bit set so that this is skipped if all parameters are already used.
139
+ while current_unused_parameters != * unused_parameters {
140
+ debug ! (
141
+ "mark_used_by_predicates: current_unused_parameters={:?} = unused_parameters={:?}" ,
142
+ current_unused_parameters, unused_parameters
143
+ ) ;
144
+ current_unused_parameters = * unused_parameters;
145
+
146
+ for ( predicate, _) in predicates. predicates {
147
+ match predicate. skip_binders ( ) {
148
+ ty:: PredicateAtom :: Trait ( predicate, ..) => {
149
+ let trait_ref = predicate. trait_ref ;
150
+ debug ! ( "mark_used_by_predicates: (trait) trait_ref={:?}" , trait_ref) ;
151
+
152
+ // Consider `T` used if `I` is used in predicates of the form
153
+ // `I: Iterator<Item = T>`
154
+ debug ! ( "mark_used_by_predicates: checking self" ) ;
155
+ if is_ty_used ( unused_parameters, trait_ref. self_ty ( ) ) {
156
+ debug ! ( "mark_used_by_predicates: used!" ) ;
157
+ for ty in trait_ref. substs . types ( ) {
158
+ mark_ty ( unused_parameters, ty) ;
159
+ }
160
+
161
+ // No need to check for a type being used in the substs if `self_ty` was
162
+ // used.
163
+ continue ;
164
+ }
165
+
166
+ // Consider `I` used if `T` is used in predicates of the form
167
+ // `I: Iterator<Item = &'a (T, E)>` (see rust-lang/rust#75326)
168
+ debug ! ( "mark_used_by_predicates: checking substs" ) ;
146
169
for ty in trait_ref. substs . types ( ) {
147
- debug ! ( "unused_generic_params: (trait) ty={:?}" , ty) ;
148
- mark_ty ( unused_parameters, ty) ;
170
+ if is_ty_used ( unused_parameters, ty) {
171
+ debug ! ( "mark_used_by_predicates: used!" ) ;
172
+ mark_ty ( unused_parameters, trait_ref. self_ty ( ) ) ;
173
+ }
149
174
}
150
175
}
151
- }
152
- ty:: PredicateAtom :: Projection ( proj, ..) => {
153
- let self_ty = proj. projection_ty . self_ty ( ) ;
154
- if is_self_ty_used ( unused_parameters, self_ty) {
155
- debug ! ( "unused_generic_params: (projection ty={:?}" , proj. ty) ;
156
- mark_ty ( unused_parameters, proj. ty ) ;
176
+ ty:: PredicateAtom :: Projection ( proj, ..) => {
177
+ let self_ty = proj. projection_ty . self_ty ( ) ;
178
+ debug ! (
179
+ "mark_used_by_predicates: (projection) self_ty={:?} proj.ty={:?}" ,
180
+ self_ty, proj. ty
181
+ ) ;
182
+
183
+ // Consider `T` used if `I` is used in predicates of the form
184
+ // `<I as Iterator>::Item = T`
185
+ debug ! ( "mark_used_by_predicates: checking self" ) ;
186
+ if is_ty_used ( unused_parameters, self_ty) {
187
+ debug ! ( "mark_used_by_predicates: used!" ) ;
188
+ mark_ty ( unused_parameters, proj. ty ) ;
189
+
190
+ // No need to check for projection type being used if `self_ty` was used.
191
+ continue ;
192
+ }
193
+
194
+ // Consider `I` used if `T` is used in predicates of the form
195
+ // `<I as Iterator>::Item = &'a (T, E)` (see rust-lang/rust#75326)
196
+ debug ! ( "mark_used_by_predicates: checking projection ty" ) ;
197
+ if is_ty_used ( unused_parameters, proj. ty ) {
198
+ debug ! ( "mark_used_by_predicates: used!" ) ;
199
+ mark_ty ( unused_parameters, self_ty) ;
200
+ }
157
201
}
202
+ ty:: PredicateAtom :: RegionOutlives ( ..)
203
+ | ty:: PredicateAtom :: TypeOutlives ( ..)
204
+ | ty:: PredicateAtom :: WellFormed ( ..)
205
+ | ty:: PredicateAtom :: ObjectSafe ( ..)
206
+ | ty:: PredicateAtom :: ClosureKind ( ..)
207
+ | ty:: PredicateAtom :: Subtype ( ..)
208
+ | ty:: PredicateAtom :: ConstEvaluatable ( ..)
209
+ | ty:: PredicateAtom :: ConstEquate ( ..) => ( ) ,
158
210
}
159
- _ => ( ) ,
160
211
}
161
212
}
213
+
214
+ if let Some ( parent) = predicates. parent {
215
+ mark_used_by_predicates ( tcx, parent, unused_parameters) ;
216
+ }
162
217
}
163
218
164
219
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
@@ -204,13 +259,13 @@ fn emit_unused_generic_params_error<'tcx>(
204
259
}
205
260
206
261
/// Visitor used to aggregate generic parameter uses.
207
- struct UsedGenericParametersVisitor < ' a , ' tcx > {
262
+ struct MarkUsedGenericParams < ' a , ' tcx > {
208
263
tcx : TyCtxt < ' tcx > ,
209
264
def_id : DefId ,
210
265
unused_parameters : & ' a mut FiniteBitSet < u32 > ,
211
266
}
212
267
213
- impl < ' a , ' tcx > UsedGenericParametersVisitor < ' a , ' tcx > {
268
+ impl < ' a , ' tcx > MarkUsedGenericParams < ' a , ' tcx > {
214
269
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
215
270
/// a closure, generator or constant).
216
271
fn visit_child_body ( & mut self , def_id : DefId , substs : SubstsRef < ' tcx > ) {
@@ -229,7 +284,7 @@ impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
229
284
}
230
285
}
231
286
232
- impl < ' a , ' tcx > Visitor < ' tcx > for UsedGenericParametersVisitor < ' a , ' tcx > {
287
+ impl < ' a , ' tcx > Visitor < ' tcx > for MarkUsedGenericParams < ' a , ' tcx > {
233
288
fn visit_local_decl ( & mut self , local : Local , local_decl : & LocalDecl < ' tcx > ) {
234
289
debug ! ( "visit_local_decl: local_decl={:?}" , local_decl) ;
235
290
if local == Local :: from_usize ( 1 ) {
@@ -256,7 +311,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
256
311
}
257
312
}
258
313
259
- impl < ' a , ' tcx > TypeVisitor < ' tcx > for UsedGenericParametersVisitor < ' a , ' tcx > {
314
+ impl < ' a , ' tcx > TypeVisitor < ' tcx > for MarkUsedGenericParams < ' a , ' tcx > {
260
315
fn visit_const ( & mut self , c : & ' tcx Const < ' tcx > ) -> bool {
261
316
debug ! ( "visit_const: c={:?}" , c) ;
262
317
if !c. has_param_types_or_consts ( ) {
@@ -318,3 +373,36 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
318
373
}
319
374
}
320
375
}
376
+
377
+ /// Visitor used to check if a generic parameter is used.
378
+ struct IsUsedGenericParams < ' a > {
379
+ unused_parameters : & ' a FiniteBitSet < u32 > ,
380
+ }
381
+
382
+ impl < ' a , ' tcx > TypeVisitor < ' tcx > for IsUsedGenericParams < ' a > {
383
+ fn visit_const ( & mut self , c : & ' tcx Const < ' tcx > ) -> bool {
384
+ debug ! ( "visit_const: c={:?}" , c) ;
385
+ if !c. has_param_types_or_consts ( ) {
386
+ return false ;
387
+ }
388
+
389
+ match c. val {
390
+ ty:: ConstKind :: Param ( param) => {
391
+ !self . unused_parameters . contains ( param. index ) . unwrap_or ( false )
392
+ }
393
+ _ => c. super_visit_with ( self ) ,
394
+ }
395
+ }
396
+
397
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
398
+ debug ! ( "visit_ty: ty={:?}" , ty) ;
399
+ if !ty. has_param_types_or_consts ( ) {
400
+ return false ;
401
+ }
402
+
403
+ match ty. kind {
404
+ ty:: Param ( param) => !self . unused_parameters . contains ( param. index ) . unwrap_or ( false ) ,
405
+ _ => ty. super_visit_with ( self ) ,
406
+ }
407
+ }
408
+ }
0 commit comments