Skip to content

Commit 1a22a0f

Browse files
committed
Auto merge of rust-lang#75595 - davidtwco:polymorphization-predicate-simplification-correction, r=eddyb
polymorphize: if any param in a predicate is used, then all are used Addresses [review](rust-lang#75518 (comment)) [comments](rust-lang#75518 (comment)) [from](rust-lang#75518 (comment)) @eddyb in rust-lang#75518 that I didn't get to resolve before bors merged. This PR modifies polymorphization's handling of predicates so that if any generic parameter is used in a predicate then all parameters in that predicate are used. r? @eddyb
2 parents f6049b6 + 5703b28 commit 1a22a0f

File tree

2 files changed

+29
-75
lines changed

2 files changed

+29
-75
lines changed

src/librustc_mir/monomorphize/polymorphize.rs

+12-75
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,6 @@ fn mark_used_by_predicates<'tcx>(
119119
def_id: DefId,
120120
unused_parameters: &mut FiniteBitSet<u32>,
121121
) {
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)
125-
};
126-
127-
let mark_ty = |unused_parameters: &mut FiniteBitSet<u32>, ty: Ty<'tcx>| {
128-
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
129-
ty.visit_with(&mut vis);
130-
};
131-
132122
let def_id = tcx.closure_base_def_id(def_id);
133123
let predicates = tcx.explicit_predicates_of(def_id);
134124
debug!("mark_used_by_predicates: predicates_of={:?}", predicates);
@@ -144,69 +134,16 @@ fn mark_used_by_predicates<'tcx>(
144134
current_unused_parameters = *unused_parameters;
145135

146136
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");
169-
for ty in trait_ref.substs.types() {
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-
}
174-
}
175-
}
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-
}
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(..) => (),
137+
// Consider all generic params in a predicate as used if any other parameter in the
138+
// predicate is used.
139+
let any_param_used = {
140+
let mut vis = HasUsedGenericParams { unused_parameters };
141+
predicate.visit_with(&mut vis)
142+
};
143+
144+
if any_param_used {
145+
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
146+
predicate.visit_with(&mut vis);
210147
}
211148
}
212149
}
@@ -375,11 +312,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
375312
}
376313

377314
/// Visitor used to check if a generic parameter is used.
378-
struct IsUsedGenericParams<'a> {
315+
struct HasUsedGenericParams<'a> {
379316
unused_parameters: &'a FiniteBitSet<u32>,
380317
}
381318

382-
impl<'a, 'tcx> TypeVisitor<'tcx> for IsUsedGenericParams<'a> {
319+
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
383320
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
384321
debug!("visit_const: c={:?}", c);
385322
if !c.has_param_types_or_consts() {

src/test/ui/polymorphization/predicates.rs

+17
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ where
6060
std::mem::size_of::<C>()
6161
}
6262

63+
// Finally, check that `F` is considered used because `G` is used when neither are in the self-ty
64+
// of the predicate.
65+
66+
trait Foobar<F, G> {}
67+
68+
impl Foobar<u32, u32> for () {}
69+
70+
#[rustc_polymorphize_error]
71+
fn foobar<F, G>() -> usize
72+
where
73+
(): Foobar<F, G>,
74+
{
75+
std::mem::size_of::<G>()
76+
}
77+
6378
fn main() {
6479
let x = &[2u32];
6580
foo(x.iter());
@@ -69,4 +84,6 @@ fn main() {
6984
let _ = a.next();
7085

7186
let _ = quux::<u8, u16, u32>();
87+
88+
let _ = foobar::<u32, u32>();
7289
}

0 commit comments

Comments
 (0)