diff options
61 files changed, 579 insertions, 184 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index c64cbb9a74e..175e32125f2 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -38,13 +38,19 @@ fn main() { // is passed (a bit janky...) let target = args.windows(2).find(|w| &*w[0] == "--target") .and_then(|w| w[1].to_str()); + let version = args.iter().find(|w| &**w == "-vV"); // Build scripts always use the snapshot compiler which is guaranteed to be // able to produce an executable, whereas intermediate compilers may not // have the standard library built yet and may not be able to produce an // executable. Otherwise we just use the standard compiler we're // bootstrapping with. - let (rustc, libdir) = if target.is_none() { + // + // Also note that cargo will detect the version of the compiler to trigger + // a rebuild when the compiler changes. If this happens, we want to make + // sure to use the actual compiler instead of the snapshot compiler becase + // that's the one that's actually changing. + let (rustc, libdir) = if target.is_none() && version.is_none() { ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") } else { ("RUSTC_REAL", "RUSTC_LIBDIR") diff --git a/src/doc/book/borrow-and-asref.md b/src/doc/book/borrow-and-asref.md index 1cfeb2620bd..c30b2e68665 100644 --- a/src/doc/book/borrow-and-asref.md +++ b/src/doc/book/borrow-and-asref.md @@ -8,7 +8,7 @@ different. Here’s a quick refresher on what these two traits mean. # Borrow -The `Borrow` trait is used when you’re writing a datastructure, and you want to +The `Borrow` trait is used when you’re writing a data structure, and you want to use either an owned or borrowed type as synonymous for some purpose. For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: @@ -86,7 +86,7 @@ We can see how they’re kind of the same: they both deal with owned and borrowe versions of some type. However, they’re a bit different. Choose `Borrow` when you want to abstract over different kinds of borrowing, or -when you’re building a datastructure that treats owned and borrowed values in +when you’re building a data structure that treats owned and borrowed values in equivalent ways, such as hashing and comparison. Choose `AsRef` when you want to convert something to a reference directly, and diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index d332cac7d8d..3ed85c1a90b 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -340,7 +340,7 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem with in our case. When you specify the explicit +However this presents a problem in our case. When you specify the explicit lifetime on a function it binds that lifetime to the *entire* scope of the function instead of just the invocation scope of our closure. This means that the borrow checker will see a mutable reference in the same lifetime as our immutable reference and fail diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index 6e13b464e4c..a62e1b7dfa9 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -59,7 +59,7 @@ handling is reducing the amount of explicit case analysis the programmer has to do while keeping code composable. Keeping code composable is important, because without that requirement, we -could [`panic`](../std/macro.panic!.html) whenever we +could [`panic`](../std/macro.panic.html) whenever we come across something unexpected. (`panic` causes the current task to unwind, and in most cases, the entire program aborts.) Here's an example: @@ -944,7 +944,7 @@ macro_rules! try { } ``` -(The [real definition](../std/macro.try!.html) is a bit more +(The [real definition](../std/macro.try.html) is a bit more sophisticated. We will address that later.) Using the `try!` macro makes it very easy to simplify our last example. Since @@ -1271,7 +1271,7 @@ macro_rules! try { ``` This is not its real definition. Its real definition is -[in the standard library](../std/macro.try!.html): +[in the standard library](../std/macro.try.html): <span id="code-try-def"></span> @@ -2178,7 +2178,7 @@ heuristics! [`From`](../std/convert/trait.From.html) and [`Error`](../std/error/trait.Error.html) - impls to make the [`try!`](../std/macro.try!.html) + impls to make the [`try!`](../std/macro.try.html) macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b9f5c6fcab9..fe9b60c393f 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -223,19 +223,19 @@ pub struct BinaryHeap<T> { /// on `BinaryHeap`. See its documentation for details. /// /// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap<T> } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> Drop for PeekMut<'a, T> { fn drop(&mut self) { self.heap.sift_down(0); } } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> Deref for PeekMut<'a, T> { type Target = T; fn deref(&self) -> &T { @@ -243,7 +243,7 @@ impl<'a, T: Ord> Deref for PeekMut<'a, T> { } } -#[unstable(feature = "binary_heap_peek_mut", issue = "34392")] +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] impl<'a, T: Ord> DerefMut for PeekMut<'a, T> { fn deref_mut(&mut self) -> &mut T { &mut self.heap.data[0] @@ -366,7 +366,6 @@ impl<T: Ord> BinaryHeap<T> { /// Basic usage: /// /// ``` - /// #![feature(binary_heap_peek_mut)] /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); /// assert!(heap.peek_mut().is_none()); @@ -380,7 +379,7 @@ impl<T: Ord> BinaryHeap<T> { /// } /// assert_eq!(heap.peek(), Some(&2)); /// ``` - #[unstable(feature = "binary_heap_peek_mut", issue = "34392")] + #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option<PeekMut<T>> { if self.is_empty() { None diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index c3a7d402375..a2e2ad37acb 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1981,8 +1981,6 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -1992,7 +1990,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// v.into_key(); /// } /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn into_key(self) -> K { self.key } @@ -2074,13 +2072,18 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.handle.reborrow().into_kv().0 } + /// Deprecated, renamed to `remove_entry` + #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] + pub fn remove_pair(self) -> (K, V) { + self.remove_entry() + } + /// Take ownership of the key and value from the map. /// /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -2089,14 +2092,14 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// // We delete the entry from the map. - /// o.remove_pair(); + /// o.remove_entry(); /// } /// /// // If now try to get the value, it will panic: /// // println!("{}", map["poneyland"]); /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - pub fn remove_pair(self) -> (K, V) { + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { self.remove_kv() } diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index be0ef85d6b1..b7cbfb60ec4 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -530,7 +530,7 @@ use string; /// assert_eq!(s, "Hello, world!"); /// ``` /// -/// [format!]: ../macro.format!.html +/// [format!]: ../macro.format.html #[stable(feature = "rust1", since = "1.0.0")] pub fn format(args: Arguments) -> string::String { let mut output = string::String::new(); diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 6842f02e0e1..73aa67849fd 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -379,8 +379,6 @@ impl<T> LinkedList<T> { /// # Examples /// /// ``` - /// #![feature(linked_list_contains)] - /// /// use std::collections::LinkedList; /// /// let mut list: LinkedList<u32> = LinkedList::new(); @@ -392,8 +390,7 @@ impl<T> LinkedList<T> { /// assert_eq!(list.contains(&0), true); /// assert_eq!(list.contains(&10), false); /// ``` - #[unstable(feature = "linked_list_contains", reason = "recently added", - issue = "32630")] + #[stable(feature = "linked_list_contains", since = "1.12.0")] pub fn contains(&self, x: &T) -> bool where T: PartialEq<T> { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 812a67a7e78..ce5635714b5 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -939,8 +939,6 @@ impl<T> VecDeque<T> { /// # Examples /// /// ``` - /// #![feature(vec_deque_contains)] - /// /// use std::collections::VecDeque; /// /// let mut vector: VecDeque<u32> = VecDeque::new(); @@ -951,8 +949,7 @@ impl<T> VecDeque<T> { /// assert_eq!(vector.contains(&1), true); /// assert_eq!(vector.contains(&10), false); /// ``` - #[unstable(feature = "vec_deque_contains", reason = "recently added", - issue = "32630")] + #[stable(feature = "vec_deque_contains", since = "1.12.0")] pub fn contains(&self, x: &T) -> bool where T: PartialEq<T> { diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index ab3231b2b99..f448fcf2dbf 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -11,7 +11,6 @@ #![deny(warnings)] #![feature(binary_heap_extras)] -#![feature(binary_heap_peek_mut)] #![feature(box_syntax)] #![feature(btree_range)] #![feature(collections)] @@ -19,7 +18,6 @@ #![feature(const_fn)] #![feature(fn_traits)] #![feature(enumset)] -#![feature(linked_list_contains)] #![feature(pattern)] #![feature(rand)] #![feature(step_by)] @@ -27,7 +25,6 @@ #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(vec_deque_contains)] #![feature(vec_into_iter_as_slice)] extern crate collections; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 17ec325e257..a388012e1da 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -233,10 +233,28 @@ impl<T:Copy> Cell<T> { /// ``` #[inline] #[unstable(feature = "as_unsafe_cell", issue = "27708")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> { &self.value } + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + /// Returns a mutable reference to the underlying data. /// /// This call borrows `Cell` mutably (at compile-time) which guarantees @@ -653,10 +671,28 @@ impl<T: ?Sized> RefCell<T> { /// ``` #[inline] #[unstable(feature = "as_unsafe_cell", issue = "27708")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> { &self.value } + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::RefCell; + /// + /// let c = RefCell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + /// Returns a mutable reference to the underlying data. /// /// This call borrows `RefCell` mutably (at compile-time) so there is no diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 4cbabe3f5ed..cb509156e32 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -563,10 +563,11 @@ impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {} /// implement the trait can be generated by the `sum` method. Like /// `FromIterator` this trait should rarely be called directly and instead /// interacted with through `Iterator::sum`. -#[unstable(feature = "iter_arith_traits", issue = "34529")] +#[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum<A = Self>: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// "summing up" the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn sum<I: Iterator<Item=A>>(iter: I) -> Self; } @@ -577,16 +578,17 @@ pub trait Sum<A = Self>: Sized { /// which implement the trait can be generated by the `product` method. Like /// `FromIterator` this trait should rarely be called directly and instead /// interacted with through `Iterator::product`. -#[unstable(feature = "iter_arith_traits", issue = "34529")] +#[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product<A = Self>: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// multiplying the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn product<I: Iterator<Item=A>>(iter: I) -> Self; } macro_rules! integer_sum_product { ($($a:ident)*) => ($( - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum<I: Iterator<Item=$a>>(iter: I) -> $a { iter.fold(0, |a, b| { @@ -595,7 +597,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product<I: Iterator<Item=$a>>(iter: I) -> $a { iter.fold(1, |a, b| { @@ -604,7 +606,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a { iter.fold(0, |a, b| { @@ -613,7 +615,7 @@ macro_rules! integer_sum_product { } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a { iter.fold(1, |a, b| { @@ -626,28 +628,28 @@ macro_rules! integer_sum_product { macro_rules! float_sum_product { ($($a:ident)*) => ($( - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum<I: Iterator<Item=$a>>(iter: I) -> $a { iter.fold(0.0, |a, b| a + b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product<I: Iterator<Item=$a>>(iter: I) -> $a { iter.fold(1.0, |a, b| a * b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a { iter.fold(0.0, |a, b| a + *b) } } - #[unstable(feature = "iter_arith_traits", issue = "34529")] + #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a { iter.fold(1.0, |a, b| a * *b) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4ac1b8394f4..5a1993e741c 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -67,8 +67,7 @@ //! } //! ``` //! -//! See the documentation for each trait for a minimum implementation that -//! prints something to the screen. +//! See the documentation for each trait for an example implementation. #![stable(feature = "rust1", since = "1.0.0")] @@ -107,6 +106,13 @@ pub trait Drop { /// /// After this function is over, the memory of `self` will be deallocated. /// + /// This function cannot be called explicitly. This is compiler error + /// [0040]. However, the [`std::mem::drop`] function in the prelude can be + /// used to call the argument's `Drop` implementation. + /// + /// [0040]: https://doc.rust-lang.org/error-index.html#E0040 + /// [`std::mem::drop`]: https://doc.rust-lang.org/std/mem/fn.drop.html + /// /// # Panics /// /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in @@ -171,25 +177,38 @@ macro_rules! forward_ref_binop { /// /// # Examples /// -/// A trivial implementation of `Add`. When `Foo + Foo` happens, it ends up -/// calling `add`, and therefore, `main` prints `Adding!`. +/// This example creates a `Point` struct that implements the `Add` trait, and +/// then demonstrates adding two `Point`s. /// /// ``` /// use std::ops::Add; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl Add for Foo { -/// type Output = Foo; +/// impl Add for Point { +/// type Output = Point; /// -/// fn add(self, _rhs: Foo) -> Foo { -/// println!("Adding!"); -/// self +/// fn add(self, other: Point) -> Point { +/// Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y /// } /// } /// /// fn main() { -/// Foo + Foo; +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); /// } /// ``` #[lang = "add"] @@ -300,6 +319,37 @@ sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo * Foo; /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables multiplication of vectors by scalars, as is +/// done in linear algebra. +/// +/// ``` +/// use std::ops::Mul; +/// +/// struct Scalar {value: usize}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec<usize>}; +/// +/// impl Mul<Vector> for Scalar { +/// type Output = Vector; +/// +/// fn mul(self, rhs: Vector) -> Vector { +/// Vector {value: rhs.value.iter().map(|v| self.value * v).collect()} +/// } +/// } +/// +/// impl PartialEq<Vector> for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 3}; +/// let vector = Vector{value: vec![2, 4, 6]}; +/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]}); +/// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Mul<RHS=Self> { @@ -354,6 +404,37 @@ mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo / Foo; /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables division of vectors by scalars, as is done in +/// linear algebra. +/// +/// ``` +/// use std::ops::Div; +/// +/// struct Scalar {value: f32}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec<f32>}; +/// +/// impl Div<Scalar> for Vector { +/// type Output = Vector; +/// +/// fn div(self, rhs: Scalar) -> Vector { +/// Vector {value: self.value.iter().map(|v| v / rhs.value).collect()} +/// } +/// } +/// +/// impl PartialEq<Vector> for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 2f32}; +/// let vector = Vector{value: vec![2f32, 4f32, 6f32]}; +/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]}); +/// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Div<RHS=Self> { @@ -475,26 +556,37 @@ rem_impl_float! { f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Neg`. When `-Foo` happens, it ends up calling -/// `neg`, and therefore, `main` prints `Negating!`. +/// An implementation of `Neg` for `Sign`, which allows the use of `-` to +/// negate its value. /// /// ``` /// use std::ops::Neg; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// enum Sign { +/// Negative, +/// Zero, +/// Positive, +/// } /// -/// impl Neg for Foo { -/// type Output = Foo; +/// impl Neg for Sign { +/// type Output = Sign; /// -/// fn neg(self) -> Foo { -/// println!("Negating!"); -/// self +/// fn neg(self) -> Sign { +/// match self { +/// Sign::Negative => Sign::Positive, +/// Sign::Zero => Sign::Zero, +/// Sign::Positive => Sign::Negative, +/// } /// } /// } /// -/// fn main() { -/// -Foo; -/// } +/// // a negative positive is a negative +/// assert_eq!(-Sign::Positive, Sign::Negative); +/// // a double negative is a positive +/// assert_eq!(-Sign::Negative, Sign::Positive); +/// // zero is its own negation +/// assert_eq!(-Sign::Zero, Sign::Zero); /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] @@ -543,26 +635,31 @@ neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `Not`. When `!Foo` happens, it ends up calling -/// `not`, and therefore, `main` prints `Not-ing!`. +/// An implementation of `Not` for `Answer`, which enables the use of `!` to +/// invert its value. /// /// ``` /// use std::ops::Not; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// enum Answer { +/// Yes, +/// No, +/// } /// -/// impl Not for Foo { -/// type Output = Foo; +/// impl Not for Answer { +/// type Output = Answer; /// -/// fn not(self) -> Foo { -/// println!("Not-ing!"); -/// self +/// fn not(self) -> Answer { +/// match self { +/// Answer::Yes => Answer::No, +/// Answer::No => Answer::Yes +/// } /// } /// } /// -/// fn main() { -/// !Foo; -/// } +/// assert_eq!(!Answer::Yes, Answer::No); +/// assert_eq!(!Answer::No, Answer::Yes); /// ``` #[lang = "not"] #[stable(feature = "rust1", since = "1.0.0")] @@ -899,25 +996,36 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// /// # Examples /// -/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up -/// calling `add_assign`, and therefore, `main` prints `Adding!`. +/// This example creates a `Point` struct that implements the `AddAssign` +/// trait, and then demonstrates add-assigning to a mutable `Point`. /// /// ``` /// use std::ops::AddAssign; /// -/// struct Foo; +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } /// -/// impl AddAssign for Foo { -/// fn add_assign(&mut self, _rhs: Foo) { -/// println!("Adding!"); +/// impl AddAssign for Point { +/// fn add_assign(&mut self, other: Point) { +/// *self = Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// }; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo += Foo; +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } /// } +/// +/// let mut point = Point { x: 1, y: 0 }; +/// point += Point { x: 2, y: 3 }; +/// assert_eq!(point, Point { x: 3, y: 3 }); /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1467,17 +1575,30 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> { /// /// # Examples /// +/// The `..` syntax is a `RangeFull`: +/// +/// ``` +/// assert_eq!((..), std::ops::RangeFull); /// ``` -/// fn main() { -/// assert_eq!((..), std::ops::RangeFull); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in .. { +/// // ... /// } /// ``` +/// +/// Used as a slicing index, `RangeFull` produces the full array as a slice. +/// +/// ``` +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index a635620d12a..a7c230ba979 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -176,21 +176,21 @@ fn ref_mut_map_accessor() { } #[test] -fn as_unsafe_cell() { +fn as_ptr() { let c1: Cell<usize> = Cell::new(0); c1.set(1); - assert_eq!(1, unsafe { *c1.as_unsafe_cell().get() }); + assert_eq!(1, unsafe { *c1.as_ptr() }); let c2: Cell<usize> = Cell::new(0); - unsafe { *c2.as_unsafe_cell().get() = 1; } + unsafe { *c2.as_ptr() = 1; } assert_eq!(1, c2.get()); let r1: RefCell<usize> = RefCell::new(0); *r1.borrow_mut() = 1; - assert_eq!(1, unsafe { *r1.as_unsafe_cell().get() }); + assert_eq!(1, unsafe { *r1.as_ptr() }); let r2: RefCell<usize> = RefCell::new(0); - unsafe { *r2.as_unsafe_cell().get() = 1; } + unsafe { *r2.as_ptr() = 1; } assert_eq!(1, *r2.borrow()); } diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 9428b4096bf..9116344c579 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(as_unsafe_cell)] #![feature(borrow_state)] #![feature(box_syntax)] #![feature(cell_extras)] diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 3ca6cf03997..250ad80f5af 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { struct_span_err!( self.tcx.sess, span, E0133, "{} requires unsafe function or block", description) - .span_label(span, &format!("unsafe call requires unsafe function or block")) + .span_label(span, &description) .emit(); } UnsafeBlock(block_id) => { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 172e27d56d4..4b3e53d931f 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -564,6 +564,15 @@ impl Handler { self.bump_err_count(); self.panic_if_treat_err_as_bug(); } + pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(self, Level::Error, msg); + result.set_span(sp); + self.bump_err_count(); + result + } pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 1de67922b1b..bcdc0d2ea3f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -493,9 +493,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let ty::TyRawPtr(_) = base_ty.sty { this.add(Qualif::NOT_CONST); if this.mode != Mode::Fn { - span_err!(this.tcx.sess, this.span, E0396, - "raw pointers cannot be dereferenced in {}s", - this.mode); + struct_span_err!(this.tcx.sess, + this.span, E0396, + "raw pointers cannot be dereferenced in {}s", + this.mode) + .span_label(this.span, + &format!("dereference of raw pointer in constant")) + .emit(); } } } @@ -681,9 +685,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { - span_err!(self.tcx.sess, self.span, E0395, - "raw pointers cannot be compared in {}s", - self.mode); + struct_span_err!( + self.tcx.sess, self.span, E0395, + "raw pointers cannot be compared in {}s", + self.mode) + .span_label( + self.span, + &format!("comparing raw pointers in static")) + .emit(); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b91ede5b2fa..af39f8a415c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3382,7 +3382,11 @@ impl<'a> Resolver<'a> { }, (true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg), _ => match (old_binding.is_import(), binding.is_import()) { - (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), + (false, false) => { + let mut e = struct_span_err!(self.session, span, E0428, "{}", msg); + e.span_label(span, &format!("already defined")); + e + }, (true, true) => { let mut e = struct_span_err!(self.session, span, E0252, "{}", msg); e.span_label(span, &format!("already imported")); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ca783455569..3d51da02b87 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -903,9 +903,12 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } else { - span_err!(ccx.tcx.sess, attr.span, E0232, - "this attribute must have a value, \ - eg `#[rustc_on_unimplemented = \"foo\"]`") + struct_span_err!( + ccx.tcx.sess, attr.span, E0232, + "this attribute must have a value") + .span_label(attr.span, &format!("attribute requires a value")) + .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`")) + .emit(); } } } @@ -1245,8 +1248,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); if hint != attr::ReprAny && vs.is_empty() { - span_err!(ccx.tcx.sess, sp, E0084, - "unsupported representation for zero-variant enum"); + struct_span_err!( + ccx.tcx.sess, sp, E0084, + "unsupported representation for zero-variant enum") + .span_label(sp, &format!("unsupported enum representation")) + .emit(); } let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 75d21399f05..39b1a04e98e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2803,7 +2803,7 @@ pub struct Macro { impl Clean<Item> for doctree::Macro { fn clean(&self, cx: &DocContext) -> Item { - let name = format!("{}!", self.name.clean(cx)); + let name = self.name.clean(cx); Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), @@ -2814,8 +2814,10 @@ impl Clean<Item> for doctree::Macro { def_id: cx.map.local_def_id(self.id), inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", - name.trim_right_matches('!'), self.matchers.iter().map(|span| - format!(" {} => {{ ... }};\n", span.to_src(cx))).collect::<String>()), + name, + self.matchers.iter().map(|span| { + format!(" {} => {{ ... }};\n", span.to_src(cx)) + }).collect::<String>()), imported_from: self.imported_from.clean(cx), }), } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d654429146d..e02cfb96ddd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1426,6 +1426,16 @@ impl Context { .open(&redir_dst) { try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); } + + // If the item is a macro, redirect from the old macro URL (with !) + // to the new one (without). + // FIXME(#35705) remove this redirect. + if item_type == ItemType::Macro { + let redir_name = format!("{}.{}!.html", item_type, name); + let redir_dst = self.dst.join(redir_name); + let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst); + try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); + } } } Ok(()) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 68035e5abe4..de7e4d2483b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -577,10 +577,6 @@ displayPath = item.path + '::'; href = rootPath + item.path.replace(/::/g, '/') + '/' + name + '/index.html'; - } else if (type === 'static' || type === 'reexport') { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + - '/index.html'; } else if (type === "primitive") { displayPath = ""; href = rootPath + item.path.replace(/::/g, '/') + @@ -591,9 +587,14 @@ } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = '#' + type + '.' + name; - displayPath = item.path + '::' + myparent.name + '::'; + var parentType = itemTypes[myparent.ty]; + if (parentType === "primitive") { + displayPath = myparent.name + '::'; + } else { + displayPath = item.path + '::' + myparent.name + '::'; + } href = rootPath + item.path.replace(/::/g, '/') + - '/' + itemTypes[myparent.ty] + + '/' + parentType + '.' + myparent.name + '.html' + anchor; } else { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index cf6f76f914a..3d3e3941bac 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1640,13 +1640,18 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { self.elem.read().0 } + /// Deprecated, renamed to `remove_entry` + #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] + pub fn remove_pair(self) -> (K, V) { + self.remove_entry() + } + /// Take the ownership of the key and value from the map. /// /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -1655,13 +1660,13 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// if let Entry::Occupied(o) = map.entry("poneyland") { /// // We delete the entry from the map. - /// o.remove_pair(); + /// o.remove_entry(); /// } /// /// assert_eq!(map.contains_key("poneyland"), false); /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - pub fn remove_pair(self) -> (K, V) { + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { pop_internal(self.elem) } @@ -1808,8 +1813,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(map_entry_recover_keys)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -1819,7 +1822,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// v.into_key(); /// } /// ``` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn into_key(self) -> K { self.key } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 0d29e62485a..3d23a9a2383 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -251,6 +251,14 @@ impl Hash for OsString { impl OsStr { /// Coerces into an `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { s.as_ref() @@ -283,6 +291,18 @@ impl OsStr { } /// Checks whether the `OsStr` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert!(os_str.is_empty()); + /// + /// let os_str = OsStr::new("foo"); + /// assert!(!os_str.is_empty()); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn is_empty(&self) -> bool { self.inner.inner.is_empty() @@ -296,6 +316,18 @@ impl OsStr { /// other methods like `OsString::with_capacity` to avoid reallocations. /// /// See `OsStr` introduction for more information about encoding. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert_eq!(os_str.len(), 0); + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.len(), 3); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn len(&self) -> usize { self.inner.inner.len() diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 88fd4186e0a..307d014fd68 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -236,7 +236,7 @@ //! to read the line and print it, so we use `()`. //! //! [result]: type.Result.html -//! [try]: ../macro.try!.html +//! [try]: ../macro.try.html //! //! ## Platform-specific behavior //! @@ -957,8 +957,8 @@ pub trait Write { /// explicitly be called. The [`write!`][write] macro should be favored to /// invoke this method instead. /// - /// [formatargs]: ../macro.format_args!.html - /// [write]: ../macro.write!.html + /// [formatargs]: ../macro.format_args.html + /// [write]: ../macro.write.html /// /// This function internally uses the [`write_all`][writeall] method on /// this trait and hence will continuously write data so long as no errors diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c05e0c3ca68..ff3b9c6d041 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -175,7 +175,7 @@ //! [`atomic`]: sync/atomic/index.html //! [`collections`]: collections/index.html //! [`for`]: ../book/loops.html#for -//! [`format!`]: macro.format!.html +//! [`format!`]: macro.format.html //! [`fs`]: fs/index.html //! [`io`]: io/index.html //! [`iter`]: iter/index.html diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 2a8bd0c88be..4c3b993497c 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -63,8 +63,7 @@ impl IpAddr { /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_unspecified(), @@ -75,7 +74,7 @@ impl IpAddr { /// Returns true if this is a loopback address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback - #[unstable(feature="ip", reason="recently added", issue="27709")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_loopback(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_loopback(), @@ -86,8 +85,6 @@ impl IpAddr { /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")] pub fn is_global(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_global(), @@ -98,7 +95,7 @@ impl IpAddr { /// Returns true if this is a multicast address ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast - #[unstable(feature="ip", reason="recently added", issue="27709")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_multicast(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_multicast(), @@ -109,8 +106,6 @@ impl IpAddr { /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation - #[unstable(feature="ip", issue="27709", - reason="recently added and depends on unstable Ipv6Addr.is_documentation()")] pub fn is_documentation(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_documentation(), @@ -147,6 +142,7 @@ impl Ipv4Addr { /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7] /// [ip7][http://man7.org/linux/man-pages/man7/ip.7.html] + #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 } @@ -515,8 +511,7 @@ impl Ipv6Addr { } /// Returns the sixteen eight-bit integers the IPv6 address consists of. - #[unstable(feature = "ipv6_to_octets", reason = "needs some testing", - issue = "32313")] + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] pub fn octets(&self) -> [u8; 16] { self.inner.s6_addr } diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index d31a5930376..2b92da6c684 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -27,7 +27,7 @@ /// assert!(!bool_val); /// ``` /// -/// [`assert!`]: macro.assert!.html +/// [`assert!`]: macro.assert.html /// [`if`]: ../book/if.html /// [`BitAnd`]: ops/trait.BitAnd.html /// [`BitOr`]: ops/trait.BitOr.html diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 11f785dffd1..d8b8c6a77a2 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -394,13 +394,15 @@ pub enum TryRecvError { /// This enumeration is the list of possible errors that `recv_timeout` could /// not return data when called. #[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[unstable(feature = "mpsc_recv_timeout", issue = "34029")] +#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { /// This channel is currently empty, but the sender(s) have not yet /// disconnected, so data may yet become available. + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Timeout, /// This channel's sending half has become disconnected, and there will /// never be any more data received on this channel + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Disconnected, } @@ -912,8 +914,6 @@ impl<T> Receiver<T> { /// # Examples /// /// ```no_run - /// #![feature(mpsc_recv_timeout)] - /// /// use std::sync::mpsc::{self, RecvTimeoutError}; /// use std::time::Duration; /// @@ -922,7 +922,7 @@ impl<T> Receiver<T> { /// let timeout = Duration::from_millis(100); /// assert_eq!(Err(RecvTimeoutError::Timeout), recv.recv_timeout(timeout)); /// ``` - #[unstable(feature = "mpsc_recv_timeout", issue = "34029")] + #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> { // Do an optimistic try_recv to avoid the performance impact of // Instant::now() in the full-channel case. diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 430ec5f94a6..dd70ba2e490 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -114,7 +114,7 @@ impl CommandExt for process::Command { pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of /// a process. - #[unstable(feature = "exit_status_from", issue = "32713")] + #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; /// If the process was terminated by a signal, returns that signal. diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 56c6a73d4f8..98166bf8cda 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -83,10 +83,11 @@ impl IntoRawHandle for process::ChildStderr { } /// Windows-specific extensions to `std::process::ExitStatus` -#[unstable(feature = "exit_status_from", issue = "32713")] +#[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of /// a process. + #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: u32) -> Self; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 126e8816d05..9443df6321b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -520,12 +520,21 @@ impl<'a> Parser<'a> { self.bug("ident interpolation not converted to real token"); } _ => { - let mut err = self.fatal(&format!("expected identifier, found `{}`", - self.this_token_to_string())); - if self.token == token::Underscore { - err.note("`_` is a wildcard pattern, not an identifier"); - } - Err(err) + let last_token = self.last_token.clone().map(|t| *t); + Err(match last_token { + Some(token::DocComment(_)) => self.span_fatal_help(self.last_span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a comment was \ + intended with `//`?"), + _ => { + let mut err = self.fatal(&format!("expected identifier, found `{}`", + self.this_token_to_string())); + if self.token == token::Underscore { + err.note("`_` is a wildcard pattern, not an identifier"); + } + err + } + }) } } } @@ -927,6 +936,7 @@ impl<'a> Parser<'a> { // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || self.token.is_path() || + self.token.is_doc_comment() || self.token == token::Comma { Some(Box::new(self.token.clone())) } else { @@ -1018,6 +1028,11 @@ impl<'a> Parser<'a> { pub fn span_err(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } + pub fn span_err_help(&self, sp: Span, m: &str, h: &str) { + let mut err = self.sess.span_diagnostic.mut_span_err(sp, m); + err.help(h); + err.emit(); + } pub fn span_bug(&self, sp: Span, m: &str) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } @@ -4021,8 +4036,14 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - s.span_err(s.span, - "expected statement after outer attribute"); + let last_token = s.last_token.clone().map(|t| *t); + match last_token { + Some(token::DocComment(_)) => s.span_err_help(s.last_span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a \ + comment was intended with `//`?"), + _ => s.span_err(s.span, "expected statement after outer attribute"), + } } }; @@ -5127,14 +5148,13 @@ impl<'a> Parser<'a> { self.bump(); } token::CloseDelim(token::Brace) => {} - _ => { - let span = self.span; - let token_str = self.this_token_to_string(); - return Err(self.span_fatal_help(span, - &format!("expected `,`, or `}}`, found `{}`", - token_str), - "struct fields should be separated by commas")) - } + token::DocComment(_) => return Err(self.span_fatal_help(self.span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a comment was \ + intended with `//`?")), + _ => return Err(self.span_fatal_help(self.span, + &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()), + "struct fields should be separated by commas")), } Ok(a_var) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 6fdc9b714d3..dc0fb02ea45 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -203,7 +203,7 @@ impl Token { pub fn is_lit(&self) -> bool { match *self { Literal(_, _) => true, - _ => false, + _ => false, } } @@ -215,6 +215,14 @@ impl Token { } } + /// Returns `true` if the token is a documentation comment. + pub fn is_doc_comment(&self) -> bool { + match *self { + DocComment(..) => true, + _ => false, + } + } + /// Returns `true` if the token is interpolated. pub fn is_interpolated(&self) -> bool { match *self { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 850127d9f29..2b4193306dd 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -42,7 +42,6 @@ #![feature(staged_api)] #![feature(question_mark)] #![feature(panic_unwind)] -#![feature(mpsc_recv_timeout)] extern crate getopts; extern crate term; diff --git a/src/test/compile-fail/E0084.rs b/src/test/compile-fail/E0084.rs index c579101325f..c7c5662f1fe 100644 --- a/src/test/compile-fail/E0084.rs +++ b/src/test/compile-fail/E0084.rs @@ -9,7 +9,9 @@ // except according to those terms. #[repr(i32)] -enum Foo {} //~ ERROR E0084 +enum Foo {} +//~^ ERROR E0084 +//~| unsupported enum representation fn main() { } diff --git a/src/test/compile-fail/E0133.rs b/src/test/compile-fail/E0133.rs index b8a4476fc59..f60d9a5083f 100644 --- a/src/test/compile-fail/E0133.rs +++ b/src/test/compile-fail/E0133.rs @@ -13,5 +13,5 @@ unsafe fn f() { return; } fn main() { f(); //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE call to unsafe function } diff --git a/src/test/compile-fail/E0232.rs b/src/test/compile-fail/E0232.rs index efeb869d71f..ce4f4638dac 100644 --- a/src/test/compile-fail/E0232.rs +++ b/src/test/compile-fail/E0232.rs @@ -10,7 +10,10 @@ #![feature(on_unimplemented)] -#[rustc_on_unimplemented] //~ ERROR E0232 +#[rustc_on_unimplemented] +//~^ ERROR E0232 +//~| NOTE attribute requires a value +//~| NOTE eg `#[rustc_on_unimplemented = "foo"]` trait Bar {} fn main() { diff --git a/src/test/compile-fail/E0395.rs b/src/test/compile-fail/E0395.rs index 6ab66313a04..98f08cd68c2 100644 --- a/src/test/compile-fail/E0395.rs +++ b/src/test/compile-fail/E0395.rs @@ -12,6 +12,6 @@ static FOO: i32 = 42; static BAR: i32 = 42; static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR E0395 - + //~| NOTE comparing raw pointers in static fn main() { } diff --git a/src/test/compile-fail/E0396.rs b/src/test/compile-fail/E0396.rs index 7f34acdfb90..47080fb6e9e 100644 --- a/src/test/compile-fail/E0396.rs +++ b/src/test/compile-fail/E0396.rs @@ -11,6 +11,7 @@ const REG_ADDR: *const u8 = 0x5f3759df as *const u8; const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396 + //~| NOTE dereference of raw pointer in constant fn main() { } diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs index 42e237d31cb..63b4efb73f0 100644 --- a/src/test/compile-fail/E0428.rs +++ b/src/test/compile-fail/E0428.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Bar; +struct Bar; //~ previous definition of `Bar` here + //~| previous definition of `Bar` here struct Bar; //~ ERROR E0428 - //~^ ERROR E0428 + //~| NOTE already defined + //~| ERROR E0428 + //~| NOTE already defined fn main () { } diff --git a/src/test/compile-fail/const-deref-ptr.rs b/src/test/compile-fail/const-deref-ptr.rs index fa15f3e87c6..c626801d48c 100644 --- a/src/test/compile-fail/const-deref-ptr.rs +++ b/src/test/compile-fail/const-deref-ptr.rs @@ -12,5 +12,6 @@ fn main() { static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396 + //~| NOTE dereference of raw pointer in constant println!("{}", C); } diff --git a/src/test/compile-fail/enum-and-module-in-same-scope.rs b/src/test/compile-fail/enum-and-module-in-same-scope.rs index a6793ee8b9f..527ac7505a6 100644 --- a/src/test/compile-fail/enum-and-module-in-same-scope.rs +++ b/src/test/compile-fail/enum-and-module-in-same-scope.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Foo { //~ NOTE previous definition +enum Foo { //~ NOTE previous definition of `Foo` here X } mod Foo { //~ ERROR a type named `Foo` has already been defined + //~| NOTE already defined pub static X: isize = 42; fn f() { f() } // Check that this does not result in a resolution error } diff --git a/src/test/compile-fail/issue-21546.rs b/src/test/compile-fail/issue-21546.rs index 11d05ceb9a0..d103d45bc4c 100644 --- a/src/test/compile-fail/issue-21546.rs +++ b/src/test/compile-fail/issue-21546.rs @@ -17,6 +17,7 @@ mod Foo { } #[allow(dead_code)] struct Foo; //~^ ERROR a module named `Foo` has already been defined in this module +//~| NOTE already defined #[allow(non_snake_case)] mod Bar { } @@ -25,6 +26,7 @@ mod Bar { } #[allow(dead_code)] struct Bar(i32); //~^ ERROR a module named `Bar` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -34,6 +36,7 @@ struct Baz(i32); #[allow(non_snake_case)] mod Baz { } //~^ ERROR a type named `Baz` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -43,6 +46,7 @@ struct Qux { x: bool } #[allow(non_snake_case)] mod Qux { } //~^ ERROR a type named `Qux` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -52,6 +56,7 @@ struct Quux; #[allow(non_snake_case)] mod Quux { } //~^ ERROR a type named `Quux` has already been defined +//~| NOTE already defined #[allow(dead_code)] @@ -61,5 +66,6 @@ enum Corge { A, B } #[allow(non_snake_case)] mod Corge { } //~^ ERROR a type named `Corge` has already been defined +//~| NOTE already defined fn main() { } diff --git a/src/test/compile-fail/issue-25826.rs b/src/test/compile-fail/issue-25826.rs index 00e1279d58a..468282fa7cc 100644 --- a/src/test/compile-fail/issue-25826.rs +++ b/src/test/compile-fail/issue-25826.rs @@ -12,5 +12,6 @@ fn id<T>(t: T) -> T { t } fn main() { const A: bool = id::<u8> as *const () < id::<u16> as *const (); //~^ ERROR raw pointers cannot be compared in constants [E0395] + //~^^ NOTE comparing raw pointers in static println!("{}", A); } diff --git a/src/test/compile-fail/issue-28776.rs b/src/test/compile-fail/issue-28776.rs index 52b0eba96cb..4a36bc88fa7 100644 --- a/src/test/compile-fail/issue-28776.rs +++ b/src/test/compile-fail/issue-28776.rs @@ -13,5 +13,5 @@ use std::ptr; fn main() { (&ptr::write)(1 as *mut _, 42); //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE call to unsafe function } diff --git a/src/test/compile-fail/trait-duplicate-methods.rs b/src/test/compile-fail/trait-duplicate-methods.rs index 41700b25bbb..7bcab1f6ac5 100644 --- a/src/test/compile-fail/trait-duplicate-methods.rs +++ b/src/test/compile-fail/trait-duplicate-methods.rs @@ -11,6 +11,7 @@ trait Foo { fn orange(&self); //~ NOTE previous definition of `orange` here fn orange(&self); //~ ERROR a value named `orange` has already been defined in this trait + //~| NOTE already define } fn main() {} diff --git a/src/test/compile-fail/trait-safety-fn-body.rs b/src/test/compile-fail/trait-safety-fn-body.rs index 0df7ee8cabe..65732a8ff69 100644 --- a/src/test/compile-fail/trait-safety-fn-body.rs +++ b/src/test/compile-fail/trait-safety-fn-body.rs @@ -20,7 +20,7 @@ unsafe impl UnsafeTrait for *mut isize { // Unsafe actions are not made legal by taking place in an unsafe trait: *self += 1; //~^ ERROR E0133 - //~| NOTE unsafe call requires unsafe function or block + //~| NOTE dereference of raw pointer } } diff --git a/src/test/compile-fail/unsafe-const-fn.rs b/src/test/compile-fail/unsafe-const-fn.rs index 174939b0900..91e16592be4 100644 --- a/src/test/compile-fail/unsafe-const-fn.rs +++ b/src/test/compile-fail/unsafe-const-fn.rs @@ -18,7 +18,7 @@ const unsafe fn dummy(v: u32) -> u32 { const VAL: u32 = dummy(0xFFFF); //~^ ERROR E0133 -//~| NOTE unsafe call requires unsafe function or block +//~| NOTE call to unsafe function fn main() { assert_eq!(VAL, 0xFFFF0000); diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs new file mode 100644 index 00000000000..1aa6af5b78f --- /dev/null +++ b/src/test/parse-fail/doc-after-struct-field.rs @@ -0,0 +1,20 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +struct X { + a: u8 /** document a */, + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} diff --git a/src/test/parse-fail/doc-before-extern-rbrace.rs b/src/test/parse-fail/doc-before-extern-rbrace.rs index 9e825193dc0..70da47ba9b4 100644 --- a/src/test/parse-fail/doc-before-extern-rbrace.rs +++ b/src/test/parse-fail/doc-before-extern-rbrace.rs @@ -12,5 +12,5 @@ extern { /// hi + //~^ ERROR expected item after doc comment } -//~^^ ERROR expected item after doc comment diff --git a/src/test/parse-fail/doc-before-fn-rbrace.rs b/src/test/parse-fail/doc-before-fn-rbrace.rs new file mode 100644 index 00000000000..bcf32612c8f --- /dev/null +++ b/src/test/parse-fail/doc-before-fn-rbrace.rs @@ -0,0 +1,16 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +fn main() { + /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} diff --git a/src/test/parse-fail/doc-before-identifier.rs b/src/test/parse-fail/doc-before-identifier.rs new file mode 100644 index 00000000000..8f1fad91b1f --- /dev/null +++ b/src/test/parse-fail/doc-before-identifier.rs @@ -0,0 +1,18 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +fn /// document +foo() {} +//~^^ ERROR expected identifier, found `/// document` + +fn main() { + foo(); +} diff --git a/src/test/parse-fail/doc-before-mod-rbrace.rs b/src/test/parse-fail/doc-before-mod-rbrace.rs new file mode 100644 index 00000000000..d38d1876384 --- /dev/null +++ b/src/test/parse-fail/doc-before-mod-rbrace.rs @@ -0,0 +1,15 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +mod Foo { + /// document + //~^ ERROR expected item after doc comment +} diff --git a/src/test/parse-fail/doc-before-rbrace.rs b/src/test/parse-fail/doc-before-rbrace.rs index 295d5ae432e..48ea2b5aea1 100644 --- a/src/test/parse-fail/doc-before-rbrace.rs +++ b/src/test/parse-fail/doc-before-rbrace.rs @@ -12,5 +12,6 @@ fn main() { println!("Hi"); /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended } -//~^ ERROR expected statement diff --git a/src/test/parse-fail/doc-before-semi.rs b/src/test/parse-fail/doc-before-semi.rs index 6a8906953be..71104b8caae 100644 --- a/src/test/parse-fail/doc-before-semi.rs +++ b/src/test/parse-fail/doc-before-semi.rs @@ -12,6 +12,7 @@ fn main() { /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended ; - //~^ ERROR expected statement } diff --git a/src/test/parse-fail/doc-before-struct-rbrace-1.rs b/src/test/parse-fail/doc-before-struct-rbrace-1.rs new file mode 100644 index 00000000000..5ba83190c8e --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-1.rs @@ -0,0 +1,21 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +struct X { + a: u8, + /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} diff --git a/src/test/parse-fail/doc-before-struct-rbrace-2.rs b/src/test/parse-fail/doc-before-struct-rbrace-2.rs new file mode 100644 index 00000000000..643e4aa17a1 --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-2.rs @@ -0,0 +1,20 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z continue-parse-after-error +struct X { + a: u8 /// document + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + +fn main() { + let y = X {a = 1}; +} diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs index df40c01686d..12de7665451 100644 --- a/src/test/rustdoc/issue-26606.rs +++ b/src/test/rustdoc/issue-26606.rs @@ -12,7 +12,7 @@ // ignore-cross-compile // build-aux-docs -// @has issue_26606_macro/macro.make_item!.html +// @has issue_26606_macro/macro.make_item.html #[macro_use] extern crate issue_26606_macro; diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs index b052ad2da2f..9aeeb71707c 100644 --- a/src/test/rustdoc/macros.rs +++ b/src/test/rustdoc/macros.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// @has macros/macro.my_macro!.html //pre 'macro_rules! my_macro {' +// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {' // @has - //pre '() => { ... };' // @has - //pre '($a:tt) => { ... };' // @has - //pre '($e:expr) => { ... };' +// @has macros/macro.my_macro!.html +// @has - //a 'macro.my_macro.html' #[macro_export] macro_rules! my_macro { () => []; diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock index ed5fe081ffb..d71df6d3f83 100644 --- a/src/tools/linkchecker/Cargo.lock +++ b/src/tools/linkchecker/Cargo.lock @@ -42,3 +42,9 @@ dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[metadata] +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" +"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" +"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" |
