diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7d3e7af1a1884..fb0d2d9c88219 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(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. + /// Copies `count * size_of` 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::()` 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). - /// - /// * 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(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); - /// + /// # #[allow(dead_code)] + /// fn swap(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(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. /// - /// 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::()` 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 + /// 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(src: *const T, dst: *mut T, count: usize); - /// 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 - /// - /// 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::()` + /// 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` with - /// // a null pointer. - /// ptr::write_bytes(&mut v, 0, mem::size_of::>()); - /// } - /// - /// // 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); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 63bcc02402015..5f778482f42f2 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() -> *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(dest: *mut T, mut src: T) -> T { @@ -333,23 +258,14 @@ pub unsafe fn replace(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(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 { @@ -412,62 +290,28 @@ 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`], `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(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(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(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) { @@ -552,58 +365,36 @@ 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 /// -/// `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(dst: *mut T, src: T) { @@ -620,11 +411,6 @@ 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, @@ -641,19 +427,12 @@ pub unsafe fn write_unaligned(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(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(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 ///