diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ef7b3b1d1470a..9f8fbaa95ae6b 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -43,8 +43,9 @@ impl *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(self) -> *const U { - self as _ + pub const fn cast(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. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6a3b9ee9a7daa..fd0ebbff48a67 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -41,9 +41,10 @@ impl *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(self) -> *mut U { - self as _ + #[inline] + pub const fn cast(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. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index f3ef094cbccc5..872c4b2530795 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -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]. @@ -450,9 +450,9 @@ impl NonNull { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn cast(self) -> NonNull { + pub const fn cast(self) -> NonNull { // 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()) } } } diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 97a369810056d..9fc7c4448fb2f 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -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::(), cs as *const u8); + + let ms: *mut [u8] = &mut [1, 2, 3]; + assert_eq!(ms.cast::(), ms as *mut u8); + + let ci: *const dyn ToString = &3; + assert_eq!(ci.cast::(), ci as *const u8); + + let mi: *mut dyn ToString = &mut 3; + assert_eq!(mi.cast::(), 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::(), e as *const Extern2); + + let p: *mut u8 = &mut 42; + let e: *mut Extern1 = p.cast(); + assert_eq!(e.cast::(), e as *mut Extern2); + + let p: NonNull = NonNull::from(&42); + let e: NonNull = p.cast(); + assert_eq!(Some(e.cast::()), NonNull::new(e.as_ptr() as *mut Extern2)); +} + #[test] fn test_as_ref() { unsafe { @@ -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::()); + let () = metadata(ptr::null::<()>().cast::<<&u32 as std::ops::Deref>::Target>()); assert_eq!(metadata("foo"), 3_usize); assert_eq!(metadata(&[4, 7][..]), 2_usize);