Change:
E.g. in and cc
I'd like to work on this :smile:
You've got it :)

Discussion:
<del> // Test that we don't duplicate storage for futures moved around in .await, and // for futures moved into other futures. // // The exact sizes can change by a few bytes (we'd like to know when they do). // What we don't want to see is the wrong multiple of 1024 (the size of BigFut) // being reflected in the size. // // See issue #59123 for a full explanation. // edition:2018 #![feature(async_await)] use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; const BIG_FUT_SIZE: usize = 1024; struct BigFut([u8; BIG_FUT_SIZE]); impl BigFut { fn new() -> Self { BigFut([0; BIG_FUT_SIZE]) } } impl Drop for BigFut { fn drop(&mut self) {} } impl Future for BigFut { type Output = (); fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(()) } } #[allow(dead_code)] struct Joiner { a: Option<BigFut>, b: Option<BigFut>, c: Option<BigFut>, } impl Future for Joiner { type Output = (); fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(()) } } fn noop() {} async fn single() { let x = BigFut::new(); x.await; } async fn single_with_noop() { let x = BigFut::new(); noop(); x.await; } async fn joined() { let a = BigFut::new(); let b = BigFut::new(); let c = BigFut::new(); let joiner = Joiner { a: Some(a), b: Some(b), c: Some(c), }; joiner.await } async fn joined_with_noop() { let a = BigFut::new(); let b = BigFut::new(); let c = BigFut::new(); let joiner = Joiner { a: Some(a), b: Some(b), c: Some(c), }; noop(); joiner.await } fn main() { assert_eq!(1028, std::mem::size_of_val(&single())); assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); assert_eq!(3084, std::mem::size_of_val(&joined())); assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); } </del>

<del> // edition:2018 #![feature(async_await)] #[path = "../auxiliary/arc_wake.rs"] mod arc_wake; use std::pin::Pin; use std::future::Future; use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; use std::task::{Context, Poll}; use arc_wake::ArcWake; struct Counter { wakes: AtomicUsize, } impl ArcWake for Counter { fn wake(self: Arc<Self>) { Self::wake_by_ref(&self) } fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } struct WakeOnceThenComplete(bool, u8); impl Future for WakeOnceThenComplete { type Output = u8; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<u8> { if self.0 { Poll::Ready(self.1) } else { cx.waker().wake_by_ref(); self.0 = true; Poll::Pending } } } fn wait(fut: impl Future<Output = u8>) -> u8 { let mut fut = Box::pin(fut); let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); let waker = ArcWake::into_waker(counter.clone()); let mut cx = Context::from_waker(&waker); loop { match fut.as_mut().poll(&mut cx) { Poll::Ready(out) => return out, Poll::Pending => (), } } } fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } async fn await1_level1() -> u8 { base().await } async fn await2_level1() -> u8 { base().await + base().await } async fn await3_level1() -> u8 { base().await + base().await + base().await } async fn await3_level2() -> u8 { await3_level1().await + await3_level1().await + await3_level1().await } async fn await3_level3() -> u8 { await3_level2().await + await3_level2().await + await3_level2().await } async fn await3_level4() -> u8 { await3_level3().await + await3_level3().await + await3_level3().await } async fn await3_level5() -> u8 { await3_level4().await + await3_level4().await + await3_level4().await } fn main() { assert_eq!(2, std::mem::size_of_val(&base())); assert_eq!(8, std::mem::size_of_val(&await1_level1())); assert_eq!(12, std::mem::size_of_val(&await2_level1())); assert_eq!(12, std::mem::size_of_val(&await3_level1())); assert_eq!(20, std::mem::size_of_val(&await3_level2())); assert_eq!(28, std::mem::size_of_val(&await3_level3())); assert_eq!(36, std::mem::size_of_val(&await3_level4())); assert_eq!(44, std::mem::size_of_val(&await3_level5())); assert_eq!(1,   wait(base())); assert_eq!(1,   wait(await1_level1())); assert_eq!(2,   wait(await2_level1())); assert_eq!(3,   wait(await3_level1())); assert_eq!(9,   wait(await3_level2())); assert_eq!(27,  wait(await3_level3())); assert_eq!(81,  wait(await3_level4())); assert_eq!(243, wait(await3_level5())); } </del>

