about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-06-04 19:32:09 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-06-04 19:32:09 -0400
commit7f7729d83be2ff8e9e933b94ff02f1bb77d688f8 (patch)
tree25ab52601c9930f70cdfc2f675727046f5d1094b
parent3d5d0f898c2f3998e50c2180c6202f193c3acdbc (diff)
downloadrust-7f7729d83be2ff8e9e933b94ff02f1bb77d688f8.tar.gz
rust-7f7729d83be2ff8e9e933b94ff02f1bb77d688f8.zip
Don't create impl candidates when obligation contains errors
Fixes #72839

In PR #72621, trait selection was modified to no longer bail out early
when an error type was encountered. This allowed us treat `ty::Error` as
`Sized`, causing us to avoid emitting a spurious "not sized" error after
a type error had already occured.

However, this means that we may now try to match an impl candidate
against the error type. Since the error type will unify with almost
anything, this can cause us to infinitely recurse (eventually triggering
an overflow) when trying to verify certain `where` clauses.

This commit causes us to skip generating any impl candidates when an
error type is involved.
-rw-r--r--src/librustc_trait_selection/traits/select/candidate_assembly.rs10
-rw-r--r--src/test/ui/issues/issue-72839-error-overflow.rs19
-rw-r--r--src/test/ui/issues/issue-72839-error-overflow.stderr9
3 files changed, 38 insertions, 0 deletions
diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
index d42c31a5474..2bd0acb3cc0 100644
--- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs
+++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
@@ -331,6 +331,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
 
+        // Essentially any user-written impl will match with an error type,
+        // so creating `ImplCandidates` isn't useful. However, we might
+        // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized)
+        // This helps us avoid overflow: see issue #72839
+        // Since compilation is already guarnateed to fail, this is just
+        // to try to show the 'nicest' possible errors to the user.
+        if obligation.references_error() {
+            return Ok(());
+        }
+
         self.tcx().for_each_relevant_impl(
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
diff --git a/src/test/ui/issues/issue-72839-error-overflow.rs b/src/test/ui/issues/issue-72839-error-overflow.rs
new file mode 100644
index 00000000000..6562d228409
--- /dev/null
+++ b/src/test/ui/issues/issue-72839-error-overflow.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #72839
+// Tests that we do not overflow during trait selection after
+// a type error occurs
+use std::ops::Rem;
+trait Foo {}
+struct MyStruct<T>(T);
+
+impl<T, U> Rem<MyStruct<T>> for MyStruct<U> where MyStruct<U>: Rem<MyStruct<T>> {
+    type Output = u8;
+    fn rem(self, _: MyStruct<T>) -> Self::Output {
+        panic!()
+    }
+}
+
+fn main() {}
+
+fn foo() {
+    if missing_var % 8 == 0 {} //~ ERROR cannot find
+}
diff --git a/src/test/ui/issues/issue-72839-error-overflow.stderr b/src/test/ui/issues/issue-72839-error-overflow.stderr
new file mode 100644
index 00000000000..c4b6f90ca69
--- /dev/null
+++ b/src/test/ui/issues/issue-72839-error-overflow.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `missing_var` in this scope
+  --> $DIR/issue-72839-error-overflow.rs:18:8
+   |
+LL |     if missing_var % 8 == 0 {}
+   |        ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.