about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2016-12-11 18:51:22 -0800
committerSteven Fackler <sfackler@gmail.com>2016-12-12 21:44:09 -0800
commit75fe727b785b43c5f31601adc19233d2efb186f0 (patch)
tree601862196601c2f65aca6c8bd8f08ccf9e4a0b96 /src
parent3db197aa9d343c7974b06a9b18ae5f78d5c64637 (diff)
downloadrust-75fe727b785b43c5f31601adc19233d2efb186f0.tar.gz
rust-75fe727b785b43c5f31601adc19233d2efb186f0.zip
Implement RFC #1725
cc #37955
Diffstat (limited to 'src')
-rw-r--r--src/libcore/ptr.rs83
-rw-r--r--src/libcoretest/lib.rs1
-rw-r--r--src/libcoretest/ptr.rs23
3 files changed, 107 insertions, 0 deletions
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 2ad38de72b1..e3ca8eca76c 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -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
 /// 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
 ///
 /// Basic usage:
@@ -137,6 +139,44 @@ pub unsafe fn read<T>(src: *const T) -> T {
     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
 /// 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
 /// memory that has previously been `read` from.
 ///
+/// The pointer must be aligned; use `write_unaligned` if that is not the case.
+///
 /// # Examples
 ///
 /// Basic usage:
@@ -171,6 +213,47 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
     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
 /// leaves the memory in `src` unchanged.
 ///
diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs
index b8c01e570f5..5b6686309a4 100644
--- a/src/libcoretest/lib.rs
+++ b/src/libcoretest/lib.rs
@@ -36,6 +36,7 @@
 #![feature(iter_min_by)]
 #![feature(ordering_chaining)]
 #![feature(result_unwrap_or_default)]
+#![feature(ptr_unaligned)]
 
 extern crate core;
 extern crate test;
diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs
index f7fe61896f8..7f6f472bfbb 100644
--- a/src/libcoretest/ptr.rs
+++ b/src/libcoretest/ptr.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use core::ptr::*;
+use core::cell::RefCell;
 
 #[test]
 fn test() {
@@ -189,3 +190,25 @@ pub fn test_variadic_fnptr() {
     let mut s = SipHasher::new();
     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]));
+}