about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorsteveklabnik <steve@steveklabnik.com>2018-05-17 13:19:41 -0400
committersteveklabnik <steve@steveklabnik.com>2018-05-17 13:19:41 -0400
commiteac94d105394a34f54beddfb77f1d4e7b18769e7 (patch)
treed022a7262c013fa064bd8d91b00f7b945166019c /src
parente3150564f889a3bad01795d9fcb31d4f14d58a99 (diff)
downloadrust-eac94d105394a34f54beddfb77f1d4e7b18769e7.tar.gz
rust-eac94d105394a34f54beddfb77f1d4e7b18769e7.zip
Revert #49767
There was [some confusion](https://github.com/rust-lang/rust/pull/49767#issuecomment-389250815) and I accidentally merged a PR that wasn't ready.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs161
-rw-r--r--src/libcore/ptr.rs370
2 files changed, 101 insertions, 430 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 7d3e7af1a18..fb0d2d9c882 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -962,122 +962,59 @@ extern "rust-intrinsic" {
     /// value is not necessarily valid to be used to actually access memory.
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-    /// and destination must *not* overlap.
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+    /// and destination may *not* overlap.
     ///
-    /// 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
+    /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
     ///
     /// # Safety
     ///
-    /// 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::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` 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.
-    ///
-    /// 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.
-    ///
-    /// [`Copy`]: ../marker/trait.Copy.html
+    /// 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.
     ///
     /// # Examples
     ///
-    /// Manually implement [`Vec::append`]:
+    /// A safe swap function:
     ///
     /// ```
+    /// use std::mem;
     /// use std::ptr;
     ///
-    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-    ///     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);
-    ///
+    /// # #[allow(dead_code)]
+    /// fn swap<T>(x: &mut T, y: &mut T) {
     ///     unsafe {
-    ///         // 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();
-    ///
-    ///         // 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);
-    ///     }
+    ///         // Give ourselves some scratch space to work with
+    ///         let mut t: T = mem::uninitialized();
     ///
-    ///     unsafe {
-    ///         // Truncate `src` without dropping its contents.
-    ///         src.set_len(0);
+    ///         // 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);
     ///
-    ///         // Notify `dst` that it now holds the contents of `src`.
-    ///         dst.set_len(dst_len + 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);
     ///     }
     /// }
-    ///
-    /// 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`]: ../../std/vec/struct.Vec.html#method.append
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
     /// and destination may overlap.
     ///
-    /// 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
+    /// `copy` is semantically equivalent to C's `memmove`.
     ///
     /// # Safety
     ///
-    /// 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::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` 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
+    /// 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.
     ///
     /// # Examples
     ///
@@ -1094,34 +1031,15 @@ extern "rust-intrinsic" {
     ///     dst
     /// }
     /// ```
+    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Sets `count * size_of::<T>()` 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
-    ///
-    /// 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.
+    /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
+    /// bytes of memory starting at `dst` to `val`.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::ptr;
     ///
@@ -1132,23 +1050,6 @@ extern "rust-intrinsic" {
     /// }
     /// assert_eq!(vec, [b'a', b'a', 0, 0]);
     /// ```
-    ///
-    /// Creating an invalid value:
-    ///
-    /// ```no_run
-    /// use std::{mem, ptr};
-    ///
-    /// let mut v = Box::new(0i32);
-    ///
-    /// unsafe {
-    ///     // Leaks the previously held value by overwriting the `Box<T>` with
-    ///     // a null pointer.
-    ///     ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
-    /// }
-    ///
-    /// // 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<T>(dst: *mut T, val: u8, count: usize);
 
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 63bcc024020..5f778482f42 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 pointers.
+//! Raw, unsafe pointers, `*const T`, and `*mut T`.
 //!
 //! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
 
@@ -38,62 +38,21 @@ pub use intrinsics::write_bytes;
 
 /// Executes the destructor (if any) of the pointed-to value.
 ///
-/// This is semantically equivalent to calling [`ptr::read`] and discarding
-/// the result, but has the following advantages:
+/// This has two use cases:
 ///
 /// * 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`]: ../ptr/fn.read.html
-///
 /// # Safety
 ///
-/// 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`]: ../ptr/fn.write.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());
-/// ```
+/// This has all the same safety problems as `ptr::read` with respect to
+/// invalid pointers, types, and double drops.
 #[stable(feature = "drop_in_place", since = "1.8.0")]
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
@@ -134,25 +93,17 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
 /// Swaps the values at two mutable locations of the same type, without
 /// deinitializing either.
 ///
-/// 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
+/// 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.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This function copies the memory through the raw pointers passed to it
+/// as arguments.
 ///
-/// * `x` and `y` must point to valid, initialized memory.
-///
-/// * `x` and `y` must be properly aligned.
+/// Ensure that these pointers are valid before calling `swap`.
 ///
 /// # Examples
 ///
@@ -288,39 +239,13 @@ 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.
-///
-/// 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.
-///
-/// [`mem::replace`]: ../mem/fn.replace.html
+/// Replaces the value at `dest` with `src`, returning the old
+/// value, without dropping either.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dest` must point to valid, initialized memory.
-///
-/// * `dest` must be properly aligned.
-///
-/// # 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 rust[0], 'r')
-/// };
-///
-/// assert_eq!(b, 'b');
-/// assert_eq!(rust, &['r', 'u', 's', 't']);
-/// ```
+/// This is only unsafe because it accepts a raw pointer.
+/// Otherwise, this operation is identical to `mem::replace`.
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
@@ -333,23 +258,14 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// 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`.
 ///
-/// * `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
+/// The pointer must be aligned; use `read_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -363,44 +279,6 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(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<T>(src: *const T) -> T {
@@ -412,62 +290,28 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// Reads the value from `src` without moving it. This leaves the
 /// memory in `src` unchanged.
 ///
-/// Unlike [`read`], `read_unaligned` works with unaligned pointers.
-///
-/// [`read`]: ./fn.read.html
+/// Unlike `read`, the pointer may be unaligned.
 ///
 /// # Safety
 ///
-/// 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
+/// 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`.
 ///
 /// # Examples
 ///
-/// Access members of a packed struct by reference:
+/// Basic usage:
 ///
 /// ```
-/// use std::ptr;
+/// let x = 12;
+/// let y = &x as *const i32;
 ///
-/// #[repr(packed, C)]
-/// #[derive(Default)]
-/// struct Packed {
-///     _padding: u8,
-///     unaligned: u32,
+/// unsafe {
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// 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")]
@@ -482,7 +326,11 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// `write` does not drop the contents of `dst`. This is safe, but it could leak
+/// # 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.
 ///
@@ -490,20 +338,9 @@ pub unsafe fn read_unaligned<T>(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.
-///
-/// [`read`]: ./fn.read.html
-///
-/// # Safety
+/// memory that has previously been `read` from.
 ///
-/// Behavior is undefined 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.
-///
-/// [`write_unaligned`]: ./fn.write_unaligned.html
+/// The pointer must be aligned; use `write_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -519,30 +356,6 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(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<T>(dst: *mut T, src: T) {
@@ -552,58 +365,36 @@ pub unsafe fn write<T>(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
 ///
-/// `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.
+/// 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.
 ///
 /// 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 with [`read_unaligned`].
-///
-/// [`write`]: ./fn.write.html
-/// [`read_unaligned`]: ./fn.read_unaligned.html
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must point to valid memory.
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///
-/// Access fields in a packed struct:
+/// Basic usage:
 ///
 /// ```
-/// 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() };
+/// let mut x = 0;
+/// let y = &mut x as *mut i32;
+/// let z = 12;
 ///
 /// unsafe {
-///     // 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);
+///     std::ptr::write_unaligned(y, z);
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
+/// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
@@ -620,11 +411,6 @@ pub unsafe fn write_unaligned<T>(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,
@@ -641,19 +427,12 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
-///
-/// * `src` must be properly aligned.
-///
-/// 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
-/// [`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`.
 ///
 /// # Examples
 ///
@@ -680,18 +459,6 @@ pub unsafe fn read_volatile<T>(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.
-///
-/// 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,
@@ -708,11 +475,14 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This operation is marked unsafe because it accepts a raw pointer.
 ///
-/// * `dst` must point to valid memory.
+/// 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.
 ///
-/// * `dst` must be properly aligned.
+/// This is appropriate for initializing uninitialized memory, or overwriting
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///