Skip to content

Commit 4fa2226

Browse files
authored
Rollup merge of rust-lang#40559 - nagisa:manually-drop, r=alexcrichton
Implement Manually Drop As the RFC has been from approx a week in FCP without any major comments, I’m taking the opportunity to submit the PR early.
2 parents c58c928 + c337b99 commit 4fa2226

File tree

12 files changed

+147
-64
lines changed

12 files changed

+147
-64
lines changed

src/doc/unstable-book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
- [loop_break_value](loop-break-value.md)
115115
- [macro_reexport](macro-reexport.md)
116116
- [main](main.md)
117+
- [manually_drop](manually-drop.md)
117118
- [map_entry_recover_keys](map-entry-recover-keys.md)
118119
- [mpsc_select](mpsc-select.md)
119120
- [n16](n16.md)

src/doc/unstable-book/src/manually-drop.md

Whitespace-only changes.

src/libcollections/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#![feature(heap_api)]
4545
#![feature(inclusive_range)]
4646
#![feature(lang_items)]
47+
#![feature(manually_drop)]
4748
#![feature(nonzero)]
4849
#![feature(pattern)]
4950
#![feature(placement_in)]

src/libcollections/slice.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
15581558
// performance than with the 2nd method.
15591559
//
15601560
// All methods were benchmarked, and the 3rd showed best results. So we chose that one.
1561-
let mut tmp = NoDrop { value: ptr::read(&v[0]) };
1561+
let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
15621562

15631563
// Intermediate state of the insertion process is always tracked by `hole`, which
15641564
// serves two purposes:
@@ -1571,13 +1571,13 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
15711571
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
15721572
// initially held exactly once.
15731573
let mut hole = InsertionHole {
1574-
src: &mut tmp.value,
1574+
src: &mut *tmp,
15751575
dest: &mut v[1],
15761576
};
15771577
ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
15781578

15791579
for i in 2..v.len() {
1580-
if !is_less(&v[i], &tmp.value) {
1580+
if !is_less(&v[i], &*tmp) {
15811581
break;
15821582
}
15831583
ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
@@ -1587,12 +1587,6 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
15871587
}
15881588
}
15891589

1590-
// Holds a value, but never drops it.
1591-
#[allow(unions_with_drop_fields)]
1592-
union NoDrop<T> {
1593-
value: T
1594-
}
1595-
15961590
// When dropped, copies from `src` into `dest`.
15971591
struct InsertionHole<T> {
15981592
src: *mut T,

src/libcore/intrinsics.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,6 @@ extern "rust-intrinsic" {
691691
/// initialize memory previous set to the result of `uninit`.
692692
pub fn uninit<T>() -> T;
693693

694-
/// Moves a value out of scope without running drop glue.
695-
pub fn forget<T>(_: T) -> ();
696-
697694
/// Reinterprets the bits of a value of one type as another type.
698695
///
699696
/// Both types must have the same size. Neither the original, nor the result,

src/libcore/mem.rs

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub use intrinsics::transmute;
171171
#[inline]
172172
#[stable(feature = "rust1", since = "1.0.0")]
173173
pub fn forget<T>(t: T) {
174-
unsafe { intrinsics::forget(t) }
174+
ManuallyDrop::new(t);
175175
}
176176

177177
/// Returns the size of a type in bytes.
@@ -736,3 +736,121 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
736736
}
737737
}
738738

