Add ptr::from_raw_parts, ptr::from_raw_parts_mut, and NonNull::from_raw_parts

The use of module-level functions instead of associated functions
on `<*const T>` or `<*mut T>` follows the precedent of
`ptr::slice_from_raw_parts` and `ptr::slice_from_raw_parts_mut`.
This commit is contained in:
Simon Sapin 2021-01-18 16:19:29 +01:00
parent 9ab83b9338
commit 937d580a25
5 changed files with 87 additions and 9 deletions

View file

@ -123,6 +123,7 @@
#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
#![cfg_attr(not(bootstrap), feature(ptr_metadata))]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]

View file

@ -36,16 +36,48 @@ pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
}
#[repr(C)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
components: PtrComponents<T>,
/// Forms a raw pointer from a data address and metadata.
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[inline]
pub const fn from_raw_parts<T: ?Sized>(
data_address: *const (),
metadata: <T as Pointee>::Metadata,
) -> *const T {
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
// and PtrComponents<T> have the same memory layouts. Only std can make this
// guarantee.
unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
}
/// Performs the same functionality as [`from_raw_parts`], except that a
/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
///
/// See the documentation of [`from_raw_parts`] for more details.
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[inline]
pub const fn from_raw_parts_mut<T: ?Sized>(
data_address: *mut (),
metadata: <T as Pointee>::Metadata,
) -> *mut T {
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
// and PtrComponents<T> have the same memory layouts. Only std can make this
// guarantee.
unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
}
#[repr(C)]
struct PtrComponents<T: ?Sized> {
data_address: usize,
metadata: <T as Pointee>::Metadata,
pub(crate) union PtrRepr<T: ?Sized> {
pub(crate) const_ptr: *const T,
pub(crate) mut_ptr: *mut T,
pub(crate) components: PtrComponents<T>,
}
#[repr(C)]
pub(crate) struct PtrComponents<T: ?Sized> {
pub(crate) data_address: *const (),
pub(crate) metadata: <T as Pointee>::Metadata,
}
// Manual impl needed to avoid `T: Copy` bound.

View file

@ -86,7 +86,7 @@ pub use crate::intrinsics::write_bytes;
mod metadata;
#[cfg(not(bootstrap))]
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
pub use metadata::{metadata, DynMetadata, Pointee, Thin};
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
mod non_null;
#[stable(feature = "nonnull", since = "1.25.0")]

View file

@ -175,6 +175,24 @@ impl<T: ?Sized> NonNull<T> {
}
}
/// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
/// `NonNull` pointer is returned, as opposed to a raw `*const` pointer.
///
/// See the documentation of [`std::ptr::from_raw_parts`] for more details.
#[cfg(not(bootstrap))]
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
#[inline]
pub const fn from_raw_parts(
data_address: NonNull<()>,
metadata: <T as super::Pointee>::Metadata,
) -> NonNull<T> {
// SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_address` is.
unsafe {
NonNull::new_unchecked(super::from_raw_parts_mut(data_address.as_ptr(), metadata))
}
}
/// Acquires the underlying `*mut` pointer.
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]

View file

@ -1,5 +1,5 @@
use core::cell::RefCell;
use core::ptr::*;
use core::ptr::{self, *};
use std::fmt::{Debug, Display};
#[test]
@ -525,3 +525,30 @@ fn dyn_metadata() {
assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
}
#[test]
#[cfg(not(bootstrap))]
fn from_raw_parts() {
let mut value = 5_u32;
let address = &mut value as *mut _ as *mut ();
let trait_object: &dyn Display = &mut value;
let vtable = metadata(trait_object);
let trait_object = NonNull::from(trait_object);
assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
let mut array = [5_u32, 5, 5, 5, 5];
let address = &mut array as *mut _ as *mut ();
let array_ptr = NonNull::from(&mut array);
let slice_ptr = NonNull::from(&mut array[..]);
assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
}