blob: 1a93a6bf664973580408ce96fa59b54a697061e8 [file] [log] [blame]
#![feature(noop_waker)]
use std::future::Future;
use std::ptr;
// This test:
// - Compares addresses of non-Copy data before and after moving it
// - Writes to the pointer after it has moved across the await point
//
// This is only meant to assert current behavior, not guarantee that this is
// how it should work in the future. In fact, upcoming changes to rustc
// *should* break these tests.
// See: https://github.com/rust-lang/rust/issues/62958
async fn data_moved_async() {
async fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
let raw_pointer2 = ptr::addr_of_mut!(data);
// `raw_pointer` points to the original location where the Vec was stored in the caller.
// `data` is where that Vec (to be precise, its ptr+capacity+len on-stack data)
// got moved to. Those will usually not be the same since the Vec got moved twice
// (into the function call, and then into the coroutine upvar).
assert_ne!(raw_pointer, raw_pointer2);
unsafe {
// This writes into the `x` in `data_moved_async`, re-initializing it.
std::ptr::write(raw_pointer, vec![3]);
}
}
// Vec<T> is not Copy
let mut x: Vec<u8> = vec![2];
let raw_pointer = ptr::addr_of_mut!(x);
helper(x, raw_pointer).await;
unsafe {
assert_eq!(*raw_pointer, vec![3]);
// Drop to prevent leak.
std::ptr::drop_in_place(raw_pointer);
}
}
// Same thing as above, but non-async.
fn data_moved() {
fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
let raw_pointer2 = ptr::addr_of_mut!(data);
assert_ne!(raw_pointer, raw_pointer2);
unsafe {
std::ptr::write(raw_pointer, vec![3]);
}
}
let mut x: Vec<u8> = vec![2];
let raw_pointer = ptr::addr_of_mut!(x);
helper(x, raw_pointer);
unsafe {
assert_eq!(*raw_pointer, vec![3]);
std::ptr::drop_in_place(raw_pointer);
}
}
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
use std::task::{Context, Poll, Waker};
let mut context = Context::from_waker(Waker::noop());
let mut pinned = Box::pin(fut);
loop {
match pinned.as_mut().poll(&mut context) {
Poll::Pending => continue,
Poll::Ready(v) => return v,
}
}
}
fn main() {
run_fut(data_moved_async());
data_moved();
}