about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2024-11-28 03:14:46 +0100
committerGitHub <noreply@github.com>2024-11-28 03:14:46 +0100
commitacf48fcb9d69e7c612efbca37dc4fbf4eb8ac2a9 (patch)
treea2455ec44d83a5f07096ffc265a03a4ea4b935b9
parent09734ac3aff28e1089a1790567d25341c985af69 (diff)
parent50fb40a987746e8847091ce354b649be4a44cde1 (diff)
downloadrust-acf48fcb9d69e7c612efbca37dc4fbf4eb8ac2a9.tar.gz
rust-acf48fcb9d69e7c612efbca37dc4fbf4eb8ac2a9.zip
Rollup merge of #133368 - compiler-errors:codegen-select-unconstrained-params, r=lcnr
Delay a bug when encountering an impl with unconstrained generics in `codegen_select`

Despite its name, `codegen_select` is what powers `Instance::try_resolve`, which is used in pre-codegen contexts to try to resolve a method where possible. One place that it's used is in the "recursion MIR lint" that detects recursive MIR bodies.

If we encounter an impl in `codegen_select` that contains unconstrained generic parameters, we expect that impl to caused an error to be reported; however, there's no temporal guarantee that this error is reported *before* we call `codegen_select`. This is what a delayed bug is *for*, and this PR makes us use a delayed bug rather than asserting something about errors already having been emitted.

Fixes  #126646
-rw-r--r--compiler/rustc_traits/src/codegen.rs21
-rw-r--r--tests/crashes/126646.rs18
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.rs20
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.stderr9
4 files changed, 44 insertions, 24 deletions
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 57225df0819..e5276e6d515 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -74,12 +74,21 @@ pub(crate) fn codegen_select_candidate<'tcx>(
     }
 
     let impl_source = infcx.resolve_vars_if_possible(impl_source);
-    let impl_source = infcx.tcx.erase_regions(impl_source);
-    if impl_source.has_infer() {
-        // Unused lifetimes on an impl get replaced with inference vars, but never resolved,
-        // causing the return value of a query to contain inference vars. We do not have a concept
-        // for this and will in fact ICE in stable hashing of the return value. So bail out instead.
-        infcx.tcx.dcx().has_errors().unwrap();
+    let impl_source = tcx.erase_regions(impl_source);
+    if impl_source.has_non_region_infer() {
+        // Unused generic types or consts on an impl get replaced with inference vars,
+        // but never resolved, causing the return value of a query to contain inference
+        // vars. We do not have a concept for this and will in fact ICE in stable hashing
+        // of the return value. So bail out instead.
+        match impl_source {
+            ImplSource::UserDefined(impl_) => {
+                tcx.dcx().span_delayed_bug(
+                    tcx.def_span(impl_.impl_def_id),
+                    "this impl has unconstrained generic parameters",
+                );
+            }
+            _ => unreachable!(),
+        }
         return Err(CodegenObligationError::FulfillmentError);
     }
 
diff --git a/tests/crashes/126646.rs b/tests/crashes/126646.rs
deleted file mode 100644
index 24e3530320a..00000000000
--- a/tests/crashes/126646.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ known-bug: rust-lang/rust#126646
-mod foo {
-    pub trait Callable {
-        type Output;
-        fn call() -> Self::Output;
-    }
-
-    impl<'a, V: ?Sized> Callable for &'a () {
-        type Output = ();
-    }
-}
-use foo::*;
-
-fn test<'a>() -> impl Sized {
-    <&'a () as Callable>::call()
-}
-
-fn main() {}
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.rs b/tests/ui/traits/resolve-impl-before-constrain-check.rs
new file mode 100644
index 00000000000..87f9c241e40
--- /dev/null
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.rs
@@ -0,0 +1,20 @@
+// Need a different module so we try to build the mir for `test`
+// before analyzing `mod foo`.
+
+mod foo {
+    pub trait Callable {
+        fn call();
+    }
+
+    impl<V: ?Sized> Callable for () {
+    //~^ ERROR the type parameter `V` is not constrained by the impl trait, self type, or predicates
+        fn call() {}
+    }
+}
+use foo::*;
+
+fn test() -> impl Sized {
+    <() as Callable>::call()
+}
+
+fn main() {}
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.stderr b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
new file mode 100644
index 00000000000..e8e569ba625
--- /dev/null
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/resolve-impl-before-constrain-check.rs:9:10
+   |
+LL |     impl<V: ?Sized> Callable for () {
+   |          ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.