739+
740+
/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
741+
///
742+
/// This wrapper is 0-cost.
743+
///
744+
/// # Examples
745+
///
746+
/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
747+
/// the type:
748+
///
749+
/// ```rust
750+
/// # #![feature(manually_drop)]
751+
/// use std::mem::ManuallyDrop;
752+
/// struct Peach;
753+
/// struct Banana;
754+
/// struct Melon;
755+
/// struct FruitBox {
756+
/// // Immediately clear there’s something non-trivial going on with these fields.
757+
/// peach: ManuallyDrop<Peach>,
758+
/// melon: Melon, // Field that’s independent of the other two.
759+
/// banana: ManuallyDrop<Banana>,
760+
/// }
761+
///
762+
/// impl Drop for FruitBox {
763+
/// fn drop(&mut self) {
764+
/// unsafe {
765+
/// // Explicit ordering in which field destructors are run specified in the intuitive
766+
/// // location – the destructor of the structure containing the fields.
767+
/// // Moreover, one can now reorder fields within the struct however much they want.
768+
/// ManuallyDrop::drop(&mut self.peach);
769+
/// ManuallyDrop::drop(&mut self.banana);
770+
/// }
771+
/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
772+
/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
773+
/// }
774+
/// }
775+
/// ```
776+
#[unstable(feature = "manually_drop", issue = "40673")]
777+
#[allow(unions_with_drop_fields)]
778+
pub union ManuallyDrop<T>{ value: T }
779+
780+
impl<T> ManuallyDrop<T> {
781+
/// Wrap a value to be manually dropped.
782+
///
783+
/// # Examples
784+
///
785+
/// ```rust
786+
/// # #![feature(manually_drop)]
787+
/// use std::mem::ManuallyDrop;
788+
/// ManuallyDrop::new(Box::new(()));
789+
/// ```
790+
#[unstable(feature = "manually_drop", issue = "40673")]
791+
#[inline]
792+
pub fn new(value: T) -> ManuallyDrop<T> {
793+
ManuallyDrop { value: value }
794+
}
795+
796+
/// Extract the value from the ManuallyDrop container.
797+
///
798+
/// # Examples
799+
///
800+
/// ```rust
801+
/// # #![feature(manually_drop)]
802+
/// use std::mem::ManuallyDrop;
803+
/// let x = ManuallyDrop::new(Box::new(()));
804+
/// let _: Box<()> = ManuallyDrop::into_inner(x);
805+
/// ```
806+
#[unstable(feature = "manually_drop", issue = "40673")]
807+
#[inline]
808+
pub fn into_inner(slot: ManuallyDrop<T>) -> T {
809+
unsafe {
810+
slot.value
811+
}
812+
}
813+
814+
/// Manually drops the contained value.
815+
///
816+
/// # Unsafety
817+
///
818+
/// This function runs the destructor of the contained value and thus the wrapped value
819+
/// now represents uninitialized data. It is up to the user of this method to ensure the
820+
/// uninitialized data is not actually used.
821+
#[unstable(feature = "manually_drop", issue = "40673")]
822+
#[inline]
823+
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
824+
ptr::drop_in_place(&mut slot.value)
825+
}
826+
}
827+
828+
#[unstable(feature = "manually_drop", issue = "40673")]
829+
impl<T> ::ops::Deref for ManuallyDrop<T> {
830+
type Target = T;
831+
#[inline]
832+
fn deref(&self) -> &Self::Target {
833+
unsafe {
834+
&self.value
835+
}
836+
}
837+
}
838+
839+
#[unstable(feature = "manually_drop", issue = "40673")]
840+
impl<T> ::ops::DerefMut for ManuallyDrop<T> {
841+
#[inline]
842+
fn deref_mut(&mut self) -> &mut Self::Target {
843+
unsafe {
844+
&mut self.value
845+
}
846+
}
847+
}
848+
849+
#[unstable(feature = "manually_drop", issue = "40673")]
850+
impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
851+
fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
852+
unsafe {
853+
fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
854+
}
855+
}
856+
}

src/libcore/slice/sort.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ use cmp;
2020
use mem;
2121
use ptr;
2222

23-
/// Holds a value, but never drops it.
24-
#[allow(unions_with_drop_fields)]
25-
union NoDrop<T> {
26-
value: T
27-
}
28-
2923
/// When dropped, copies from `src` into `dest`.
3024
struct CopyOnDrop<T> {
3125
src: *mut T,
@@ -49,15 +43,15 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
4943
// Read the first element into a stack-allocated variable. If a following comparison
5044
// operation panics, `hole` will get dropped and automatically write the element back
5145
// into the slice.
52-
let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) };
46+
let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
5347
let mut hole = CopyOnDrop {
54-
src: &mut tmp.value,
48+
src: &mut *tmp,
5549
dest: v.get_unchecked_mut(1),
5650
};
5751
ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1);
5852

5953
for i in 2..len {
60-
if !is_less(v.get_unchecked(i), &tmp.value) {
54+
if !is_less(v.get_unchecked(i), &*tmp) {
6155
break;
6256
}
6357

@@ -81,15 +75,15 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
8175
// Read the last element into a stack-allocated variable. If a following comparison
8276
// operation panics, `hole` will get dropped and automatically write the element back
8377
// into the slice.
84-
let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) };
78+
let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
8579
let mut hole = CopyOnDrop {
86-
src: &mut tmp.value,
80+
src: &mut *tmp,
8781
dest: v.get_unchecked_mut(len - 2),
8882
};
8983
ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1);
9084