<del> // This used to compile the future down to ud2, due to uninhabited types being // handled incorrectly in generators. // compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 #![feature(async_await)] #![allow(unused)] use std::future::Future; use std::task::Poll; use std::task::Context; use std::pin::Pin; use std::rc::Rc; struct Never(); impl Future for Never { type Output = (); fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending } } fn main() { let fut = async { let _rc = Rc::new(()); // Also crashes with Arc Never().await; }; let _bla = fut; // Moving the future is required. } </del>

<del> // edition:2018 use std::sync::Arc; use std::task::{ Waker, RawWaker, RawWakerVTable, }; macro_rules! waker_vtable { ($ty:ident) => { &RawWakerVTable::new( clone_arc_raw::<$ty>, wake_arc_raw::<$ty>, wake_by_ref_arc_raw::<$ty>, drop_arc_raw::<$ty>, ) }; } pub trait ArcWake { fn wake(self: Arc<Self>); fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.clone().wake() } fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized { let ptr = Arc::into_raw(wake) as *const (); unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) } } } unsafe fn increase_refcount<T: ArcWake>(data: *const ()) { // Retain Arc by creating a copy let arc: Arc<T> = Arc::from_raw(data as *const T); let arc_clone = arc.clone(); // Forget the Arcs again, so that the refcount isn't decrased let _ = Arc::into_raw(arc); let _ = Arc::into_raw(arc_clone); } unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { increase_refcount::<T>(data); RawWaker::new(data, waker_vtable!(T)) } unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { // Drop Arc let _: Arc<T> = Arc::from_raw(data as *const T); } unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { let arc: Arc<T> = Arc::from_raw(data as *const T); ArcWake::wake(arc); } unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { let arc: Arc<T> = Arc::from_raw(data as *const T); ArcWake::wake_by_ref(&arc); let _ = Arc::into_raw(arc); } </del>

<del> // aux-build:arc_wake.rs extern crate arc_wake; use std::future::Future; use std::pin::Pin; use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; use std::task::{ Context, Poll, }; use arc_wake::ArcWake; struct Counter { wakes: AtomicUsize, } impl ArcWake for Counter { fn wake(self: Arc<Self>) { Self::wake_by_ref(&self) } fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } struct MyFuture; impl Future for MyFuture { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // Wake twice let waker = cx.waker(); waker.wake_by_ref(); waker.wake_by_ref(); Poll::Ready(()) } } fn test_waker() { let counter = Arc::new(Counter { wakes: AtomicUsize::new(0), }); let waker = ArcWake::into_waker(counter.clone()); assert_eq!(2, Arc::strong_count(&counter)); { let mut context = Context::from_waker(&waker); assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); } drop(waker); assert_eq!(1, Arc::strong_count(&counter)); } fn main() { test_waker(); } </del>

<ins> // Test that we don't duplicate storage for futures moved around in .await, and // for futures moved into other futures. // // The exact sizes can change by a few bytes (we'd like to know when they do). // What we don't want to see is the wrong multiple of 1024 (the size of BigFut) // being reflected in the size. // // See issue #59123 for a full explanation. // ignore-wasm32-bare (sizes don't match) // run-pass // edition:2018 #![feature(async_await)] use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; const BIG_FUT_SIZE: usize = 1024; struct BigFut([u8; BIG_FUT_SIZE]); impl BigFut { fn new() -> Self { BigFut([0; BIG_FUT_SIZE]) } } impl Drop for BigFut { fn drop(&mut self) {} } impl Future for BigFut { type Output = (); fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(()) } } #[allow(dead_code)] struct Joiner { a: Option<BigFut>, b: Option<BigFut>, c: Option<BigFut>, } impl Future for Joiner { type Output = (); fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Ready(()) } } fn noop() {} async fn single() { let x = BigFut::new(); x.await; } async fn single_with_noop() { let x = BigFut::new(); noop(); x.await; } async fn joined() { let a = BigFut::new(); let b = BigFut::new(); let c = BigFut::new(); let joiner = Joiner { a: Some(a), b: Some(b), c: Some(c), }; joiner.await } async fn joined_with_noop() { let a = BigFut::new(); let b = BigFut::new(); let c = BigFut::new(); let joiner = Joiner { a: Some(a), b: Some(b), c: Some(c), }; noop(); joiner.await } fn main() { assert_eq!(1028, std::mem::size_of_val(&single())); assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); assert_eq!(3084, std::mem::size_of_val(&joined())); assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); } </ins>

