From e9af03a22279b62ded4c7ea897d5ac3a9b54728c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 29 Jun 2017 01:00:00 +0200 Subject: [PATCH 01/23] =?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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] =?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/23] 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 } } } From 8aa8f80ac0108c5c0296baa20e08ebf21c283f25 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 24 Jul 2017 11:17:29 -0700 Subject: [PATCH 14/23] std::thread::spawn: Fix grammar in documentation --- src/libstd/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 07a3a01ce8666..5f01e63520188 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -413,7 +413,7 @@ impl Builder { /// *by value* from the thread where it is spawned to the new thread. Its /// return value will need to be passed from the new thread to the thread /// where it is `join`ed. -/// As a reminder, the [`Send`] marker trait, expresses that it is safe to be +/// As a reminder, the [`Send`] marker trait expresses that it is safe to be /// passed from thread to thread. [`Sync`] expresses that it is safe to have a /// reference be passed from thread to thread. /// From 95b0f22240dcce4f827703a0e1de1b1bea3e902a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jul 2017 13:43:05 -0700 Subject: [PATCH 15/23] Fix printing regions with -Z verbose --- src/librustc/mir/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d176ae761e181..f3d92d3692de5 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1208,14 +1208,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { BorrowKind::Mut | BorrowKind::Unique => "mut ", }; - // When identifying regions, add trailing space if - // necessary. - let region = if ppaux::identify_regions() { + // When printing regions, add trailing space if necessary. + let region = { let mut region = format!("{}", region); if region.len() > 0 { region.push(' '); } region - } else { - "".to_owned() }; write!(fmt, "&{}{}{:?}", region, kind_str, lv) } From ea23e50fcb506b076531404172bfcbb74cd20c8c Mon Sep 17 00:00:00 2001 From: Danek Duvall Date: Mon, 24 Jul 2017 15:57:57 -0700 Subject: [PATCH 16/23] DNS functions are in libresolv on Solaris, just like on MacOS --- src/libstd/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 2abd47ab8dfbd..0b5c2db171d65 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -45,6 +45,7 @@ fn main() { println!("cargo:rustc-link-lib=socket"); println!("cargo:rustc-link-lib=posix4"); println!("cargo:rustc-link-lib=pthread"); + println!("cargo:rustc-link-lib=resolv"); } else if target.contains("apple-darwin") { println!("cargo:rustc-link-lib=System"); From 4e1249d75f420392d7f1f45188d39d32cdab2662 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jul 2017 16:32:11 -0700 Subject: [PATCH 17/23] avoid printing 'static --- src/librustc/mir/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f3d92d3692de5..d78e17ce03cef 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1209,10 +1209,13 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; // When printing regions, add trailing space if necessary. - let region = { + let region = if ppaux::verbose() || ppaux::identify_regions() { let mut region = format!("{}", region); if region.len() > 0 { region.push(' '); } region + } else { + // Do not even print 'static + "".to_owned() }; write!(fmt, "&{}{}{:?}", region, kind_str, lv) } From 53884705cbaad44def64b409be1ca7107997f776 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 25 Jul 2017 11:39:41 +1200 Subject: [PATCH 18/23] Fix the spans of catch blocks to include the `do` --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d6a57c2874f8b..2cd84d202ffc9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2243,9 +2243,9 @@ impl<'a> Parser<'a> { attrs); } if self.is_catch_expr() { + let lo = self.span; assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); - let lo = self.prev_span; return self.parse_catch_expr(lo, attrs); } if self.eat_keyword(keywords::Return) { From 04aa5c1c76d516c065e3d3626887090cd05ded82 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 25 Jul 2017 11:31:59 +0900 Subject: [PATCH 19/23] Add tests for issues with the E-needstest label --- src/test/compile-fail/issue-33504.rs | 19 +++++++++++++++++ src/test/compile-fail/issue-39211.rs | 24 +++++++++++++++++++++ src/test/run-fail/issue-29798.rs | 20 ++++++++++++++++++ src/test/run-pass/issue-29516.rs | 28 +++++++++++++++++++++++++ src/test/run-pass/issue-34780.rs | 19 +++++++++++++++++ src/test/run-pass/issue-39467.rs | 19 +++++++++++++++++ src/test/run-pass/issue-39720.rs | 31 ++++++++++++++++++++++++++++ src/test/rustdoc/issue-19181.rs | 15 ++++++++++++++ 8 files changed, 175 insertions(+) create mode 100644 src/test/compile-fail/issue-33504.rs create mode 100644 src/test/compile-fail/issue-39211.rs create mode 100644 src/test/run-fail/issue-29798.rs create mode 100644 src/test/run-pass/issue-29516.rs create mode 100644 src/test/run-pass/issue-34780.rs create mode 100644 src/test/run-pass/issue-39467.rs create mode 100644 src/test/run-pass/issue-39720.rs create mode 100644 src/test/rustdoc/issue-19181.rs diff --git a/src/test/compile-fail/issue-33504.rs b/src/test/compile-fail/issue-33504.rs new file mode 100644 index 0000000000000..bc78d20745a54 --- /dev/null +++ b/src/test/compile-fail/issue-33504.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +// Shadowing a unit-like enum in a closure + +struct Test; + +fn main() { + || { + let Test = 1; //~ ERROR let bindings cannot shadow unit structs + }; +} diff --git a/src/test/compile-fail/issue-39211.rs b/src/test/compile-fail/issue-39211.rs new file mode 100644 index 0000000000000..96ba1c8399786 --- /dev/null +++ b/src/test/compile-fail/issue-39211.rs @@ -0,0 +1,24 @@ +// Copyright 2017 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. + +#![feature(associated_consts)] + +trait VecN { + const DIM: usize; +} +trait Mat { + type Row: VecN; +} + +fn m() { + let a = [3; M::Row::DIM]; //~ ERROR associated type `Row` not found for `M` +} +fn main() { +} diff --git a/src/test/run-fail/issue-29798.rs b/src/test/run-fail/issue-29798.rs new file mode 100644 index 0000000000000..a77175975f941 --- /dev/null +++ b/src/test/run-fail/issue-29798.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +// error-pattern:index out of bounds: the len is 5 but the index is 5 + +#![feature(const_fn)] +const fn test(x: usize) -> i32 { + [42;5][x] +} + +fn main () { + let _ = test(5); +} diff --git a/src/test/run-pass/issue-29516.rs b/src/test/run-pass/issue-29516.rs new file mode 100644 index 0000000000000..b586abc29e243 --- /dev/null +++ b/src/test/run-pass/issue-29516.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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. + +#![feature(optin_builtin_traits)] + +trait NotSame {} +impl NotSame for .. {} +impl !NotSame for (A, A) {} + +trait OneOfEach {} + +impl OneOfEach for (A,) {} + +impl OneOfEach for (A, B) +where + (B,): OneOfEach, + (A, B): NotSame, +{ +} + +fn main() {} diff --git a/src/test/run-pass/issue-34780.rs b/src/test/run-pass/issue-34780.rs new file mode 100644 index 0000000000000..eda4ebb7132a8 --- /dev/null +++ b/src/test/run-pass/issue-34780.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +#![feature(associated_consts)] + +use std::marker::PhantomData; + +trait Tr<'a> { + const C: PhantomData<&'a u8> = PhantomData::<&'a u8>; +} + +fn main() {} diff --git a/src/test/run-pass/issue-39467.rs b/src/test/run-pass/issue-39467.rs new file mode 100644 index 0000000000000..9f94be271eeb6 --- /dev/null +++ b/src/test/run-pass/issue-39467.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +macro_rules! expr { () => { () } } + +enum A {} + +impl A { + const A: () = expr!(); +} + +fn main() {} diff --git a/src/test/run-pass/issue-39720.rs b/src/test/run-pass/issue-39720.rs new file mode 100644 index 0000000000000..f90696e3cdf16 --- /dev/null +++ b/src/test/run-pass/issue-39720.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(C)] +#[repr(simd)] +#[derive(Copy, Clone, Debug)] +pub struct char3(pub i8, pub i8, pub i8); + +#[repr(C)] +#[repr(simd)] +#[derive(Copy, Clone, Debug)] +pub struct short3(pub i16, pub i16, pub i16); + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +fn main() { + let cast: short3 = unsafe { simd_cast(char3(10, -3, -9)) }; + + println!("{:?}", cast); +} diff --git a/src/test/rustdoc/issue-19181.rs b/src/test/rustdoc/issue-19181.rs new file mode 100644 index 0000000000000..a2935b73596c3 --- /dev/null +++ b/src/test/rustdoc/issue-19181.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +// compile-flags:--test + +// rustdoc should not panic when target crate has compilation errors + +fn main() { 0 } From 9ea65a8a71b901fbc47d4e9f5bed3e9f9ff9cb7e Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 25 Jul 2017 06:19:30 +0100 Subject: [PATCH 20/23] Add missing impl and tests for int to int TryFrom impls --- src/libcore/num/mod.rs | 25 ++++++++++++++----------- src/libcore/tests/num/mod.rs | 20 ++++++++++++++++---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 0ebac027c39ac..c6c91dacdc7ee 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2627,8 +2627,11 @@ try_from_both_bounded!(i32, u16, u8); try_from_both_bounded!(i64, u32, u16, u8); try_from_both_bounded!(i128, u64, u32, u16, u8); -#[unstable(feature = "try_from", issue = "33417")] -pub use self::ptr_try_from_impls::*; +// usize/isize +try_from_unbounded!(usize, usize); +try_from_upper_bounded!(usize, isize); +try_from_lower_bounded!(isize, usize); +try_from_unbounded!(isize, isize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { @@ -2636,12 +2639,12 @@ mod ptr_try_from_impls { use convert::TryFrom; try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, isize); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); try_from_unbounded!(usize, i32, i64, i128); try_from_both_bounded!(isize, u8); - try_from_lower_bounded!(isize, usize, u16, u32, u64, u128); + try_from_lower_bounded!(isize, u16, u32, u64, u128); try_from_both_bounded!(isize, i8); try_from_unbounded!(isize, i16, i32, i64, i128); @@ -2662,12 +2665,12 @@ mod ptr_try_from_impls { use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, isize); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); try_from_unbounded!(usize, i64, i128); try_from_both_bounded!(isize, u8, u16); - try_from_lower_bounded!(isize, usize, u32, u64, u128); + try_from_lower_bounded!(isize, u32, u64, u128); try_from_both_bounded!(isize, i8, i16); try_from_unbounded!(isize, i32, i64, i128); @@ -2688,12 +2691,12 @@ mod ptr_try_from_impls { use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64, isize); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); try_from_unbounded!(usize, i128); try_from_both_bounded!(isize, u8, u16, u32); - try_from_lower_bounded!(isize, usize, u64, u128); + try_from_lower_bounded!(isize, u64, u128); try_from_both_bounded!(isize, i8, i16, i32); try_from_unbounded!(isize, i64, i128); diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 3e872b34e433d..046b81e19f70d 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -279,7 +279,7 @@ test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } test_impl_try_from_always_ok! { test_try_u64u128, u64, u128 } test_impl_try_from_always_ok! { test_try_u64i128, u64, i128 } -test_impl_try_from_always_ok! { test_try_u128, u128, u128 } +test_impl_try_from_always_ok! { test_try_u128u128, u128, u128 } test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } @@ -301,8 +301,12 @@ test_impl_try_from_always_ok! { test_try_i64i128, i64, i128 } test_impl_try_from_always_ok! { test_try_i128i128, i128, i128 } +test_impl_try_from_always_ok! { test_try_usizeusize, usize, usize } +test_impl_try_from_always_ok! { test_try_isizeisize, isize, isize } + assume_usize_width! { test_impl_try_from_always_ok! { test_try_u8usize, u8, usize } + test_impl_try_from_always_ok! { test_try_u8isize, u8, isize } test_impl_try_from_always_ok! { test_try_i8isize, i8, isize } test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } @@ -317,19 +321,27 @@ assume_usize_width! { cfg_block!( #[cfg(target_pointer_width = "16")] { - test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } - test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } } #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } } #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } @@ -451,8 +463,8 @@ assume_usize_width! { cfg_block!( #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u64, isize } } #[cfg(target_pointer_width = "32")] { From 6e36769d292ee303538ed577ad2e853de57b75a4 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Mon, 24 Jul 2017 10:16:16 -0500 Subject: [PATCH 21/23] add a note to Vec's Extend<&T> impl about its slice specialization --- src/liballoc/vec.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 780a51aec3bab..b7d8059adb1db 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1962,6 +1962,12 @@ impl Vec { } +/// Extend implementation that copies elements out of references before pushing them onto the Vec. +/// +/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to +/// append the entire slice at once. +/// +/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { From f0fda53cc107ccb581a2493e9f02200413e6055d Mon Sep 17 00:00:00 2001 From: Danek Duvall Date: Tue, 25 Jul 2017 14:32:08 -0700 Subject: [PATCH 22/23] Constrain the layout of Blake2bCtx for proper SPARC compilation On SPARC, optimization fuel ends up emitting incorrect load and store instructions for the transmute() call in blake2b_compress(). If we force Blake2bCtx to be repr(C), the problem disappears. Fixes #43346 --- src/librustc_data_structures/blake2b.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index bdef9fefd41e4..5adeef1ab3a6d 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -23,6 +23,7 @@ use std::mem; use std::slice; +#[repr(C)] pub struct Blake2bCtx { b: [u8; 128], h: [u64; 8], From 552ff07758545173c94fa260e5266ec07cd0bbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Jul 2017 15:15:45 -0700 Subject: [PATCH 23/23] Point at path segment on module not found Point at the correct path segment on a import statement where a module doesn't exist. New output: ```rust error[E0432]: unresolved import `std::bar` --> :1:10 | 1 | use std::bar::{foo1, foo2}; | ^^^ Could not find `bar` in `std` ``` instead of: ```rust error[E0432]: unresolved import `std::bar::foo1` --> :1:16 | 1 | use std::bar::{foo1, foo2}; | ^^^^ Could not find `bar` in `std` error[E0432]: unresolved import `std::bar::foo2` --> :1:22 | 1 | use std::bar::{foo1, foo2}; | ^^^^ Could not find `bar` in `std` ``` --- src/librustc_resolve/build_reduced_graph.rs | 22 ++- src/librustc_resolve/lib.rs | 141 ++++++++++-------- src/librustc_resolve/macros.rs | 19 ++- src/librustc_resolve/resolve_imports.rs | 71 +++++---- .../compile-fail/dollar-crate-is-keyword-2.rs | 2 +- src/test/compile-fail/import2.rs | 2 +- src/test/compile-fail/issue-1697.rs | 2 +- src/test/compile-fail/issue-30560.rs | 4 +- src/test/compile-fail/issue-33464.rs | 9 +- .../compile-fail/resolve_self_super_hint.rs | 8 +- src/test/compile-fail/super-at-top-level.rs | 2 +- src/test/compile-fail/unresolved-import.rs | 6 +- src/test/compile-fail/use-from-trait-xc.rs | 6 +- src/test/compile-fail/use-from-trait.rs | 4 +- src/test/compile-fail/use-mod-4.rs | 2 +- .../macros/macro_path_as_generic_bound.stderr | 2 +- .../ui/span/non-existing-module-import.rs | 13 ++ .../ui/span/non-existing-module-import.stderr | 8 + 18 files changed, 194 insertions(+), 129 deletions(-) create mode 100644 src/test/ui/span/non-existing-module-import.rs create mode 100644 src/test/ui/span/non-existing-module-import.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4b6b754dca655..a061484b5c4a5 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -35,6 +35,7 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::codemap::respan; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; @@ -119,7 +120,7 @@ impl<'a> Resolver<'a> { .unwrap() .1 .iter() - .map(|seg| seg.identifier) + .map(|seg| respan(seg.span, seg.identifier)) .collect() } @@ -127,14 +128,16 @@ impl<'a> Resolver<'a> { ViewPathList(ref module_ident_path, _) => { module_ident_path.segments .iter() - .map(|seg| seg.identifier) + .map(|seg| respan(seg.span, seg.identifier)) .collect() } }; // This can be removed once warning cycle #36888 is complete. - if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() && - token::Ident(module_path[1]).is_path_segment_keyword() { + if module_path.len() >= 2 && + module_path[0].node.name == keywords::CrateRoot.name() && + token::Ident(module_path[1].node).is_path_segment_keyword() + { module_path.remove(0); } @@ -202,10 +205,13 @@ impl<'a> Resolver<'a> { let (module_path, ident, rename, type_ns_only) = { if node.name.name != keywords::SelfValue.name() { let rename = node.rename.unwrap_or(node.name); - (module_path.clone(), node.name, rename, false) + (module_path.clone(), + respan(source_item.span, node.name), + rename, + false) } else { let ident = *module_path.last().unwrap(); - if ident.name == keywords::CrateRoot.name() { + if ident.node.name == keywords::CrateRoot.name() { resolve_error( self, source_item.span, @@ -215,13 +221,13 @@ impl<'a> Resolver<'a> { continue; } let module_path = module_path.split_last().unwrap().1; - let rename = node.rename.unwrap_or(ident); + let rename = node.rename.unwrap_or(ident.node); (module_path.to_vec(), ident, rename, true) } }; let subclass = SingleImport { target: rename, - source: ident, + source: ident.node, result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), type_ns_only: type_ns_only, }; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 49e6929aeef1d..a339ee8a5ecc4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,6 +45,7 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; +use syntax::codemap::{dummy_spanned, respan}; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; @@ -149,7 +150,7 @@ enum ResolutionError<'a> { /// error E0431: `self` import can only appear in an import list with a non-empty prefix SelfImportOnlyInImportListWithNonEmptyPrefix, /// error E0432: unresolved import - UnresolvedImport(Option<(&'a str, &'a str)>), + UnresolvedImport(Option<(Span, &'a str, &'a str)>), /// error E0433: failed to resolve FailedToResolve(&'a str), /// error E0434: can't capture dynamic environment in a fn item @@ -297,12 +298,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, non-empty prefix") } ResolutionError::UnresolvedImport(name) => { - let msg = match name { - Some((n, _)) => format!("unresolved import `{}`", n), - None => "unresolved import".to_owned(), + let (span, msg) = match name { + Some((sp, n, _)) => (sp, format!("unresolved import `{}`", n)), + None => (span, "unresolved import".to_owned()), }; let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg); - if let Some((_, p)) = name { + if let Some((_, _, p)) = name { err.span_label(span, p); } err @@ -820,7 +821,7 @@ enum PathResult<'a> { Module(Module<'a>), NonModule(PathResolution), Indeterminate, - Failed(String, bool /* is the error from the last segment? */), + Failed(Span, String, bool /* is the error from the last segment? */), } enum ModuleKind { @@ -1276,19 +1277,21 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { let namespace = if is_value { ValueNS } else { TypeNS }; let hir::Path { ref segments, span, ref mut def } = *path; - let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect(); + let path: Vec = segments.iter() + .map(|seg| respan(span, Ident::with_empty_ctxt(seg.name))) + .collect(); match self.resolve_path(&path, Some(namespace), true, span) { PathResult::Module(module) => *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) { - PathResult::Failed(msg, _) => { + PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } _ => {} }, PathResult::Indeterminate => unreachable!(), - PathResult::Failed(msg, _) => { + PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } } @@ -1909,7 +1912,9 @@ impl<'a> Resolver<'a> { let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - let path: Vec<_> = trait_ref.path.segments.iter().map(|seg| seg.identifier).collect(); + let path: Vec<_> = trait_ref.path.segments.iter() + .map(|seg| respan(seg.span, seg.identifier)) + .collect(); let def = self.smart_resolve_path_fragment(trait_ref.ref_id, None, &path, @@ -2334,7 +2339,9 @@ impl<'a> Resolver<'a> { path: &Path, source: PathSource) -> PathResolution { - let segments = &path.segments.iter().map(|seg| seg.identifier).collect::>(); + let segments = &path.segments.iter() + .map(|seg| respan(seg.span, seg.identifier)) + .collect::>(); let ident_span = path.segments.last().map_or(path.span, |seg| seg.span); self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source) } @@ -2342,7 +2349,7 @@ impl<'a> Resolver<'a> { fn smart_resolve_path_fragment(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[SpannedIdent], span: Span, ident_span: Span, source: PathSource) @@ -2361,10 +2368,11 @@ impl<'a> Resolver<'a> { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), format!("not a {}", expected), span) } else { - let item_str = path[path.len() - 1]; + let item_str = path[path.len() - 1].node; + let item_span = path[path.len() - 1].span; let (mod_prefix, mod_str) = if path.len() == 1 { (format!(""), format!("this scope")) - } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { + } else if path.len() == 2 && path[0].node.name == keywords::CrateRoot.name() { (format!(""), format!("the crate root")) } else { let mod_path = &path[..path.len() - 1]; @@ -2375,7 +2383,7 @@ impl<'a> Resolver<'a> { (mod_prefix, format!("`{}`", names_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), ident_span) + format!("not found in {}", mod_str), item_span) }; let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); @@ -2396,7 +2404,7 @@ impl<'a> Resolver<'a> { // Try to lookup the name in more relaxed fashion for better error reporting. let ident = *path.last().unwrap(); - let candidates = this.lookup_import_candidates(ident.name, ns, is_expected); + let candidates = this.lookup_import_candidates(ident.node.name, ns, is_expected); if !candidates.is_empty() { let mut module_span = this.current_module.span; module_span.hi = module_span.lo; @@ -2404,7 +2412,7 @@ impl<'a> Resolver<'a> { show_candidates(&mut err, module_span, &candidates, def.is_some()); } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = - this.lookup_import_candidates(ident.name, ns, is_enum_variant); + this.lookup_import_candidates(ident.node.name, ns, is_enum_variant); let mut enum_candidates = enum_candidates.iter() .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); enum_candidates.sort(); @@ -2422,8 +2430,8 @@ impl<'a> Resolver<'a> { } } if path.len() == 1 && this.self_type_is_available(span) { - if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = this.self_value_is_available(path[0].ctxt, span); + if let Some(candidate) = this.lookup_assoc_candidate(ident.node, ns, is_expected) { + let self_is_available = this.self_value_is_available(path[0].node.ctxt, span); match candidate { AssocSuggestion::Field => { err.span_suggestion(span, "try", @@ -2538,7 +2546,7 @@ impl<'a> Resolver<'a> { // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. if ns == ValueNS { - let item_name = *path.last().unwrap(); + let item_name = path.last().unwrap().node; let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } @@ -2570,7 +2578,7 @@ impl<'a> Resolver<'a> { fn resolve_qpath_anywhere(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[SpannedIdent], primary_ns: Namespace, span: Span, defer_to_typeck: bool, @@ -2590,9 +2598,10 @@ impl<'a> Resolver<'a> { }; } } - let is_global = self.global_macros.get(&path[0].name).cloned() + let is_global = self.global_macros.get(&path[0].node.name).cloned() .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); - if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].modern())) { + if primary_ns != MacroNS && (is_global || + self.macro_names.contains(&path[0].node.modern())) { // Return some dummy definition, it's enough for error reporting. return Some( PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) @@ -2605,7 +2614,7 @@ impl<'a> Resolver<'a> { fn resolve_qpath(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[SpannedIdent], ns: Namespace, span: Span, global_by_default: bool) @@ -2645,8 +2654,9 @@ impl<'a> Resolver<'a> { // The same fallback is used when `a` resolves to nothing. PathResult::Module(..) | PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && - self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { - let prim = self.primitive_type_table.primitive_types[&path[0].name]; + self.primitive_type_table.primitive_types + .contains_key(&path[0].node.name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { if !self.session.features.borrow().i128_type { @@ -2661,7 +2671,7 @@ impl<'a> Resolver<'a> { PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), - PathResult::Failed(msg, false) => { + PathResult::Failed(span, msg, false) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); err_path_resolution() } @@ -2670,8 +2680,8 @@ impl<'a> Resolver<'a> { }; if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && - path[0].name != keywords::DollarCrate.name() { + path[0].node.name != keywords::CrateRoot.name() && + path[0].node.name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) { PathResult::NonModule(path_res) => path_res.base_def(), @@ -2689,7 +2699,7 @@ impl<'a> Resolver<'a> { } fn resolve_path(&mut self, - path: &[Ident], + path: &[SpannedIdent], opt_ns: Option, // `None` indicates a module path record_used: bool, path_span: Span) @@ -2698,15 +2708,16 @@ impl<'a> Resolver<'a> { let mut allow_super = true; for (i, &ident) in path.iter().enumerate() { + debug!("resolve_path ident {} {:?}", i, ident); let is_last = i == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; - if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() { - let mut ctxt = ident.ctxt.modern(); + if i == 0 && ns == TypeNS && ident.node.name == keywords::SelfValue.name() { + let mut ctxt = ident.node.ctxt.modern(); module = Some(self.resolve_self(&mut ctxt, self.current_module)); continue - } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() { - let mut ctxt = ident.ctxt.modern(); + } else if allow_super && ns == TypeNS && ident.node.name == keywords::Super.name() { + let mut ctxt = ident.node.ctxt.modern(); let self_module = match i { 0 => self.resolve_self(&mut ctxt, self.current_module), _ => module.unwrap(), @@ -2716,26 +2727,26 @@ impl<'a> Resolver<'a> { continue } else { let msg = "There are too many initial `super`s.".to_string(); - return PathResult::Failed(msg, false); + return PathResult::Failed(ident.span, msg, false); } } allow_super = false; - if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { - module = Some(self.resolve_crate_root(ident.ctxt.modern())); + if i == 0 && ns == TypeNS && ident.node.name == keywords::CrateRoot.name() { + module = Some(self.resolve_crate_root(ident.node.ctxt.modern())); continue - } else if i == 0 && ns == TypeNS && ident.name == keywords::DollarCrate.name() { - module = Some(self.resolve_crate_root(ident.ctxt)); + } else if i == 0 && ns == TypeNS && ident.node.name == keywords::DollarCrate.name() { + module = Some(self.resolve_crate_root(ident.node.ctxt)); continue } let binding = if let Some(module) = module { - self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span) + self.resolve_ident_in_module(module, ident.node, ns, false, record_used, path_span) } else if opt_ns == Some(MacroNS) { - self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span) + self.resolve_lexical_macro_path_segment(ident.node, ns, record_used, path_span) .map(MacroBinding::binding) } else { - match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) { + match self.resolve_ident_in_lexical_scope(ident.node, ns, record_used, path_span) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), Some(LexicalScopeBinding::Def(def)) if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => { @@ -2760,7 +2771,9 @@ impl<'a> Resolver<'a> { def, path.len() - i - 1 )); } else { - return PathResult::Failed(format!("Not a module `{}`", ident), is_last); + return PathResult::Failed(ident.span, + format!("Not a module `{}`", ident.node), + is_last); } } Err(Undetermined) => return PathResult::Indeterminate, @@ -2775,19 +2788,19 @@ impl<'a> Resolver<'a> { let msg = if module.and_then(ModuleData::def) == self.graph_root.def() { let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; let mut candidates = - self.lookup_import_candidates(ident.name, TypeNS, is_mod); + self.lookup_import_candidates(ident.node.name, TypeNS, is_mod); candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string())); if let Some(candidate) = candidates.get(0) { format!("Did you mean `{}`?", candidate.path) } else { - format!("Maybe a missing `extern crate {};`?", ident) + format!("Maybe a missing `extern crate {};`?", ident.node) } } else if i == 0 { - format!("Use of undeclared type or module `{}`", ident) + format!("Use of undeclared type or module `{}`", ident.node) } else { - format!("Could not find `{}` in `{}`", ident, path[i - 1]) + format!("Could not find `{}` in `{}`", ident.node, path[i - 1].node) }; - return PathResult::Failed(msg, is_last); + return PathResult::Failed(ident.span, msg, is_last); } } } @@ -2807,8 +2820,7 @@ impl<'a> Resolver<'a> { // An invalid forward use of a type parameter from a previous default. if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind { if record_used { - resolve_error(self, span, - ResolutionError::ForwardDeclaredTyParam); + resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam); } assert_eq!(def, Def::Err); return Def::Err; @@ -2978,7 +2990,7 @@ impl<'a> Resolver<'a> { } fn lookup_typo_candidate(&mut self, - path: &[Ident], + path: &[SpannedIdent], ns: Namespace, filter_fn: FilterFn, span: Span) @@ -3039,7 +3051,7 @@ impl<'a> Resolver<'a> { } } - let name = path[path.len() - 1].name; + let name = path[path.len() - 1].node.name; // Make sure error reporting is deterministic. names.sort_by_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { @@ -3573,27 +3585,31 @@ fn is_struct_like(def: Def) -> bool { } } -fn is_self_type(path: &[Ident], namespace: Namespace) -> bool { - namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name() +fn is_self_type(path: &[SpannedIdent], namespace: Namespace) -> bool { + namespace == TypeNS && path.len() == 1 && path[0].node.name == keywords::SelfType.name() } -fn is_self_value(path: &[Ident], namespace: Namespace) -> bool { - namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name() +fn is_self_value(path: &[SpannedIdent], namespace: Namespace) -> bool { + namespace == ValueNS && path.len() == 1 && path[0].node.name == keywords::SelfValue.name() } -fn names_to_string(idents: &[Ident]) -> String { +fn names_to_string(idents: &[SpannedIdent]) -> String { let mut result = String::new(); - for (i, ident) in idents.iter().filter(|i| i.name != keywords::CrateRoot.name()).enumerate() { + for (i, ident) in idents.iter() + .filter(|i| i.node.name != keywords::CrateRoot.name()) + .enumerate() { if i > 0 { result.push_str("::"); } - result.push_str(&ident.name.as_str()); + result.push_str(&ident.node.name.as_str()); } result } fn path_names_to_string(path: &Path) -> String { - names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::>()) + names_to_string(&path.segments.iter() + .map(|seg| respan(seg.span, seg.identifier)) + .collect::>()) } /// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. @@ -3661,7 +3677,10 @@ fn module_to_string(module: Module) -> String { if names.is_empty() { return "???".to_string(); } - names_to_string(&names.into_iter().rev().collect::>()) + names_to_string(&names.into_iter() + .rev() + .map(|n| dummy_spanned(n)) + .collect::>()) } fn err_path_resolution() -> PathResolution { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index a993aca92dd12..18ec2b3cc1b9a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -19,6 +19,7 @@ use rustc::hir::map::{self, DefCollector}; use rustc::{ty, lint}; use syntax::ast::{self, Name, Ident}; use syntax::attr::{self, HasAttrs}; +use syntax::codemap::respan; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; @@ -393,7 +394,7 @@ impl<'a> Resolver<'a> { return Err(Determinacy::Determined); } - let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); + let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect(); let invocation = self.invocations[&scope]; self.current_module = invocation.module.get(); @@ -418,16 +419,19 @@ impl<'a> Resolver<'a> { Err(Determinacy::Determined) }, }; + let path = path.iter().map(|p| p.node).collect::>(); self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); return def; } - let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false); + let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, + path[0].node, + false); let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { Ok(Def::Macro(binding.def_id, MacroKind::Bang)) } else { - match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) { + match self.resolve_lexical_macro_path_segment(path[0].node, MacroNS, false, span) { Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { @@ -438,7 +442,7 @@ impl<'a> Resolver<'a> { }; self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() - .push((scope, path[0], span, kind)); + .push((scope, path[0].node, span, kind)); result } @@ -576,9 +580,10 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(path, Some(MacroNS), true, span) { + let path = path.iter().map(|p| respan(span, *p)).collect::>(); + match self.resolve_path(&path, Some(MacroNS), true, span) { PathResult::NonModule(_) => {}, - PathResult::Failed(msg, _) => { + PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } _ => unreachable!(), @@ -652,7 +657,7 @@ impl<'a> Resolver<'a> { } }; let ident = Ident::from_str(name); - self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro, span) + self.lookup_typo_candidate(&vec![respan(span, ident)], MacroNS, is_macro, span) }); if let Some(suggestion) = suggestion { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4bff5da3d6b09..5e799b14f209c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -21,9 +21,9 @@ use rustc::ty; use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE; use rustc::hir::def_id::DefId; use rustc::hir::def::*; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{Ident, NodeId}; +use syntax::ast::{Ident, SpannedIdent, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; use syntax::parse::token; @@ -57,7 +57,7 @@ pub enum ImportDirectiveSubclass<'a> { pub struct ImportDirective<'a> { pub id: NodeId, pub parent: Module<'a>, - pub module_path: Vec, + pub module_path: Vec, pub imported_module: Cell>>, // the resolution of `module_path` pub subclass: ImportDirectiveSubclass<'a>, pub span: Span, @@ -256,7 +256,7 @@ impl<'a> Resolver<'a> { // Add an import directive to the current module. pub fn add_import_directive(&mut self, - module_path: Vec, + module_path: Vec, subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, @@ -478,9 +478,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } let mut errors = false; + let mut seen_spans = FxHashSet(); for i in 0 .. self.determined_imports.len() { let import = self.determined_imports[i]; - if let Some(err) = self.finalize_import(import) { + if let Some((span, err)) = self.finalize_import(import) { errors = true; if let SingleImport { source, ref result, .. } = import.subclass { @@ -496,9 +497,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(import); - let path = import_path_to_string(&import.module_path, &import.subclass); - let error = ResolutionError::UnresolvedImport(Some((&path, &err))); - resolve_error(self.resolver, import.span, error); + if !seen_spans.contains(&span) { + let path = import_path_to_string(&import.module_path[..], + &import.subclass, + span); + let error = ResolutionError::UnresolvedImport(Some((span, &path, &err))); + resolve_error(self.resolver, span, error); + seen_spans.insert(span); + } } } @@ -516,7 +522,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { /// If successful, the resolved bindings are written into the module. fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool { debug!("(resolving import for module) resolving import `{}::...` in `{}`", - names_to_string(&directive.module_path), + names_to_string(&directive.module_path[..]), module_to_string(self.current_module)); self.current_module = directive.parent; @@ -528,7 +534,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::Invisible); - let result = self.resolve_path(&directive.module_path, None, false, directive.span); + let result = self.resolve_path(&directive.module_path[..], None, false, directive.span); directive.vis.set(vis); match result { @@ -593,23 +599,25 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } // If appropriate, returns an error to report. - fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option { + fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; let module_result = self.resolve_path(&module_path, None, true, span); let module = match module_result { PathResult::Module(module) => module, - PathResult::Failed(msg, _) => { + PathResult::Failed(span, msg, _) => { let (mut self_path, mut self_result) = (module_path.clone(), None); - if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() { - self_path[0].name = keywords::SelfValue.name(); + if !self_path.is_empty() && + !token::Ident(self_path[0].node).is_path_segment_keyword() + { + self_path[0].node.name = keywords::SelfValue.name(); self_result = Some(self.resolve_path(&self_path, None, false, span)); } return if let Some(PathResult::Module(..)) = self_result { - Some(format!("Did you mean `{}`?", names_to_string(&self_path))) + Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..])))) } else { - Some(msg) + Some((span, msg)) }; }, _ => return None, @@ -619,7 +627,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only), GlobImport { .. } if module.def_id() == directive.parent.def_id() => { // Importing a module into itself is not allowed. - return Some("Cannot glob-import a module into itself.".to_string()); + return Some((directive.span, + "Cannot glob-import a module into itself.".to_string())); } GlobImport { is_prelude, ref max_vis } => { if !is_prelude && @@ -708,7 +717,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } else { format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) }; - Some(msg) + Some((span, msg)) } else { // `resolve_ident_in_module` reported a privacy error. self.import_dummy_binding(directive); @@ -888,16 +897,24 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } -fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String { - let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name(); - let names = if global { &names[1..] } else { names }; - if names.is_empty() { - import_directive_subclass_to_string(subclass) +fn import_path_to_string(names: &[SpannedIdent], + subclass: &ImportDirectiveSubclass, + span: Span) -> String { + let pos = names.iter() + .position(|p| span == p.span && p.node.name != keywords::CrateRoot.name()); + let global = !names.is_empty() && names[0].node.name == keywords::CrateRoot.name(); + if let Some(pos) = pos { + let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] }; + names_to_string(names) } else { - (format!("{}::{}", - names_to_string(names), - import_directive_subclass_to_string(subclass))) - .to_string() + let names = if global { &names[1..] } else { names }; + if names.is_empty() { + import_directive_subclass_to_string(subclass) + } else { + (format!("{}::{}", + names_to_string(names), + import_directive_subclass_to_string(subclass))) + } } } diff --git a/src/test/compile-fail/dollar-crate-is-keyword-2.rs b/src/test/compile-fail/dollar-crate-is-keyword-2.rs index e221fc6e9e055..ac96279d61467 100644 --- a/src/test/compile-fail/dollar-crate-is-keyword-2.rs +++ b/src/test/compile-fail/dollar-crate-is-keyword-2.rs @@ -13,7 +13,7 @@ mod a {} macro_rules! m { () => { use a::$crate; //~ ERROR unresolved import `a::$crate` - use a::$crate::b; //~ ERROR unresolved import `a::$crate::b` + use a::$crate::b; //~ ERROR unresolved import `a::$crate` type A = a::$crate; //~ ERROR cannot find type `$crate` in module `a` } } diff --git a/src/test/compile-fail/import2.rs b/src/test/compile-fail/import2.rs index f5b03f9b2e971..c4bd9ff1e2abe 100644 --- a/src/test/compile-fail/import2.rs +++ b/src/test/compile-fail/import2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use baz::zed::bar; //~ ERROR unresolved import `baz::zed::bar` [E0432] +use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] //~^ Could not find `zed` in `baz` mod baz {} diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index 1375200271c55..f8a68264339b9 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -10,7 +10,7 @@ // Testing that we don't fail abnormally after hitting the errors -use unresolved::*; //~ ERROR unresolved import `unresolved::*` [E0432] +use unresolved::*; //~ ERROR unresolved import `unresolved` [E0432] //~^ Maybe a missing `extern crate unresolved;`? fn main() {} diff --git a/src/test/compile-fail/issue-30560.rs b/src/test/compile-fail/issue-30560.rs index b0cfd8714fc02..0b1afd75ca935 100644 --- a/src/test/compile-fail/issue-30560.rs +++ b/src/test/compile-fail/issue-30560.rs @@ -10,10 +10,10 @@ type Alias = (); use Alias::*; -//~^ ERROR unresolved import `Alias::*` [E0432] +//~^ ERROR unresolved import `Alias` [E0432] //~| Not a module `Alias` use std::io::Result::*; -//~^ ERROR unresolved import `std::io::Result::*` [E0432] +//~^ ERROR unresolved import `std::io::Result` [E0432] //~| Not a module `Result` trait T {} diff --git a/src/test/compile-fail/issue-33464.rs b/src/test/compile-fail/issue-33464.rs index 992bd33ea2e57..b7dbaf20ecae1 100644 --- a/src/test/compile-fail/issue-33464.rs +++ b/src/test/compile-fail/issue-33464.rs @@ -11,13 +11,10 @@ // Make sure that the spans of import errors are correct. use abc::one_el; -//~^ ERROR 13:5: 13:16 +//~^ ERROR 13:5: 13:8 use abc::{a, bbb, cccccc}; -//~^ ERROR 15:11: 15:12 -//~^^ ERROR 15:14: 15:17 -//~^^^ ERROR 15:19: 15:25 +//~^ ERROR 15:5: 15:8 use a_very_long_name::{el, el2}; -//~^ ERROR 19:24: 19:26 -//~^^ ERROR 19:28: 19:31 +//~^ ERROR 17:5: 17:21 fn main() {} diff --git a/src/test/compile-fail/resolve_self_super_hint.rs b/src/test/compile-fail/resolve_self_super_hint.rs index d49f136f11f31..099513484480b 100644 --- a/src/test/compile-fail/resolve_self_super_hint.rs +++ b/src/test/compile-fail/resolve_self_super_hint.rs @@ -13,19 +13,19 @@ mod a { extern crate alloc; use alloc::HashMap; - //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~^ ERROR unresolved import `alloc` [E0432] //~| Did you mean `self::alloc`? mod b { use alloc::HashMap; - //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~^ ERROR unresolved import `alloc` [E0432] //~| Did you mean `a::alloc`? mod c { use alloc::HashMap; - //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~^ ERROR unresolved import `alloc` [E0432] //~| Did you mean `a::alloc`? mod d { use alloc::HashMap; - //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~^ ERROR unresolved import `alloc` [E0432] //~| Did you mean `a::alloc`? } } diff --git a/src/test/compile-fail/super-at-top-level.rs b/src/test/compile-fail/super-at-top-level.rs index 7d11ff6c9b54d..4db673e2006f5 100644 --- a/src/test/compile-fail/super-at-top-level.rs +++ b/src/test/compile-fail/super-at-top-level.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::f; //~ ERROR unresolved import `super::f` [E0432] +use super::f; //~ ERROR unresolved import `super` [E0432] //~^ There are too many initial `super`s. fn main() { diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index 47490af0ff35e..a3eeb6de96bda 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -use foo::bar; //~ ERROR unresolved import `foo::bar` [E0432] +use foo::bar; //~ ERROR unresolved import `foo` [E0432] //~^ Maybe a missing `extern crate foo;`? use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] @@ -41,7 +41,7 @@ mod m { MyVariant } - use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432] + use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432] //~^ Did you mean `self::MyEnum`? } @@ -50,7 +50,7 @@ mod items { Variant } - use Enum::*; //~ ERROR unresolved import `Enum::*` [E0432] + use Enum::*; //~ ERROR unresolved import `Enum` [E0432] //~^ Did you mean `self::Enum`? fn item() {} diff --git a/src/test/compile-fail/use-from-trait-xc.rs b/src/test/compile-fail/use-from-trait-xc.rs index a40fa2337214e..3848b6814d9a5 100644 --- a/src/test/compile-fail/use-from-trait-xc.rs +++ b/src/test/compile-fail/use-from-trait-xc.rs @@ -22,13 +22,13 @@ use use_from_trait_xc::Trait::CONST; //~^ ERROR `CONST` is not directly importable use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private -//~^ ERROR unresolved import `use_from_trait_xc::Foo::new` +//~^ ERROR unresolved import `use_from_trait_xc::Foo` use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private -//~^ ERROR unresolved import `use_from_trait_xc::Foo::C` +//~^ ERROR unresolved import `use_from_trait_xc::Foo` use use_from_trait_xc::Bar::new as bnew; -//~^ ERROR unresolved import `use_from_trait_xc::Bar::new` +//~^ ERROR unresolved import `use_from_trait_xc::Bar` use use_from_trait_xc::Baz::new as baznew; //~^ ERROR unresolved import `use_from_trait_xc::Baz::new` diff --git a/src/test/compile-fail/use-from-trait.rs b/src/test/compile-fail/use-from-trait.rs index 33adc2b5bfe5a..29db949acd04a 100644 --- a/src/test/compile-fail/use-from-trait.rs +++ b/src/test/compile-fail/use-from-trait.rs @@ -17,11 +17,11 @@ use Trait::C; //~^ ERROR `C` is not directly importable use Foo::new; -//~^ ERROR unresolved import `Foo::new` [E0432] +//~^ ERROR unresolved import `Foo` [E0432] //~| Not a module `Foo` use Foo::C2; -//~^ ERROR unresolved import `Foo::C2` [E0432] +//~^ ERROR unresolved import `Foo` [E0432] //~| Not a module `Foo` pub trait Trait { diff --git a/src/test/compile-fail/use-mod-4.rs b/src/test/compile-fail/use-mod-4.rs index f102a68c2c5e2..275e5ff1da6ff 100644 --- a/src/test/compile-fail/use-mod-4.rs +++ b/src/test/compile-fail/use-mod-4.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use foo::self; //~ ERROR unresolved import `foo::self` +use foo::self; //~ ERROR unresolved import `foo` //~^ ERROR `self` imports are only allowed within a { } list use std::mem::self; diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index e4044f5aaf2be..5c3bb66d83a87 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -2,7 +2,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m` --> $DIR/macro_path_as_generic_bound.rs:17:6 | 17 | foo!(m::m2::A); - | ^^^^^^^^ Use of undeclared type or module `m` + | ^ Use of undeclared type or module `m` error: cannot continue compilation due to previous error diff --git a/src/test/ui/span/non-existing-module-import.rs b/src/test/ui/span/non-existing-module-import.rs new file mode 100644 index 0000000000000..3d45a94d531c1 --- /dev/null +++ b/src/test/ui/span/non-existing-module-import.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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 std::bar::{foo1, foo2}; + +fn main() {} diff --git a/src/test/ui/span/non-existing-module-import.stderr b/src/test/ui/span/non-existing-module-import.stderr new file mode 100644 index 0000000000000..93339576f4904 --- /dev/null +++ b/src/test/ui/span/non-existing-module-import.stderr @@ -0,0 +1,8 @@ +error[E0432]: unresolved import `std::bar` + --> $DIR/non-existing-module-import.rs:11:10 + | +11 | use std::bar::{foo1, foo2}; + | ^^^ Could not find `bar` in `std` + +error: aborting due to previous error +