From e9af03a22279b62ded4c7ea897d5ac3a9b54728c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 29 Jun 2017 01:00:00 +0200 Subject: [PATCH 01/13] =?UTF-8?q?Add=20`new=5Fchecked(=E2=80=A6)=20->=20Op?= =?UTF-8?q?tion`=20to=20NonZero,=20Unique,=20and=20Shared.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libcore/nonzero.rs | 70 ++++++++++++++++++++++++++++++++---------- src/libcore/ptr.rs | 14 +++++++-- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 977438051d93b..0564d73dd6d08 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -16,22 +16,48 @@ use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct -pub unsafe trait Zeroable {} - -unsafe impl Zeroable for *const T {} -unsafe impl Zeroable for *mut T {} -unsafe impl Zeroable for isize {} -unsafe impl Zeroable for usize {} -unsafe impl Zeroable for i8 {} -unsafe impl Zeroable for u8 {} -unsafe impl Zeroable for i16 {} -unsafe impl Zeroable for u16 {} -unsafe impl Zeroable for i32 {} -unsafe impl Zeroable for u32 {} -unsafe impl Zeroable for i64 {} -unsafe impl Zeroable for u64 {} -unsafe impl Zeroable for i128 {} -unsafe impl Zeroable for u128 {} +pub unsafe trait Zeroable { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} + +macro_rules! impl_zeroable_for_pointer_types { + ( $( $Ptr: ty )+ ) => { + $( + /// For fat pointers to be considered "zero", only the "data" part needs to be null. + unsafe impl Zeroable for $Ptr { + #[inline] + fn is_zero(&self) -> bool { + // Cast because `is_null` is only available on thin pointers + (*self as *mut u8).is_null() + } + } + )+ + } +} + +macro_rules! impl_zeroable_for_integer_types { + ( $( $Int: ty )+ ) => { + $( + unsafe impl Zeroable for $Int { + #[inline] + fn is_zero(&self) -> bool { + *self == 0 + } + } + )+ + } +} + +impl_zeroable_for_pointer_types! { + *const T + *mut T +} + +impl_zeroable_for_integer_types! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 +} /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. @@ -43,10 +69,20 @@ impl NonZero { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline] - pub const unsafe fn new(inner: T) -> NonZero { + pub const unsafe fn new(inner: T) -> Self { NonZero(inner) } + /// Creates an instance of NonZero with the provided value. + #[inline] + pub fn new_checked(inner: T) -> Option { + if inner.is_zero() { + None + } else { + Some(NonZero(inner)) + } + } + /// Gets the inner value. pub fn get(self) -> T { self.0 diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b19e07b8578c0..e83ca63834ab5 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1110,10 +1110,15 @@ impl Unique { /// # Safety /// /// `ptr` must be non-null. - pub const unsafe fn new(ptr: *mut T) -> Unique { + pub const unsafe fn new(ptr: *mut T) -> Self { Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } + /// Creates a new `Unique` if `ptr` is non-null. + pub fn new_checked(ptr: *mut T) -> Option { + NonZero::new_checked(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) + } + /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T @@ -1224,10 +1229,15 @@ impl Shared { /// # Safety /// /// `ptr` must be non-null. - pub unsafe fn new(ptr: *mut T) -> Self { + pub const unsafe fn new(ptr: *mut T) -> Self { Shared { pointer: NonZero::new(ptr), _marker: PhantomData } } + /// Creates a new `Shared` if `ptr` is non-null. + pub fn new_checked(ptr: *mut T) -> Option { + NonZero::new_checked(ptr as *const T).map(|nz| Shared { pointer: nz, _marker: PhantomData }) + } + /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T From 0a08ad0443631ca86e61526916fb4ee61fe1abce Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 29 Jun 2017 01:03:35 +0200 Subject: [PATCH 02/13] Rename {NonZero,Shared,Unique}::new to new_unchecked --- src/doc/nomicon | 2 +- src/liballoc/allocator.rs | 6 +++--- src/liballoc/arc.rs | 6 +++--- src/liballoc/btree/node.rs | 10 +++++----- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/raw_vec.rs | 6 +++--- src/liballoc/rc.rs | 10 +++++----- src/liballoc/vec.rs | 4 ++-- src/liballoc/vec_deque.rs | 2 +- src/libcore/nonzero.rs | 2 +- src/libcore/ptr.rs | 12 ++++++------ src/libcore/tests/nonzero.rs | 6 +++--- src/libcore/tests/ptr.rs | 2 +- src/librustc/ty/subst.rs | 4 ++-- src/librustc_data_structures/array_vec.rs | 2 +- .../obligation_forest/node_index.rs | 2 +- src/librustc_mir/dataflow/move_paths/mod.rs | 2 +- src/libstd/collections/hash/table.rs | 6 +++--- src/test/run-pass/issue-23433.rs | 2 +- src/test/ui/print_type_sizes/nullable.rs | 2 +- 20 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/doc/nomicon b/src/doc/nomicon index 81134a4dff811..f8fd6710399a1 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 81134a4dff811403b3b2f349b0c59a819f0fe0c1 +Subproject commit f8fd6710399a1a557155cb5be4922fe6a6f694c0 diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index ca5388b470147..efc59d2cbc86f 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -892,7 +892,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p| Unique::new(p as *mut T)) } + unsafe { self.alloc(k).map(|p| Unique::new_unchecked(p as *mut T)) } } else { Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) } @@ -963,7 +963,7 @@ pub unsafe trait Alloc { unsafe { self.alloc(layout.clone()) .map(|p| { - Unique::new(p as *mut T) + Unique::new_unchecked(p as *mut T) }) } } @@ -1012,7 +1012,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p|Unique::new(p as *mut T)) + .map(|p|Unique::new_unchecked(p as *mut T)) } _ => { Err(AllocErr::invalid_input("invalid layout for realloc_array")) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 85c7efb7ac50c..cc792c9f83f79 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -280,7 +280,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data: data, }; - Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } } + Arc { ptr: unsafe { Shared::new_unchecked(Box::into_raw(x)) } } } /// Returns the contained value, if the `Arc` has exactly one strong reference. @@ -382,7 +382,7 @@ impl Arc { // `data` field from the pointer. let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner, data)); Arc { - ptr: Shared::new(ptr as *mut u8 as *mut _), + ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _), } } } @@ -842,7 +842,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::new(Box::into_raw(box ArcInner { + ptr: Shared::new_unchecked(Box::into_raw(box ArcInner { strong: atomic::AtomicUsize::new(0), weak: atomic::AtomicUsize::new(1), data: uninitialized(), diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 0eaff6f2192c8..0a752702b1213 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -141,23 +141,23 @@ struct BoxedNode { impl BoxedNode { fn from_leaf(node: Box>) -> Self { unsafe { - BoxedNode { ptr: Unique::new(Box::into_raw(node)) } + BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node)) } } } fn from_internal(node: Box>) -> Self { unsafe { - BoxedNode { ptr: Unique::new(Box::into_raw(node) as *mut LeafNode) } + BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node) as *mut LeafNode) } } } unsafe fn from_ptr(ptr: NonZero<*const LeafNode>) -> Self { - BoxedNode { ptr: Unique::new(ptr.get() as *mut LeafNode) } + BoxedNode { ptr: Unique::new_unchecked(ptr.get() as *mut LeafNode) } } fn as_ptr(&self) -> NonZero<*const LeafNode> { unsafe { - NonZero::new(self.ptr.as_ptr()) + NonZero::new_unchecked(self.ptr.as_ptr()) } } } @@ -391,7 +391,7 @@ impl NodeRef { node: NodeRef { height: self.height + 1, node: unsafe { - NonZero::new(self.as_leaf().parent as *mut LeafNode) + NonZero::new_unchecked(self.as_leaf().parent as *mut LeafNode) }, root: self.root, _marker: PhantomData diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index e8973b7d28537..08d6fac3849ba 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -157,7 +157,7 @@ impl LinkedList { unsafe { node.next = self.head; node.prev = None; - let node = Some(Shared::new(Box::into_raw(node))); + let node = Some(Shared::new_unchecked(Box::into_raw(node))); match self.head { None => self.tail = node, @@ -192,7 +192,7 @@ impl LinkedList { unsafe { node.next = None; node.prev = self.tail; - let node = Some(Shared::new(Box::into_raw(node))); + let node = Some(Shared::new_unchecked(Box::into_raw(node))); match self.tail { None => self.head = node, @@ -921,7 +921,7 @@ impl<'a, T> IterMut<'a, T> { Some(prev) => prev, }; - let node = Some(Shared::new(Box::into_raw(box Node { + let node = Some(Shared::new_unchecked(Box::into_raw(box Node { next: Some(head), prev: Some(prev), element: element, diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d1aab4c70be4a..ca55831220da6 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -104,7 +104,7 @@ impl RawVec { }; RawVec { - ptr: Unique::new(ptr as *mut _), + ptr: Unique::new_unchecked(ptr as *mut _), cap: cap, a: a, } @@ -159,7 +159,7 @@ impl RawVec { /// If the ptr and capacity come from a RawVec created via `a`, then this is guaranteed. pub unsafe fn from_raw_parts_in(ptr: *mut T, cap: usize, a: A) -> Self { RawVec { - ptr: Unique::new(ptr), + ptr: Unique::new_unchecked(ptr), cap: cap, a: a, } @@ -176,7 +176,7 @@ impl RawVec { /// If the ptr and capacity come from a RawVec, then this is guaranteed. pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self { RawVec { - ptr: Unique::new(ptr), + ptr: Unique::new_unchecked(ptr), cap: cap, a: Heap, } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 9e72238fbd463..6ff6b6b037256 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -309,7 +309,7 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - ptr: Shared::new(Box::into_raw(box RcBox { + ptr: Shared::new_unchecked(Box::into_raw(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value: value, @@ -418,7 +418,7 @@ impl Rc { let ptr = (ptr as *const u8).offset(-offset_of!(RcBox, value)); Rc { - ptr: Shared::new(ptr as *mut u8 as *mut _) + ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _) } } } @@ -443,7 +443,7 @@ impl Rc { // Combine the allocation address and the string length into a fat pointer to `RcBox`. let rcbox_ptr: *mut RcBox = mem::transmute([ptr as usize, value.len()]); assert!(aligned_len * size_of::() == size_of_val(&*rcbox_ptr)); - Rc { ptr: Shared::new(rcbox_ptr) } + Rc { ptr: Shared::new_unchecked(rcbox_ptr) } } } } @@ -476,7 +476,7 @@ impl Rc<[T]> { // Free the original allocation without freeing its (moved) contents. box_free(Box::into_raw(value)); - Rc { ptr: Shared::new(ptr as *mut _) } + Rc { ptr: Shared::new_unchecked(ptr as *mut _) } } } } @@ -1016,7 +1016,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::new(Box::into_raw(box RcBox { + ptr: Shared::new_unchecked(Box::into_raw(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: uninitialized(), diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 780a51aec3bab..bc1521c406967 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1126,7 +1126,7 @@ impl Vec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - vec: Shared::new(self as *mut _), + vec: Shared::new_unchecked(self as *mut _), } } } @@ -1727,7 +1727,7 @@ impl IntoIterator for Vec { let cap = self.buf.cap(); mem::forget(self); IntoIter { - buf: Shared::new(begin), + buf: Shared::new_unchecked(begin), cap: cap, ptr: begin, end: end, diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 18175a5d01bd2..a99b7bbe0539d 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -893,7 +893,7 @@ impl VecDeque { self.head = drain_tail; Drain { - deque: unsafe { Shared::new(self as *mut _) }, + deque: unsafe { Shared::new_unchecked(self as *mut _) }, after_tail: drain_head, after_head: head, iter: Iter { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 0564d73dd6d08..6acdcad876391 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -69,7 +69,7 @@ impl NonZero { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline] - pub const unsafe fn new(inner: T) -> Self { + pub const unsafe fn new_unchecked(inner: T) -> Self { NonZero(inner) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e83ca63834ab5..5ece63e23b11d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1098,7 +1098,7 @@ impl Unique { pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; - Unique::new(ptr) + Unique::new_unchecked(ptr) } } } @@ -1110,8 +1110,8 @@ impl Unique { /// # Safety /// /// `ptr` must be non-null. - pub const unsafe fn new(ptr: *mut T) -> Self { - Unique { pointer: NonZero::new(ptr), _marker: PhantomData } + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } } /// Creates a new `Unique` if `ptr` is non-null. @@ -1217,7 +1217,7 @@ impl Shared { pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; - Shared::new(ptr) + Shared::new_unchecked(ptr) } } } @@ -1229,8 +1229,8 @@ impl Shared { /// # Safety /// /// `ptr` must be non-null. - pub const unsafe fn new(ptr: *mut T) -> Self { - Shared { pointer: NonZero::new(ptr), _marker: PhantomData } + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + Shared { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } } /// Creates a new `Shared` if `ptr` is non-null. diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 588fffda35fca..a795dd575043d 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -16,7 +16,7 @@ use std::mem::size_of; #[test] fn test_create_nonzero_instance() { let _a = unsafe { - NonZero::new(21) + NonZero::new_unchecked(21) }; } @@ -28,14 +28,14 @@ fn test_size_nonzero_in_option() { #[test] fn test_match_on_nonzero_option() { let a = Some(unsafe { - NonZero::new(42) + NonZero::new_unchecked(42) }); match a { Some(val) => assert_eq!(val.get(), 42), None => panic!("unexpected None while matching on Some(NonZero(_))") } - match unsafe { Some(NonZero::new(43)) } { + match unsafe { Some(NonZero::new_unchecked(43)) } { Some(val) => assert_eq!(val.get(), 43), None => panic!("unexpected None while matching on Some(NonZero(_))") } diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index e28dc6a6881fd..c2d53840f8f57 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -167,7 +167,7 @@ fn test_set_memory() { #[test] fn test_unsized_unique() { let xs: &[i32] = &[1, 2, 3]; - let ptr = unsafe { Unique::new(xs as *const [i32] as *mut [i32]) }; + let ptr = unsafe { Unique::new_unchecked(xs as *const [i32] as *mut [i32]) }; let ys = unsafe { ptr.as_ref() }; let zs: &[i32] = &[1, 2, 3]; assert!(ys == zs); diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index f6112d4887d7d..e2881ac9b798e 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -47,7 +47,7 @@ impl<'tcx> From> for Kind<'tcx> { let ptr = ty as *const _ as usize; Kind { ptr: unsafe { - NonZero::new(ptr | TYPE_TAG) + NonZero::new_unchecked(ptr | TYPE_TAG) }, marker: PhantomData } @@ -62,7 +62,7 @@ impl<'tcx> From> for Kind<'tcx> { let ptr = r as *const _ as usize; Kind { ptr: unsafe { - NonZero::new(ptr | REGION_TAG) + NonZero::new_unchecked(ptr | REGION_TAG) }, marker: PhantomData } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 078bb801751d0..de028f6109046 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -146,7 +146,7 @@ impl ArrayVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - array_vec: Shared::new(self as *mut _), + array_vec: Shared::new_unchecked(self as *mut _), } } } diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index 023c56ca59be8..9fa6045146dcc 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -19,7 +19,7 @@ pub struct NodeIndex { impl NodeIndex { pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); - unsafe { NodeIndex { index: NonZero::new((value as u32) + 1) } } + unsafe { NodeIndex { index: NonZero::new_unchecked((value as u32) + 1) } } } pub fn get(self) -> usize { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index d7ed0938e886a..63c204fbdcda2 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -42,7 +42,7 @@ pub(crate) mod indexes { impl Idx for $Index { fn new(idx: usize) -> Self { - unsafe { $Index(NonZero::new(idx + 1)) } + unsafe { $Index(NonZero::new_unchecked(idx + 1)) } } fn index(self) -> usize { self.0.get() - 1 diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 06f4f7643ec83..f3aec589e7d27 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -44,7 +44,7 @@ impl TaggedHashUintPtr { #[inline] unsafe fn new(ptr: *mut HashUint) -> Self { debug_assert!(ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize); - TaggedHashUintPtr(Unique::new(ptr)) + TaggedHashUintPtr(Unique::new_unchecked(ptr)) } #[inline] @@ -56,7 +56,7 @@ impl TaggedHashUintPtr { } else { usize_ptr &= !1; } - self.0 = Unique::new(usize_ptr as *mut HashUint) + self.0 = Unique::new_unchecked(usize_ptr as *mut HashUint) } } @@ -877,7 +877,7 @@ impl RawTable { elems_left: elems_left, marker: marker::PhantomData, }, - table: unsafe { Shared::new(self) }, + table: unsafe { Shared::new_unchecked(self) }, marker: marker::PhantomData, } } diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 82f80586b9f94..6c4c425cb8e02 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -16,7 +16,7 @@ use std::ptr::Unique; fn main() { let mut a = [0u8; 5]; - let b: Option> = unsafe { Some(Unique::new(&mut a)) }; + let b: Option> = unsafe { Some(Unique::new_unchecked(&mut a)) }; match b { Some(_) => println!("Got `Some`"), None => panic!("Unexpected `None`"), diff --git a/src/test/ui/print_type_sizes/nullable.rs b/src/test/ui/print_type_sizes/nullable.rs index f7fdcac81daad..df5c53daf7e1e 100644 --- a/src/test/ui/print_type_sizes/nullable.rs +++ b/src/test/ui/print_type_sizes/nullable.rs @@ -57,7 +57,7 @@ pub struct NestedNonZero { impl Default for NestedNonZero { fn default() -> Self { unsafe { - NestedNonZero { pre: 0, val: NonZero::new(Default::default()), post: 0 } + NestedNonZero { pre: 0, val: NonZero::new_unchecked(Default::default()), post: 0 } } } } From ddaf9b24f035f11a5ce53b39352d3e76093b766e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 29 Jun 2017 01:06:20 +0200 Subject: [PATCH 03/13] Rename {NonZero,Shared,Unique}::new_checked to new --- src/libcore/nonzero.rs | 2 +- src/libcore/ptr.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 6acdcad876391..65ebb8c5ae376 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -75,7 +75,7 @@ impl NonZero { /// Creates an instance of NonZero with the provided value. #[inline] - pub fn new_checked(inner: T) -> Option { + pub fn new(inner: T) -> Option { if inner.is_zero() { None } else { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5ece63e23b11d..633cd20bbf29a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1115,8 +1115,8 @@ impl Unique { } /// Creates a new `Unique` if `ptr` is non-null. - pub fn new_checked(ptr: *mut T) -> Option { - NonZero::new_checked(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) + pub fn new(ptr: *mut T) -> Option { + NonZero::new(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) } /// Acquires the underlying `*mut` pointer. @@ -1234,8 +1234,8 @@ impl Shared { } /// Creates a new `Shared` if `ptr` is non-null. - pub fn new_checked(ptr: *mut T) -> Option { - NonZero::new_checked(ptr as *const T).map(|nz| Shared { pointer: nz, _marker: PhantomData }) + pub fn new(ptr: *mut T) -> Option { + NonZero::new(ptr as *const T).map(|nz| Shared { pointer: nz, _marker: PhantomData }) } /// Acquires the underlying `*mut` pointer. From 1ef24bb3e23975b8183a04b0691ee0ecb878c17e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 14 Jul 2017 12:37:57 +0200 Subject: [PATCH 04/13] Implement From> for Shared --- src/libcore/ptr.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 633cd20bbf29a..29e2114f38a58 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -16,6 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use convert::From; use intrinsics; use ops::CoerceUnsized; use fmt; @@ -1288,3 +1289,10 @@ impl fmt::Pointer for Shared { fmt::Pointer::fmt(&self.as_ptr(), f) } } + +#[unstable(feature = "shared", issue = "27730")] +impl From> for Shared { + fn from(unique: Unique) -> Self { + Shared { pointer: unique.pointer, _marker: PhantomData } + } +} From cbd2b6b4842754495a2673df234e2496494245be Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 14 Jul 2017 12:47:06 +0200 Subject: [PATCH 05/13] Add Box::into_unique --- src/liballoc/arc.rs | 4 ++-- src/liballoc/boxed.rs | 31 +++++++++++++++++++++++++++++++ src/liballoc/btree/node.rs | 4 +--- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/rc.rs | 24 +++++++++++------------- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index cc792c9f83f79..9e31425193417 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -280,7 +280,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data: data, }; - Arc { ptr: unsafe { Shared::new_unchecked(Box::into_raw(x)) } } + Arc { ptr: Shared::from(Box::into_unique(x)) } } /// Returns the contained value, if the `Arc` has exactly one strong reference. @@ -842,7 +842,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::new_unchecked(Box::into_raw(box ArcInner { + ptr: Shared::from(Box::into_unique(box ArcInner { strong: atomic::AtomicUsize::new(0), weak: atomic::AtomicUsize::new(1), data: uninitialized(), diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 94f5f4042e134..6318d22059f96 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -297,6 +297,37 @@ impl Box { pub fn into_raw(b: Box) -> *mut T { unsafe { mem::transmute(b) } } + + /// Consumes the `Box`, returning the wrapped pointer as `Unique`. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Box`. In particular, the + /// caller should properly destroy `T` and release the memory. The + /// proper way to do so is to convert the raw pointer back into a + /// `Box` with the [`Box::from_raw`] function. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_unique(b)` instead of `b.into_unique()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// [`Box::from_raw`]: struct.Box.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(unique)] + /// + /// fn main() { + /// let x = Box::new(5); + /// let ptr = Box::into_unique(x); + /// } + /// ``` + #[unstable(feature = "unique", reason = "needs an RFC to flesh out design", + issue = "27730")] + #[inline] + pub fn into_unique(b: Box) -> Unique { + unsafe { mem::transmute(b) } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 0a752702b1213..05ac9cba5e09d 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -140,9 +140,7 @@ struct BoxedNode { impl BoxedNode { fn from_leaf(node: Box>) -> Self { - unsafe { - BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node)) } - } + BoxedNode { ptr: Box::into_unique(node) } } fn from_internal(node: Box>) -> Self { diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 08d6fac3849ba..850dd6adcf0af 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -157,7 +157,7 @@ impl LinkedList { unsafe { node.next = self.head; node.prev = None; - let node = Some(Shared::new_unchecked(Box::into_raw(node))); + let node = Some(Shared::from(Box::into_unique(node))); match self.head { None => self.tail = node, @@ -192,7 +192,7 @@ impl LinkedList { unsafe { node.next = None; node.prev = self.tail; - let node = Some(Shared::new_unchecked(Box::into_raw(node))); + let node = Some(Shared::from(Box::into_unique(node))); match self.tail { None => self.head = node, @@ -921,7 +921,7 @@ impl<'a, T> IterMut<'a, T> { Some(prev) => prev, }; - let node = Some(Shared::new_unchecked(Box::into_raw(box Node { + let node = Some(Shared::from(Box::into_unique(box Node { next: Some(head), prev: Some(prev), element: element, diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 6ff6b6b037256..a2184054b377e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -303,18 +303,16 @@ impl Rc { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(value: T) -> Rc { - unsafe { - Rc { - // there is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - ptr: Shared::new_unchecked(Box::into_raw(box RcBox { - strong: Cell::new(1), - weak: Cell::new(1), - value: value, - })), - } + Rc { + // there is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + ptr: Shared::from(Box::into_unique(box RcBox { + strong: Cell::new(1), + weak: Cell::new(1), + value: value, + })), } } @@ -1016,7 +1014,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::new_unchecked(Box::into_raw(box RcBox { + ptr: Shared::from(Box::into_unique(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: uninitialized(), From a4edae95ad0e85b50845be1757670929ff60c88a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 14 Jul 2017 13:05:21 +0200 Subject: [PATCH 06/13] Add conversions from references to NonZero pointers, Unique, and Shared --- src/liballoc/btree/node.rs | 2 +- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 2 +- src/libcore/nonzero.rs | 19 +++++++++++++++ src/libcore/ptr.rs | 28 +++++++++++++++++++++++ src/librustc_data_structures/array_vec.rs | 2 +- src/libstd/collections/hash/table.rs | 2 +- 7 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 05ac9cba5e09d..a6cbab8497b6f 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -155,7 +155,7 @@ impl BoxedNode { fn as_ptr(&self) -> NonZero<*const LeafNode> { unsafe { - NonZero::new_unchecked(self.ptr.as_ptr()) + NonZero::from(self.ptr.as_ref()) } } } diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index bc1521c406967..8a1d14b48a1a3 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1126,7 +1126,7 @@ impl Vec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - vec: Shared::new_unchecked(self as *mut _), + vec: Shared::from(self), } } } diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index a99b7bbe0539d..fdd6c79ef2e9d 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -893,7 +893,7 @@ impl VecDeque { self.head = drain_tail; Drain { - deque: unsafe { Shared::new_unchecked(self as *mut _) }, + deque: Shared::from(&mut *self), after_tail: drain_head, after_head: head, iter: Iter { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 65ebb8c5ae376..3ff1068b93763 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -90,3 +90,22 @@ impl NonZero { } impl, U: Zeroable> CoerceUnsized> for NonZero {} + +impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*mut T> { + fn from(reference: &'a mut T) -> Self { + NonZero(reference) + } +} + +impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*const T> { + fn from(reference: &'a mut T) -> Self { + let ptr: *mut T = reference; + NonZero(ptr) + } +} + +impl<'a, T: ?Sized> From<&'a T> for NonZero<*const T> { + fn from(reference: &'a T) -> Self { + NonZero(reference) + } +} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 29e2114f38a58..9413a908cb18c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1164,6 +1164,20 @@ impl fmt::Pointer for Unique { } } +#[unstable(feature = "unique", issue = "27730")] +impl<'a, T: ?Sized> From<&'a mut T> for Unique { + fn from(reference: &'a mut T) -> Self { + Unique { pointer: NonZero::from(reference), _marker: PhantomData } + } +} + +#[unstable(feature = "unique", issue = "27730")] +impl<'a, T: ?Sized> From<&'a T> for Unique { + fn from(reference: &'a T) -> Self { + Unique { pointer: NonZero::from(reference), _marker: PhantomData } + } +} + /// A wrapper around a raw `*mut T` that indicates that the possessor /// of this wrapper has shared ownership of the referent. Useful for /// building abstractions like `Rc`, `Arc`, or doubly-linked lists, which @@ -1296,3 +1310,17 @@ impl From> for Shared { Shared { pointer: unique.pointer, _marker: PhantomData } } } + +#[unstable(feature = "shared", issue = "27730")] +impl<'a, T: ?Sized> From<&'a mut T> for Shared { + fn from(reference: &'a mut T) -> Self { + Shared { pointer: NonZero::from(reference), _marker: PhantomData } + } +} + +#[unstable(feature = "shared", issue = "27730")] +impl<'a, T: ?Sized> From<&'a T> for Shared { + fn from(reference: &'a T) -> Self { + Shared { pointer: NonZero::from(reference), _marker: PhantomData } + } +} diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index de028f6109046..ced73e9e42627 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -146,7 +146,7 @@ impl ArrayVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - array_vec: Shared::new_unchecked(self as *mut _), + array_vec: Shared::from(self), } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index f3aec589e7d27..3844690860b5a 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -877,7 +877,7 @@ impl RawTable { elems_left: elems_left, marker: marker::PhantomData, }, - table: unsafe { Shared::new_unchecked(self) }, + table: Shared::from(self), marker: marker::PhantomData, } } From 938552a2289d6018e78d9626f011d8eea59be7d9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:28:02 +0200 Subject: [PATCH 07/13] Use checked NonZero constructor instead of explicit null check in btree --- src/liballoc/btree/node.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index a6cbab8497b6f..06d3a113b9474 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -382,21 +382,19 @@ impl NodeRef { >, Self > { - if self.as_leaf().parent.is_null() { - Err(self) - } else { + if let Some(non_zero) = NonZero::new(self.as_leaf().parent as *const LeafNode) { Ok(Handle { node: NodeRef { height: self.height + 1, - node: unsafe { - NonZero::new_unchecked(self.as_leaf().parent as *mut LeafNode) - }, + node: non_zero, root: self.root, _marker: PhantomData }, idx: self.as_leaf().parent_idx as usize, _marker: PhantomData }) + } else { + Err(self) } } From 13d17adf6059552358c8601aaa407aea5ddddb98 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:30:47 +0200 Subject: [PATCH 08/13] Use checked NonZero constructor in obligation forest NodeIndex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … to remove an `unsafe` block. --- src/librustc_data_structures/obligation_forest/node_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index 9fa6045146dcc..a72cc6b57eade 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -19,7 +19,7 @@ pub struct NodeIndex { impl NodeIndex { pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); - unsafe { NodeIndex { index: NonZero::new_unchecked((value as u32) + 1) } } + NodeIndex { index: NonZero::new((value as u32) + 1).unwrap() } } pub fn get(self) -> usize { From 06e130fb241cf3c828040d7d4958bf1945226e9c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:32:37 +0200 Subject: [PATCH 09/13] Use checked NonZero constructor in MIR move path indices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … to protect against UB in the unlikely case that `idx + 1` overflows. --- src/librustc_mir/dataflow/move_paths/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 63c204fbdcda2..dd970fdff91ec 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -42,7 +42,7 @@ pub(crate) mod indexes { impl Idx for $Index { fn new(idx: usize) -> Self { - unsafe { $Index(NonZero::new_unchecked(idx + 1)) } + $Index(NonZero::new(idx + 1).unwrap()) } fn index(self) -> usize { self.0.get() - 1 From 1ba8b1532169e608693d815a4e53d70a64e1329e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:38:20 +0200 Subject: [PATCH 10/13] Use safe conversion instead of unsafe constructor in issue-23433 test --- src/test/run-pass/issue-23433.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 6c4c425cb8e02..aa13d6fad47c9 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -16,7 +16,7 @@ use std::ptr::Unique; fn main() { let mut a = [0u8; 5]; - let b: Option> = unsafe { Some(Unique::new_unchecked(&mut a)) }; + let b: Option> = Some(Unique::from(&mut a)); match b { Some(_) => println!("Got `Some`"), None => panic!("Unexpected `None`"), From f732911cf568f8f7b98dbcfd85241e299d2c8418 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:45:38 +0200 Subject: [PATCH 11/13] Fix unstable feature name for some impls for Unique --- src/libcore/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 9413a908cb18c..60cf1a2053068 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1144,14 +1144,14 @@ impl Unique { } } -#[unstable(feature = "shared", issue = "27730")] +#[unstable(feature = "unique", issue = "27730")] impl Clone for Unique { fn clone(&self) -> Self { *self } } -#[unstable(feature = "shared", issue = "27730")] +#[unstable(feature = "unique", issue = "27730")] impl Copy for Unique { } #[unstable(feature = "unique", issue = "27730")] From ff7f220a431e1405a791d865f84e98143fd8af0e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:49:19 +0200 Subject: [PATCH 12/13] =?UTF-8?q?Don=E2=80=99t=20create=20NonZero(0)=20in?= =?UTF-8?q?=20test/ui/print=5Ftype=5Fsizes/nullable.rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/ui/print_type_sizes/nullable.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/ui/print_type_sizes/nullable.rs b/src/test/ui/print_type_sizes/nullable.rs index df5c53daf7e1e..a8f07d8d95569 100644 --- a/src/test/ui/print_type_sizes/nullable.rs +++ b/src/test/ui/print_type_sizes/nullable.rs @@ -42,7 +42,7 @@ impl Default for EmbeddedDiscr { } #[derive(Default)] -pub struct IndirectNonZero { +pub struct IndirectNonZero { pre: u8, nested: NestedNonZero, post: u16, @@ -54,14 +54,22 @@ pub struct NestedNonZero { post: u16, } -impl Default for NestedNonZero { +impl Default for NestedNonZero { fn default() -> Self { unsafe { - NestedNonZero { pre: 0, val: NonZero::new_unchecked(Default::default()), post: 0 } + NestedNonZero { pre: 0, val: NonZero::new_unchecked(T::one()), post: 0 } } } } +pub trait One { + fn one() -> Self; +} + +impl One for u32 { + fn one() -> Self { 1 } +} + pub fn main() { let _x: MyOption> = Default::default(); let _y: EmbeddedDiscr = Default::default(); From 0d1864b8cf9585e6133aa3da2b06b29cbfb791bd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 17 Jul 2017 14:52:36 +0200 Subject: [PATCH 13/13] Remove unnecessary unsafe in test/ui/print_type_sizes/nullable.rs --- src/test/ui/print_type_sizes/nullable.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/ui/print_type_sizes/nullable.rs b/src/test/ui/print_type_sizes/nullable.rs index a8f07d8d95569..5052c59a39dcf 100644 --- a/src/test/ui/print_type_sizes/nullable.rs +++ b/src/test/ui/print_type_sizes/nullable.rs @@ -56,9 +56,7 @@ pub struct NestedNonZero { impl Default for NestedNonZero { fn default() -> Self { - unsafe { - NestedNonZero { pre: 0, val: NonZero::new_unchecked(T::one()), post: 0 } - } + NestedNonZero { pre: 0, val: NonZero::new(T::one()).unwrap(), post: 0 } } }