<ins> // run-pass // aux-build:arc_wake.rs // edition:2018 #![feature(async_await)] extern crate arc_wake; use std::pin::Pin; use std::future::Future; use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; use std::task::{Context, Poll}; use arc_wake::ArcWake; struct Counter { wakes: AtomicUsize, } impl ArcWake for Counter { fn wake(self: Arc<Self>) { Self::wake_by_ref(&self) } fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } struct WakeOnceThenComplete(bool, u8); impl Future for WakeOnceThenComplete { type Output = u8; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<u8> { if self.0 { Poll::Ready(self.1) } else { cx.waker().wake_by_ref(); self.0 = true; Poll::Pending } } } fn wait(fut: impl Future<Output = u8>) -> u8 { let mut fut = Box::pin(fut); let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); let waker = ArcWake::into_waker(counter.clone()); let mut cx = Context::from_waker(&waker); loop { match fut.as_mut().poll(&mut cx) { Poll::Ready(out) => return out, Poll::Pending => (), } } } fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } async fn await1_level1() -> u8 { base().await } async fn await2_level1() -> u8 { base().await + base().await } async fn await3_level1() -> u8 { base().await + base().await + base().await } async fn await3_level2() -> u8 { await3_level1().await + await3_level1().await + await3_level1().await } async fn await3_level3() -> u8 { await3_level2().await + await3_level2().await + await3_level2().await } async fn await3_level4() -> u8 { await3_level3().await + await3_level3().await + await3_level3().await } async fn await3_level5() -> u8 { await3_level4().await + await3_level4().await + await3_level4().await } fn main() { assert_eq!(2, std::mem::size_of_val(&base())); assert_eq!(8, std::mem::size_of_val(&await1_level1())); assert_eq!(12, std::mem::size_of_val(&await2_level1())); assert_eq!(12, std::mem::size_of_val(&await3_level1())); assert_eq!(20, std::mem::size_of_val(&await3_level2())); assert_eq!(28, std::mem::size_of_val(&await3_level3())); assert_eq!(36, std::mem::size_of_val(&await3_level4())); assert_eq!(44, std::mem::size_of_val(&await3_level5())); assert_eq!(1,   wait(base())); assert_eq!(1,   wait(await1_level1())); assert_eq!(2,   wait(await2_level1())); assert_eq!(3,   wait(await3_level1())); assert_eq!(9,   wait(await3_level2())); assert_eq!(27,  wait(await3_level3())); assert_eq!(81,  wait(await3_level4())); assert_eq!(243, wait(await3_level5())); } </ins>

<ins> // run-pass // aux-build:arc_wake.rs extern crate arc_wake; use std::future::Future; use std::pin::Pin; use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; use std::task::{ Context, Poll, }; use arc_wake::ArcWake; struct Counter { wakes: AtomicUsize, } impl ArcWake for Counter { fn wake(self: Arc<Self>) { Self::wake_by_ref(&self) } fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } struct MyFuture; impl Future for MyFuture { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // Wake twice let waker = cx.waker(); waker.wake_by_ref(); waker.wake_by_ref(); Poll::Ready(()) } } fn test_waker() { let counter = Arc::new(Counter { wakes: AtomicUsize::new(0), }); let waker = ArcWake::into_waker(counter.clone()); assert_eq!(2, Arc::strong_count(&counter)); { let mut context = Context::from_waker(&waker); assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); } drop(waker); assert_eq!(1, Arc::strong_count(&counter)); } fn main() { test_waker(); } </ins>

<ins> // This used to compile the future down to ud2, due to uninhabited types being // handled incorrectly in generators. // compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 // run-pass #![feature(async_await)] #![allow(unused)] use std::future::Future; use std::task::Poll; use std::task::Context; use std::pin::Pin; use std::rc::Rc; struct Never(); impl Future for Never { type Output = (); fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending } } fn main() { let fut = async { let _rc = Rc::new(()); // Also crashes with Arc Never().await; }; let _bla = fut; // Moving the future is required. } </ins>