diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index ef569b4bef3b3..0257140621622 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -361,7 +361,11 @@ 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 + // Don't do this if we are tainted by errors, because fallback causes us + // to fail to infer upvars for the outer coroutine-closure. + && self.tainted_by_errors().is_none() + { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, ty::INNERMOST, 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 0000000000000..8fc9924a12fb0 --- /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() {} + +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 0000000000000..b4dc3e268bdaf --- /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() {} + | ^^^^^^^^^^ required by this bound in `trait_error` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.