diff options
| author | bors <bors@rust-lang.org> | 2018-07-28 14:26:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-07-28 14:26:16 +0000 |
| commit | 26e73dabeb7a15e0e38feb2cadca3c1f740a61d2 (patch) | |
| tree | 9489ee4780c8d54342e84750241f875003fa1d24 /src/libcore | |
| parent | 5b465e309da475aaedcb742ef29094c82e970051 (diff) | |
| parent | 4e6aea1a10a50fcde27b74edbd99db69bfae724e (diff) | |
| download | rust-26e73dabeb7a15e0e38feb2cadca3c1f740a61d2.tar.gz rust-26e73dabeb7a15e0e38feb2cadca3c1f740a61d2.zip | |
Auto merge of #52711 - eddyb:unsized-manuallydrop, r=nikomatsakis
Change ManuallyDrop<T> to a lang item. This PR implements the approach @RalfJung proposes in https://internals.rust-lang.org/t/pre-rfc-unions-drop-types-and-manuallydrop/8025 (lang item `struct` instead of `union`). A followup PR can easily solve #47034 as well, by just adding a few `?Sized` to `libcore/mem.rs`. r? @nikomatsakis
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/manually_drop_stage0.rs | 195 | ||||
| -rw-r--r-- | src/libcore/mem.rs | 108 | ||||
| -rw-r--r-- | src/libcore/tests/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcore/tests/manually_drop.rs | 24 |
4 files changed, 236 insertions, 92 deletions
diff --git a/src/libcore/manually_drop_stage0.rs b/src/libcore/manually_drop_stage0.rs new file mode 100644 index 00000000000..8643219cb61 --- /dev/null +++ b/src/libcore/manually_drop_stage0.rs @@ -0,0 +1,195 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop<Peach>, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop<Banana>, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[stable(feature = "manually_drop", since = "1.20.0")] +#[allow(unions_with_drop_fields)] +#[derive(Copy)] +pub union ManuallyDrop<T>{ value: T } + +impl<T> ManuallyDrop<T> { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_manually_drop_new")] + #[inline] + pub const fn new(value: T) -> ManuallyDrop<T> { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub fn into_inner(slot: ManuallyDrop<T>) -> T { + unsafe { + slot.value + } + } + + /// Manually drops the contained value. + /// + /// # Safety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop<T>) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl<T> Deref for ManuallyDrop<T> { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl<T> DerefMut for ManuallyDrop<T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: Clone> Clone for ManuallyDrop<T> { + fn clone(&self) -> Self { + ManuallyDrop::new(self.deref().clone()) + } + + fn clone_from(&mut self, source: &Self) { + self.deref_mut().clone_from(source); + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: Default> Default for ManuallyDrop<T> { + fn default() -> Self { + ManuallyDrop::new(Default::default()) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: PartialEq> PartialEq for ManuallyDrop<T> { + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other) + } + + fn ne(&self, other: &Self) -> bool { + self.deref().ne(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: Eq> Eq for ManuallyDrop<T> {} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: PartialOrd> PartialOrd for ManuallyDrop<T> { + fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> { + self.deref().partial_cmp(other) + } + + fn lt(&self, other: &Self) -> bool { + self.deref().lt(other) + } + + fn le(&self, other: &Self) -> bool { + self.deref().le(other) + } + + fn gt(&self, other: &Self) -> bool { + self.deref().gt(other) + } + + fn ge(&self, other: &Self) -> bool { + self.deref().ge(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: Ord> Ord for ManuallyDrop<T> { + fn cmp(&self, other: &Self) -> ::cmp::Ordering { + self.deref().cmp(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl<T: ::hash::Hash> ::hash::Hash for ManuallyDrop<T> { + fn hash<H: ::hash::Hasher>(&self, state: &mut H) { + self.deref().hash(state); + } +} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index a0fe6e98806..1a54f03bb00 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -918,7 +918,6 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> { } } - /// A wrapper to inhibit compiler from automatically calling `T`’s destructor. /// /// This wrapper is 0-cost. @@ -954,11 +953,18 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> { /// } /// } /// ``` +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] -#[allow(unions_with_drop_fields)] -#[derive(Copy)] -pub union ManuallyDrop<T>{ value: T } +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ManuallyDrop<T> { + value: T, +} + +#[cfg(stage0)] +include!("manually_drop_stage0.rs"); +#[cfg(not(stage0))] impl<T> ManuallyDrop<T> { /// Wrap a value to be manually dropped. /// @@ -972,7 +978,7 @@ impl<T> ManuallyDrop<T> { #[rustc_const_unstable(feature = "const_manually_drop_new")] #[inline] pub const fn new(value: T) -> ManuallyDrop<T> { - ManuallyDrop { value: value } + ManuallyDrop { value } } /// Extract the value from the ManuallyDrop container. @@ -987,9 +993,7 @@ impl<T> ManuallyDrop<T> { #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] pub fn into_inner(slot: ManuallyDrop<T>) -> T { - unsafe { - slot.value - } + slot.value } /// Manually drops the contained value. @@ -1006,102 +1010,22 @@ impl<T> ManuallyDrop<T> { } } +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] impl<T> Deref for ManuallyDrop<T> { type Target = T; #[inline] fn deref(&self) -> &Self::Target { - unsafe { - &self.value - } + &self.value } } +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] impl<T> DerefMut for ManuallyDrop<T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - &mut self.value - } - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> { - fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { - unsafe { - fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() - } - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: Clone> Clone for ManuallyDrop<T> { - fn clone(&self) -> Self { - ManuallyDrop::new(self.deref().clone()) - } - - fn clone_from(&mut self, source: &Self) { - self.deref_mut().clone_from(source); - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: Default> Default for ManuallyDrop<T> { - fn default() -> Self { - ManuallyDrop::new(Default::default()) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: PartialEq> PartialEq for ManuallyDrop<T> { - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other) - } - - fn ne(&self, other: &Self) -> bool { - self.deref().ne(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: Eq> Eq for ManuallyDrop<T> {} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: PartialOrd> PartialOrd for ManuallyDrop<T> { - fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> { - self.deref().partial_cmp(other) - } - - fn lt(&self, other: &Self) -> bool { - self.deref().lt(other) - } - - fn le(&self, other: &Self) -> bool { - self.deref().le(other) - } - - fn gt(&self, other: &Self) -> bool { - self.deref().gt(other) - } - - fn ge(&self, other: &Self) -> bool { - self.deref().ge(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: Ord> Ord for ManuallyDrop<T> { - fn cmp(&self, other: &Self) -> ::cmp::Ordering { - self.deref().cmp(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl<T: ::hash::Hash> ::hash::Hash for ManuallyDrop<T> { - fn hash<H: ::hash::Hasher>(&self, state: &mut H) { - self.deref().hash(state); + &mut self.value } } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index ca7db6e4639..6fcfaae4535 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -62,6 +62,7 @@ mod fmt; mod hash; mod intrinsics; mod iter; +mod manually_drop; mod mem; mod nonzero; mod num; diff --git a/src/libcore/tests/manually_drop.rs b/src/libcore/tests/manually_drop.rs new file mode 100644 index 00000000000..96bc9247da6 --- /dev/null +++ b/src/libcore/tests/manually_drop.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::mem::ManuallyDrop; + +#[test] +fn smoke() { + struct TypeWithDrop; + impl Drop for TypeWithDrop { + fn drop(&mut self) { + unreachable!("Should not get dropped"); + } + } + + let x = ManuallyDrop::new(TypeWithDrop); + drop(x); +} |
