Skip to content
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

Remove T: Sized on pointer as_ref() and as_mut() #44932

Merged
merged 5 commits into from
Nov 7, 2017
Merged
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
@@ -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()
}
}
)+
28 changes: 21 additions & 7 deletions src/libcore/ptr.rs
Original file line number Diff line number Diff line change
@@ -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:
@@ -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
@@ -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 {
@@ -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:
@@ -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
@@ -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 {
@@ -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 {
68 changes: 68 additions & 0 deletions src/libcore/tests/ptr.rs
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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]
@@ -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);
}
}

@@ -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);
}
}