| // aux-build:arc_wake.rs |
| // edition:2018 |
| // run-pass |
| |
| #![deny(dead_code)] |
| #![allow(unused_variables)] |
| #![allow(unused_must_use)] |
| #![allow(path_statements)] |
| |
| // Test that the drop order for locals in a fn and async fn matches up. |
| extern crate arc_wake; |
| |
| use arc_wake::ArcWake; |
| use std::cell::RefCell; |
| use std::future::Future; |
| use std::pin::Pin; |
| use std::rc::Rc; |
| use std::sync::Arc; |
| use std::task::{Context, Poll}; |
| |
| struct EmptyWaker; |
| |
| impl ArcWake for EmptyWaker { |
| fn wake(self: Arc<Self>) {} |
| } |
| |
| #[derive(Debug, Eq, PartialEq)] |
| enum DropOrder { |
| Function, |
| Val(&'static str), |
| } |
| |
| type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; |
| |
| struct D(&'static str, DropOrderListPtr); |
| |
| impl Drop for D { |
| fn drop(&mut self) { |
| self.1.borrow_mut().push(DropOrder::Val(self.0)); |
| } |
| } |
| |
| struct NeverReady; |
| |
| impl Future for NeverReady { |
| type Output = (); |
| fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { |
| Poll::Pending |
| } |
| } |
| |
| async fn simple_variable_declaration_async(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| NeverReady.await; |
| } |
| |
| fn simple_variable_declaration_sync(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| } |
| |
| async fn varable_completely_contained_within_block_async(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| async { |
| let x = D("x", l.clone()); |
| } |
| .await; |
| let y = D("y", l.clone()); |
| NeverReady.await; |
| } |
| |
| fn varable_completely_contained_within_block_sync(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| { |
| let x = D("x", l.clone()); |
| } |
| let y = D("y", l.clone()); |
| } |
| |
| async fn variables_moved_into_separate_blocks_async(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| async move { x }.await; |
| async move { y }.await; |
| NeverReady.await; |
| } |
| |
| fn variables_moved_into_separate_blocks_sync(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| { |
| x |
| }; |
| { |
| y |
| }; |
| } |
| |
| async fn variables_moved_into_same_block_async(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| async move { |
| x; |
| y; |
| }; |
| NeverReady.await; |
| } |
| |
| fn variables_moved_into_same_block_sync(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| { |
| x; |
| y; |
| }; |
| return; |
| } |
| |
| async fn move_after_current_await_doesnt_affect_order(l: DropOrderListPtr) { |
| l.borrow_mut().push(DropOrder::Function); |
| let x = D("x", l.clone()); |
| let y = D("y", l.clone()); |
| NeverReady.await; |
| async move { |
| x; |
| y; |
| }; |
| } |
| |
| fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>( |
| f: impl FnOnce(DropOrderListPtr) -> Fut, |
| g: impl FnOnce(DropOrderListPtr), |
| ) { |
| let empty = Arc::new(EmptyWaker); |
| let waker = ArcWake::into_waker(empty); |
| let mut cx = Context::from_waker(&waker); |
| |
| let actual_order = Rc::new(RefCell::new(Vec::new())); |
| let mut fut = Box::pin(f(actual_order.clone())); |
| let _ = fut.as_mut().poll(&mut cx); |
| drop(fut); |
| |
| let expected_order = Rc::new(RefCell::new(Vec::new())); |
| g(expected_order.clone()); |
| assert_eq!(*actual_order.borrow(), *expected_order.borrow()); |
| } |
| |
| fn main() { |
| assert_drop_order_after_cancel( |
| simple_variable_declaration_async, |
| simple_variable_declaration_sync, |
| ); |
| assert_drop_order_after_cancel( |
| varable_completely_contained_within_block_async, |
| varable_completely_contained_within_block_sync, |
| ); |
| assert_drop_order_after_cancel( |
| variables_moved_into_separate_blocks_async, |
| variables_moved_into_separate_blocks_sync, |
| ); |
| assert_drop_order_after_cancel( |
| variables_moved_into_same_block_async, |
| variables_moved_into_same_block_sync, |
| ); |
| assert_drop_order_after_cancel( |
| move_after_current_await_doesnt_affect_order, |
| simple_variable_declaration_sync, |
| ); |
| } |