Skip to content

Commit

Permalink
Auto merge of #44932 - cuviper:unsized-ptr-is_null, r=alexcrichton
Browse files Browse the repository at this point in the history
Remove `T: Sized` on pointer `as_ref()` and `as_mut()`

`NonZero::is_zero()` was already casting all pointers to thin `*mut u8` to check for null.  The same test on unsized fat pointers can also be used with `as_ref()` and `as_mut()` to get fat references.

(This PR formerly changed `is_null()` too, but checking just the data pointer is not obviously correct for trait objects, especially if `*const self` sorts of methods are ever allowed.)
  • Loading branch information
bors committed Nov 7, 2017
2 parents 7f6417e + 604f049 commit ee22861
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
18 changes: 12 additions & 6 deletions src/libcore/ptr.rs
Expand Up @@ -517,8 +517,10 @@ impl<T: ?Sized> *const T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
if self.is_null() {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
// Check for null via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
if (self as *const u8).is_null() {
None
} else {
Some(&*self)
Expand Down Expand Up @@ -1148,8 +1150,10 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
if self.is_null() {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
// Check for null via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
if (self as *const u8).is_null() {
None
} else {
Some(&*self)
Expand Down Expand Up @@ -1272,8 +1276,10 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized {
if self.is_null() {
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
// Check for null via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
if (self as *mut u8).is_null() {
None
} else {
Some(&mut *self)
Expand Down
51 changes: 51 additions & 0 deletions src/libcore/tests/ptr.rs
Expand Up @@ -85,6 +85,39 @@ fn test_as_ref() {
let p = &u as *const isize;
assert_eq!(p.as_ref().unwrap(), &2);
}

// Pointers to unsized types -- slices
let s: &mut [u8] = &mut [1, 2, 3];
let cs: *const [u8] = s;
assert_eq!(cs.as_ref(), Some(&*s));

let ms: *mut [u8] = s;
assert_eq!(ms.as_ref(), Some(&*s));

let cz: *const [u8] = &[];
assert_eq!(cz.as_ref(), Some(&[][..]));

let mz: *mut [u8] = &mut [];
assert_eq!(mz.as_ref(), Some(&[][..]));

let ncs: *const [u8] = null::<[u8; 3]>();
assert_eq!(ncs.as_ref(), None);

let nms: *mut [u8] = null_mut::<[u8; 3]>();
assert_eq!(nms.as_ref(), None);

// Pointers to unsized types -- trait objects
let ci: *const ToString = &3;
assert!(ci.as_ref().is_some());

let mi: *mut ToString = &mut 3;
assert!(mi.as_ref().is_some());

let nci: *const ToString = null::<isize>();
assert!(nci.as_ref().is_none());

let nmi: *mut ToString = null_mut::<isize>();
assert!(nmi.as_ref().is_none());
}
}

Expand All @@ -103,6 +136,24 @@ fn test_as_mut() {
let p = &mut u as *mut isize;
assert!(p.as_mut().unwrap() == &mut 2);
}

// Pointers to unsized types -- slices
let s: &mut [u8] = &mut [1, 2, 3];
let ms: *mut [u8] = s;
assert_eq!(ms.as_mut(), Some(s));

let mz: *mut [u8] = &mut [];
assert_eq!(mz.as_mut(), Some(&mut [][..]));

let nms: *mut [u8] = null_mut::<[u8; 3]>();
assert_eq!(nms.as_mut(), None);

// Pointers to unsized types -- trait objects
let mi: *mut ToString = &mut 3;
assert!(mi.as_mut().is_some());

let nmi: *mut ToString = null_mut::<isize>();
assert!(nmi.as_mut().is_none());
}
}

Expand Down

0 comments on commit ee22861

Please sign in to comment.