From 38713126dd8502e283aa8ec7c6b678a4c43f8c3b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 19:11:51 +0200 Subject: [PATCH] Move away from the ad-hoc NoDrop unions --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 12 ++------ src/libcore/slice/sort.rs | 30 ++++++++---------- src/librustc_data_structures/array_vec.rs | 37 +++++------------------ src/librustc_data_structures/lib.rs | 1 + 5 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f6..b474bd5d91af1 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -44,6 +44,7 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(nonzero)] #![feature(pattern)] #![feature(placement_in)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd9..3069adb12e92c 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1558,7 +1558,7 @@ fn insert_head(v: &mut [T], is_less: &mut F) // performance than with the 2nd method. // // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let mut tmp = NoDrop { value: ptr::read(&v[0]) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); // Intermediate state of the insertion process is always tracked by `hole`, which // serves two purposes: @@ -1571,13 +1571,13 @@ fn insert_head(v: &mut [T], is_less: &mut F) // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it // initially held exactly once. let mut hole = InsertionHole { - src: &mut tmp.value, + src: &mut *tmp, dest: &mut v[1], }; ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); for i in 2..v.len() { - if !is_less(&v[i], &tmp.value) { + if !is_less(&v[i], &*tmp) { break; } ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); @@ -1587,12 +1587,6 @@ fn insert_head(v: &mut [T], is_less: &mut F) } } - // Holds a value, but never drops it. - #[allow(unions_with_drop_fields)] - union NoDrop { - value: T - } - // When dropped, copies from `src` into `dest`. struct InsertionHole { src: *mut T, diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 7065fdb79fc40..6f9f2915dfe10 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -20,12 +20,6 @@ use cmp; use mem; use ptr; -/// Holds a value, but never drops it. -#[allow(unions_with_drop_fields)] -union NoDrop { - value: T -} - /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { src: *mut T, @@ -49,15 +43,15 @@ fn shift_head(v: &mut [T], is_less: &mut F) // Read the first element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(1), }; ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(v.get_unchecked(i), &tmp.value) { + if !is_less(v.get_unchecked(i), &*tmp) { break; } @@ -81,15 +75,15 @@ fn shift_tail(v: &mut [T], is_less: &mut F) // Read the last element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(len - 2), }; ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); for i in (0..len-2).rev() { - if !is_less(&tmp.value, v.get_unchecked(i)) { + if !is_less(&*tmp, v.get_unchecked(i)) { break; } @@ -403,12 +397,12 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Find the first pair of out-of-order elements. let mut l = 0; @@ -452,12 +446,12 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Now partition the slice. let mut l = 0; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 29fbcb70756ba..adb2219722602 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -20,10 +20,11 @@ use std::fmt; use std::mem; use std::collections::range::RangeArgument; use std::collections::Bound::{Excluded, Included, Unbounded}; +use std::mem::ManuallyDrop; pub unsafe trait Array { type Element; - type PartialStorage: Default + Unsize<[ManuallyDrop]>; + type PartialStorage: Unsize<[ManuallyDrop]>; const LEN: usize; } @@ -66,7 +67,7 @@ impl ArrayVec { pub fn new() -> Self { ArrayVec { count: 0, - values: Default::default(), + values: unsafe { ::std::mem::uninitialized() }, } } @@ -81,7 +82,7 @@ impl ArrayVec { /// Panics when the stack vector is full. pub fn push(&mut self, el: A::Element) { let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop { value: el }; + arr[self.count] = ManuallyDrop::new(el); self.count += 1; } @@ -90,8 +91,8 @@ impl ArrayVec { let arr = &mut self.values as &mut [ManuallyDrop<_>]; self.count -= 1; unsafe { - let value = ptr::read(&arr[self.count]); - Some(value.value) + let value = ptr::read(&*arr[self.count]); + Some(value) } } else { None @@ -210,7 +211,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option { let arr = &self.store as &[ManuallyDrop<_>]; unsafe { - self.indices.next().map(|i| ptr::read(&arr[i]).value) + self.indices.next().map(|i| ptr::read(&*arr[i])) } } @@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value }) + self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) } fn size_hint(&self) -> (usize, Option) { @@ -295,25 +296,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { self.iter_mut() } } - -// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. -#[allow(unions_with_drop_fields)] -pub union ManuallyDrop { - value: T, - #[allow(dead_code)] - empty: (), -} - -impl ManuallyDrop { - fn new() -> ManuallyDrop { - ManuallyDrop { - empty: () - } - } -} - -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new() - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index c1735b4a4ec9a..72c533a74618b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -39,6 +39,7 @@ #![feature(conservative_impl_trait)] #![feature(discriminant_value)] #![feature(specialization)] +#![feature(manually_drop)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))]