Skip to content

Commit 21b740b

Browse files
Don't ICE when generating Fn shim for async closure with borrowck error
1 parent 8c2c9a9 commit 21b740b

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

compiler/rustc_mir_transform/src/shim.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,19 +1070,26 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
10701070
let locals = local_decls_for_sig(&sig, span);
10711071

10721072
let mut fields = vec![];
1073+
1074+
// Move all of the closure args.
10731075
for idx in 1..sig.inputs().len() {
10741076
fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
10751077
}
1078+
10761079
for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
10771080
if receiver_by_ref {
10781081
// The only situation where it's possible is when we capture immuatable references,
10791082
// since those don't need to be reborrowed with the closure's env lifetime. Since
10801083
// references are always `Copy`, just emit a copy.
1081-
assert_matches!(
1082-
ty.kind(),
1083-
ty::Ref(_, _, hir::Mutability::Not),
1084-
"field should be captured by immutable ref if we have an `Fn` instance"
1085-
);
1084+
if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) {
1085+
// This copy is only sound if it's a `&T`. This may be
1086+
// reachable e.g. when eagerly computing the `Fn` instance
1087+
// of an async closure that doesn't borrowck.
1088+
tcx.dcx().delayed_bug(format!(
1089+
"field should be captured by immutable ref if we have \
1090+
an `Fn` instance, but it was: {ty}"
1091+
));
1092+
}
10861093
fields.push(Operand::Copy(tcx.mk_place_field(
10871094
self_local,
10881095
FieldIdx::from_usize(idx),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3
2+
3+
#![feature(async_closure)]
4+
5+
fn main() {}
6+
7+
fn needs_fn_mut<T>(mut x: impl FnMut() -> T) {
8+
x();
9+
}
10+
11+
fn hello(x: Ty) {
12+
needs_fn_mut(async || {
13+
//~^ ERROR cannot move out of `x`
14+
x.hello();
15+
});
16+
}
17+
18+
struct Ty;
19+
impl Ty {
20+
fn hello(self) {}
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0507]: cannot move out of `x` which is behind a mutable reference
2+
--> $DIR/closure-shim-borrowck-error.rs:12:18
3+
|
4+
LL | needs_fn_mut(async || {
5+
| ^^^^^^^^ `x` is moved here
6+
LL |
7+
LL | x.hello();
8+
| -
9+
| |
10+
| variable moved due to use in coroutine
11+
| move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
12+
|
13+
note: if `Ty` implemented `Clone`, you could clone the value
14+
--> $DIR/closure-shim-borrowck-error.rs:18:1
15+
|
16+
LL | x.hello();
17+
| - you could clone this value
18+
...
19+
LL | struct Ty;
20+
| ^^^^^^^^^ consider implementing `Clone` for this type
21+
22+
error: aborting due to 1 previous error
23+
24+
For more information about this error, try `rustc --explain E0507`.

0 commit comments

Comments
 (0)