Skip to content

Commit 95b87e3

Browse files
committed
Add tests for moving data across await point
This patch adds a few tests to assert the current behavior when passing data across an await point. This will help to test out an upcoming fix for the issue of arguments in async functions growing in size because of the generator upvar that is generated when we desugar the async function. See rust-lang/rust#62958 Also relates to rust-lang/rust#107500
1 parent fb38aea commit 95b87e3

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::future::Future;
2+
3+
// This test:
4+
// - Compares addresses of non-Copy data before and after moving it
5+
// - Writes to the pointer after it has moved across the await point
6+
async fn data_moved_async() {
7+
// Vec<T> is not Copy
8+
let mut x: Vec<u8> = vec![2];
9+
let raw_pointer = &mut x as *mut Vec<u8>;
10+
helper_async(x, raw_pointer).await;
11+
unsafe {
12+
assert_eq!(*raw_pointer, vec![3]);
13+
// Drop to prevent leak.
14+
std::ptr::drop_in_place(raw_pointer);
15+
}
16+
}
17+
18+
async fn helper_async(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
19+
let raw_pointer2 = &mut data as *mut Vec<u8>;
20+
// Addresses are different because the generator upvar for `data` is a copy.
21+
// To be more precise, there is a `move` happening in the MIR of the
22+
// generator closure, which copies the pointer.
23+
//
24+
// When copy propagation is enabled for generator upvars, the pointer addresses
25+
// here should be equal.
26+
assert_ne!(raw_pointer, raw_pointer2);
27+
unsafe {
28+
std::ptr::write(raw_pointer, vec![3]);
29+
}
30+
}
31+
32+
// Same thing as above, but non-async.
33+
fn data_moved() {
34+
let mut x: Vec<u8> = vec![2];
35+
let raw_pointer = &mut x as *mut Vec<u8>;
36+
helper(x, raw_pointer);
37+
unsafe {
38+
assert_eq!(*raw_pointer, vec![3]);
39+
std::ptr::drop_in_place(raw_pointer);
40+
}
41+
}
42+
43+
#[inline(always)]
44+
fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
45+
let raw_pointer2 = &mut data as *mut Vec<u8>;
46+
assert_ne!(raw_pointer, raw_pointer2);
47+
unsafe {
48+
std::ptr::write(raw_pointer, vec![3]);
49+
}
50+
}
51+
52+
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
53+
use std::sync::Arc;
54+
use std::task::{Context, Poll, Wake, Waker};
55+
56+
struct MyWaker;
57+
impl Wake for MyWaker {
58+
fn wake(self: Arc<Self>) {
59+
unimplemented!()
60+
}
61+
}
62+
63+
let waker = Waker::from(Arc::new(MyWaker));
64+
let mut context = Context::from_waker(&waker);
65+
66+
let mut pinned = Box::pin(fut);
67+
loop {
68+
match pinned.as_mut().poll(&mut context) {
69+
Poll::Pending => continue,
70+
Poll::Ready(v) => return v,
71+
}
72+
}
73+
}
74+
75+
fn main() {
76+
run_fut(data_moved_async());
77+
data_moved();
78+
}

0 commit comments

Comments
 (0)