summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2020-08-14 12:33:20 +0100
committerDavid Wood <david@davidtw.co>2020-08-14 23:01:14 +0100
commitbf3ef26713b8208e0127f4c51725897dbcd11bd9 (patch)
tree885a852b01789a6ddec14806197a7dd8eb02ede3
parent3fbed1739c384faabf00cd8a62abedbf506e949b (diff)
downloadrust-bf3ef26713b8208e0127f4c51725897dbcd11bd9.tar.gz
polymorphize: `I` used if `T` used in `I: Foo<T>`
This commit adjusts polymorphization's handling of predicates so that after ensuring that `T` is used in `I: Foo<T>` if `I` is used, it now ensures that `I` is used if `T` is used in `I: Foo<T>`. This is necessary to mark generic parameters that only exist in impl parameters as used - thereby avoiding symbol clashes when using the new mangling scheme. Signed-off-by: David Wood <david@davidtw.co>
-rw-r--r--src/librustc_mir/monomorphize/polymorphize.rs150
-rw-r--r--src/test/ui/polymorphization/predicates.rs48
-rw-r--r--src/test/ui/polymorphization/symbol-ambiguity.rs22
3 files changed, 189 insertions, 31 deletions
diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs
index fc9f7f1af62..d946c1947c2 100644
--- a/src/librustc_mir/monomorphize/polymorphize.rs
+++ b/src/librustc_mir/monomorphize/polymorphize.rs
@@ -69,8 +69,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
// Visit MIR and accumululate used generic parameters.
let body = tcx.optimized_mir(def_id);
- let mut vis =
- UsedGenericParametersVisitor { tcx, def_id, unused_parameters: &mut unused_parameters };
+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
vis.visit_body(body);
debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
@@ -120,45 +119,101 @@ fn mark_used_by_predicates<'tcx>(
def_id: DefId,
unused_parameters: &mut FiniteBitSet<u32>,
) {
- let def_id = tcx.closure_base_def_id(def_id);
-
- let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u32>, self_ty: Ty<'tcx>| {
- debug!("unused_generic_params: self_ty={:?}", self_ty);
- if let ty::Param(param) = self_ty.kind {
- !unused_parameters.contains(param.index).unwrap_or(false)
- } else {
- false
- }
+ let is_ty_used = |unused_parameters: &FiniteBitSet<u32>, ty: Ty<'tcx>| -> bool {
+ let mut vis = IsUsedGenericParams { unused_parameters };
+ ty.visit_with(&mut vis)
};
let mark_ty = |unused_parameters: &mut FiniteBitSet<u32>, ty: Ty<'tcx>| {
- let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters };
+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
ty.visit_with(&mut vis);
};
+ let def_id = tcx.closure_base_def_id(def_id);
let predicates = tcx.explicit_predicates_of(def_id);
- debug!("mark_parameters_used_in_predicates: predicates_of={:?}", predicates);
- for (predicate, _) in predicates.predicates {
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(predicate, ..) => {
- let trait_ref = predicate.trait_ref;
- if is_self_ty_used(unused_parameters, trait_ref.self_ty()) {
+ debug!("mark_used_by_predicates: predicates_of={:?}", predicates);
+
+ let mut current_unused_parameters = FiniteBitSet::new_empty();
+ // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
+ // bit set so that this is skipped if all parameters are already used.
+ while current_unused_parameters != *unused_parameters {
+ debug!(
+ "mark_used_by_predicates: current_unused_parameters={:?} = unused_parameters={:?}",
+ current_unused_parameters, unused_parameters
+ );
+ current_unused_parameters = *unused_parameters;
+
+ for (predicate, _) in predicates.predicates {
+ match predicate.skip_binders() {
+ ty::PredicateAtom::Trait(predicate, ..) => {
+ let trait_ref = predicate.trait_ref;
+ debug!("mark_used_by_predicates: (trait) trait_ref={:?}", trait_ref);
+
+ // Consider `T` used if `I` is used in predicates of the form
+ // `I: Iterator<Item = T>`
+ debug!("mark_used_by_predicates: checking self");
+ if is_ty_used(unused_parameters, trait_ref.self_ty()) {
+ debug!("mark_used_by_predicates: used!");
+ for ty in trait_ref.substs.types() {
+ mark_ty(unused_parameters, ty);
+ }
+
+ // No need to check for a type being used in the substs if `self_ty` was
+ // used.
+ continue;
+ }
+
+ // Consider `I` used if `T` is used in predicates of the form
+ // `I: Iterator<Item = &'a (T, E)>` (see rust-lang/rust#75326)
+ debug!("mark_used_by_predicates: checking substs");
for ty in trait_ref.substs.types() {
- debug!("unused_generic_params: (trait) ty={:?}", ty);
- mark_ty(unused_parameters, ty);
+ if is_ty_used(unused_parameters, ty) {
+ debug!("mark_used_by_predicates: used!");
+ mark_ty(unused_parameters, trait_ref.self_ty());
+ }
}
}
- }
- ty::PredicateAtom::Projection(proj, ..) => {
- let self_ty = proj.projection_ty.self_ty();
- if is_self_ty_used(unused_parameters, self_ty) {
- debug!("unused_generic_params: (projection ty={:?}", proj.ty);
- mark_ty(unused_parameters, proj.ty);
+ ty::PredicateAtom::Projection(proj, ..) => {
+ let self_ty = proj.projection_ty.self_ty();
+ debug!(
+ "mark_used_by_predicates: (projection) self_ty={:?} proj.ty={:?}",
+ self_ty, proj.ty
+ );
+
+ // Consider `T` used if `I` is used in predicates of the form
+ // `<I as Iterator>::Item = T`
+ debug!("mark_used_by_predicates: checking self");
+ if is_ty_used(unused_parameters, self_ty) {
+ debug!("mark_used_by_predicates: used!");
+ mark_ty(unused_parameters, proj.ty);
+
+ // No need to check for projection type being used if `self_ty` was used.
+ continue;
+ }
+
+ // Consider `I` used if `T` is used in predicates of the form
+ // `<I as Iterator>::Item = &'a (T, E)` (see rust-lang/rust#75326)
+ debug!("mark_used_by_predicates: checking projection ty");
+ if is_ty_used(unused_parameters, proj.ty) {
+ debug!("mark_used_by_predicates: used!");
+ mark_ty(unused_parameters, self_ty);
+ }
}
+ ty::PredicateAtom::RegionOutlives(..)
+ | ty::PredicateAtom::TypeOutlives(..)
+ | ty::PredicateAtom::WellFormed(..)
+ | ty::PredicateAtom::ObjectSafe(..)
+ | ty::PredicateAtom::ClosureKind(..)
+ | ty::PredicateAtom::Subtype(..)
+ | ty::PredicateAtom::ConstEvaluatable(..)
+ | ty::PredicateAtom::ConstEquate(..) => (),
}
- _ => (),
}
}
+
+ if let Some(parent) = predicates.parent {
+ mark_used_by_predicates(tcx, parent, unused_parameters);
+ }
}
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
@@ -204,13 +259,13 @@ fn emit_unused_generic_params_error<'tcx>(
}
/// Visitor used to aggregate generic parameter uses.
-struct UsedGenericParametersVisitor<'a, 'tcx> {
+struct MarkUsedGenericParams<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
unused_parameters: &'a mut FiniteBitSet<u32>,
}
-impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
+impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
/// a closure, generator or constant).
fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
@@ -229,7 +284,7 @@ impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
debug!("visit_local_decl: local_decl={:?}", local_decl);
if local == Local::from_usize(1) {
@@ -256,7 +311,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
}
}
-impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() {
@@ -318,3 +373,36 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
}
}
}
+
+/// Visitor used to check if a generic parameter is used.
+struct IsUsedGenericParams<'a> {
+ unused_parameters: &'a FiniteBitSet<u32>,
+}
+
+impl<'a, 'tcx> TypeVisitor<'tcx> for IsUsedGenericParams<'a> {
+ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
+ debug!("visit_const: c={:?}", c);
+ if !c.has_param_types_or_consts() {
+ return false;
+ }
+
+ match c.val {
+ ty::ConstKind::Param(param) => {
+ !self.unused_parameters.contains(param.index).unwrap_or(false)
+ }
+ _ => c.super_visit_with(self),
+ }
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+ debug!("visit_ty: ty={:?}", ty);
+ if !ty.has_param_types_or_consts() {
+ return false;
+ }
+
+ match ty.kind {
+ ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false),
+ _ => ty.super_visit_with(self),
+ }
+ }
+}
diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs
index 82a94933b47..60555dc12dc 100644
--- a/src/test/ui/polymorphization/predicates.rs
+++ b/src/test/ui/polymorphization/predicates.rs
@@ -18,7 +18,55 @@ where
bar::<I>()
}
+#[rustc_polymorphize_error]
+fn baz<I, T>(_: I)
+where
+ std::iter::Repeat<I>: Iterator<Item = T>,
+{
+ bar::<I>()
+}
+
+// In addition, check that `I` is considered used in `next::{{closure}}`, because `T` is used and
+// `T` is really just `I::Item`. `E` is used due to the fixed-point marking of predicates.
+
+pub(crate) struct Foo<'a, I, E>(I, &'a E);
+
+impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+where
+ I: Iterator<Item = &'a (T, E)>,
+{
+ type Item = T;
+
+ #[rustc_polymorphize_error]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.find(|_| true)
+ }
+}
+
+// Furthermore, check that `B` is considered used because `C` is used, and that `A` is considered
+// used because `B` is now used.
+
+trait Baz<Z> {}
+
+impl Baz<u16> for u8 {}
+impl Baz<u32> for u16 {}
+
+#[rustc_polymorphize_error]
+fn quux<A, B, C: Default>() -> usize
+where
+ A: Baz<B>,
+ B: Baz<C>,
+{
+ std::mem::size_of::<C>()
+}
+
fn main() {
let x = &[2u32];
foo(x.iter());
+ baz(x.iter());
+
+ let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
+ let _ = a.next();
+
+ let _ = quux::<u8, u16, u32>();
}
diff --git a/src/test/ui/polymorphization/symbol-ambiguity.rs b/src/test/ui/polymorphization/symbol-ambiguity.rs
new file mode 100644
index 00000000000..d97bae183d9
--- /dev/null
+++ b/src/test/ui/polymorphization/symbol-ambiguity.rs
@@ -0,0 +1,22 @@
+// build-pass
+// compile-flags: -Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+pub(crate) struct Foo<'a, I, E>(I, &'a E);
+
+impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+where
+ I: Iterator<Item = &'a (T, E)>,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.find(|_| true)
+ }
+}
+
+fn main() {
+ let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
+ let mut b = Foo([(1u16, 1u32)].iter(), &1u32);
+ let _ = a.next();
+ let _ = b.next();
+}