From 591eeff22af299043637e75bb5735c3c65e0c7fe Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 21 Jul 2018 21:27:49 +0300 Subject: [PATCH 1/4] Change ManuallyDrop from an union to a struct and make it a lang item. --- src/libcore/manually_drop_stage0.rs | 195 +++++++++++++++++++ src/libcore/mem.rs | 108 ++-------- src/librustc/middle/lang_items.rs | 2 + src/librustc/traits/query/dropck_outlives.rs | 5 +- src/librustc/ty/util.rs | 6 +- src/librustc_mir/util/elaborate_drops.rs | 4 +- 6 files changed, 225 insertions(+), 95 deletions(-) create mode 100644 src/libcore/manually_drop_stage0.rs diff --git a/src/libcore/manually_drop_stage0.rs b/src/libcore/manually_drop_stage0.rs new file mode 100644 index 0000000000000..8643219cb6115 --- /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 or the MIT license +// , 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, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// 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{ value: T } + +impl ManuallyDrop { + /// 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 { + 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 { + 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) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl Deref for ManuallyDrop { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl DerefMut for ManuallyDrop { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl ::fmt::Debug for ManuallyDrop { + 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 Clone for ManuallyDrop { + 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 Default for ManuallyDrop { + fn default() -> Self { + ManuallyDrop::new(Default::default()) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl PartialEq for ManuallyDrop { + 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 Eq for ManuallyDrop {} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl PartialOrd for ManuallyDrop { + 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 Ord for ManuallyDrop { + fn cmp(&self, other: &Self) -> ::cmp::Ordering { + self.deref().cmp(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl ::hash::Hash for ManuallyDrop { + fn hash(&self, state: &mut H) { + self.deref().hash(state); + } +} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index a0fe6e9880606..1a54f03bb0067 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -918,7 +918,6 @@ pub fn discriminant(v: &T) -> Discriminant { } } - /// A wrapper to inhibit compiler from automatically calling `T`’s destructor. /// /// This wrapper is 0-cost. @@ -954,11 +953,18 @@ pub fn discriminant(v: &T) -> Discriminant { /// } /// } /// ``` +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] -#[allow(unions_with_drop_fields)] -#[derive(Copy)] -pub union ManuallyDrop{ value: T } +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ManuallyDrop { + value: T, +} + +#[cfg(stage0)] +include!("manually_drop_stage0.rs"); +#[cfg(not(stage0))] impl ManuallyDrop { /// Wrap a value to be manually dropped. /// @@ -972,7 +978,7 @@ impl ManuallyDrop { #[rustc_const_unstable(feature = "const_manually_drop_new")] #[inline] pub const fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value: value } + ManuallyDrop { value } } /// Extract the value from the ManuallyDrop container. @@ -987,9 +993,7 @@ impl ManuallyDrop { #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] pub fn into_inner(slot: ManuallyDrop) -> T { - unsafe { - slot.value - } + slot.value } /// Manually drops the contained value. @@ -1006,102 +1010,22 @@ impl ManuallyDrop { } } +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] impl Deref for ManuallyDrop { 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 DerefMut for ManuallyDrop { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - &mut self.value - } - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl ::fmt::Debug for ManuallyDrop { - 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 Clone for ManuallyDrop { - 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 Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new(Default::default()) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl PartialEq for ManuallyDrop { - 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 Eq for ManuallyDrop {} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl PartialOrd for ManuallyDrop { - 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 Ord for ManuallyDrop { - fn cmp(&self, other: &Self) -> ::cmp::Ordering { - self.deref().cmp(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl ::hash::Hash for ManuallyDrop { - fn hash(&self, state: &mut H) { - self.deref().hash(state); + &mut self.value } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6c1ef851cbeca..cf94a0fb4b4ba 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -324,6 +324,8 @@ language_item_table! { NonZeroItem, "non_zero", non_zero; + ManuallyDropItem, "manually_drop", manually_drop; + DebugTraitLangItem, "debug_trait", debug_trait; // A lang item for each of the 128-bit operators we can optionally lower. diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 73a9ff4e483b2..a48d24bb97a9c 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -243,7 +243,10 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> ty::TyAdt(def, _) => { if def.is_union() { - // Unions never run have a dtor. + // Unions never have a dtor. + true + } else if Some(def.did) == tcx.lang_items().manually_drop() { + // `ManuallyDrop` never has a dtor. true } else { // Other types might. Moreover, PhantomData doesn't diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d5425aff6ba69..95caa0c185be1 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -932,6 +932,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Foreign types can never have destructors ty::TyForeign(..) => false, + // `ManuallyDrop` doesn't have a destructor regardless of field types. + ty::TyAdt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, + // Issue #22536: We first query type_moves_by_default. It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no @@ -967,7 +970,8 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyTuple(ref tys) => tys.iter().cloned().any(needs_drop), - // unions don't have destructors regardless of the child types + // unions don't have destructors because of the child types, + // only if they manually implement `Drop` (handled above). ty::TyAdt(def, _) if def.is_union() => false, ty::TyAdt(def, substs) => diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 689eb62042bcc..bbffeec631abd 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -369,7 +369,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }); } - let contents_drop = if adt.is_union() { + let skip_contents = + adt.is_union() || Some(adt.did) == self.tcx().lang_items().manually_drop(); + let contents_drop = if skip_contents { (self.succ, self.unwind) } else { self.open_drop_for_adt_contents(adt, substs) From 5feedbd9f835efeb753ff74e699268c6edbef679 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Jul 2018 12:12:55 +0200 Subject: [PATCH 2/4] add smoke test for ManuallyDrop --- src/libcore/tests/lib.rs | 1 + src/libcore/tests/manually_drop.rs | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/libcore/tests/manually_drop.rs diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index ca7db6e4639a5..6fcfaae453500 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 0000000000000..96bc9247da6e7 --- /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 or the MIT license +// , 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); +} From c9eef354290fdb04b107ab3a1832d9c10d94c712 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Jul 2018 13:38:20 +0200 Subject: [PATCH 3/4] update reference to fix links --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 0f63519ea10c0..0644ecc4c9106 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0f63519ea10c028f48b2dbf7d0a2454203b68b0b +Subproject commit 0644ecc4c91065aae808b19883b93893ff8edfb5 From 4e6aea1a10a50fcde27b74edbd99db69bfae724e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Jul 2018 18:40:47 +0200 Subject: [PATCH 4/4] uodate reference again to hopefully fix all link issues --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 0644ecc4c9106..219e261ddb833 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0644ecc4c91065aae808b19883b93893ff8edfb5 +Subproject commit 219e261ddb833a5683627b0a9be87a0f4486abb9