Skip to content

Commit b63dca1

Browse files
authored
Rollup merge of #123049 - compiler-errors:coroutine-closure-rcvr, r=oli-obk
In `ConstructCoroutineInClosureShim`, pass receiver by mut ref, not mut pointer The receivers were compatible at codegen time, but did not necessarily have the same layouts due to niches, which was caught by miri. Fixes rust-lang/miri#3400 r? oli-obk
2 parents 0029a11 + 22bc5c5 commit b63dca1

8 files changed

+81
-21
lines changed

compiler/rustc_mir_transform/src/shim.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1015,8 +1015,8 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
10151015
bug!();
10161016
};
10171017

1018-
// We use `*mut Self` here because we only need to emit an ABI-compatible shim body,
1019-
// rather than match the signature exactly.
1018+
// We use `&mut Self` here because we only need to emit an ABI-compatible shim body,
1019+
// rather than match the signature exactly (which might take `&self` instead).
10201020
//
10211021
// The self type here is a coroutine-closure, not a coroutine, and we never read from
10221022
// it because it never has any captures, because this is only true in the Fn/FnMut
@@ -1025,7 +1025,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
10251025
if receiver_by_ref {
10261026
// Triple-check that there's no captures here.
10271027
assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit);
1028-
self_ty = Ty::new_mut_ptr(tcx, self_ty);
1028+
self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty);
10291029
}
10301030

10311031
let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {

compiler/rustc_ty_utils/src/abi.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,12 @@ fn fn_sig_for_fn_abi<'tcx>(
125125
coroutine_kind = ty::ClosureKind::FnOnce;
126126

127127
// Implementations of `FnMut` and `Fn` for coroutine-closures
128-
// still take their receiver by ref.
129-
if receiver_by_ref { Ty::new_mut_ptr(tcx, coroutine_ty) } else { coroutine_ty }
128+
// still take their receiver by (mut) ref.
129+
if receiver_by_ref {
130+
Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty)
131+
} else {
132+
coroutine_ty
133+
}
130134
} else {
131135
tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region)
132136
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![feature(async_closure, noop_waker, async_fn_traits)]
2+
3+
use std::future::Future;
4+
use std::pin::pin;
5+
use std::task::*;
6+
7+
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
8+
let mut fut = pin!(fut);
9+
let ctx = &mut Context::from_waker(Waker::noop());
10+
11+
loop {
12+
match fut.as_mut().poll(ctx) {
13+
Poll::Pending => {}
14+
Poll::Ready(t) => break t,
15+
}
16+
}
17+
}
18+
19+
async fn call_once(f: impl async FnOnce(DropMe)) {
20+
f(DropMe("world")).await;
21+
}
22+
23+
#[derive(Debug)]
24+
struct DropMe(&'static str);
25+
26+
impl Drop for DropMe {
27+
fn drop(&mut self) {
28+
println!("{}", self.0);
29+
}
30+
}
31+
32+
pub fn main() {
33+
block_on(async {
34+
let b = DropMe("hello");
35+
let async_closure = async move |a: DropMe| {
36+
println!("{a:?} {b:?}");
37+
};
38+
call_once(async_closure).await;
39+
});
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DropMe("world") DropMe("hello")
2+
world
3+
hello
+23-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(async_closure, noop_waker, async_fn_traits)]
22

33
use std::future::Future;
4+
use std::ops::{AsyncFnMut, AsyncFnOnce};
45
use std::pin::pin;
56
use std::task::*;
67

@@ -16,25 +17,36 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
1617
}
1718
}
1819

19-
async fn call_once(f: impl async FnOnce(DropMe)) {
20-
f(DropMe("world")).await;
20+
async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
21+
f(0).await;
2122
}
2223

23-
#[derive(Debug)]
24-
struct DropMe(&'static str);
24+
async fn call_once(f: impl AsyncFnOnce(i32)) {
25+
f(1).await;
26+
}
2527

26-
impl Drop for DropMe {
27-
fn drop(&mut self) {
28-
println!("{}", self.0);
29-
}
28+
async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
29+
f(0).await;
30+
}
31+
32+
async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
33+
f(1).await;
3034
}
3135

3236
pub fn main() {
3337
block_on(async {
34-
let b = DropMe("hello");
35-
let async_closure = async move |a: DropMe| {
36-
println!("{a:?} {b:?}");
38+
let b = 2i32;
39+
let mut async_closure = async move |a: i32| {
40+
println!("{a} {b}");
3741
};
42+
call_mut(&mut async_closure).await;
3843
call_once(async_closure).await;
44+
45+
// No-capture closures implement `Fn`.
46+
let async_closure = async move |a: i32| {
47+
println!("{a}");
48+
};
49+
call_normal(&async_closure).await;
50+
call_normal_once(async_closure).await;
3951
});
4052
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
DropMe("world") DropMe("hello")
2-
world
3-
hello
1+
0 2
2+
1 2
3+
0
4+
1

tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
22

3-
fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
3+
fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
44
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
55

66
bb0: {

tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
22

3-
fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
3+
fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
44
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
55

66
bb0: {

0 commit comments

Comments
 (0)