about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-03-18 19:05:49 +0000
committerMichael Goulet <michael@errs.io>2023-03-28 02:07:35 +0000
commite3b0a728b4aa886fcb451b2a3bd7662942a5acaa (patch)
tree9be689198918130f279885a498c861aeedbdfc0e
parent5bf139e3609255f6bdeae0f8dcc40eeb1021148b (diff)
downloadrust-e3b0a728b4aa886fcb451b2a3bd7662942a5acaa.tar.gz
rust-e3b0a728b4aa886fcb451b2a3bd7662942a5acaa.zip
Erase impl regions when checking for impossible to eagerly monomorphize items
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs48
-rw-r--r--tests/ui/codegen/mono-impossible-2.rs19
2 files changed, 48 insertions, 19 deletions
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index aff27e5664b..c286046fb67 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1326,27 +1326,40 @@ fn create_mono_items_for_default_impls<'tcx>(
         return;
     }
 
+    let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
+        return;
+    };
+
+    // Lifetimes never affect trait selection, so we are allowed to eagerly
+    // instantiate an instance of an impl method if the impl (and method,
+    // which we check below) is only parameterized over lifetime. In that case,
+    // we use the ReErased, which has no lifetime information associated with
+    // it, to validate whether or not the impl is legal to instantiate at all.
+    let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
+        GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+            unreachable!(
+                "`own_requires_monomorphization` check means that \
+                we should have no type/const params"
+            )
+        }
+    };
+    let impl_substs = InternalSubsts::for_item(tcx, item.owner_id.to_def_id(), only_region_params);
+    let trait_ref = trait_ref.subst(tcx, impl_substs);
+
     // Unlike 'lazy' monomorphization that begins by collecting items transitively
     // called by `main` or other global items, when eagerly monomorphizing impl
     // items, we never actually check that the predicates of this impl are satisfied
     // in a empty reveal-all param env (i.e. with no assumptions).
     //
-    // Even though this impl has no substitutions, because we don't consider higher-
-    // ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
-    // we must now check that the impl has no impossible-to-satisfy predicates.
-    if tcx.subst_and_check_impossible_predicates((
-        item.owner_id.to_def_id(),
-        &InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
-    )) {
+    // Even though this impl has no type or const substitutions, because we don't
+    // consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to
+    // be trivially false. We must now check that the impl has no impossible-to-satisfy
+    // predicates.
+    if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_substs)) {
         return;
     }
 
-    let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
-        return;
-    };
-
-    let trait_ref = trait_ref.subst_identity();
-
     let param_env = ty::ParamEnv::reveal_all();
     let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
     let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
@@ -1359,12 +1372,9 @@ fn create_mono_items_for_default_impls<'tcx>(
             continue;
         }
 
-        let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
-            GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                trait_ref.substs[param.index as usize]
-            }
-        });
+        // As mentioned above, the method is legal to eagerly instantiate if it
+        // only has lifetime substitutions. This is validated by
+        let substs = trait_ref.substs.extend_to(tcx, method.def_id, only_region_params);
         let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
diff --git a/tests/ui/codegen/mono-impossible-2.rs b/tests/ui/codegen/mono-impossible-2.rs
new file mode 100644
index 00000000000..21eb2c9b2f2
--- /dev/null
+++ b/tests/ui/codegen/mono-impossible-2.rs
@@ -0,0 +1,19 @@
+//compile-flags: --crate-type=lib -Clink-dead-code=on
+// build-pass
+
+// Make sure that we don't monomorphize the impossible method `<() as Visit>::visit`,
+// which does not hold under a reveal-all param env.
+
+pub trait Visit {
+    fn visit() {}
+}
+
+pub trait Array {
+    type Element;
+}
+
+impl<'a> Visit for () where (): Array<Element = &'a ()> {}
+
+impl Array for () {
+    type Element = ();
+}