Skip to content

Commit a3ebc6e

Browse files
Revert "directly expose copy and copy_nonoverlapping intrinsics"
This reverts commit 18d12ad.
1 parent 9c14391 commit a3ebc6e

File tree

3 files changed

+234
-180
lines changed

3 files changed

+234
-180
lines changed

library/core/src/intrinsics.rs

Lines changed: 198 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,157 +1742,6 @@ extern "rust-intrinsic" {
17421742
/// Allocate at compile time. Should not be called at runtime.
17431743
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
17441744
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
1745-
1746-
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
1747-
/// and destination must *not* overlap.
1748-
///
1749-
/// For regions of memory which might overlap, use [`copy`] instead.
1750-
///
1751-
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
1752-
/// with the argument order swapped.
1753-
///
1754-
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
1755-
///
1756-
/// # Safety
1757-
///
1758-
/// Behavior is undefined if any of the following conditions are violated:
1759-
///
1760-
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
1761-
///
1762-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1763-
///
1764-
/// * Both `src` and `dst` must be properly aligned.
1765-
///
1766-
/// * The region of memory beginning at `src` with a size of `count *
1767-
/// size_of::<T>()` bytes must *not* overlap with the region of memory
1768-
/// beginning at `dst` with the same size.
1769-
///
1770-
/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
1771-
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
1772-
/// in the region beginning at `*src` and the region beginning at `*dst` can
1773-
/// [violate memory safety][read-ownership].
1774-
///
1775-
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1776-
/// `0`, the pointers must be non-NULL and properly aligned.
1777-
///
1778-
/// [`read`]: crate::ptr::read
1779-
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
1780-
/// [valid]: crate::ptr#safety
1781-
///
1782-
/// # Examples
1783-
///
1784-
/// Manually implement [`Vec::append`]:
1785-
///
1786-
/// ```
1787-
/// use std::ptr;
1788-
///
1789-
/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
1790-
/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
1791-
/// let src_len = src.len();
1792-
/// let dst_len = dst.len();
1793-
///
1794-
/// // Ensure that `dst` has enough capacity to hold all of `src`.
1795-
/// dst.reserve(src_len);
1796-
///
1797-
/// unsafe {
1798-
/// // The call to offset is always safe because `Vec` will never
1799-
/// // allocate more than `isize::MAX` bytes.
1800-
/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
1801-
/// let src_ptr = src.as_ptr();
1802-
///
1803-
/// // Truncate `src` without dropping its contents. We do this first,
1804-
/// // to avoid problems in case something further down panics.
1805-
/// src.set_len(0);
1806-
///
1807-
/// // The two regions cannot overlap because mutable references do
1808-
/// // not alias, and two different vectors cannot own the same
1809-
/// // memory.
1810-
/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
1811-
///
1812-
/// // Notify `dst` that it now holds the contents of `src`.
1813-
/// dst.set_len(dst_len + src_len);
1814-
/// }
1815-
/// }
1816-
///
1817-
/// let mut a = vec!['r'];
1818-
/// let mut b = vec!['u', 's', 't'];
1819-
///
1820-
/// append(&mut a, &mut b);
1821-
///
1822-
/// assert_eq!(a, &['r', 'u', 's', 't']);
1823-
/// assert!(b.is_empty());
1824-
/// ```
1825-
///
1826-
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
1827-
#[doc(alias = "memcpy")]
1828-
#[stable(feature = "rust1", since = "1.0.0")]
1829-
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1830-
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
1831-
1832-
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
1833-
/// and destination may overlap.
1834-
///
1835-
/// If the source and destination will *never* overlap,
1836-
/// [`copy_nonoverlapping`] can be used instead.
1837-
///
1838-
/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
1839-
/// order swapped. Copying takes place as if the bytes were copied from `src`
1840-
/// to a temporary array and then copied from the array to `dst`.
1841-
///
1842-
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
1843-
///
1844-
/// # Safety
1845-
///
1846-
/// Behavior is undefined if any of the following conditions are violated:
1847-
///
1848-
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
1849-
///
1850-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1851-
///
1852-
/// * Both `src` and `dst` must be properly aligned.
1853-
///
1854-
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
1855-
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
1856-
/// in the region beginning at `*src` and the region beginning at `*dst` can
1857-
/// [violate memory safety][read-ownership].
1858-
///
1859-
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1860-
/// `0`, the pointers must be non-NULL and properly aligned.
1861-
///
1862-
/// [`read`]: crate::ptr::read
1863-
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
1864-
/// [valid]: crate::ptr#safety
1865-
///
1866-
/// # Examples
1867-
///
1868-
/// Efficiently create a Rust vector from an unsafe buffer:
1869-
///
1870-
/// ```
1871-
/// use std::ptr;
1872-
///
1873-
/// /// # Safety
1874-
/// ///
1875-
/// /// * `ptr` must be correctly aligned for its type and non-zero.
1876-
/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
1877-
/// /// * Those elements must not be used after calling this function unless `T: Copy`.
1878-
/// # #[allow(dead_code)]
1879-
/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
1880-
/// let mut dst = Vec::with_capacity(elts);
1881-
///
1882-
/// // SAFETY: Our precondition ensures the source is aligned and valid,
1883-
/// // and `Vec::with_capacity` ensures that we have usable space to write them.
1884-
/// ptr::copy(ptr, dst.as_mut_ptr(), elts);
1885-
///
1886-
/// // SAFETY: We created it with this much capacity earlier,
1887-
/// // and the previous `copy` has initialized these elements.
1888-
/// dst.set_len(elts);
1889-
/// dst
1890-
/// }
1891-
/// ```
1892-
#[doc(alias = "memmove")]
1893-
#[stable(feature = "rust1", since = "1.0.0")]
1894-
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1895-
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
18961745
}
18971746

