about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs8
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs23
-rw-r--r--tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr20
4 files changed, 50 insertions, 3 deletions
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index ef569b4bef3..86f36eedd90 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -43,7 +43,8 @@ use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, Pro
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{
-    self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
+    self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs,
+    UpvarCapture,
 };
 use rustc_session::lint;
 use rustc_span::sym;
@@ -191,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
             }
         };
+        let args = self.resolve_vars_if_possible(args);
         let closure_def_id = closure_def_id.expect_local();
 
         assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
@@ -361,7 +363,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // For coroutine-closures, we additionally must compute the
         // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref
         // version of the coroutine-closure's output coroutine.
-        if let UpvarArgs::CoroutineClosure(args) = args {
+        if let UpvarArgs::CoroutineClosure(args) = args
+            && !args.references_error()
+        {
             let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
                 self.tcx,
                 ty::INNERMOST,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index dd73f0f4a35..ad64745d579 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -771,7 +771,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
     }
 }
 
-#[derive(Debug, Copy, Clone, HashStable)]
+#[derive(Debug, Copy, Clone, HashStable, TypeFoldable, TypeVisitable)]
 pub enum UpvarArgs<'tcx> {
     Closure(GenericArgsRef<'tcx>),
     Coroutine(GenericArgsRef<'tcx>),
diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs
new file mode 100644
index 00000000000..8fc9924a12f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs
@@ -0,0 +1,23 @@
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+struct DropMe;
+
+trait Impossible {}
+fn trait_error<T: Impossible>() {}
+
+pub fn main() {
+    let b = DropMe;
+    let async_closure = async move || {
+        // Type error here taints the environment. This causes us to fallback all
+        // variables to `Error`. This means that when we compute the upvars for the
+        // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization`
+        // and `ExprUseVisitor`` will bail early when it sees error. This means
+        // that our underlying assumption that the parent and child captures are
+        // compatible ends up being broken, previously leading to an ICE.
+        trait_error::<()>();
+        //~^ ERROR the trait bound `(): Impossible` is not satisfied
+        let _b = b;
+    };
+}
diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr
new file mode 100644
index 00000000000..b4dc3e268bd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `(): Impossible` is not satisfied
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:19:23
+   |
+LL |         trait_error::<()>();
+   |                       ^^ the trait `Impossible` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:7:1
+   |
+LL | trait Impossible {}
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `trait_error`
+  --> $DIR/dont-ice-when-body-tainted-by-errors.rs:8:19
+   |
+LL | fn trait_error<T: Impossible>() {}
+   |                   ^^^^^^^^^^ required by this bound in `trait_error`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.