From 8b8091d370fa31844d6ed55f4ccdd32e5dbd20f9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 6 Apr 2018 00:34:45 -0700 Subject: [PATCH 01/20] Rewrite docs for `std::ptr` - Add links to the GNU libc docs for `memmove`, `memcpy`, and `memset`, as well as internally linking to other functions in `std::ptr` - List sources of UB for all functions. - Add example to `ptr::drop_in_place` and compares it to `ptr::read`. - Add examples which more closely mirror real world uses for the functions in `std::ptr`. Also, move the reimplementation of `mem::swap` to the examples of `ptr::read` and use a more interesting example for `copy_nonoverlapping`. - Change module level description --- src/libcore/intrinsics.rs | 177 +++++++++++++--- src/libcore/ptr.rs | 421 +++++++++++++++++++++++++++++++------- 2 files changed, 496 insertions(+), 102 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250..d6bd2b86855 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -959,59 +959,134 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of` bytes from `src` to `dst`. The source - /// and destination may *not* overlap. + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination must *not* overlap. /// - /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`. + /// For regions of memory which might overlap, use [`copy`] instead. + /// + /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`]. + /// + /// [`copy`]: ./fn.copy.html + /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy /// /// # Safety /// - /// Beyond requiring that the program must be allowed to access both regions - /// of memory, it is Undefined Behavior for source and destination to - /// overlap. Care must also be taken with the ownership of `src` and - /// `dst`. This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents - /// of `src` from being dropped or used. + /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. + /// The caller must ensure that `src` points to a valid sequence of type + /// `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// * The two regions of memory must *not* overlap. + /// + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. + /// + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// - /// A safe swap function: + /// Manually implement [`Vec::append`]: /// /// ``` - /// use std::mem; /// use std::ptr; /// - /// # #[allow(dead_code)] - /// fn swap(x: &mut T, y: &mut T) { + /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. + /// fn append(dst: &mut Vec, src: &mut Vec) { + /// let src_len = src.len(); + /// let dst_len = dst.len(); + /// + /// // Ensure that `dst` has enough capacity to hold all of `src`. + /// dst.reserve(src_len); + /// /// unsafe { - /// // Give ourselves some scratch space to work with - /// let mut t: T = mem::uninitialized(); + /// // The call to offset is always safe because `Vec` will never + /// // allocate more than `isize::MAX` bytes. + /// let dst = dst.as_mut_ptr().offset(dst_len as isize); + /// let src = src.as_ptr(); /// - /// // Perform the swap, `&mut` pointers never alias - /// ptr::copy_nonoverlapping(x, &mut t, 1); - /// ptr::copy_nonoverlapping(y, x, 1); - /// ptr::copy_nonoverlapping(&t, y, 1); + /// // The two regions cannot overlap becuase mutable references do + /// // not alias, and two different vectors cannot own the same + /// // memory. + /// ptr::copy_nonoverlapping(src, dst, src_len); + /// } /// - /// // y and t now point to the same thing, but we need to completely forget `t` - /// // because it's no longer relevant. - /// mem::forget(t); + /// unsafe { + /// // Truncate `src` without dropping its contents. + /// src.set_len(0); + /// + /// // Notify `dst` that it now holds the contents of `src`. + /// dst.set_len(dst_len + src_len); /// } /// } + /// + /// let mut a = vec!['r']; + /// let mut b = vec!['u', 's', 't']; + /// + /// append(&mut a, &mut b); + /// + /// assert_eq!(a, &['r', 'u', 's', 't']); + /// assert!(b.is_empty()); /// ``` + /// + /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - /// Copies `count * size_of` bytes from `src` to `dst`. The source + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination may overlap. /// - /// `copy` is semantically equivalent to C's `memmove`. + /// If the source and destination will *never* overlap, + /// [`copy_nonoverlapping`] can be used instead. + /// + /// `copy` is semantically equivalent to C's [`memmove`]. + /// + /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html + /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove /// /// # Safety /// - /// Care must be taken with the ownership of `src` and `dst`. - /// This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents of `src` - /// from being dropped or used. + /// `copy` is unsafe because it dereferences a raw pointer. The caller must + /// ensure that `src` points to a valid sequence of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling `copy`. `copy` + /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which + /// can result in undefined behavior if both copies are used. + /// + /// [`Copy`]: ../marker/trait.Copy.html + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1028,15 +1103,39 @@ extern "rust-intrinsic" { /// dst /// } /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] pub fn copy(src: *const T, dst: *mut T, count: usize); - /// Invokes memset on the specified pointer, setting `count * size_of::()` - /// bytes of memory starting at `dst` to `val`. + /// Sets `count * size_of::()` bytes of memory starting at `dst` to + /// `val`. + /// + /// `write_bytes` is semantically equivalent to C's [`memset`]. + /// + /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset + /// + /// # Safety + /// + /// `write_bytes` is unsafe because it dereferences a raw pointer. The + /// caller must ensure that the poiinter points to a valid value of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count` bytes must be valid. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, the caller must ensure that writing `count` bytes to the + /// given region of memory results in a valid value of `T`. Creating an + /// invalid value of `T` can result in undefined behavior. An example is + /// provided below. /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::ptr; /// @@ -1047,6 +1146,22 @@ extern "rust-intrinsic" { /// } /// assert_eq!(vec, [b'a', b'a', 0, 0]); /// ``` + /// + /// Creating an invalid value: + /// + /// ```ignore + /// use std::{mem, ptr}; + /// + /// let mut v = Box::new(0i32); + /// + /// unsafe { + /// // Leaks the previously held value by overwriting the `Box` with + /// // a null pointer. + /// ptr::write_bytes(&mut v, 0, mem::size_of::>()); + /// } + /// + /// // At this point, using or dropping `v` results in undefined behavior. + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5e..98d5030477b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Raw, unsafe pointers, `*const T`, and `*mut T`. +//! Manually manage memory through raw, unsafe pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -38,21 +38,68 @@ pub use intrinsics::write_bytes; /// Executes the destructor (if any) of the pointed-to value. /// -/// This has two use cases: +/// This is semantically equivalent to calling [`ptr::read`] and discarding +/// the result, but has the following advantages: /// /// * It is *required* to use `drop_in_place` to drop unsized types like /// trait objects, because they can't be read out onto the stack and /// dropped normally. /// -/// * It is friendlier to the optimizer to do this over `ptr::read` when +/// * It is friendlier to the optimizer to do this over [`ptr::read`] when /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// +/// [`ptr::read`]: ./fn.read.html +/// /// # Safety /// -/// This has all the same safety problems as `ptr::read` with respect to -/// invalid pointers, types, and double drops. +/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must point to valid memory. +/// +/// * `to_drop` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], using the pointed-to value after +/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = +/// foo` counts as a use because it will cause the the value to be dropped +/// again. [`write`] can be used to overwrite data without causing it to be +/// dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// Manually remove the last item from a vector: +/// +/// ``` +/// use std::ptr; +/// use std::rc::Rc; +/// +/// let last = Rc::new(1); +/// let weak = Rc::downgrade(&last); +/// +/// let mut v = vec![Rc::new(0), last]; +/// +/// unsafe { +/// // Without a call `drop_in_place`, the last item would never be dropped, +/// // and the memory it manages would be leaked. +/// ptr::drop_in_place(&mut v[1]); +/// v.set_len(1); +/// } +/// +/// assert_eq!(v, &[0.into()]); +/// +/// // Ensure that the last item was dropped. +/// assert!(weak.upgrade().is_none()); +/// ``` #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -93,17 +140,32 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which -/// is otherwise equivalent. If the values do overlap, then the overlapping -/// region of memory from `x` will be used. This is demonstrated in the -/// examples section below. +/// But for the following two exceptions, this function is semantically +/// equivalent to [`mem::swap`]: +/// +/// * It operates on raw pointers instead of references. When references are +/// available, [`mem::swap`] should be preferred. +/// +/// * The two pointed-to values may overlap. If the values do overlap, then the +/// overlapping region of memory from `x` will be used. This is demonstrated +/// in the examples below. +/// +/// [`mem::swap`]: ../mem/fn.swap.html /// /// # Safety /// -/// This function copies the memory through the raw pointers passed to it -/// as arguments. +/// `swap` is unsafe because it dereferences a raw pointer. The caller must +/// ensure that both pointers point to valid values of type `T`. /// -/// Ensure that these pointers are valid before calling `swap`. +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `x` and `y` must point to valid, initialized memory. +/// +/// * `x` and `y` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -241,13 +303,46 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old -/// value, without dropping either. +/// Replaces the value at `dest` with `src`, returning the old value, without +/// dropping either. +/// +/// This function is semantically equivalent to [`mem::replace`] except that it +/// operates on raw pointers instead of references. When references are +/// available, [`mem::replace`] should be preferred. /// /// # Safety /// -/// This is only unsafe because it accepts a raw pointer. -/// Otherwise, this operation is identical to `mem::replace`. +/// `replace` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// [`mem::replace`]: ../mem/fn.replace.html +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dest` must point to valid, initialized memory. +/// +/// * `dest` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let mut rust = vec!['b', 'u', 's', 't']; +/// +/// // `mem::replace` would have the same effect without requiring the unsafe +/// // block. +/// let b = unsafe { +/// ptr::replace(&mut a[0], 'r') +/// }; +/// +/// assert_eq!(b, 'b'); +/// assert_eq!(rust, &['r', 'u', 's', 't']); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn replace(dest: *mut T, mut src: T) -> T { @@ -260,14 +355,29 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. /// -/// The pointer must be aligned; use `read_unaligned` if that is not the case. +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the +/// case. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read`. `read` creates +/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result +/// in undefined behavior if both copies are used. Note that `*src = foo` counts +/// as a use because it will attempt to drop the value previously at `*src`. +/// [`write`] can be used to overwrite data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -281,6 +391,44 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// // Create a bitwise copy of the value at `a` in `tmp`. +/// let tmp = ptr::read(a); +/// +/// // Exiting at this point (either by explicitly returning or by +/// // calling a function which panics) would cause the value in `tmp` to +/// // be dropped while the same value is still referenced by `a`. This +/// // could trigger undefined behavior if `T` is not `Copy`. +/// +/// // Create a bitwise copy of the value at `b` in `a`. +/// // This is safe because mutable references cannot alias. +/// ptr::copy_nonoverlapping(b, a, 1); +/// +/// // As above, exiting here could trigger undefined behavior because +/// // the same value is referenced by `a` and `b`. +/// +/// // Move `tmp` into `b`. +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -292,28 +440,66 @@ pub unsafe fn read(src: *const T) -> T { /// Reads the value from `src` without moving it. This leaves the /// memory in `src` unchanged. /// -/// Unlike `read`, the pointer may be unaligned. +/// Unlike [`read`], `read_unaligned` works with unaligned pointers. /// -/// # Safety +/// [`read`]: ./fn.read.html /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_unaligned`. +/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, and this can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_unaligned`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access members of a packed struct by reference: /// /// ``` -/// let x = 12; -/// let y = &x as *const i32; +/// use std::ptr; /// -/// unsafe { -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, /// } +/// +/// let x = Packed { +/// _padding: 0x00, +/// unaligned: 0x01020304, +/// }; +/// +/// let v = unsafe { +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned load instruction, +/// // causing undefined behavior. +/// // let v = *unaligned; // ERROR +/// +/// // Instead, use `read_unaligned` to read improperly aligned values. +/// let v = ptr::read_unaligned(unaligned); +/// +/// v +/// }; +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] @@ -328,11 +514,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak +/// `write` does not drop the contents of `dst`. This is safe, but it could leak /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// @@ -340,9 +522,26 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. /// -/// The pointer must be aligned; use `write_unaligned` if that is not the case. +/// [`read`]: ./fn.read.html +/// +/// # Safety +/// +/// `write` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write` can trigger undefined behavior if any of the following conditions +/// are violated: +/// +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the +/// case. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples /// @@ -358,6 +557,30 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// let tmp = ptr::read(a); +/// ptr::copy_nonoverlapping(b, a, 1); +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -367,36 +590,65 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike `write`, the pointer may be unaligned. +/// Unlike [`write`], the pointer may be unaligned. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. +/// +/// [`write`]: ./fn.write.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// +/// # Safety +/// +/// `write_unaligned` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write_unaligned` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access fields in a packed struct: /// /// ``` -/// let mut x = 0; -/// let y = &mut x as *mut i32; -/// let z = 12; +/// use std::{mem, ptr}; +/// +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, +/// } +/// +/// let v = 0x01020304; +/// let mut x: Packed = unsafe { mem::zeroed() }; /// /// unsafe { -/// std::ptr::write_unaligned(y, z); -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &mut x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned store instruction, +/// // causing undefined behavior. +/// // *unaligned = v; // ERROR +/// +/// // Instead, use `write_unaligned` to write improperly aligned values. +/// ptr::write_unaligned(unaligned, v); /// } -/// ``` +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { @@ -429,12 +681,28 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_volatile`. +/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, which can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_volatile`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_volatile`]: ./fn.write_volatile.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -461,6 +729,13 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -477,14 +752,18 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// This operation is marked unsafe because it accepts a raw pointer. +/// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// # [Undefined Behavior] /// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// `write_volatile` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// From ee259e4dd340f9532511b7249e4eb961f111b63f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 15:51:25 -0700 Subject: [PATCH 02/20] Change `write_bytes` test causing UB to `no_run` This also fixes improper text wrapping. --- src/libcore/intrinsics.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6bd2b86855..8e3180cd2a6 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the - /// region at `dst` can be used or dropped after calling - /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of - /// `T`, regardless of whether `T: Copy`, which can result in undefined - /// behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the + /// region at `src` *or* the region at `dst` can be used or dropped after + /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise + /// copies of `T`, regardless of whether `T: Copy`, which can result in + /// undefined behavior if both copies are used. /// /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// @@ -1149,7 +1149,7 @@ extern "rust-intrinsic" { /// /// Creating an invalid value: /// - /// ```ignore + /// ```no_run /// use std::{mem, ptr}; /// /// let mut v = Box::new(0i32); @@ -1161,6 +1161,7 @@ extern "rust-intrinsic" { /// } /// /// // At this point, using or dropping `v` results in undefined behavior. + /// // v = Box::new(0i32); // ERROR /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); From b564c4a0ee96acb0a68b8421b6cecac47e2a2e8b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:20:20 -0700 Subject: [PATCH 03/20] Fix example for `ptr::replace` --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 98d5030477b..9069feab06c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -337,7 +337,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// // `mem::replace` would have the same effect without requiring the unsafe /// // block. /// let b = unsafe { -/// ptr::replace(&mut a[0], 'r') +/// ptr::replace(&mut rust[0], 'r') /// }; /// /// assert_eq!(b, 'b'); From 6eceb94d09636d272f8448d0eb26e072b891cb45 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:22:27 -0700 Subject: [PATCH 04/20] Don't link "Undefined Behavior" heading The rendered version does not make clear that this is a link to another page, and it breaks the anchor link. --- src/libcore/intrinsics.rs | 9 +++------ src/libcore/ptr.rs | 31 +++++++++---------------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8e3180cd2a6..daa43337fd7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -975,7 +975,7 @@ extern "rust-intrinsic" { /// The caller must ensure that `src` points to a valid sequence of type /// `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -998,8 +998,6 @@ extern "rust-intrinsic" { /// copies of `T`, regardless of whether `T: Copy`, which can result in /// undefined behavior if both copies are used. /// - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html - /// /// # Examples /// /// Manually implement [`Vec::append`]: @@ -1065,7 +1063,7 @@ extern "rust-intrinsic" { /// `copy` is unsafe because it dereferences a raw pointer. The caller must /// ensure that `src` points to a valid sequence of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -1086,7 +1084,6 @@ extern "rust-intrinsic" { /// can result in undefined behavior if both copies are used. /// /// [`Copy`]: ../marker/trait.Copy.html - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1118,7 +1115,7 @@ extern "rust-intrinsic" { /// `write_bytes` is unsafe because it dereferences a raw pointer. The /// caller must ensure that the poiinter points to a valid value of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 9069feab06c..4cb9c655441 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -57,7 +57,7 @@ pub use intrinsics::write_bytes; /// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -73,7 +73,6 @@ pub use intrinsics::write_bytes; /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -157,7 +156,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// `swap` is unsafe because it dereferences a raw pointer. The caller must /// ensure that both pointers point to valid values of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -165,8 +164,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * `x` and `y` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Swapping two non-overlapping regions: @@ -317,7 +314,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -325,8 +322,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `dest` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// ``` @@ -358,7 +353,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `read` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -377,7 +372,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// [`Copy`]: ../marker/trait.Copy.html /// [`read_unaligned`]: ./fn.read_unaligned.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -447,7 +441,7 @@ pub unsafe fn read(src: *const T) -> T { /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -463,7 +457,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_unaligned`]: ./fn.write_unaligned.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -530,7 +523,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// `write` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write` can trigger undefined behavior if any of the following conditions /// are violated: @@ -540,7 +533,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples @@ -609,15 +601,13 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// `write_unaligned` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_unaligned` can trigger undefined behavior if any of the following /// conditions are violated: /// /// * `dst` must point to valid memory. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Access fields in a packed struct: @@ -684,7 +674,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// `read_volatile` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -702,7 +692,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_volatile`]: ./fn.write_volatile.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -754,7 +743,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_volatile` can trigger undefined behavior if any of the following /// conditions are violated: @@ -763,8 +752,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Basic usage: From 422b6164e505bc240948dc6e420a82c89ead0711 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:28:10 -0700 Subject: [PATCH 05/20] Fix broken link in `write_unaligned` docs --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4cb9c655441..c679a1a2456 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -592,7 +592,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been [`read`] from. +/// memory that has previously been read with [`read_unaligned`]. /// /// [`write`]: ./fn.write.html /// [`read_unaligned`]: ./fn.read_unaligned.html From d7ce9a213c11f825b8b47f7d9fd970cfb97033bd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 20:45:16 -0700 Subject: [PATCH 06/20] Fix broken relative links --- src/libcore/intrinsics.rs | 12 ++++++------ src/libcore/ptr.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index daa43337fd7..8c510842c2a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the - /// region at `src` *or* the region at `dst` can be used or dropped after - /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise - /// copies of `T`, regardless of whether `T: Copy`, which can result in - /// undefined behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only + /// the region at `src` *or* the region at `dst` can be used or dropped + /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates + /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result + /// in undefined behavior if both copies are used. /// /// # Examples /// @@ -1043,7 +1043,7 @@ extern "rust-intrinsic" { /// assert!(b.is_empty()); /// ``` /// - /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append + /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c679a1a2456..962fb0f31a4 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -50,7 +50,7 @@ pub use intrinsics::write_bytes; /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// -/// [`ptr::read`]: ./fn.read.html +/// [`ptr::read`]: ../ptr/fn.read.html /// /// # Safety /// @@ -72,7 +72,7 @@ pub use intrinsics::write_bytes; /// dropped. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ./fn.write.html +/// [`write`]: ../ptr/fn.write.html /// /// # Examples /// From d7209d5babae4e1e428771287eaca6165e43972c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 9 Apr 2018 14:23:08 -0700 Subject: [PATCH 07/20] Fix various nits from PR review - Remove redundant "unsafe" from module description. - Add a missing `Safety` heading to `read_unaligned`. - Remove weasel words in `Undefined Behavior` description for `write{,_unaligned,_bytes}`. --- src/libcore/ptr.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 962fb0f31a4..3d15e4b1658 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Manually manage memory through raw, unsafe pointers. +//! Manually manage memory through raw pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -438,6 +438,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`read`]: ./fn.read.html /// +/// # Safety +/// /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// @@ -525,8 +527,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write` can trigger undefined behavior if any of the following conditions -/// are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -603,8 +604,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Undefined Behavior /// -/// `write_unaligned` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -745,8 +745,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write_volatile` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// From e350ba48ed80c000fd2d2b5ac37e53a9efe1f587 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 14:14:43 -0700 Subject: [PATCH 08/20] Use the "Safety" heading instead of "Undefined Behavior" --- src/libcore/intrinsics.rs | 30 +++++++------------------- src/libcore/ptr.rs | 44 +-------------------------------------- 2 files changed, 9 insertions(+), 65 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8c510842c2a..df3f6c43031 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -971,12 +971,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. - /// The caller must ensure that `src` points to a valid sequence of type - /// `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -986,17 +980,19 @@ extern "rust-intrinsic" { /// `count * size_of::()` bytes must be valid (but may or may not be /// initialized). /// + /// * The two regions of memory must *not* overlap. + /// /// * `src` must be properly aligned. /// /// * `dst` must be properly aligned. /// - /// * The two regions of memory must *not* overlap. + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only - /// the region at `src` *or* the region at `dst` can be used or dropped - /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates - /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result - /// in undefined behavior if both copies are used. + /// [`Copy`]: ../marker/trait.Copy.html /// /// # Examples /// @@ -1060,11 +1056,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy` is unsafe because it dereferences a raw pointer. The caller must - /// ensure that `src` points to a valid sequence of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -1112,11 +1103,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `write_bytes` is unsafe because it dereferences a raw pointer. The - /// caller must ensure that the poiinter points to a valid value of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `dst` and has a length of diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d15e4b1658..50627ee464d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -54,11 +54,6 @@ pub use intrinsics::write_bytes; /// /// # Safety /// -/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `to_drop` must point to valid memory. @@ -153,11 +148,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// # Safety /// -/// `swap` is unsafe because it dereferences a raw pointer. The caller must -/// ensure that both pointers point to valid values of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `x` and `y` must point to valid, initialized memory. @@ -307,14 +297,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// # Safety -/// -/// `replace` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # Undefined Behavior +/// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -350,11 +335,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// `read` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -440,11 +420,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// # Safety /// -/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -523,10 +498,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Safety /// -/// `write` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -600,10 +571,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Safety /// -/// `write_unaligned` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -671,11 +638,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -741,10 +703,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// `write_volatile` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. From 827251e92bef9bd613cf44e2dc074fa1dc71ea0f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 15:52:16 -0700 Subject: [PATCH 09/20] Shorten ownership safety discussion in `read_volatile` Non-`Copy` types should not be in volatile memory. --- src/libcore/ptr.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 50627ee464d..f3cf2068766 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -622,6 +622,11 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory read with `read_volatile` should almost always be written to using +/// [`write_volatile`]. +/// +/// [`write_volatile`]: ./fn.write_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -644,16 +649,13 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// * `src` must be properly aligned. /// -/// Additionally, if `T` is not [`Copy`], only the returned value *or* the -/// pointed-to value can be used or dropped after calling `read_volatile`. -/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: -/// Copy`, which can result in undefined behavior if both copies are used. -/// Note that `*src = foo` counts as a use because it will attempt to drop the -/// value previously at `*src`. [`write_volatile`] can be used to overwrite -/// data without causing it to be dropped. +/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to +/// object, regardless of whether `T` is [`Copy`]. Using both values can cause +/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is +/// almost certainly incorrect. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write_volatile`]: ./fn.write_volatile.html +/// [`read`]: ./fn.read.html /// /// # Examples /// @@ -680,6 +682,9 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory written with `write_volatile` should almost always be read from using +/// [`read_volatile`]. +/// /// `write_volatile` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care must be taken not to overwrite /// an object that should be dropped. @@ -687,6 +692,8 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// +/// [`read_volatile`]: ./fn.read_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, From 37783563edf74b6e3a4c816ec2ff3911fad30e8c Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 10 May 2018 12:11:47 +0900 Subject: [PATCH 10/20] Update the man page with additional --print options --- src/doc/man/rustc.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 39d10539959..8f611063dbe 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -55,7 +55,7 @@ Configure the output that \fBrustc\fR will produce. Each emission may also have an optional explicit output \fIPATH\fR specified for that particular emission kind. This path takes precedence over the \fB-o\fR option. .TP -\fB\-\-print\fR [crate\-name|file\-names|sysroot] +\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs] Comma separated list of compiler information to print on stdout. .TP \fB\-g\fR From 4b14573d50ef13e869db6f997873b1051d2a2c34 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 May 2018 00:02:05 +0200 Subject: [PATCH 11/20] Add minification process --- src/Cargo.lock | 20 ++++++++++++----- src/librustdoc/Cargo.toml | 1 + src/librustdoc/html/render.rs | 36 +++++++++++++++++++++--------- src/librustdoc/html/static/main.js | 4 ++-- src/librustdoc/lib.rs | 10 ++++++++- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 21c35458398..1746621661c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -233,7 +233,7 @@ dependencies = [ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -417,7 +417,7 @@ dependencies = [ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1169,7 +1169,7 @@ dependencies = [ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1187,6 +1187,14 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "minifier" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz-sys" version = "0.1.10" @@ -2222,6 +2230,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ + "minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2654,7 +2663,7 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3099,6 +3108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "26f3e36a4db1981b16567e4abfd6ddc3641bc9b950bdc868701f656bf9b74bdd" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" "checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa" @@ -3197,7 +3207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" "checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c" +"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 3a376bb9aff..96a2194eeee 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,3 +10,4 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.1.2", default-features = false } tempdir = "0.3" +minifier = "0.0.11" diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 21de2db1dfe..f945534c409 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -76,6 +76,8 @@ use html::item_type::ItemType; use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; use html::{highlight, layout}; +use minifier; + /// A pair of name and its optional document. pub type NameDoc = (String, Option); @@ -509,7 +511,8 @@ pub fn run(mut krate: clean::Crate, css_file_extension: Option, renderinfo: RenderInfo, sort_modules_alphabetically: bool, - themes: Vec) -> Result<(), Error> { + themes: Vec, + enable_minification: bool) -> Result<(), Error> { let src_root = match krate.src { FileName::Real(ref p) => match p.parent() { Some(p) => p.to_path_buf(), @@ -661,7 +664,7 @@ pub fn run(mut krate: clean::Crate, CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear()); - write_shared(&cx, &krate, &*cache, index)?; + write_shared(&cx, &krate, &*cache, index, enable_minification)?; // And finally render the whole crate's documentation cx.krate(krate) @@ -740,7 +743,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { fn write_shared(cx: &Context, krate: &clean::Crate, cache: &Cache, - search_index: String) -> Result<(), Error> { + search_index: String, + enable_minification: bool) -> Result<(), Error> { // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. @@ -814,16 +818,20 @@ themePicker.onclick = function() {{ .join(",")).as_bytes(), )?; - write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), - include_bytes!("static/main.js"))?; - write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), - include_bytes!("static/settings.js"))?; + write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), + include_str!("static/main.js"), + enable_minification)?; + write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), + include_str!("static/settings.js"), + enable_minification)?; { let mut data = format!("var resourcesSuffix = \"{}\";\n", - cx.shared.resource_suffix).into_bytes(); - data.extend_from_slice(include_bytes!("static/storage.js")); - write(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), &data)?; + cx.shared.resource_suffix); + data.push_str(include_str!("static/storage.js")); + write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), + &data, + enable_minification)?; } if let Some(ref css) = cx.shared.css_file_extension { @@ -1020,6 +1028,14 @@ fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> { Ok(try_err!(fs::write(&dst, contents), &dst)) } +fn write_minify(dst: PathBuf, contents: &str, enable_minification: bool) -> Result<(), Error> { + if enable_minification { + write(dst, minifier::js::minify(contents).as_bytes()) + } else { + write(dst, contents.as_bytes()) + } +} + /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a /// static HTML tree. Each component in the cleaned path will be passed as an diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8569abeb09c..2e7a1c68579 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -196,7 +196,7 @@ onEach(e.getElementsByTagName('span'), function(i_e) { removeClass(i_e, 'line-highlighted'); }); - }) + }); for (i = from; i <= to; ++i) { addClass(document.getElementById(i), 'line-highlighted'); } @@ -1944,7 +1944,7 @@ hasClass(next.nextElementSibling, 'docblock')))) { insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); } - } + }; onEach(document.getElementsByClassName('method'), func); onEach(document.getElementsByClassName('impl'), func); onEach(document.getElementsByClassName('impl-items'), function(e) { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 059d4169895..e79f67db130 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -46,6 +46,7 @@ extern crate test as testing; extern crate rustc_errors as errors; extern crate pulldown_cmark; extern crate tempdir; +extern crate minifier; extern crate serialize as rustc_serialize; // used by deriving @@ -297,6 +298,11 @@ pub fn opts() -> Vec { "How errors and other messages are produced", "human|json|short") }), + unstable("disable-minification", |o| { + o.optflag("", + "disable-minification", + "Disable minification applied on JS files") + }), ] } @@ -478,6 +484,7 @@ pub fn main_args(args: &[String]) -> isize { let linker = matches.opt_str("linker").map(PathBuf::from); let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); let resource_suffix = matches.opt_str("resource-suffix"); + let enable_minification = !matches.opt_present("disable-minification"); let edition = matches.opt_str("edition").unwrap_or("2015".to_string()); let edition = match edition.parse() { @@ -521,7 +528,8 @@ pub fn main_args(args: &[String]) -> isize { css_file_extension, renderinfo, sort_modules_alphabetically, - themes) + themes, + enable_minification) .expect("failed to generate documentation"); 0 } From e2db0a5630a39fc1725cae1e804120cff75dc1cb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 May 2018 00:45:41 +0200 Subject: [PATCH 12/20] Update js tester tool --- src/tools/rustdoc-js/tester.js | 173 +++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 49 deletions(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 25f7a2d1294..1fc0d649f4f 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -12,73 +12,148 @@ const fs = require('fs'); const TEST_FOLDER = 'src/test/rustdoc-js/'; +function getNextStep(content, pos, stop) { + while (pos < content.length && content[pos] !== stop && + (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) { + pos += 1; + } + if (pos >= content.length) { + return null; + } + if (content[pos] !== stop) { + return pos * -1; + } + return pos; +} + // Stupid function extractor based on indent. function extractFunction(content, functionName) { - var x = content.split('\n'); - var in_func = false; var indent = 0; - var lines = []; + var splitter = "function " + functionName + "("; - for (var i = 0; i < x.length; ++i) { - if (in_func === false) { - var splitter = "function " + functionName + "("; - if (x[i].trim().startsWith(splitter)) { - in_func = true; - indent = x[i].split(splitter)[0].length; - lines.push(x[i]); - } - } else { - lines.push(x[i]); - if (x[i].trim() === "}" && x[i].split("}")[0].length === indent) { - return lines.join("\n"); - } + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; } + var pos = start; + while (pos < content.length && content[pos] !== ')') { + pos += 1; + } + if (pos >= content.length) { + break; + } + pos = getNextStep(content, pos + 1, '{'); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + var is_escaped = false; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === '{') { + indent += 1; + } else if (content[pos] === '}') { + indent -= 1; + if (indent === 0) { + return content.slice(start, pos + 1); + } + } + pos += 1; + } + content = content.slice(start + 1); } return null; } // Stupid function extractor for array. function extractArrayVariable(content, arrayName) { - var x = content.split('\n'); - var found_var = false; - var lines = []; - - for (var i = 0; i < x.length; ++i) { - if (found_var === false) { - var splitter = "var " + arrayName + " = ["; - if (x[i].trim().startsWith(splitter)) { - found_var = true; - i -= 1; - } - } else { - lines.push(x[i]); - if (x[i].endsWith('];')) { - return lines.join("\n"); - } + var splitter = "var " + arrayName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + pos = getNextStep(content, pos, '['); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ']' && + pos + 1 < content.length && + content[pos + 1] === ';') { + return content.slice(start, pos + 2); + } + pos += 1; + } + content = content.slice(start + 1); } return null; } // Stupid function extractor for variable. function extractVariable(content, varName) { - var x = content.split('\n'); - var found_var = false; - var lines = []; - - for (var i = 0; i < x.length; ++i) { - if (found_var === false) { - var splitter = "var " + varName + " = "; - if (x[i].trim().startsWith(splitter)) { - found_var = true; - i -= 1; - } - } else { - lines.push(x[i]); - if (x[i].endsWith(';')) { - return lines.join("\n"); - } + var splitter = "var " + varName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ';') { + return content.slice(start, pos + 1); + } + pos += 1; + } + content = content.slice(start + 1); } return null; } @@ -101,7 +176,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { for (var i = 0; i < thingsToLoad.length; ++i) { var tmp = funcToCall(fileContent, thingsToLoad[i]); if (tmp === null) { - console.error('enable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); process.exit(1); } content += tmp; From 3daded02facb956919c304ac46af7d69145ab8d2 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 12 May 2018 18:25:09 +0100 Subject: [PATCH 13/20] rustdoc: Add support for pub(restricted) --- src/librustdoc/clean/mod.rs | 17 ++++++++++-- src/librustdoc/html/format.rs | 15 ++++++++-- src/test/rustdoc/pub-restricted.rs | 44 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/pub-restricted.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 007938e86ed..0d628d47766 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -17,7 +17,7 @@ pub use self::ItemEnum::*; pub use self::TyParamBound::*; pub use self::SelfTy::*; pub use self::FunctionRetTy::*; -pub use self::Visibility::*; +pub use self::Visibility::{Public, Inherited}; use syntax; use rustc_target::spec::abi::Abi; @@ -2976,11 +2976,22 @@ impl<'tcx> Clean for ty::FieldDef { pub enum Visibility { Public, Inherited, + Crate, + Restricted(DefId, Path), } impl Clean> for hir::Visibility { - fn clean(&self, _: &DocContext) -> Option { - Some(if *self == hir::Visibility::Public { Public } else { Inherited }) + fn clean(&self, cx: &DocContext) -> Option { + Some(match *self { + hir::Visibility::Public => Visibility::Public, + hir::Visibility::Inherited => Visibility::Inherited, + hir::Visibility::Crate => Visibility::Crate, + hir::Visibility::Restricted { ref path, .. } => { + let path = path.clean(cx); + let did = register_def(cx, path.def); + Visibility::Restricted(did, path) + } + }) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a9a4c511374..2db57c97dd4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -927,8 +927,19 @@ impl<'a> fmt::Display for Method<'a> { impl<'a> fmt::Display for VisSpace<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.get() { - Some(clean::Public) => write!(f, "pub "), - Some(clean::Inherited) | None => Ok(()) + Some(clean::Public) => f.write_str("pub "), + Some(clean::Inherited) | None => Ok(()), + Some(clean::Visibility::Crate) => write!(f, "pub(crate) "), + Some(clean::Visibility::Restricted(did, ref path)) => { + f.write_str("pub(")?; + if path.segments.len() != 1 + || (path.segments[0].name != "self" && path.segments[0].name != "super") + { + f.write_str("in ")?; + } + resolved_path(f, did, path, true, false)?; + f.write_str(") ") + } } } } diff --git a/src/test/rustdoc/pub-restricted.rs b/src/test/rustdoc/pub-restricted.rs new file mode 100644 index 00000000000..cc8f628cad4 --- /dev/null +++ b/src/test/rustdoc/pub-restricted.rs @@ -0,0 +1,44 @@ +// Copyright 2018 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. + +// ignore-tidy-linelength + +// compile-flags: --document-private-items + +#![feature(crate_visibility_modifier)] + +#![crate_name = "foo"] + +// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' +pub struct FooPublic; +// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' +crate struct FooJustCrate; +// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' +pub(crate) struct FooPubCrate; +// @has 'foo/struct.FooSelf.html' '//pre' 'pub(self) struct FooSelf' +pub(self) struct FooSelf; +// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(self) struct FooInSelf' +pub(in self) struct FooInSelf; +mod a { + // @has 'foo/a/struct.FooSuper.html' '//pre' 'pub(super) struct FooSuper' + pub(super) struct FooSuper; + // @has 'foo/a/struct.FooInSuper.html' '//pre' 'pub(super) struct FooInSuper' + pub(in super) struct FooInSuper; + // @has 'foo/a/struct.FooInA.html' '//pre' 'pub(in a) struct FooInA' + pub(in a) struct FooInA; + mod b { + // @has 'foo/a/b/struct.FooInSelfSuperB.html' '//pre' 'pub(in self::super::b) struct FooInSelfSuperB' + pub(in self::super::b) struct FooInSelfSuperB; + // @has 'foo/a/b/struct.FooInSuperSuper.html' '//pre' 'pub(in super::super) struct FooInSuperSuper' + pub(in super::super) struct FooInSuperSuper; + // @has 'foo/a/b/struct.FooInAB.html' '//pre' 'pub(in a::b) struct FooInAB' + pub(in a::b) struct FooInAB; + } +} From 87890561f3d09c86b2d99a2115930622b0899d50 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sun, 13 May 2018 12:52:50 -0300 Subject: [PATCH 14/20] Improve eager type resolution error message This PR improves the span of eager resolution type errors referring to indexing and field access to use the base span rather than the whole expression. Also a note "Type must be known at this point." is added to where we at some point in the past emitted the "type must be known at this context" error, so that early failures can be differentiated and will hopefully be less surprising. Fixes #50692 (or at least does the best we can for the moment) r? @estebank --- .../infer/error_reporting/need_type_info.rs | 9 +++++-- src/librustc/traits/error_reporting.rs | 10 ++++---- src/librustc_typeck/check/mod.rs | 8 +++--- src/librustc_typeck/check/writeback.rs | 2 +- .../issue-42234-unknown-receiver-type.stderr | 4 +++ .../span/method-and-field-eager-resolution.rs | 25 +++++++++++++++++++ .../method-and-field-eager-resolution.stderr | 23 +++++++++++++++++ 7 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/span/method-and-field-eager-resolution.rs create mode 100644 src/test/ui/span/method-and-field-eager-resolution.stderr diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index ea3c0a8ddb4..7352c14490d 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -14,6 +14,7 @@ use infer::InferCtxt; use infer::type_variable::TypeVariableOrigin; use ty::{self, Ty, TyInfer, TyVar}; use syntax_pos::Span; +use errors::DiagnosticBuilder; struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, @@ -86,7 +87,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn need_type_info(&self, body_id: Option, span: Span, ty: Ty<'tcx>) { + pub fn need_type_info_err(&self, + body_id: Option, + span: Span, + ty: Ty<'tcx>) + -> DiagnosticBuilder<'gcx> { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); @@ -142,6 +147,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(target_span, label_message); } - err.emit(); + err } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 25be4a2ff5c..f6ec01546c1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1234,7 +1234,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items().sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info(body_id, span, self_ty); + self.need_type_info_err(body_id, span, self_ty).emit(); } else { let mut err = struct_span_err!(self.tcx.sess, span, E0283, @@ -1251,7 +1251,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(body_id, span, ty); + self.need_type_info_err(body_id, span, ty).emit(); } } @@ -1262,9 +1262,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info(body_id, - obligation.cause.span, - a); + self.need_type_info_err(body_id, + obligation.cause.span, + a).emit(); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7b859635f60..9ac55fda3c1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3067,7 +3067,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base: &'gcx hir::Expr, field: &Spanned) -> Ty<'tcx> { let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(expr.span, + let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); @@ -4080,7 +4080,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if idx_t.references_error() { idx_t } else { - let base_t = self.structurally_resolved_type(expr.span, base_t); + let base_t = self.structurally_resolved_type(base.span, base_t); match self.lookup_indexing(expr, base, base_t, idx_t, needs) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable @@ -5053,7 +5053,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info((**self).body_id, sp, ty); + self.need_type_info_err((**self).body_id, sp, ty) + .note("type must be known at this point") + .emit(); } self.demand_suptype(sp, self.tcx.types.err, ty); self.tcx.types.err diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 57c1d33cb5d..b0ee1154e86 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -593,7 +593,7 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { fn report_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t); + .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t).emit(); } } } diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 23315e3b76a..e1e13e9256d 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -5,6 +5,8 @@ LL | let x: Option<_> = None; | - consider giving `x` a type LL | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^^^^^ cannot infer type for `T` + | + = note: type must be known at this point error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:22:5 @@ -12,6 +14,8 @@ error[E0282]: type annotations needed LL | / data.iter() //~ ERROR 22:5: 23:20: type annotations needed LL | | .sum::<_>() | |___________________^ cannot infer type for `_` + | + = note: type must be known at this point error: aborting due to 2 previous errors diff --git a/src/test/ui/span/method-and-field-eager-resolution.rs b/src/test/ui/span/method-and-field-eager-resolution.rs new file mode 100644 index 00000000000..29011abb460 --- /dev/null +++ b/src/test/ui/span/method-and-field-eager-resolution.rs @@ -0,0 +1,25 @@ +// Copyright 2018 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. + +// Test that spans get only base in eager type resolution (structurally_resolve_type). + +fn main() { + let mut x = Default::default(); + x.0; + //~^ ERROR type annotations needed + x = 1; +} + +fn foo() { + let mut x = Default::default(); + x[0]; + //~^ ERROR type annotations needed + x = 1; +} diff --git a/src/test/ui/span/method-and-field-eager-resolution.stderr b/src/test/ui/span/method-and-field-eager-resolution.stderr new file mode 100644 index 00000000000..21e19828a99 --- /dev/null +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -0,0 +1,23 @@ +error[E0282]: type annotations needed + --> $DIR/method-and-field-eager-resolution.rs:15:5 + | +LL | let mut x = Default::default(); + | ----- consider giving `x` a type +LL | x.0; + | ^ cannot infer type for `_` + | + = note: type must be known at this point + +error[E0282]: type annotations needed + --> $DIR/method-and-field-eager-resolution.rs:22:5 + | +LL | let mut x = Default::default(); + | ----- consider giving `x` a type +LL | x[0]; + | ^ cannot infer type for `_` + | + = note: type must be known at this point + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. From 2c4b152356fb95afb27a101d7df6c8a7ad6ebf5b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 13 May 2018 15:54:40 -0400 Subject: [PATCH 15/20] =?UTF-8?q?Add=20=E2=80=9CExamples=E2=80=9D=20sectio?= =?UTF-8?q?n=20header=20in=20f32/f64=20doc=20comments.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is recommend by [RFC 0505] and as far as I know, the only primitive types without this heading. [RFC 0505]: https://github.com/rust-lang/rfcs/blob/c892139be692586e0846fbf934be6fceec17f329/text/0505-api-comment-conventions.md#using-markdown --- src/libstd/f32.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f64.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f849db4ec60..7314d32b020 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -49,6 +49,8 @@ impl f32 { /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f32; /// let g = 3.0_f32; @@ -80,6 +82,8 @@ impl f32 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f32; /// let g = 4.0_f32; @@ -100,6 +104,8 @@ impl f32 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.3_f32; @@ -115,6 +121,8 @@ impl f32 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.7_f32; @@ -130,6 +138,8 @@ impl f32 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -148,6 +158,8 @@ impl f32 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -174,6 +186,8 @@ impl f32 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -200,6 +214,8 @@ impl f32 { /// Using `mul_add` can be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -225,6 +241,8 @@ impl f32 { /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f32 = 7.0; @@ -248,6 +266,8 @@ impl f32 { /// /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f32 = 7.0; @@ -273,6 +293,8 @@ impl f32 { /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -289,6 +311,8 @@ impl f32 { /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -311,6 +335,8 @@ impl f32 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -334,6 +360,8 @@ impl f32 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -358,6 +386,8 @@ impl f32 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -376,6 +406,8 @@ impl f32 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -404,6 +436,8 @@ impl f32 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -420,6 +454,8 @@ impl f32 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -441,6 +477,8 @@ impl f32 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -466,6 +504,8 @@ impl f32 { /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -493,6 +533,8 @@ impl f32 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -512,6 +554,8 @@ impl f32 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -531,6 +575,8 @@ impl f32 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -552,6 +598,8 @@ impl f32 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -573,6 +621,8 @@ impl f32 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -591,6 +641,8 @@ impl f32 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -611,6 +663,8 @@ impl f32 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -630,6 +684,8 @@ impl f32 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -653,6 +709,8 @@ impl f32 { /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -682,6 +740,8 @@ impl f32 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -703,6 +763,8 @@ impl f32 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -722,6 +784,8 @@ impl f32 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -740,6 +804,8 @@ impl f32 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -761,6 +827,8 @@ impl f32 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -782,6 +850,8 @@ impl f32 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -803,6 +873,8 @@ impl f32 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -825,6 +897,8 @@ impl f32 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -846,6 +920,8 @@ impl f32 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 40c3f4d0ef7..75edba8979f 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -49,6 +49,8 @@ impl f64 { /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f64; /// let g = 3.0_f64; @@ -64,6 +66,8 @@ impl f64 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f64; /// let g = 4.0_f64; @@ -80,6 +84,8 @@ impl f64 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.3_f64; @@ -95,6 +101,8 @@ impl f64 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.7_f64; @@ -110,6 +118,8 @@ impl f64 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// let x = 3.5_f64; /// let y = -3.5_f64; @@ -126,6 +136,8 @@ impl f64 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -152,6 +164,8 @@ impl f64 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -178,6 +192,8 @@ impl f64 { /// Using `mul_add` can be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. /// + /// # Examples + /// /// ``` /// let m = 10.0_f64; /// let x = 4.0_f64; @@ -201,6 +217,8 @@ impl f64 { /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f64 = 7.0; @@ -224,6 +242,8 @@ impl f64 { /// /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f64 = 7.0; @@ -248,6 +268,8 @@ impl f64 { /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - x*x).abs(); @@ -262,6 +284,8 @@ impl f64 { /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - x*x).abs(); @@ -278,6 +302,8 @@ impl f64 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// let positive = 4.0_f64; /// let negative = -4.0_f64; @@ -299,6 +325,8 @@ impl f64 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -317,6 +345,8 @@ impl f64 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// let f = 2.0_f64; /// @@ -333,6 +363,8 @@ impl f64 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -355,6 +387,8 @@ impl f64 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// let five = 5.0_f64; /// @@ -369,6 +403,8 @@ impl f64 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// let two = 2.0_f64; /// @@ -390,6 +426,8 @@ impl f64 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// let ten = 10.0_f64; /// @@ -409,6 +447,8 @@ impl f64 { /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// let x = 3.0_f64; /// let y = -3.0_f64; @@ -434,6 +474,8 @@ impl f64 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// let x = 8.0_f64; /// @@ -451,6 +493,8 @@ impl f64 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let y = 3.0_f64; @@ -468,6 +512,8 @@ impl f64 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -485,6 +531,8 @@ impl f64 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -502,6 +550,8 @@ impl f64 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -520,6 +570,8 @@ impl f64 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -540,6 +592,8 @@ impl f64 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -559,6 +613,8 @@ impl f64 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// let f = 1.0_f64; /// @@ -580,6 +636,8 @@ impl f64 { /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -609,6 +667,8 @@ impl f64 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -630,6 +690,8 @@ impl f64 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// let x = 7.0_f64; /// @@ -647,6 +709,8 @@ impl f64 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -665,6 +729,8 @@ impl f64 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -686,6 +752,8 @@ impl f64 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -707,6 +775,8 @@ impl f64 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -728,6 +798,8 @@ impl f64 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.sinh().asinh(); @@ -748,6 +820,8 @@ impl f64 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.cosh().acosh(); @@ -767,6 +841,8 @@ impl f64 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// From 703ecebe02333014e6c948370042db9df696d818 Mon Sep 17 00:00:00 2001 From: Katrin Leinweber <9948149+katrinleinweber@users.noreply.github.com> Date: Mon, 14 May 2018 07:17:56 +0200 Subject: [PATCH 16/20] Hyperlink DOI against preferred resolver https://www.doi.org/doi_handbook/3_Resolution.html#3.8 --- src/libsyntax_pos/hygiene.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 658408519b9..be031ea98c9 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -13,7 +13,7 @@ //! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012. //! *Macros that work together: Compile-time bindings, partial expansion, //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. -//! DOI=10.1017/S0956796812000093 +//! DOI=10.1017/S0956796812000093 use GLOBALS; use Span; From 120cd2cfd67310571982236bccb1e7679ef9beea Mon Sep 17 00:00:00 2001 From: Matt Kraai Date: Mon, 14 May 2018 07:15:48 -0700 Subject: [PATCH 17/20] Uncapitalize "You" --- src/libcore/iter/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ddbb5998942..173dfc36f04 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -587,7 +587,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// that information can be useful. For example, if you want to iterate /// backwards, a good start is to know where the end is. /// -/// When implementing an `ExactSizeIterator`, You must also implement +/// When implementing an `ExactSizeIterator`, you must also implement /// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* /// return the exact size of the iterator. /// From 2ccf71c3b24e9a3ba5062c8230aa66079b748edb Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 11 May 2018 01:08:58 +0800 Subject: [PATCH 18/20] Migrate the toolstate update bot to rust-highfive --- .travis.yml | 2 +- appveyor.yml | 2 +- src/ci/docker/x86_64-gnu-tools/repo.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 23c47bc9f76..9e62b895ed2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -197,7 +197,7 @@ env: # AWS_SECRET_ACCESS_KEY=... - secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo=" # TOOLSTATE_REPO_ACCESS_TOKEN=... - - secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk=" + - secure: "ESfcXqv4N2VMhqi2iIyw6da9VrsA78I4iR1asouCaq4hzTTrkB4WNRrfURy6xg72gQ4nMhtRJbB0/2jmc9Cu1+g2CzXtyiL223aJ5CKrXdcvbitopQSDfp07dMWm+UED+hNFEanpErKAeU/6FM3A+J+60PMk8MCF1h9tqNRISJw=" before_install: # We'll use the AWS cli to download/upload cached docker layers, so install diff --git a/appveyor.yml b/appveyor.yml index 60f5b4be8de..b1e2e1545cf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80 SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c TOOLSTATE_REPO_ACCESS_TOKEN: - secure: PTZiSxJMVUZ0VnMR5i13E4OagbXfglj7pcskDQiKufVrDm13mLoI0vDJAEM35+bY + secure: gKGlVktr7iuqCoYSxHxDE9ltLOKU0nYDEuQxvWbNxUIW7ri5ppn8L06jQzN0GGzN # By default schannel checks revocation of certificates unlike some other SSL # backends, but we've historically had problems on CI where a revocation diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh index c10afef753e..807e6fb7b64 100644 --- a/src/ci/docker/x86_64-gnu-tools/repo.sh +++ b/src/ci/docker/x86_64-gnu-tools/repo.sh @@ -60,7 +60,7 @@ commit_toolstate_change() { OLDFLAGS="$-" set -eu - git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com' + git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com' git config --global user.name 'Rust Toolstate Update' git config --global credential.helper store printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \ From df2bbf796001b28362547b5a42cf514e6e09e204 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Sat, 12 May 2018 14:34:41 +0200 Subject: [PATCH 19/20] ci: Add Dockerfile for dist-sparc64-linux --- .../disabled/dist-sparc64-linux/Dockerfile | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/ci/docker/disabled/dist-sparc64-linux/Dockerfile diff --git a/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile new file mode 100644 index 00000000000..952c265a139 --- /dev/null +++ b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-sparc64-linux-gnu \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV HOSTS=sparc64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS From a10577ca5367272a8a4b02f5d5ba7be81e43d170 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 15 May 2018 20:34:17 +1200 Subject: [PATCH 20/20] save-analysis: handle aliasing imports a bit more nicely --- src/Cargo.lock | 54 +++++++++-- src/librustc_save_analysis/Cargo.toml | 2 +- src/librustc_save_analysis/dump_visitor.rs | 100 ++------------------- 3 files changed, 55 insertions(+), 101 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 2f52c889558..6103c77ec22 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -79,15 +79,15 @@ dependencies = [ [[package]] name = "assert_cli" -version = "0.5.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -183,6 +183,11 @@ dependencies = [ name = "build_helper" version = "0.1.0" +[[package]] +name = "bytecount" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.2" @@ -570,6 +575,11 @@ name = "diff" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "difference" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "difference" version = "2.0.0" @@ -1550,7 +1560,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1689,6 +1699,15 @@ dependencies = [ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rls-data" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rls-rustc" version = "0.2.2" @@ -2140,7 +2159,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2290,7 +2309,7 @@ dependencies = [ name = "rustfmt-nightly" version = "0.6.1" dependencies = [ - "assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2417,6 +2436,21 @@ name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "skeptic" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "smallvec" version = "0.6.0" @@ -2988,7 +3022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8ca6beaa44a3520407b28a4a779a19b1364fcadcb2f258c41a7baf3102ced0" +"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" @@ -2996,6 +3030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" +"checksum bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "882585cd7ec84e902472df34a5e01891202db3bf62614e1f0afe459c1afcf744" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3" "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" @@ -3020,6 +3055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" "checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" @@ -3132,6 +3168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46" "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" +"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988" "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" @@ -3162,6 +3199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" +"checksum skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4474d6da9593171bcb086890fc344a3a12783cb24e5b141f8a5d0e43561f4b6" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" "checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 976614c9542..7b94170ef6d 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -16,7 +16,7 @@ rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.15" +rls-data = "0.16" rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index abaa02a856e..2ef294fe430 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -268,80 +268,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } - fn process_def_kind( - &mut self, - ref_id: NodeId, - span: Span, - sub_span: Option, - def_id: DefId, - ) { - if self.span.filter_generated(sub_span, span) { - return; - } - - let def = self.save_ctxt.get_path_def(ref_id); - match def { - HirDef::Mod(_) => { - let span = self.span_from_span(sub_span.expect("No span found for mod ref")); - self.dumper.dump_ref(Ref { - kind: RefKind::Mod, - span, - ref_id: ::id_from_def_id(def_id), - }); - } - HirDef::Struct(..) | - HirDef::Variant(..) | - HirDef::Union(..) | - HirDef::Enum(..) | - HirDef::TyAlias(..) | - HirDef::TyForeign(..) | - HirDef::TraitAlias(..) | - HirDef::Trait(_) => { - let span = self.span_from_span(sub_span.expect("No span found for type ref")); - self.dumper.dump_ref(Ref { - kind: RefKind::Type, - span, - ref_id: ::id_from_def_id(def_id), - }); - } - HirDef::Static(..) | - HirDef::Const(..) | - HirDef::StructCtor(..) | - HirDef::VariantCtor(..) => { - let span = self.span_from_span(sub_span.expect("No span found for var ref")); - self.dumper.dump_ref(Ref { - kind: RefKind::Variable, - span, - ref_id: ::id_from_def_id(def_id), - }); - } - HirDef::Fn(..) => { - let span = self.span_from_span(sub_span.expect("No span found for fn ref")); - self.dumper.dump_ref(Ref { - kind: RefKind::Function, - span, - ref_id: ::id_from_def_id(def_id), - }); - } - // With macros 2.0, we can legitimately get a ref to a macro, but - // we don't handle it properly for now (FIXME). - HirDef::Macro(..) => {} - HirDef::Local(..) | - HirDef::Upvar(..) | - HirDef::SelfTy(..) | - HirDef::Label(_) | - HirDef::TyParam(..) | - HirDef::Method(..) | - HirDef::AssociatedTy(..) | - HirDef::AssociatedConst(..) | - HirDef::PrimTy(_) | - HirDef::GlobalAsm(_) | - HirDef::Err => { - span_bug!(span, "process_def_kind for unexpected item: {:?}", def); - } - } - } - fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { for arg in formals { self.visit_pat(&arg.pat); @@ -1348,29 +1274,17 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; let sub_span = self.span.span_for_last_ident(path.span); - let mod_id = match self.lookup_def_id(id) { - Some(def_id) => { - self.process_def_kind(id, path.span, sub_span, def_id); - Some(def_id) - } - None => None, - }; - - // 'use' always introduces an alias, if there is not an explicit - // one, there is an implicit one. - let sub_span = match self.span.sub_span_after_keyword(use_tree.span, - keywords::As) { - Some(sub_span) => Some(sub_span), - None => sub_span, - }; + let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As); + let ref_id = self.lookup_def_id(id); if !self.span.filter_generated(sub_span, path.span) { - let span = - self.span_from_span(sub_span.expect("No span found for use")); + let span = self.span_from_span(sub_span.expect("No span found for use")); + let alias_span = alias_span.map(|sp| self.span_from_span(sp)); self.dumper.import(&access, Import { kind: ImportKind::Use, - ref_id: mod_id.map(|id| ::id_from_def_id(id)), + ref_id: ref_id.map(|id| ::id_from_def_id(id)), span, + alias_span, name: ident.to_string(), value: String::new(), parent, @@ -1407,6 +1321,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { kind: ImportKind::GlobUse, ref_id: None, span, + alias_span: None, name: "*".to_owned(), value: names.join(", "), parent, @@ -1500,6 +1415,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc kind: ImportKind::ExternCrate, ref_id: None, span, + alias_span: None, name: item.ident.to_string(), value: String::new(), parent,