diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 10598e78ec5cb..9d61feef81a80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -307,7 +307,7 @@ are: [gsearchdocs]: https://www.google.com/search?q=site:doc.rust-lang.org+your+query+here [rif]: http://internals.rust-lang.org [rr]: https://doc.rust-lang.org/book/README.html -[tlgba]: http://tomlee.co/2014/04/03/a-more-detailed-tour-of-the-rust-compiler/ +[tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/ [ro]: http://www.rustaceans.org/ [rctd]: ./COMPILER_TESTS.md [cheatsheet]: http://buildbot.rust-lang.org/homu/ diff --git a/src/doc/book/casting-between-types.md b/src/doc/book/casting-between-types.md index 7d03d2991abdc..7056a6c0f1708 100644 --- a/src/doc/book/casting-between-types.md +++ b/src/doc/book/casting-between-types.md @@ -165,10 +165,15 @@ Rust lets us: ```rust use std::mem; -unsafe { - let a = [0u8, 0u8, 0u8, 0u8]; - - let b = mem::transmute::<[u8; 4], u32>(a); +fn main() { + unsafe { + let a = [0u8, 1u8, 0u8, 0u8]; + let b = mem::transmute::<[u8; 4], u32>(a); + println!("{}", b); // 256 + // or, more concisely: + let c: u32 = mem::transmute(a); + println!("{}", c); // 256 + } } ``` diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 8ae23a646e488..ad34de9e3df97 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -31,6 +31,16 @@ // Since Rust doesn't actually have dependent types and polymorphic recursion, // we make do with lots of unsafety. +// A major goal of this module is to avoid complexity by treating the tree as a generic (if +// weirdly shaped) container and avoiding dealing with most of the B-Tree invariants. As such, +// this module doesn't care whether the entries are sorted, which nodes can be underfull, or +// even what underfull means. However, we do rely on a few invariants: +// +// - Trees must have uniform depth/height. This means that every path down to a leaf from a +// given node has exactly the same length. +// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. +// This implies that even an empty internal node has at least one edge. + use alloc::heap; use core::marker::PhantomData; use core::mem; @@ -43,17 +53,43 @@ use boxed::Box; const B: usize = 6; pub const CAPACITY: usize = 2 * B - 1; +/// The underlying representation of leaf nodes. Note that it is often unsafe to actually store +/// these, since only the first `len` keys and values are assumed to be initialized. As such, +/// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned +/// case. +/// +/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by +/// avoiding accidentally dropping unused and uninitialized keys and values. struct LeafNode { + /// The arrays storing the actual data of the node. Only the first `len` elements of each + /// array are initialized and valid. keys: [K; CAPACITY], vals: [V; CAPACITY], + + /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. + /// This either points to an actual node or is null. parent: *const InternalNode, + + /// This node's index into the parent node's `edges` array. + /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. + /// This is only guaranteed to be initialized when `parent` is nonnull. parent_idx: u16, + + /// The number of keys and values this node stores. + /// + /// This is at the end of the node's representation and next to `parent_idx` to encourage + /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space + /// overhead. len: u16, } impl LeafNode { + /// Creates a new `LeafNode`. Unsafe because all nodes should really be hidden behind + /// `BoxedNode`, preventing accidental dropping of uninitialized keys and values. unsafe fn new() -> Self { LeafNode { + // As a general policy, we leave fields uninitialized if they can be, as this should + // be both slightly faster and easier to track in Valgrind. keys: mem::uninitialized(), vals: mem::uninitialized(), parent: ptr::null(), @@ -63,15 +99,28 @@ impl LeafNode { } } -// We use repr(C) so that a pointer to an internal node can be -// directly used as a pointer to a leaf node +/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden +/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an +/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the +/// node, allowing code to act on leaf and internal nodes generically without having to even check +/// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. #[repr(C)] struct InternalNode { data: LeafNode, + + /// The pointers to the children of this node. `len + 1` of these are considered + /// initialized and valid. edges: [BoxedNode; 2 * B], } impl InternalNode { + /// Creates a new `InternalNode`. + /// + /// This is unsafe for two reasons. First, it returns an `InternalNode` by value, risking + /// dropping of uninitialized fields. Second, an invariant of internal nodes is that `len + 1` + /// edges are initialized and valid, meaning that even when the node is empty (having a + /// `len` of 0), there must be one initialized and valid edge. This function does not set up + /// such an edge. unsafe fn new() -> Self { InternalNode { data: LeafNode::new(), @@ -80,8 +129,12 @@ impl InternalNode { } } +/// An owned pointer to a node. This basically is either `Box>` or +/// `Box>`. However, it contains no information as to which of the two types +/// of nodes is acutally behind the box, and, partially due to this lack of information, has no +/// destructor. struct BoxedNode { - ptr: Unique> // we don't know if this points to a leaf node or an internal node + ptr: Unique> } impl BoxedNode { @@ -156,7 +209,7 @@ impl Root { } } - /// Add a new internal node with a single edge, pointing to the previous root, and make that + /// Adds a new internal node with a single edge, pointing to the previous root, and make that /// new node the root. This increases the height by 1 and is the opposite of `pop_level`. pub fn push_level(&mut self) -> NodeRef { @@ -180,7 +233,7 @@ impl Root { ret } - /// Remove the root node, using its first child as the new root. This cannot be called when + /// Removes the root node, using its first child as the new root. This cannot be called when /// the tree consists only of a leaf node. As it is intended only to be called when the root /// has only one edge, no cleanup is done on any of the other children are elements of the root. /// This decreases the height by 1 and is the opposite of `push_level`. @@ -229,6 +282,7 @@ impl Root { pub struct NodeRef { height: usize, node: NonZero<*const LeafNode>, + // This is null unless the borrow type is `Mut` root: *const Root, _marker: PhantomData<(BorrowType, Type)> } @@ -268,10 +322,14 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { impl NodeRef { + /// Finds the length of the node. This is the number of keys or values. In an + /// internal node, the number of edges is `len() + 1`. pub fn len(&self) -> usize { self.as_leaf().len as usize } + /// Removes any static information about whether this node is a `Leaf` or an + /// `Internal` node. pub fn forget_type(self) -> NodeRef { NodeRef { height: self.height, @@ -281,6 +339,7 @@ impl NodeRef { } } + /// Temporarily takes out another, immutable reference to the same node. fn reborrow<'a>(&'a self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, @@ -304,6 +363,13 @@ impl NodeRef { self.reborrow().into_slices().1 } + /// Finds the parent of the current node. Returns `Ok(handle)` if the current + /// node actually has a parent, where `handle` points to the edge of the parent + /// that points to the current node. Returns `Err(self)` if the current node has + /// no parent, giving back the original `NodeRef`. + /// + /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should + /// both, upon success, do nothing. pub fn ascend(self) -> Result< Handle< NodeRef< @@ -344,6 +410,9 @@ impl NodeRef { } impl NodeRef { + /// Similar to `ascend`, gets a reference to a node's parent node, but also + /// deallocate the current node in the process. This is unsafe because the + /// current node will still be accessible despite being deallocated. pub unsafe fn deallocate_and_ascend(self) -> Option< Handle< NodeRef< @@ -362,6 +431,9 @@ impl NodeRef { } impl NodeRef { + /// Similar to `ascend`, gets a reference to a node's parent node, but also + /// deallocate the current node in the process. This is unsafe because the + /// current node will still be accessible despite being deallocated. pub unsafe fn deallocate_and_ascend(self) -> Option< Handle< NodeRef< @@ -384,6 +456,8 @@ impl NodeRef { } impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// Unsafely asserts to the compiler some static information about whether this + /// node is a `Leaf`. unsafe fn cast_unchecked(&mut self) -> NodeRef { @@ -395,6 +469,16 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } } + /// Temporarily takes out another, mutable reference to the same node. Beware, as + /// this method is very dangerous, doubly so since it may not immediately appear + /// dangerous. + /// + /// Because mutable pointers can roam anywhere around the tree and can even (through + /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` + /// can easily be used to make the original mutable pointer dangling, or, in the case + /// of a reborrowed handle, out of bounds. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts + // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. unsafe fn reborrow_mut(&mut self) -> NodeRef { NodeRef { height: self.height, @@ -437,6 +521,8 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Gets a mutable reference to the root itself. This is useful primarily when the + /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. pub fn into_root_mut(self) -> &'a mut Root { unsafe { &mut *(self.root as *mut Root) @@ -460,6 +546,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } impl<'a, K, V> NodeRef, K, V, marker::Leaf> { + /// Adds a key/value pair the end of the node. pub fn push(&mut self, key: K, val: V) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() < CAPACITY); @@ -474,6 +561,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { self.as_leaf_mut().len += 1; } + /// Adds a key/value pair to the beginning of the node. pub fn push_front(&mut self, key: K, val: V) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() < CAPACITY); @@ -488,6 +576,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { } impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Adds a key/value pair and an edge to go to the right of that pair to + /// the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { // Necessary for correctness, but this is an internal module debug_assert!(edge.height == self.height - 1); @@ -506,6 +596,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { } } + /// Adds a key/value pair and an edge to go to the left of that pair to + /// the beginning of the node. pub fn push_front(&mut self, key: K, val: V, edge: Root) { // Necessary for correctness, but this is an internal module debug_assert!(edge.height == self.height - 1); @@ -534,6 +626,8 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { } impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { + /// Removes a key/value pair from the end of this node. If this is an internal node, + /// also removes the edge that was to the right of that pair. pub fn pop(&mut self) -> (K, V, Option>) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() > 0); @@ -558,6 +652,8 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } } + /// Removes a key/value pair from the beginning of this node. If this is an internal node, + /// also removes the edge that was to the left of that pair. pub fn pop_front(&mut self) -> (K, V, Option>) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() > 0); @@ -597,6 +693,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } impl NodeRef { + /// Checks whether a node is an `Internal` node or a `Leaf` node. pub fn force(self) -> ForceResult< NodeRef, NodeRef @@ -619,6 +716,14 @@ impl NodeRef { } } +/// A reference to a specific key/value pair or edge within a node. The `Node` parameter +/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key/value +/// pair) or `Edge` (signifying a handle on an edge). +/// +/// Note that even `Leaf` nodes can have `Edge` handles. Instead of representing a pointer to +/// a child node, these represent the spaces where child pointers would go between the key/value +/// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one +/// to the left of the node, one between the two pairs, and one at the right of the node. pub struct Handle { node: Node, idx: usize, @@ -626,6 +731,8 @@ pub struct Handle { } impl Copy for Handle { } +// We don't need the full generality of `#[derive(Clone)]`, as the only time `Node` will be +// `Clone`able is when it is an immutable reference and therefore `Copy`. impl Clone for Handle { fn clone(&self) -> Self { *self @@ -633,12 +740,14 @@ impl Clone for Handle { } impl Handle { + /// Retrieves the node that contains the edge of key/value pair this handle pointes to. pub fn into_node(self) -> Node { self.node } } impl Handle, marker::KV> { + /// Creates a new handle to a key/value pair in `node`. `idx` must be less than `node.len()`. pub fn new_kv(node: NodeRef, idx: usize) -> Self { // Necessary for correctness, but in a private module debug_assert!(idx < node.len()); @@ -670,6 +779,7 @@ impl PartialEq impl Handle, HandleType> { + /// Temporarily takes out another, immutable handle on the same location. pub fn reborrow(&self) -> Handle, HandleType> { @@ -685,6 +795,16 @@ impl impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeType>, HandleType> { + /// Temporarily takes out another, mutable handle on the same location. Beware, as + /// this method is very dangerous, doubly so since it may not immediately appear + /// dangerous. + /// + /// Because mutable pointers can roam anywhere around the tree and can even (through + /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` + /// can easily be used to make the original mutable pointer dangling, or, in the case + /// of a reborrowed handle, out of bounds. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts + // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. pub unsafe fn reborrow_mut(&mut self) -> Handle, HandleType> { @@ -700,6 +820,8 @@ impl<'a, K, V, NodeType, HandleType> impl Handle, marker::Edge> { + /// Creates a new handle to an edge in `node`. `idx` must be less than or equal to + /// `node.len()`. pub fn new_edge(node: NodeRef, idx: usize) -> Self { // Necessary for correctness, but in a private module debug_assert!(idx <= node.len()); @@ -733,6 +855,11 @@ impl } impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { + /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// this edge. This method assumes that there is enough space in the node for the new + /// pair to fit. + /// + /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); @@ -747,6 +874,10 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge } } + /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// this edge. This method splits the node if there isn't enough room. + /// + /// The returned pointer points to the inserted value. pub fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { @@ -774,6 +905,8 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::Edge> { + /// Fixes the parent pointer and index in the child node below this edge. This is useful + /// when the ordering of edges has been changed, such as in the various `insert` methods. fn correct_parent_link(mut self) { let idx = self.idx as u16; let ptr = self.node.as_internal_mut() as *mut _; @@ -782,18 +915,24 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: child.as_leaf_mut().parent_idx = idx; } + /// Unsafely asserts to the compiler some static information about whether the underlying + /// node of this handle is a `Leaf`. unsafe fn cast_unchecked(&mut self) -> Handle, marker::Edge> { Handle::new_edge(self.node.cast_unchecked(), self.idx) } + /// Inserts a new key/value pair and an edge that will go to the right of that new pair + /// between this edge and the key/value pair to the right of this edge. This method assumes + /// that there is enough space in the node for the new pair to fit. fn insert_fit(&mut self, key: K, val: V, edge: Root) { // Necessary for correctness, but in an internal module debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); unsafe { + // This cast is a lie, but it allows us to reuse the key/value insertion logic. self.cast_unchecked::().insert_fit(key, val); slice_insert( @@ -811,6 +950,9 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } + /// Inserts a new key/value pair and an edge that will go to the right of that new pair + /// between this edge and the key/value pair to the right of this edge. This method splits + /// the node if there isn't enough room. pub fn insert(mut self, key: K, val: V, edge: Root) -> InsertResult<'a, K, V, marker::Internal> { @@ -843,6 +985,10 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: impl Handle, marker::Edge> { + /// Finds the node pointed to by this edge. + /// + /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should + /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { NodeRef { height: self.node.height - 1, @@ -885,6 +1031,13 @@ impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker } impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the key/value pairs to the right of + /// this handle. + /// - The key and value pointed to by this handle and extracted. + /// - All the key/value pairs to the right of this handle are put into a newly + /// allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { unsafe { @@ -920,6 +1073,8 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> } } + /// Removes the key/value pair pointed to by this handle, returning the edge between the + /// now adjacent key/value pairs to the left and right of this handle. pub fn remove(mut self) -> (Handle, K, V, marker::Leaf>, marker::Edge>, K, V) { unsafe { @@ -932,6 +1087,13 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the edges and key/value pairs to the + /// right of this handle. + /// - The key and value pointed to by this handle and extracted. + /// - All the edges and key/value pairs to the right of this handle are put into + /// a newly allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Internal>, K, V, Root) { unsafe { @@ -979,6 +1141,9 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } + /// Returns whether it is valid to call `.merge()`, i.e., whether there is enough room in + /// a node to hold the combination of the nodes to the left and right of this handle along + /// with the key/value pair at this handle. pub fn can_merge(&self) -> bool { ( self.reborrow() @@ -993,6 +1158,11 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: ) <= CAPACITY } + /// Combines the node immediately to the left of this handle, the key/value pair pointed + /// to by this handle, and the node immediately to the right of this handle into one new + /// child of the underlying node, returning an edge referencing that new child. + /// + /// Assumes that this edge `.can_merge()`. pub fn merge(mut self) -> Handle, K, V, marker::Internal>, marker::Edge> { let self1 = unsafe { ptr::read(&self) }; @@ -1068,6 +1238,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: impl Handle, HandleType> { + /// Check whether the underlying node is an `Internal` node or a `Leaf` node. pub fn force(self) -> ForceResult< Handle, HandleType>, Handle, HandleType> diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f0bbe9672ab8c..589ac90b308ad 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -38,9 +38,23 @@ use slice::SliceExt; /// all standard arithmetic operations on the underlying value are /// intended to have wrapping semantics. #[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_display", since = "1.10.0")] +impl fmt::Display for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + mod wrapping; // All these modules are technically private and only exposed for libcoretest: diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a6b5355d94786..a3c7ab481a765 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -119,6 +119,17 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `src` is not used before the data is overwritten again (e.g. with `write`, /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use /// because it will attempt to drop the value previously at `*src`. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let x = 12; +/// let y = &x as *const i32; +/// +/// unsafe { println!("{}", std::ptr::read(y)); } +/// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -155,6 +166,21 @@ pub unsafe fn read_and_drop(dest: *mut T) -> T { /// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; +/// +/// unsafe { +/// std::ptr::write(y, z); +/// println!("{}", std::ptr::read(y)); +/// } +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -185,6 +211,17 @@ pub unsafe fn write(dst: *mut T, src: T) { /// `src` is not used before the data is overwritten again (e.g. with `write`, /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use /// because it will attempt to drop the value previously at `*src`. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let x = 12; +/// let y = &x as *const i32; +/// +/// unsafe { println!("{}", std::ptr::read_volatile(y)); } +/// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn read_volatile(src: *const T) -> T { @@ -217,6 +254,21 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; +/// +/// unsafe { +/// std::ptr::write_volatile(y, z); +/// println!("{}", std::ptr::read_volatile(y)); +/// } +/// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn write_volatile(dst: *mut T, src: T) { diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index cf477c2a956aa..217445715a81b 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -12,5 +12,4 @@ crate-type = ["dylib"] log = { path = "../liblog" } syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } -rustc_bitflags = { path = "../librustc_bitflags" } arena = { path = "../libarena" } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 2bec7725b76b7..2547c756b9d6a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -13,7 +13,6 @@ //! Here we build the "reduced graph": the graph of the module tree without //! any imports resolved. -use DefModifiers; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; use Module; use Namespace::{self, TypeNS, ValueNS}; @@ -28,9 +27,9 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty::{self, VariantKind}; -use syntax::ast::Name; +use syntax::ast::{Name, NodeId}; use syntax::attr::AttrMetaMethods; -use syntax::parse::token::{special_idents, SELF_KEYWORD_NAME, SUPER_KEYWORD_NAME}; +use syntax::parse::token::keywords; use syntax::codemap::{Span, DUMMY_SP}; use rustc::hir; @@ -53,10 +52,9 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, Span) { } } -impl<'a> ToNameBinding<'a> for (Def, Span, DefModifiers, ty::Visibility) { +impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { fn to_name_binding(self) -> NameBinding<'a> { - let kind = NameBindingKind::Def(self.0); - NameBinding { modifiers: self.2, kind: kind, span: Some(self.1), vis: self.3 } + NameBinding { kind: NameBindingKind::Def(self.0), span: Some(self.1), vis: self.2 } } } @@ -100,12 +98,42 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { block.stmts.iter().any(is_item) } + fn sanity_check_import(&self, view_path: &hir::ViewPath, id: NodeId) { + let path = match view_path.node { + ViewPathSimple(_, ref path) | + ViewPathGlob (ref path) | + ViewPathList(ref path, _) => path + }; + + // Check for type parameters + let found_param = path.segments.iter().any(|segment| { + !segment.parameters.types().is_empty() || + !segment.parameters.lifetimes().is_empty() || + !segment.parameters.bindings().is_empty() + }); + if found_param { + self.session.span_err(path.span, + "type or lifetime parameter is found in import path"); + } + + // Checking for special identifiers in path + // prevent `self` or `super` at beginning of global path + if path.global && path.segments.len() > 0 { + let first = path.segments[0].identifier.name; + if first == keywords::Super.to_name() || first == keywords::SelfValue.to_name() { + self.session.add_lint( + lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, id, path.span, + format!("expected identifier, found keyword `{}`", first) + ); + } + } + } + /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) { let parent = *parent_ref; let name = item.name; let sp = item.span; - let modifiers = DefModifiers::IMPORTABLE; self.current_module = parent; let vis = self.resolve_visibility(&item.vis); @@ -114,10 +142,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - let is_global; let module_path: Vec = match view_path.node { ViewPathSimple(_, ref full_path) => { - is_global = full_path.global; full_path.segments .split_last() .unwrap() @@ -129,7 +155,6 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ViewPathGlob(ref module_ident_path) | ViewPathList(ref module_ident_path, _) => { - is_global = module_ident_path.global; module_ident_path.segments .iter() .map(|seg| seg.identifier.name) @@ -137,22 +162,10 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { } }; - // Checking for special identifiers in path - // prevent `self` or `super` at beginning of global path - if is_global && (module_path.first() == Some(&SELF_KEYWORD_NAME) || - module_path.first() == Some(&SUPER_KEYWORD_NAME)) { - self.session.add_lint( - lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, - item.id, - item.span, - format!("expected identifier, found keyword `{}`", - module_path.first().unwrap().as_str())); - } + self.sanity_check_import(view_path, item.id); // Build up the import directives. - let is_prelude = item.attrs.iter().any(|attr| { - attr.name() == special_idents::prelude_import.name.as_str() - }); + let is_prelude = item.attrs.iter().any(|attr| attr.name() == "prelude_import"); match view_path.node { ViewPathSimple(binding, ref full_path) => { @@ -268,21 +281,21 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ItemStatic(_, m, _) => { let mutbl = m == hir::MutMutable; let def = Def::Static(self.ast_map.local_def_id(item.id), mutbl); - self.define(parent, name, ValueNS, (def, sp, modifiers, vis)); + self.define(parent, name, ValueNS, (def, sp, vis)); } ItemConst(_, _) => { let def = Def::Const(self.ast_map.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, modifiers, vis)); + self.define(parent, name, ValueNS, (def, sp, vis)); } ItemFn(_, _, _, _, _, _) => { let def = Def::Fn(self.ast_map.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, modifiers, vis)); + self.define(parent, name, ValueNS, (def, sp, vis)); } // These items live in the type namespace. ItemTy(..) => { let def = Def::TyAlias(self.ast_map.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, modifiers, vis)); + self.define(parent, name, TypeNS, (def, sp, vis)); } ItemEnum(ref enum_definition, _) => { @@ -301,13 +314,13 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ItemStruct(ref struct_def, _) => { // Define a name in the type namespace. let def = Def::Struct(self.ast_map.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, modifiers, vis)); + self.define(parent, name, TypeNS, (def, sp, vis)); // If this is a newtype or unit-like struct, define a name // in the value namespace as well if !struct_def.is_struct() { let def = Def::Struct(self.ast_map.local_def_id(struct_def.id())); - self.define(parent, name, ValueNS, (def, sp, modifiers, vis)); + self.define(parent, name, ValueNS, (def, sp, vis)); } // Record the def ID and fields of this struct. @@ -339,8 +352,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { hir::TypeTraitItem(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS), }; - let modifiers = DefModifiers::empty(); // NB: not DefModifiers::IMPORTABLE - self.define(module_parent, item.name, ns, (def, item.span, modifiers, vis)); + self.define(module_parent, item.name, ns, (def, item.span, vis)); self.trait_item_map.insert((item.name, def_id), item_def_id); } @@ -363,11 +375,9 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. - let modifiers = DefModifiers::IMPORTABLE; let def = Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())); - - self.define(parent, name, ValueNS, (def, variant.span, modifiers, parent.vis)); - self.define(parent, name, TypeNS, (def, variant.span, modifiers, parent.vis)); + self.define(parent, name, ValueNS, (def, variant.span, parent.vis)); + self.define(parent, name, TypeNS, (def, variant.span, parent.vis)); } /// Constructs the reduced graph for one foreign item. @@ -375,7 +385,6 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { foreign_item: &ForeignItem, parent: Module<'b>) { let name = foreign_item.name; - let modifiers = DefModifiers::IMPORTABLE; let def = match foreign_item.node { ForeignItemFn(..) => { @@ -387,7 +396,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { }; self.current_module = parent; let vis = self.resolve_visibility(&foreign_item.vis); - self.define(parent, name, ValueNS, (def, foreign_item.span, modifiers, vis)); + self.define(parent, name, ValueNS, (def, foreign_item.span, vis)); } fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'b>) { @@ -422,10 +431,6 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { let name = xcdef.name; let vis = if parent.is_trait() { ty::Visibility::Public } else { xcdef.vis }; - let modifiers = match parent.is_normal() { - true => DefModifiers::IMPORTABLE, - false => DefModifiers::empty(), - }; match def { Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => { @@ -439,9 +444,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { debug!("(building reduced graph for external crate) building variant {}", name); // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. - let modifiers = DefModifiers::IMPORTABLE; - self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis)); - self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis)); + self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) { // Not adding fields for variants as they are not accessed with a self receiver self.structs.insert(variant_id, Vec::new()); @@ -454,7 +458,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { Def::Method(..) => { debug!("(building reduced graph for external crate) building value (fn/static) {}", name); - self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis)); + self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } Def::Trait(def_id) => { debug!("(building reduced graph for external crate) building type {}", name); @@ -480,16 +484,16 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { } Def::TyAlias(..) | Def::AssociatedTy(..) => { debug!("(building reduced graph for external crate) building type {}", name); - self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis)); + self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); } Def::Struct(def_id) if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => { debug!("(building reduced graph for external crate) building type and value for {}", name); - self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis)); + self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) { let def = Def::Struct(ctor_def_id); - self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis)); + self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } // Record the def ID and fields of this struct. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2147331d441d9..f32cf7aa9f41a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -29,9 +29,6 @@ extern crate log; extern crate syntax; extern crate arena; #[macro_use] -#[no_link] -extern crate rustc_bitflags; -#[macro_use] extern crate rustc; use self::PatternBindingMode::*; @@ -915,18 +912,9 @@ impl<'a> fmt::Debug for ModuleS<'a> { } } -bitflags! { - #[derive(Debug)] - flags DefModifiers: u8 { - const IMPORTABLE = 1 << 1, - const GLOB_IMPORTED = 1 << 3, - } -} - // Records a possibly-private value, type, or module definition. #[derive(Clone, Debug)] pub struct NameBinding<'a> { - modifiers: DefModifiers, kind: NameBindingKind<'a>, span: Option, vis: ty::Visibility, @@ -938,7 +926,7 @@ enum NameBindingKind<'a> { Module(Module<'a>), Import { binding: &'a NameBinding<'a>, - id: NodeId, + directive: &'a ImportDirective<'a>, // Some(error) if using this imported name causes the import to be a privacy error privacy_error: Option>>, }, @@ -950,7 +938,6 @@ struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); impl<'a> NameBinding<'a> { fn create_from_module(module: Module<'a>, span: Option) -> Self { NameBinding { - modifiers: DefModifiers::IMPORTABLE, kind: NameBindingKind::Module(module), span: span, vis: module.vis, @@ -973,10 +960,6 @@ impl<'a> NameBinding<'a> { } } - fn defined_with(&self, modifiers: DefModifiers) -> bool { - self.modifiers.contains(modifiers) - } - fn is_pseudo_public(&self) -> bool { self.pseudo_vis() == ty::Visibility::Public } @@ -1003,6 +986,20 @@ impl<'a> NameBinding<'a> { _ => false, } } + + fn is_glob_import(&self) -> bool { + match self.kind { + NameBindingKind::Import { directive, .. } => directive.is_glob(), + _ => false, + } + } + + fn is_importable(&self) -> bool { + match self.def().unwrap() { + Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false, + _ => true, + } + } } /// Interns the names of the primitive types. @@ -1228,12 +1225,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.used_crates.insert(krate); } - let (import_id, privacy_error) = match binding.kind { - NameBindingKind::Import { id, ref privacy_error, .. } => (id, privacy_error), + let (directive, privacy_error) = match binding.kind { + NameBindingKind::Import { directive, ref privacy_error, .. } => + (directive, privacy_error), _ => return, }; - self.used_imports.insert((import_id, ns)); + self.used_imports.insert((directive.id, ns)); if let Some(error) = privacy_error.as_ref() { self.privacy_errors.push((**error).clone()); } @@ -1241,14 +1239,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !self.make_glob_map { return; } - if self.glob_map.contains_key(&import_id) { - self.glob_map.get_mut(&import_id).unwrap().insert(name); + if self.glob_map.contains_key(&directive.id) { + self.glob_map.get_mut(&directive.id).unwrap().insert(name); return; } let mut new_set = FnvHashSet(); new_set.insert(name); - self.glob_map.insert(import_id, new_set); + self.glob_map.insert(directive.id, new_set); } fn get_trait_name(&self, did: DefId) -> Name { @@ -2408,7 +2406,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } - } else { + } else if let Err(false) = self.resolve_path(pat_id, &path, 0, ValueNS) { resolve_error( self, path.span, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e712dbdcbf7af..03492043dd449 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,7 +10,6 @@ use self::ImportDirectiveSubclass::*; -use DefModifiers; use Module; use Namespace::{self, TypeNS, ValueNS}; use {NameBinding, NameBindingKind, PrivacyError}; @@ -59,11 +58,11 @@ impl ImportDirectiveSubclass { /// One import directive. #[derive(Debug,Clone)] pub struct ImportDirective<'a> { + pub id: NodeId, module_path: Vec, target_module: Cell>>, // the resolution of `module_path` subclass: ImportDirectiveSubclass, span: Span, - id: NodeId, vis: ty::Visibility, // see note in ImportResolutionPerNamespace about how to use this is_prelude: bool, } @@ -71,24 +70,22 @@ pub struct ImportDirective<'a> { impl<'a> ImportDirective<'a> { // Given the binding to which this directive resolves in a particular namespace, // this returns the binding for the name this directive defines in that namespace. - fn import(&self, binding: &'a NameBinding<'a>, privacy_error: Option>>) + fn import(&'a self, binding: &'a NameBinding<'a>, privacy_error: Option>>) -> NameBinding<'a> { - let mut modifiers = DefModifiers::IMPORTABLE; - if let GlobImport = self.subclass { - modifiers = modifiers | DefModifiers::GLOB_IMPORTED; - } - NameBinding { kind: NameBindingKind::Import { binding: binding, - id: self.id, + directive: self, privacy_error: privacy_error, }, span: Some(self.span), - modifiers: modifiers, vis: self.vis, } } + + pub fn is_glob(&self) -> bool { + match self.subclass { ImportDirectiveSubclass::GlobImport => true, _ => false } + } } #[derive(Clone, Default)] @@ -141,9 +138,9 @@ impl<'a> SingleImports<'a> { impl<'a> NameResolution<'a> { fn try_define(&mut self, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { if let Some(old_binding) = self.binding { - if binding.defined_with(DefModifiers::GLOB_IMPORTED) { + if binding.is_glob_import() { self.duplicate_globs.push(binding); - } else if old_binding.defined_with(DefModifiers::GLOB_IMPORTED) { + } else if old_binding.is_glob_import() { self.duplicate_globs.push(old_binding); self.binding = Some(binding); } else { @@ -160,7 +157,7 @@ impl<'a> NameResolution<'a> { fn binding(&self) -> Option<&'a NameBinding<'a>> { self.binding.and_then(|binding| match self.single_imports { SingleImports::None => Some(binding), - _ if !binding.defined_with(DefModifiers::GLOB_IMPORTED) => Some(binding), + _ if !binding.is_glob_import() => Some(binding), _ => None, // The binding could be shadowed by a single import, so it is not known. }) } @@ -170,7 +167,7 @@ impl<'a> NameResolution<'a> { fn try_result(&self, ns: Namespace, allow_private_imports: bool) -> Option>> { match self.binding { - Some(binding) if !binding.defined_with(DefModifiers::GLOB_IMPORTED) => + Some(binding) if !binding.is_glob_import() => return Some(Success(binding)), _ => {} // Items and single imports are not shadowable }; @@ -337,7 +334,7 @@ impl<'a> ::ModuleS<'a> { } fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { - if !binding.defined_with(DefModifiers::IMPORTABLE) || !binding.is_pseudo_public() { return } + if !binding.is_importable() || !binding.is_pseudo_public() { return } for &(importer, directive) in self.glob_importers.borrow_mut().iter() { let _ = importer.try_define_child(name, ns, directive.import(binding, None)); } @@ -410,7 +407,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // resolution for it so that later resolve stages won't complain. if let SingleImport { target, .. } = e.import_directive.subclass { let dummy_binding = self.resolver.arenas.alloc_name_binding(NameBinding { - modifiers: DefModifiers::GLOB_IMPORTED, kind: NameBindingKind::Def(Def::Err), span: None, vis: ty::Visibility::Public, @@ -517,7 +513,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { determined.set(true); if let Success(binding) = *result { - if !binding.defined_with(DefModifiers::IMPORTABLE) { + if !binding.is_importable() { let msg = format!("`{}` is not directly importable", target); span_err!(self.resolver.session, directive.span, E0253, "{}", &msg); } @@ -662,7 +658,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { - if binding.defined_with(DefModifiers::IMPORTABLE) && binding.is_pseudo_public() { + if binding.is_importable() && binding.is_pseudo_public() { let _ = module_.try_define_child(name, ns, directive.import(binding, None)); } } @@ -705,14 +701,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } } - if let NameBindingKind::Import { binding: orig_binding, id, .. } = binding.kind { + if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { if ns == TypeNS && orig_binding.is_variant() && !orig_binding.vis.is_at_least(binding.vis, &self.resolver.ast_map) { let msg = format!("variant `{}` is private, and cannot be reexported \ (error E0364), consider declaring its enum as `pub`", name); let lint = lint::builtin::PRIVATE_IN_PUBLIC; - self.resolver.session.add_lint(lint, id, binding.span.unwrap(), msg); + self.resolver.session.add_lint(lint, directive.id, binding.span.unwrap(), msg); } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1cfbfb37d34bd..646efe09da81e 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2717,7 +2717,7 @@ Rust does not currently support this. A simple example that causes this error: ```compile_fail fn main() { - let _: Box; + let _: Box; } ``` @@ -2727,7 +2727,7 @@ following compiles correctly: ``` fn main() { - let _: Box; + let _: Box; } ``` "##, diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 6fc26bb7eed71..624748f352ee1 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -1030,7 +1030,7 @@ impl f32 { /// let abs_difference_1 = (f.1 - x.cos()).abs(); /// /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_0 <= f32::EPSILON); + /// assert!(abs_difference_1 <= f32::EPSILON); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 93e5969a275c3..6515301aefd14 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -903,7 +903,7 @@ impl f64 { /// let abs_difference_1 = (f.1 - x.cos()).abs(); /// /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_1 < 1e-10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d0047e743c303..f3d3bbd9f9905 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -81,6 +81,8 @@ type ItemInfo = (Ident, ItemKind, Option >); pub enum PathParsingMode { /// A path with no type parameters; e.g. `foo::bar::Baz` NoTypesAllowed, + /// Same as `NoTypesAllowed`, but may end with `::{` or `::*`, which are left unparsed + ImportPrefix, /// A path with a lifetime and type parameters, with no double colons /// before the type parameters; e.g. `foo::bar<'a>::Baz` LifetimeAndTypesWithoutColons, @@ -591,20 +593,6 @@ impl<'a> Parser<'a> { } } - pub fn parse_path_list_item(&mut self) -> PResult<'a, ast::PathListItem> { - let lo = self.span.lo; - let node = if self.eat_keyword(keywords::SelfValue) { - let rename = self.parse_rename()?; - ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename } - } else { - let ident = self.parse_ident()?; - let rename = self.parse_rename()?; - ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID } - }; - let hi = self.last_span.hi; - Ok(spanned(lo, hi, node)) - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -1763,8 +1751,8 @@ impl<'a> Parser<'a> { LifetimeAndTypesWithColons => { self.parse_path_segments_with_colons()? } - NoTypesAllowed => { - self.parse_path_segments_without_types()? + NoTypesAllowed | ImportPrefix => { + self.parse_path_segments_without_types(mode == ImportPrefix)? } }; path.segments.extend(segments); @@ -1801,8 +1789,8 @@ impl<'a> Parser<'a> { LifetimeAndTypesWithColons => { self.parse_path_segments_with_colons()? } - NoTypesAllowed => { - self.parse_path_segments_without_types()? + NoTypesAllowed | ImportPrefix => { + self.parse_path_segments_without_types(mode == ImportPrefix)? } }; @@ -1920,7 +1908,8 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` - pub fn parse_path_segments_without_types(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_types(&mut self, import_prefix: bool) + -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. @@ -1932,9 +1921,11 @@ impl<'a> Parser<'a> { parameters: ast::PathParameters::none() }); - // If we do not see a `::`, stop. - if !self.eat(&token::ModSep) { + // If we do not see a `::` or see `::{`/`::*`, stop. + if !self.check(&token::ModSep) || import_prefix && self.is_import_coupler() { return Ok(segments); + } else { + self.bump(); } } } @@ -6127,106 +6118,67 @@ impl<'a> Parser<'a> { self.parse_item_(attrs, true, false) } + fn parse_path_list_items(&mut self) -> PResult<'a, Vec> { + self.parse_unspanned_seq(&token::OpenDelim(token::Brace), + &token::CloseDelim(token::Brace), + SeqSep::trailing_allowed(token::Comma), |this| { + let lo = this.span.lo; + let node = if this.eat_keyword(keywords::SelfValue) { + let rename = this.parse_rename()?; + ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename } + } else { + let ident = this.parse_ident()?; + let rename = this.parse_rename()?; + ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID } + }; + let hi = this.last_span.hi; + Ok(spanned(lo, hi, node)) + }) + } + + /// `::{` or `::*` + fn is_import_coupler(&mut self) -> bool { + self.check(&token::ModSep) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) || + *t == token::BinOp(token::Star)) + } - /// Matches view_path : MOD? non_global_path as IDENT - /// | MOD? non_global_path MOD_SEP LBRACE RBRACE - /// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE - /// | MOD? non_global_path MOD_SEP STAR - /// | MOD? non_global_path + /// Matches ViewPath: + /// MOD_SEP? non_global_path + /// MOD_SEP? non_global_path as IDENT + /// MOD_SEP? non_global_path MOD_SEP STAR + /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE + /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P> { let lo = self.span.lo; - - // Allow a leading :: because the paths are absolute either way. - // This occurs with "use $crate::..." in macros. - let is_global = self.eat(&token::ModSep); - - if self.check(&token::OpenDelim(token::Brace)) { - // use {foo,bar} - let idents = self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_path_list_item())?; - let path = ast::Path { + if self.check(&token::OpenDelim(token::Brace)) || self.is_import_coupler() { + // `{foo, bar}` or `::{foo, bar}` + let prefix = ast::Path { + global: self.eat(&token::ModSep), + segments: Vec::new(), span: mk_sp(lo, self.span.hi), - global: is_global, - segments: Vec::new() }; - return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents)))); - } - - let first_ident = self.parse_ident()?; - let mut path = vec!(first_ident); - if let token::ModSep = self.token { - // foo::bar or foo::{a,b,c} or foo::* - while self.check(&token::ModSep) { + let items = self.parse_path_list_items()?; + Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + } else { + let prefix = self.parse_path(ImportPrefix)?; + if self.is_import_coupler() { + // `foo::bar::{a, b}` or `foo::bar::*` self.bump(); - - match self.token { - token::Ident(..) => { - let ident = self.parse_ident()?; - path.push(ident); - } - - // foo::bar::{a,b,c} - token::OpenDelim(token::Brace) => { - let idents = self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_path_list_item() - )?; - let path = ast::Path { - span: mk_sp(lo, self.span.hi), - global: is_global, - segments: path.into_iter().map(|identifier| { - ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - } - }).collect() - }; - return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents)))); - } - - // foo::bar::* - token::BinOp(token::Star) => { + if self.check(&token::BinOp(token::Star)) { self.bump(); - let path = ast::Path { - span: mk_sp(lo, self.span.hi), - global: is_global, - segments: path.into_iter().map(|identifier| { - ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - } - }).collect() - }; - return Ok(P(spanned(lo, self.span.hi, ViewPathGlob(path)))); - } - - // fall-through for case foo::bar::; - token::Semi => { - self.span_err(self.span, "expected identifier or `{` or `*`, found `;`"); - } - - _ => break + Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix)))) + } else { + let items = self.parse_path_list_items()?; + Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) } + } else { + // `foo::bar` or `foo::bar as baz` + let rename = self.parse_rename()?. + unwrap_or(prefix.segments.last().unwrap().identifier); + Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename, prefix)))) } } - let mut rename_to = path[path.len() - 1]; - let path = ast::Path { - span: mk_sp(lo, self.last_span.hi), - global: is_global, - segments: path.into_iter().map(|identifier| { - ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - } - }).collect() - }; - rename_to = self.parse_rename()?.unwrap_or(rename_to); - Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))) } fn parse_rename(&mut self) -> PResult<'a, Option> { diff --git a/src/test/compile-fail/import-prefix-macro-1.rs b/src/test/compile-fail/import-prefix-macro-1.rs new file mode 100644 index 0000000000000..beb15a11a9695 --- /dev/null +++ b/src/test/compile-fail/import-prefix-macro-1.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +mod a { + pub mod b { + pub mod c { + pub struct S; + pub struct Z; + } + } +} + +macro_rules! import { + ($p: path) => (use $p {S, Z}); //~ERROR expected one of `::`, `;`, or `as`, found `{` +} + +import! { a::b::c } + +fn main() {} diff --git a/src/test/compile-fail/import-prefix-macro-2.rs b/src/test/compile-fail/import-prefix-macro-2.rs new file mode 100644 index 0000000000000..56c6273aa9a29 --- /dev/null +++ b/src/test/compile-fail/import-prefix-macro-2.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +mod a { + pub mod b { + pub mod c { + pub struct S; + pub struct Z; + } + } +} + +macro_rules! import { + ($p: path) => (use ::$p {S, Z}); //~ERROR expected identifier, found `a::b::c` +} + +import! { a::b::c } + +fn main() {} diff --git a/src/test/compile-fail/import-ty-params.rs b/src/test/compile-fail/import-ty-params.rs new file mode 100644 index 0000000000000..66d4d6d06211d --- /dev/null +++ b/src/test/compile-fail/import-ty-params.rs @@ -0,0 +1,25 @@ +// Copyright 2016 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. + +mod a { + pub mod b { + pub mod c { + pub struct S(T); + } + } +} + +macro_rules! import { + ($p: path) => (use $p;); +} + +import! { a::b::c::S } //~ERROR type or lifetime parameter is found in import path + +fn main() {} diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index 9ebdcf1a9ecb0..9b67595800320 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -42,4 +42,8 @@ fn main() { //~^ ERROR mismatched types //~| expected `char` //~| found `bool` + + match () { + E::V => {} //~ ERROR failed to resolve. Use of undeclared type or module `E` + } } diff --git a/src/test/compile-fail/self_type_keyword-2.rs b/src/test/compile-fail/self_type_keyword-2.rs new file mode 100644 index 0000000000000..613f54eb33134 --- /dev/null +++ b/src/test/compile-fail/self_type_keyword-2.rs @@ -0,0 +1,13 @@ +// Copyright 2015 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 self::Self as Foo; //~ ERROR unresolved import `self::Self` + +pub fn main() {} diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs index 6296673787407..b28f48bb1056e 100644 --- a/src/test/compile-fail/self_type_keyword.rs +++ b/src/test/compile-fail/self_type_keyword.rs @@ -39,9 +39,6 @@ pub fn main() { } } -use self::Self as Foo; -//~^ ERROR expected identifier, found keyword `Self` - use std::option::Option as Self; //~^ ERROR expected identifier, found keyword `Self` diff --git a/src/test/parse-fail/use-ends-with-mod-sep.rs b/src/test/parse-fail/use-ends-with-mod-sep.rs index 143886e23377f..e6a10d43e2994 100644 --- a/src/test/parse-fail/use-ends-with-mod-sep.rs +++ b/src/test/parse-fail/use-ends-with-mod-sep.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -use std::any::; //~ ERROR expected identifier or `{` or `*`, found `;` +use std::any::; //~ ERROR expected identifier, found `;` diff --git a/src/test/run-pass/import-prefix-macro.rs b/src/test/run-pass/import-prefix-macro.rs new file mode 100644 index 0000000000000..cfe4ff78e6258 --- /dev/null +++ b/src/test/run-pass/import-prefix-macro.rs @@ -0,0 +1,35 @@ +// Copyright 2016 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. + +mod a { + pub mod b { + pub mod c { + pub struct S; + pub struct Z; + } + pub struct W; + } +} + +macro_rules! import { + (1 $p: path) => (use $p;); + (2 $p: path) => (use $p::{Z};); + (3 $p: path) => (use $p::*;); +} + +import! { 1 a::b::c::S } +import! { 2 a::b::c } +import! { 3 a::b } + +fn main() { + let s = S; + let z = Z; + let w = W; +}