From 57a7e514a4fee2d76bae4b6f2ee72a760518f892 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 15 Sep 2024 16:07:08 -0400 Subject: [PATCH] Don't ICE when generating Fn shim for async closure with borrowck error --- compiler/rustc_mir_transform/src/shim.rs | 17 +++++++++---- .../closure-shim-borrowck-error.rs} | 2 +- .../closure-shim-borrowck-error.stderr | 24 +++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) rename tests/{crashes/129262.rs => ui/async-await/async-closures/closure-shim-borrowck-error.rs} (87%) create mode 100644 tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f1bd803d83530..47d04d8a00bf0 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1070,19 +1070,26 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let locals = local_decls_for_sig(&sig, span); let mut fields = vec![]; + + // Move all of the closure args. for idx in 1..sig.inputs().len() { fields.push(Operand::Move(Local::from_usize(idx + 1).into())); } + for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { if receiver_by_ref { // The only situation where it's possible is when we capture immuatable references, // since those don't need to be reborrowed with the closure's env lifetime. Since // references are always `Copy`, just emit a copy. - assert_matches!( - ty.kind(), - ty::Ref(_, _, hir::Mutability::Not), - "field should be captured by immutable ref if we have an `Fn` instance" - ); + if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) { + // This copy is only sound if it's a `&T`. This may be + // reachable e.g. when eagerly computing the `Fn` instance + // of an async closure that doesn't borrowck. + tcx.dcx().delayed_bug(format!( + "field should be captured by immutable ref if we have \ + an `Fn` instance, but it was: {ty}" + )); + } fields.push(Operand::Copy(tcx.mk_place_field( self_local, FieldIdx::from_usize(idx), diff --git a/tests/crashes/129262.rs b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs similarity index 87% rename from tests/crashes/129262.rs rename to tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs index c430af35988d8..4cbbefb0f5298 100644 --- a/tests/crashes/129262.rs +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs @@ -1,4 +1,3 @@ -//@ known-bug: rust-lang/rust#129262 //@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3 #![feature(async_closure)] @@ -11,6 +10,7 @@ fn needs_fn_mut(mut x: impl FnMut() -> T) { fn hello(x: Ty) { needs_fn_mut(async || { + //~^ ERROR cannot move out of `x` x.hello(); }); } diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr new file mode 100644 index 0000000000000..bab26c1948217 --- /dev/null +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr @@ -0,0 +1,24 @@ +error[E0507]: cannot move out of `x` which is behind a mutable reference + --> $DIR/closure-shim-borrowck-error.rs:12:18 + | +LL | needs_fn_mut(async || { + | ^^^^^^^^ `x` is moved here +LL | +LL | x.hello(); + | - + | | + | variable moved due to use in coroutine + | move occurs because `x` has type `Ty`, which does not implement the `Copy` trait + | +note: if `Ty` implemented `Clone`, you could clone the value + --> $DIR/closure-shim-borrowck-error.rs:18:1 + | +LL | x.hello(); + | - you could clone this value +... +LL | struct Ty; + | ^^^^^^^^^ consider implementing `Clone` for this type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`.