Auto merge of #38309 - sfackler:rfc-1725, r=alexcrichton
Implement RFC #1725 (read_unaligned, write_unaligned) cc #37955 r? @alexcrichton
This commit is contained in:
commit
0d1b9f4614
|
@ -117,6 +117,8 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
|
||||||
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
|
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
|
||||||
/// because it will attempt to drop the value previously at `*src`.
|
/// because it will attempt to drop the value previously at `*src`.
|
||||||
///
|
///
|
||||||
|
/// The pointer must be aligned; use `read_unaligned` if that is not the case.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
|
@ -137,6 +139,44 @@ pub unsafe fn read<T>(src: *const T) -> T {
|
||||||
tmp
|
tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads the value from `src` without moving it. This leaves the
|
||||||
|
/// memory in `src` unchanged.
|
||||||
|
///
|
||||||
|
/// Unlike `read`, the pointer may be unaligned.
|
||||||
|
///
|
||||||
|
/// # 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`,
|
||||||
|
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
|
||||||
|
/// because it will attempt to drop the value previously at `*src`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(ptr_unaligned)]
|
||||||
|
///
|
||||||
|
/// let x = 12;
|
||||||
|
/// let y = &x as *const i32;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// assert_eq!(std::ptr::read_unaligned(y), 12);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
#[unstable(feature = "ptr_unaligned", issue = "37955")]
|
||||||
|
pub unsafe fn read_unaligned<T>(src: *const T) -> T {
|
||||||
|
let mut tmp: T = mem::uninitialized();
|
||||||
|
copy_nonoverlapping(src as *const u8,
|
||||||
|
&mut tmp as *mut T as *mut u8,
|
||||||
|
mem::size_of::<T>());
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
/// Overwrites a memory location with the given value without reading or
|
/// Overwrites a memory location with the given value without reading or
|
||||||
/// dropping the old value.
|
/// dropping the old value.
|
||||||
///
|
///
|
||||||
|
@ -151,6 +191,8 @@ pub unsafe fn read<T>(src: *const T) -> T {
|
||||||
/// This is appropriate for initializing uninitialized memory, or overwriting
|
/// 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.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
|
@ -171,6 +213,47 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
|
||||||
intrinsics::move_val_init(&mut *dst, src)
|
intrinsics::move_val_init(&mut *dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overwrites a memory location with the given value without reading or
|
||||||
|
/// dropping the old value.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// This is appropriate for initializing uninitialized memory, or overwriting
|
||||||
|
/// memory that has previously been `read` from.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(ptr_unaligned)]
|
||||||
|
///
|
||||||
|
/// let mut x = 0;
|
||||||
|
/// let y = &mut x as *mut i32;
|
||||||
|
/// let z = 12;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// std::ptr::write_unaligned(y, z);
|
||||||
|
/// assert_eq!(std::ptr::read_unaligned(y), 12);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "ptr_unaligned", issue = "37955")]
|
||||||
|
pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
|
||||||
|
copy_nonoverlapping(&src as *const T as *const u8,
|
||||||
|
dst as *mut u8,
|
||||||
|
mem::size_of::<T>());
|
||||||
|
mem::forget(src);
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs a volatile read of the value from `src` without moving it. This
|
/// Performs a volatile read of the value from `src` without moving it. This
|
||||||
/// leaves the memory in `src` unchanged.
|
/// leaves the memory in `src` unchanged.
|
||||||
///
|
///
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#![feature(iter_min_by)]
|
#![feature(iter_min_by)]
|
||||||
#![feature(ordering_chaining)]
|
#![feature(ordering_chaining)]
|
||||||
#![feature(result_unwrap_or_default)]
|
#![feature(result_unwrap_or_default)]
|
||||||
|
#![feature(ptr_unaligned)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use core::ptr::*;
|
use core::ptr::*;
|
||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -189,3 +190,25 @@ pub fn test_variadic_fnptr() {
|
||||||
let mut s = SipHasher::new();
|
let mut s = SipHasher::new();
|
||||||
assert_eq!(p.hash(&mut s), q.hash(&mut s));
|
assert_eq!(p.hash(&mut s), q.hash(&mut s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_unaligned_drop() {
|
||||||
|
thread_local! {
|
||||||
|
static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dropper(u32);
|
||||||
|
|
||||||
|
impl Drop for Dropper {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
DROPS.with(|d| d.borrow_mut().push(self.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let c = Dropper(0);
|
||||||
|
let mut t = Dropper(1);
|
||||||
|
unsafe { write_unaligned(&mut t, c); }
|
||||||
|
}
|
||||||
|
DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue