From 892df1db60c3c81c57899ef3712b43f63d971b25 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 10 May 2017 12:48:36 -0400 Subject: [PATCH 1/3] expose needs_drop under mem:: --- src/libcore/mem.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b397aba6b92df..18428d378e3d2 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -302,6 +302,58 @@ pub fn align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } +/// Returns whether dropping values of type `T` matters. +/// +/// This is purely an optimization hint, and may be implemented conservatively. +/// For instance, always returning `true` would be a valid implementation of +/// this function. +/// +/// Low level implementations of things like collections, which need to manually +/// drop their data, should use this function to avoid unnecessarily +/// trying to drop all their contents when they are destroyed. This might not +/// make a difference in release builds (where a loop that has no side-effects +/// is easily detected and eliminated), but is often a big win for debug builds. +/// +/// Note that `ptr::drop_in_place` already performs this check, so if your workload +/// can be reduced to some small number of drop_in_place calls, using this is +/// unnecessary. In particular note that you can drop_in_place a slice, and that +/// will do a single needs_drop check for all the values. +/// +/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using +/// needs_drop explicitly. Types like HashMap, on the other hand, have to drop +/// values one at a time and should use this API. +/// +/// +/// # Examples +/// +/// Here's an example of how a collection might make use of needs_drop: +/// +/// ```ignore +/// #![feature(needs_drop)] +/// use std::{mem, ptr}; +/// +/// pub struct MyCollection { /* ... */ } +/// +/// impl Drop for MyCollection { +/// fn drop(&mut self) { +/// unsafe { +/// // drop the data +/// if mem::needs_drop::() { +/// for x in self.iter_mut() { +/// ptr::drop_in_place(x); +/// } +/// } +/// self.free_buffer(); +/// } +/// } +/// } +/// ``` +#[inline] +#[unstable(feature = "needs_drop", issue = "41890")] +pub fn needs_drop() -> bool { + unsafe { intrinsics::needs_drop::() } +} + /// Creates a value whose bytes are all zero. /// /// This has the same effect as allocating space with From e847d46bcb01c71e18610eeb30db6f2b6a7f3214 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 10 May 2017 13:13:42 -0400 Subject: [PATCH 2/3] migrate everything to using mem::needs_drop --- src/libarena/lib.rs | 9 ++++----- src/libstd/collections/hash/table.rs | 3 +-- src/libstd/lib.rs | 1 + src/libstd/sys/redox/fast_thread_local.rs | 7 ++++--- src/libstd/sys/unix/fast_thread_local.rs | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index c4c1635aa2a5a..4338ac7fd022c 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -32,6 +32,7 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(generic_param_attrs)] +#![feature(needs_drop)] #![cfg_attr(stage0, feature(staged_api))] #![cfg_attr(test, feature(test))] @@ -82,7 +83,7 @@ impl TypedArenaChunk { unsafe fn destroy(&mut self, len: usize) { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. - if intrinsics::needs_drop::() { + if mem::needs_drop::() { let mut start = self.start(); // Destroy all allocated objects. for _ in 0..len { @@ -350,7 +351,7 @@ impl DroplessArena { #[inline] pub fn alloc(&self, object: T) -> &mut T { unsafe { - assert!(!intrinsics::needs_drop::()); + assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); self.align_for::(); @@ -379,9 +380,7 @@ impl DroplessArena { #[inline] pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] where T: Copy { - unsafe { - assert!(!intrinsics::needs_drop::()); - } + assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); assert!(slice.len() != 0); self.align_for::(); diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index a15269cc87c5d..50c721db849aa 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -12,9 +12,8 @@ use alloc::heap::{allocate, deallocate}; use cmp; use hash::{BuildHasher, Hash, Hasher}; -use intrinsics::needs_drop; use marker; -use mem::{align_of, size_of}; +use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, Shared}; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a4c3b276efdd2..b0820d6f05a05 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -281,6 +281,7 @@ #![feature(linkage)] #![feature(macro_reexport)] #![feature(needs_panic_runtime)] +#![feature(needs_drop)] #![feature(never_type)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index f6414673dace1..7dc61ce6654b9 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -12,9 +12,10 @@ #![unstable(feature = "thread_local_internals", issue = "0")] use cell::{Cell, UnsafeCell}; -use intrinsics; +use mem; use ptr; + pub struct Key { inner: UnsafeCell>, @@ -37,7 +38,7 @@ impl Key { pub fn get(&'static self) -> Option<&'static UnsafeCell>> { unsafe { - if intrinsics::needs_drop::() && self.dtor_running.get() { + if mem::needs_drop::() && self.dtor_running.get() { return None } self.register_dtor(); @@ -46,7 +47,7 @@ impl Key { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::() || self.dtor_registered.get() { + if !mem::needs_drop::() || self.dtor_registered.get() { return } diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 07d76a93dd150..6b3973de84c97 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -13,7 +13,7 @@ use cell::{Cell, UnsafeCell}; use fmt; -use intrinsics; +use mem; use ptr; pub struct Key { @@ -44,7 +44,7 @@ impl Key { pub fn get(&'static self) -> Option<&'static UnsafeCell>> { unsafe { - if intrinsics::needs_drop::() && self.dtor_running.get() { + if mem::needs_drop::() && self.dtor_running.get() { return None } self.register_dtor(); @@ -53,7 +53,7 @@ impl Key { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::() || self.dtor_registered.get() { + if !mem::needs_drop::() || self.dtor_registered.get() { return } From 1f01b09ddcd5d5ab0927528b1db0962b4310e3fc Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Thu, 11 May 2017 10:15:56 -0400 Subject: [PATCH 3/3] Add stub entry to unstable book for needs_drop --- src/doc/unstable-book/src/library-features/needs-drop.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/doc/unstable-book/src/library-features/needs-drop.md diff --git a/src/doc/unstable-book/src/library-features/needs-drop.md b/src/doc/unstable-book/src/library-features/needs-drop.md new file mode 100644 index 0000000000000..10ae95695a2db --- /dev/null +++ b/src/doc/unstable-book/src/library-features/needs-drop.md @@ -0,0 +1,7 @@ +# `needs_drop` + +The tracking issue for this feature is: [#41890] + +[#41890]: https://github.com/rust-lang/rust/issues/41890 + +------------------------