Skip to content

Commit

Permalink
Rollup merge of #123049 - compiler-errors:coroutine-closure-rcvr, r=o…
Browse files Browse the repository at this point in the history
…li-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 #3400

r? oli-obk
  • Loading branch information
matthiaskrgr committed Mar 26, 2024
2 parents 860b63e + 4bf56fa commit dfb5b89
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 14 deletions.
40 changes: 40 additions & 0 deletions tests/pass/async-closure-drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#![feature(async_closure, noop_waker, async_fn_traits)]

use std::future::Future;
use std::pin::pin;
use std::task::*;

pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
let mut fut = pin!(fut);
let ctx = &mut Context::from_waker(Waker::noop());

loop {
match fut.as_mut().poll(ctx) {
Poll::Pending => {}
Poll::Ready(t) => break t,
}
}
}

async fn call_once(f: impl async FnOnce(DropMe)) {
f(DropMe("world")).await;
}

#[derive(Debug)]
struct DropMe(&'static str);

impl Drop for DropMe {
fn drop(&mut self) {
println!("{}", self.0);
}
}

pub fn main() {
block_on(async {
let b = DropMe("hello");
let async_closure = async move |a: DropMe| {
println!("{a:?} {b:?}");
};
call_once(async_closure).await;
});
}
3 changes: 3 additions & 0 deletions tests/pass/async-closure-drop.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DropMe("world") DropMe("hello")
world
hello
34 changes: 23 additions & 11 deletions tests/pass/async-closure.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(async_closure, noop_waker, async_fn_traits)]

use std::future::Future;
use std::ops::{AsyncFnMut, AsyncFnOnce};
use std::pin::pin;
use std::task::*;

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

async fn call_once(f: impl async FnOnce(DropMe)) {
f(DropMe("world")).await;
async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
f(0).await;
}

#[derive(Debug)]
struct DropMe(&'static str);
async fn call_once(f: impl AsyncFnOnce(i32)) {
f(1).await;
}

impl Drop for DropMe {
fn drop(&mut self) {
println!("{}", self.0);
}
async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
f(0).await;
}

async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
f(1).await;
}

pub fn main() {
block_on(async {
let b = DropMe("hello");
let async_closure = async move |a: DropMe| {
println!("{a:?} {b:?}");
let b = 2i32;
let mut async_closure = async move |a: i32| {
println!("{a} {b}");
};
call_mut(&mut async_closure).await;
call_once(async_closure).await;

// No-capture closures implement `Fn`.
let async_closure = async move |a: i32| {
println!("{a}");
};
call_normal(&async_closure).await;
call_normal_once(async_closure).await;
});
}
7 changes: 4 additions & 3 deletions tests/pass/async-closure.stdout
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
DropMe("world") DropMe("hello")
world
hello
0 2
1 2
0
1

0 comments on commit dfb5b89

Please sign in to comment.