Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 1 addition & 2 deletions src/libcore/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ macro_rules! impl_zeroable_for_pointer_types {
unsafe impl<T: ?Sized> Zeroable for $Ptr {
#[inline]
fn is_zero(&self) -> bool {
// Cast because `is_null` is only available on thin pointers
(*self as *mut u8).is_null()
(*self).is_null()
}
}
)+
Expand Down
28 changes: 21 additions & 7 deletions src/libcore/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
impl<T: ?Sized> *const T {
/// Returns `true` if the pointer is null.
///
/// Note that unsized types have many possible null pointers, as only the
/// raw data pointer is considered, not their length, vtable, etc.
/// Therefore, two pointers that are null may still not compare equal to
/// each other.
///
/// # Examples
///
/// Basic usage:
Expand All @@ -487,8 +492,10 @@ impl<T: ?Sized> *const T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_null(self) -> bool where T: Sized {
self == null()
pub fn is_null(self) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
(self as *const u8) == null()
}

/// Returns `None` if the pointer is null, or else returns a reference to
Expand Down Expand Up @@ -519,7 +526,7 @@ 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 {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
Expand Down Expand Up @@ -1107,6 +1114,11 @@ impl<T: ?Sized> *const T {
impl<T: ?Sized> *mut T {
/// Returns `true` if the pointer is null.
///
/// Note that unsized types have many possible null pointers, as only the
/// raw data pointer is considered, not their length, vtable, etc.
/// Therefore, two pointers that are null may still not compare equal to
/// each other.
///
/// # Examples
///
/// Basic usage:
Expand All @@ -1118,8 +1130,10 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_null(self) -> bool where T: Sized {
self == null_mut()
pub fn is_null(self) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
(self as *mut u8) == null_mut()
}

/// Returns `None` if the pointer is null, or else returns a reference to
Expand Down Expand Up @@ -1150,7 +1164,7 @@ 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 {
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
Expand Down Expand Up @@ -1274,7 +1288,7 @@ 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 {
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
if self.is_null() {
None
} else {
Expand Down
68 changes: 68 additions & 0 deletions src/libcore/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::mem;
use core::ptr::*;
use core::cell::RefCell;


/// Create a null pointer to a mutable slice. This is implemented like
/// `slice::from_raw_parts_mut`, which we can't use directly because
/// having a null `&mut [T]` even temporarily is UB.
fn null_slice<T>() -> *mut [T] {
unsafe {
#[repr(C)]
struct Repr<T> {
pub data: *mut T,
pub len: usize,
}

mem::transmute(Repr { data: null_mut::<T>(), len: 0 })
Copy link
Member

@eddyb eddyb Sep 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this: you can just cast null_mut::<[T; 0]>() to *mut [T].

EDIT: ah yes I see that @bluss commented about this already.

}
}

#[test]
fn test() {
unsafe {
Expand Down Expand Up @@ -62,6 +79,26 @@ fn test_is_null() {

let mq = unsafe { mp.offset(1) };
assert!(!mq.is_null());

// Pointers to unsized types
let s: &mut [u8] = &mut [1, 2, 3];
let cs: *const [u8] = s;
assert!(!cs.is_null());

let ms: *mut [u8] = s;
assert!(!ms.is_null());

let cz: *const [u8] = &[];
assert!(!cz.is_null());

let mz: *mut [u8] = &mut [];
assert!(!mz.is_null());

let ncs: *const [u8] = null_slice();
assert!(ncs.is_null());

let nms: *mut [u8] = null_slice();
assert!(nms.is_null());
}

#[test]
Expand All @@ -85,6 +122,26 @@ fn test_as_ref() {
let p = &u as *const isize;
assert_eq!(p.as_ref().unwrap(), &2);
}

// Pointers to unsized types
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_slice();
assert_eq!(ncs.as_ref(), None);

let nms: *mut [u8] = null_slice();
assert_eq!(nms.as_ref(), None);
}
}

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

// Pointers to unsized types
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_slice();
assert_eq!(nms.as_mut(), None);
}
}

Expand Down