18981747
// Some functions are defined here because they accidentally got made
@@ -1906,6 +1755,204 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
19061755
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
19071756
}
19081757

1758+
/// Checks whether the regions of memory starting at `src` and `dst` of size
1759+
/// `count * size_of::<T>()` do *not* overlap.
1760+
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
1761+
let src_usize = src as usize;
1762+
let dst_usize = dst as usize;
1763+
let size = mem::size_of::<T>().checked_mul(count).unwrap();
1764+
let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
1765+
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
1766+
// they do not overlap.
1767+
diff >= size
1768+
}
1769+
1770+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
1771+
/// and destination must *not* overlap.
1772+
///
1773+
/// For regions of memory which might overlap, use [`copy`] instead.
1774+
///
1775+
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
1776+
/// with the argument order swapped.
1777+
///
1778+
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
1779+
///
1780+
/// # Safety
1781+
///
1782+
/// Behavior is undefined if any of the following conditions are violated:
1783+
///
1784+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
1785+
///
1786+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1787+
///
1788+
/// * Both `src` and `dst` must be properly aligned.
1789+
///
1790+
/// * The region of memory beginning at `src` with a size of `count *
1791+
/// size_of::<T>()` bytes must *not* overlap with the region of memory
1792+
/// beginning at `dst` with the same size.
1793+
///
1794+
/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
1795+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
1796+
/// in the region beginning at `*src` and the region beginning at `*dst` can
1797+
/// [violate memory safety][read-ownership].
1798+
///
1799+
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1800+
/// `0`, the pointers must be non-NULL and properly aligned.
1801+
///
1802+
/// [`read`]: crate::ptr::read
1803+
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
1804+
/// [valid]: crate::ptr#safety
1805+
///
1806+
/// # Examples
1807+
///
1808+
/// Manually implement [`Vec::append`]:
1809+
///
1810+
/// ```
1811+
/// use std::ptr;
1812+
///
1813+
/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
1814+
/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
1815+
/// let src_len = src.len();
1816+
/// let dst_len = dst.len();
1817+
///
1818+
/// // Ensure that `dst` has enough capacity to hold all of `src`.
1819+
/// dst.reserve(src_len);
1820+
///
1821+
/// unsafe {
1822+
/// // The call to offset is always safe because `Vec` will never
1823+
/// // allocate more than `isize::MAX` bytes.
1824+
/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
1825+
/// let src_ptr = src.as_ptr();
1826+
///
1827+
/// // Truncate `src` without dropping its contents. We do this first,
1828+
/// // to avoid problems in case something further down panics.
1829+
/// src.set_len(0);
1830+
///
1831+
/// // The two regions cannot overlap because mutable references do
1832+
/// // not alias, and two different vectors cannot own the same
1833+
/// // memory.
1834+
/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
1835+
///
1836+
/// // Notify `dst` that it now holds the contents of `src`.
1837+
/// dst.set_len(dst_len + src_len);
1838+
/// }
1839+
/// }
1840+
///
1841+
/// let mut a = vec!['r'];
1842+
/// let mut b = vec!['u', 's', 't'];
1843+
///
1844+
/// append(&mut a, &mut b);
1845+
///
1846+
/// assert_eq!(a, &['r', 'u', 's', 't']);
1847+
/// assert!(b.is_empty());
1848+
/// ```
1849+
///
1850+
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
1851+
#[doc(alias = "memcpy")]
1852+
#[stable(feature = "rust1", since = "1.0.0")]
1853+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1854+
#[inline]
1855+
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
1856+
extern "rust-intrinsic" {
1857+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1858+
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
1859+
}
1860+
1861+
// FIXME: Perform these checks only at run time
1862+
/*if cfg!(debug_assertions)
1863+
&& !(is_aligned_and_not_null(src)
1864+
&& is_aligned_and_not_null(dst)
1865+
&& is_nonoverlapping(src, dst, count))
1866+
{
1867+
// Not panicking to keep codegen impact smaller.
1868+
abort();
1869+
}*/
1870+
1871+
// SAFETY: the safety contract for `copy_nonoverlapping` must be
1872+
// upheld by the caller.
1873+
unsafe { copy_nonoverlapping(src, dst, count) }
1874+
}
1875+
1876+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
1877+
/// and destination may overlap.
1878+
///
1879+
/// If the source and destination will *never* overlap,
1880+
/// [`copy_nonoverlapping`] can be used instead.
1881+
///
1882+
/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
1883+
/// order swapped. Copying takes place as if the bytes were copied from `src`
1884+
/// to a temporary array and then copied from the array to `dst`.
1885+
///
1886+
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
1887+
///
1888+
/// # Safety
1889+
///
1890+
/// Behavior is undefined if any of the following conditions are violated:
1891+
///
1892+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
1893+
///
1894+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1895+
///
1896+
/// * Both `src` and `dst` must be properly aligned.
1897+
///
1898+
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
1899+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
1900+
/// in the region beginning at `*src` and the region beginning at `*dst` can
1901+
/// [violate memory safety][read-ownership].
1902+
///
1903+
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1904+
/// `0`, the pointers must be non-NULL and properly aligned.
1905+
///
1906+
/// [`read`]: crate::ptr::read
1907+
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
1908+
/// [valid]: crate::ptr#safety
1909+
///
1910+
/// # Examples
1911+
///
1912+
/// Efficiently create a Rust vector from an unsafe buffer:
1913+
///
1914+
/// ```
1915+
/// use std::ptr;
1916+
///
1917+
/// /// # Safety
1918+
/// ///
1919+
/// /// * `ptr` must be correctly aligned for its type and non-zero.
1920+
/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
1921+
/// /// * Those elements must not be used after calling this function unless `T: Copy`.
1922+
/// # #[allow(dead_code)]
1923+
/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
1924+
/// let mut dst = Vec::with_capacity(elts);
1925+
///
1926+
/// // SAFETY: Our precondition ensures the source is aligned and valid,
1927+
/// // and `Vec::with_capacity` ensures that we have usable space to write them.
1928+
/// ptr::copy(ptr, dst.as_mut_ptr(), elts);
1929+
///
1930+
/// // SAFETY: We created it with this much capacity earlier,
1931+
/// // and the previous `copy` has initialized these elements.
1932+
/// dst.set_len(elts);
1933+
/// dst
1934+
/// }
1935+
/// ```
1936+
#[doc(alias = "memmove")]
1937+
#[stable(feature = "rust1", since = "1.0.0")]
1938+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1939+
#[inline]
1940+
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
1941+
extern "rust-intrinsic" {
1942+
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
1943+
fn copy<T>(src: *const T, dst: *mut T, count: usize);
1944+
}
1945+
1946+
// FIXME: Perform these checks only at run time
1947+
/*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
1948+
// Not panicking to keep codegen impact smaller.
1949+
abort();
1950+
}*/
1951+
1952+
// SAFETY: the safety contract for `copy` must be upheld by the caller.
1953+
unsafe { copy(src, dst, count) }
1954+
}
1955+
19091956
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
19101957
/// `val`.
19111958
///

library/core/src/ptr/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -898,14 +898,18 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
898898
/// ```
899899
#[inline]
900900
#[stable(feature = "rust1", since = "1.0.0")]
901-
#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
902-
pub const unsafe fn write<T>(dst: *mut T, src: T) {
901+
pub unsafe fn write<T>(dst: *mut T, src: T) {
902+
// We are calling the intrinsics directly to avoid function calls in the generated code
903+
// as `intrinsics::copy_nonoverlapping` is a wrapper function.
904+
extern "rust-intrinsic" {
905+
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
906+
}
907+
903908
// SAFETY: the caller must guarantee that `dst` is valid for writes.
904909
// `dst` cannot overlap `src` because the caller has mutable access
905910
// to `dst` while `src` is owned by this function.
906911
unsafe {
907912
copy_nonoverlapping(&src as *const T, dst, 1);
908-
// We are calling the intrinsic directly to avoid function calls in the generated code.
909913
intrinsics::forget(src);
910914
}
911915
}

0 commit comments

Comments
 (0)