Skip to content

Commit

Permalink
Add ptr::from_raw_parts, ptr::from_raw_parts_mut, and `NonNull::f…
Browse files Browse the repository at this point in the history
…rom_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`.
  • Loading branch information
SimonSapin committed Feb 15, 2021
1 parent 9ab83b9 commit 937d580
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 8 deletions.
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Expand Up @@ -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)]
Expand Down
44 changes: 38 additions & 6 deletions library/core/src/ptr/metadata.rs
Expand Up @@ -36,16 +36,48 @@ pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
}

/// 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)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
components: PtrComponents<T>,
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)]
struct PtrComponents<T: ?Sized> {
data_address: usize,
metadata: <T as Pointee>::Metadata,
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.
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ptr/mod.rs
Expand Up @@ -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")]
Expand Down
18 changes: 18 additions & 0 deletions library/core/src/ptr/non_null.rs
Expand Up @@ -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")]
Expand Down
29 changes: 28 additions & 1 deletion library/core/tests/ptr.rs
@@ -1,5 +1,5 @@
use core::cell::RefCell;
use core::ptr::*;
use core::ptr::{self, *};
use std::fmt::{Debug, Display};

#[test]
Expand Down Expand Up @@ -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);
}

0 comments on commit 937d580

Please sign in to comment.