diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index 74bf353907455..ca193a14f565a 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -14,6 +14,16 @@ use crate::ops::{Deref, DerefMut}; /// #![feature(drop_guard)] /// /// use std::mem::DropGuard; +/// use std::mem::defer; +/// +/// { +/// // Create a new guard that will do something +/// // when dropped. +/// let _guard = defer! { println!("Goodbye, world!") }; +/// +/// // The guard will be dropped here, printing: +/// // "Goodbye, world!" +/// } /// /// { /// // Create a new guard around a string that will @@ -39,11 +49,28 @@ where f: ManuallyDrop, } +/// Create a new instance of `DropGuard` with a cleanup closure. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused)] +/// #![feature(drop_guard)] +/// +/// use std::mem::defer; +/// +/// let _guard = defer! { println!("Goodbye, world!") }; +/// ``` +#[unstable(feature = "drop_guard", issue = "144426")] +pub macro defer($($t:tt)*) { + $crate::mem::DropGuard::new((), |()| { $($t)* }) +} + impl DropGuard where F: FnOnce(T), { - /// Create a new instance of `DropGuard`. + /// Create a new instance of `DropGuard` with a value and a cleanup closure. /// /// # Example /// diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index ad5fda0cfe4db..1fd9d9e8ec37e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -25,7 +25,7 @@ pub use transmutability::{Assume, TransmuteFrom}; mod drop_guard; #[unstable(feature = "drop_guard", issue = "144426")] -pub use drop_guard::DropGuard; +pub use drop_guard::{DropGuard, defer}; // This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do // the special magic "types have equal size" check at the call site. diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 5247e01fba01b..91fe625de9728 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -800,7 +800,7 @@ fn const_maybe_uninit_zeroed() { #[test] fn drop_guards_only_dropped_by_closure_when_run() { let value_drops = Cell::new(0); - let value = DropGuard::new((), |()| value_drops.set(1 + value_drops.get())); + let value = defer! { value_drops.set(1 + value_drops.get()) }; let closure_drops = Cell::new(0); let guard = DropGuard::new(value, |_| closure_drops.set(1 + closure_drops.get())); assert_eq!(value_drops.get(), 0); @@ -825,10 +825,10 @@ fn drop_guard_into_inner() { fn drop_guard_always_drops_value_if_closure_drop_unwinds() { // Create a value with a destructor, which we will validate ran successfully. let mut value_was_dropped = false; - let value_with_tracked_destruction = DropGuard::new((), |_| value_was_dropped = true); + let value_with_tracked_destruction = defer! { value_was_dropped = true }; // Create a closure that will begin unwinding when dropped. - let drop_bomb = DropGuard::new((), |_| panic!()); + let drop_bomb = defer! { panic!() }; let closure_that_panics_on_drop = move |_| { let _drop_bomb = drop_bomb; }; @@ -841,3 +841,11 @@ fn drop_guard_always_drops_value_if_closure_drop_unwinds() { })); assert!(value_was_dropped); } + +#[test] +fn defer_moved_value() { + let data = "owned data".to_string(); + let _guard = defer! { + std::thread::spawn(move || { assert_eq!(data.as_str(), "owned data") }).join().ok(); + }; +}