about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-09-15 16:07:08 -0400
committerMichael Goulet <michael@errs.io>2024-09-16 10:57:58 -0400
commit57a7e514a4fee2d76bae4b6f2ee72a760518f892 (patch)
tree67c8d49ffc936318c8a925eaf116f5082d45f87b
parent13b5a4e43b92cf738acad403ea56900947f9d37b (diff)
downloadrust-57a7e514a4fee2d76bae4b6f2ee72a760518f892.tar.gz
rust-57a7e514a4fee2d76bae4b6f2ee72a760518f892.zip
Don't ICE when generating Fn shim for async closure with borrowck error
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs17
-rw-r--r--tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs (renamed from tests/crashes/129262.rs)2
-rw-r--r--tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr24
3 files changed, 37 insertions, 6 deletions
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index f1bd803d835..47d04d8a00b 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
index c430af35988..4cbbefb0f52 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<T>(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 00000000000..bab26c19482
--- /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`.