9185
for i in (0..len-2).rev() {
92-
if !is_less(&tmp.value, v.get_unchecked(i)) {
86+
if !is_less(&*tmp, v.get_unchecked(i)) {
9387
break;
9488
}
9589

@@ -403,12 +397,12 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
403397

404398
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
405399
// operation panics, the pivot will be automatically written back into the slice.
406-
let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
400+
let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
407401
let _pivot_guard = CopyOnDrop {
408-
src: unsafe { &mut tmp.value },
402+
src: &mut *tmp,
409403
dest: pivot,
410404
};
411-
let pivot = unsafe { &tmp.value };
405+
let pivot = &*tmp;
412406

413407
// Find the first pair of out-of-order elements.
414408
let mut l = 0;
@@ -452,12 +446,12 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
452446

453447
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
454448
// operation panics, the pivot will be automatically written back into the slice.
455-
let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } };
449+
let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
456450
let _pivot_guard = CopyOnDrop {
457-
src: unsafe { &mut tmp.value },
451+
src: &mut *tmp,
458452
dest: pivot,
459453
};
460-
let pivot = unsafe { &tmp.value };
454+
let pivot = &*tmp;
461455

462456
// Now partition the slice.
463457
let mut l = 0;

src/librustc_data_structures/array_vec.rs

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ use std::fmt;
2020
use std::mem;
2121
use std::collections::range::RangeArgument;
2222
use std::collections::Bound::{Excluded, Included, Unbounded};
23+
use std::mem::ManuallyDrop;
2324

2425
pub unsafe trait Array {
2526
type Element;
26-
type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
27+
type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
2728
const LEN: usize;
2829
}
2930

@@ -66,7 +67,7 @@ impl<A: Array> ArrayVec<A> {
6667
pub fn new() -> Self {
6768
ArrayVec {
6869
count: 0,
69-
values: Default::default(),
70+
values: unsafe { ::std::mem::uninitialized() },
7071
}
7172
}
7273

@@ -81,7 +82,7 @@ impl<A: Array> ArrayVec<A> {
8182
/// Panics when the stack vector is full.
8283
pub fn push(&mut self, el: A::Element) {
8384
let arr = &mut self.values as &mut [ManuallyDrop<_>];
84-
arr[self.count] = ManuallyDrop { value: el };
85+
arr[self.count] = ManuallyDrop::new(el);
8586
self.count += 1;
8687
}
8788

@@ -90,8 +91,8 @@ impl<A: Array> ArrayVec<A> {
9091
let arr = &mut self.values as &mut [ManuallyDrop<_>];
9192
self.count -= 1;
9293
unsafe {
93-
let value = ptr::read(&arr[self.count]);
94-
Some(value.value)
94+
let value = ptr::read(&*arr[self.count]);
95+
Some(value)
9596
}
9697
} else {
9798
None
@@ -210,7 +211,7 @@ impl<A: Array> Iterator for Iter<A> {
210211
fn next(&mut self) -> Option<A::Element> {
211212
let arr = &self.store as &[ManuallyDrop<_>];
212213
unsafe {
213-
self.indices.next().map(|i| ptr::read(&arr[i]).value)
214+
self.indices.next().map(|i| ptr::read(&*arr[i]))
214215
}
215216
}
216217

@@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> {
233234

234235
#[inline]
235236
fn next(&mut self) -> Option<A::Element> {
236-
self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
237+
self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
237238
}
238239

239240
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -295,25 +296,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec<A> {
295296
self.iter_mut()
296297
}
297298
}
298-
299-
// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
300-
#[allow(unions_with_drop_fields)]
301-
pub union ManuallyDrop<T> {
302-
value: T,
303-
#[allow(dead_code)]
304-
empty: (),
305-
}
306-
307-
impl<T> ManuallyDrop<T> {
308-
fn new() -> ManuallyDrop<T> {
309-
ManuallyDrop {
310-
empty: ()
311-
}
312-
}
313-
}
314-
315-
impl<T> Default for ManuallyDrop<T> {
316-
fn default() -> Self {
317-
ManuallyDrop::new()
318-
}
319-
}

src/librustc_data_structures/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#![feature(conservative_impl_trait)]
4040
#![feature(discriminant_value)]
4141
#![feature(specialization)]
42+
#![feature(manually_drop)]
4243

4344
#![cfg_attr(unix, feature(libc))]
4445
#![cfg_attr(test, feature(test))]

src/librustc_trans/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
188188
C_nil(ccx)
189189
}
190190
// Effectively no-ops
191-
"uninit" | "forget" => {
191+
"uninit" => {
192192
C_nil(ccx)
193193
}
194194
"needs_drop" => {

src/librustc_typeck/check/intrinsic.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
124124
"rustc_peek" => (1, vec![param(0)], param(0)),
125125
"init" => (1, Vec::new(), param(0)),
126126
"uninit" => (1, Vec::new(), param(0)),
127-
"forget" => (1, vec![ param(0) ], tcx.mk_nil()),
128127
"transmute" => (2, vec![ param(0) ], param(1)),
129128
"move_val_init" => {
130129
(1,

0 commit comments

Comments
 (0)