about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2020-08-16 16:35:38 +0100
committerDavid Wood <david@davidtw.co>2020-08-17 14:13:58 +0100
commit5703b2863e1b4b815007b5a3380734634acd1f37 (patch)
treeab1435787a1a9a3fbcccf2b95e9eaba88439811e
parent97ba0c7171c4d2d9b899a2bd8e40a8974c47b86d (diff)
downloadrust-5703b2863e1b4b815007b5a3380734634acd1f37.tar.gz
rust-5703b2863e1b4b815007b5a3380734634acd1f37.zip
polymorphize: ∃ used param ∈ predicate → all used
This commit 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.

Signed-off-by: David Wood <david@davidtw.co>
-rw-r--r--src/librustc_mir/monomorphize/polymorphize.rs87
-rw-r--r--src/test/ui/polymorphization/predicates.rs17
2 files changed, 29 insertions, 75 deletions
diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs
index d946c1947c2..69f3288ee39 100644
--- a/src/librustc_mir/monomorphize/polymorphize.rs
+++ b/src/librustc_mir/monomorphize/polymorphize.rs
@@ -119,16 +119,6 @@ fn mark_used_by_predicates<'tcx>(
     def_id: DefId,
     unused_parameters: &mut FiniteBitSet<u32>,
 ) {
-    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 = 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_used_by_predicates: predicates_of={:?}", predicates);
@@ -144,69 +134,16 @@ fn mark_used_by_predicates<'tcx>(
         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() {
-                        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();
-                    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(..) => (),
+            // Consider all generic params in a predicate as used if any other parameter in the
+            // predicate is used.
+            let any_param_used = {
+                let mut vis = HasUsedGenericParams { unused_parameters };
+                predicate.visit_with(&mut vis)
+            };
+
+            if any_param_used {
+                let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
+                predicate.visit_with(&mut vis);
             }
         }
     }
@@ -375,11 +312,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
 }
 
 /// Visitor used to check if a generic parameter is used.
-struct IsUsedGenericParams<'a> {
+struct HasUsedGenericParams<'a> {
     unused_parameters: &'a FiniteBitSet<u32>,
 }
 
-impl<'a, 'tcx> TypeVisitor<'tcx> for IsUsedGenericParams<'a> {
+impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
         debug!("visit_const: c={:?}", c);
         if !c.has_param_types_or_consts() {
diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs
index 60555dc12dc..97f1ef2c90a 100644
--- a/src/test/ui/polymorphization/predicates.rs
+++ b/src/test/ui/polymorphization/predicates.rs
@@ -60,6 +60,21 @@ where
     std::mem::size_of::<C>()
 }
 
+// Finally, check that `F` is considered used because `G` is used when neither are in the self-ty
+// of the predicate.
+
+trait Foobar<F, G> {}
+
+impl Foobar<u32, u32> for () {}
+
+#[rustc_polymorphize_error]
+fn foobar<F, G>() -> usize
+where
+    (): Foobar<F, G>,
+{
+    std::mem::size_of::<G>()
+}
+
 fn main() {
     let x = &[2u32];
     foo(x.iter());
@@ -69,4 +84,6 @@ fn main() {
     let _ = a.next();
 
     let _ = quux::<u8, u16, u32>();
+
+    let _ = foobar::<u32, u32>();
 }