Skip to content

Extend pointer cast to be able to return thin (including extern) types #101259

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ impl<T: ?Sized> *const T {
#[stable(feature = "ptr_cast", since = "1.38.0")]
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
#[inline]
pub const fn cast<U>(self) -> *const U {
self as _
pub const fn cast<U: ?Sized + Thin>(self) -> *const U {
// TODO: Just use `self as _` when the compiler understands `Thin`
from_raw_parts(self as *const (), ())
}

/// Use the pointer value in a new pointer of another type.
Expand Down
7 changes: 4 additions & 3 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ impl<T: ?Sized> *mut T {
/// Casts to a pointer of another type.
#[stable(feature = "ptr_cast", since = "1.38.0")]
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
#[inline(always)]
pub const fn cast<U>(self) -> *mut U {
self as _
#[inline]
pub const fn cast<U: ?Sized + Thin>(self) -> *mut U {
// TODO: Just use `self as _` when the compiler understands `Thin`
from_raw_parts_mut(self as *mut (), ())
}

/// Use the pointer value in a new pointer of another type.
Expand Down
6 changes: 3 additions & 3 deletions library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::marker::Unsize;
use crate::mem::{self, MaybeUninit};
use crate::num::NonZeroUsize;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::ptr::Unique;
use crate::ptr::{Thin, Unique};
use crate::slice::{self, SliceIndex};

/// `*mut T` but non-zero and [covariant].
Expand Down Expand Up @@ -450,9 +450,9 @@ impl<T: ?Sized> NonNull<T> {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn cast<U>(self) -> NonNull<U> {
pub const fn cast<U: ?Sized + Thin>(self) -> NonNull<U> {
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
unsafe { NonNull::new_unchecked(self.as_ptr().cast()) }
}
}

Expand Down
38 changes: 36 additions & 2 deletions library/core/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,40 @@ fn test_is_null() {
assert!(em.is_null());
}

#[test]
fn test_cast() {
// `cast` works like `as` for unsized types
let cs: *const [u8] = &[1, 2, 3];
assert_eq!(cs.cast::<u8>(), cs as *const u8);

let ms: *mut [u8] = &mut [1, 2, 3];
assert_eq!(ms.cast::<u8>(), ms as *mut u8);

let ci: *const dyn ToString = &3;
assert_eq!(ci.cast::<u8>(), ci as *const u8);

let mi: *mut dyn ToString = &mut 3;
assert_eq!(mi.cast::<u8>(), mi as *mut u8);

// `cast` can be used to cast between extern types
extern "C" {
type Extern1;
type Extern2;
}

let p: *const u8 = &42;
let e: *const Extern1 = p.cast();
assert_eq!(e.cast::<Extern2>(), e as *const Extern2);

let p: *mut u8 = &mut 42;
let e: *mut Extern1 = p.cast();
assert_eq!(e.cast::<Extern2>(), e as *mut Extern2);

let p: NonNull<u8> = NonNull::from(&42);
let e: NonNull<Extern1> = p.cast();
assert_eq!(Some(e.cast::<Extern2>()), NonNull::new(e.as_ptr() as *mut Extern2));
}

#[test]
fn test_as_ref() {
unsafe {
Expand Down Expand Up @@ -485,8 +519,8 @@ fn ptr_metadata() {
let () = metadata(&[4, 7]);
let () = metadata(&(4, String::new()));
let () = metadata(&Pair(4, String::new()));
let () = metadata(ptr::null::<()>() as *const Extern);
let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target);
let () = metadata(ptr::null::<()>().cast::<Extern>());
let () = metadata(ptr::null::<()>().cast::<<&u32 as std::ops::Deref>::Target>());

assert_eq!(metadata("foo"), 3_usize);
assert_eq!(metadata(&[4, 7][..]), 2_usize);
Expand Down