]> git.lizzy.rs Git - rust.git/commitdiff
Restore `T: Sized` on `ptr::is_null`
authorJosh Stone <jistone@redhat.com>
Tue, 10 Oct 2017 18:35:41 +0000 (11:35 -0700)
committerJosh Stone <jistone@redhat.com>
Tue, 10 Oct 2017 18:35:41 +0000 (11:35 -0700)
The exact semantics of `is_null` on unsized pointers are still debatable,
especially for trait objects.  It may be legal to call `*mut self`
methods on a trait object someday, as with Go interfaces, so `is_null`
might need to validate the vtable pointer too.

For `as_ref` and `as_mut`, we're assuming that you cannot have a non-null
data pointer with a null vtable, so casting the unsized check is fine.

src/libcore/nonzero.rs
src/libcore/ptr.rs
src/libcore/tests/ptr.rs

index 8271be5d38f88230f46ed0b43d318b9be2fd03ed..f075d825f5d53f81f5f03bf8bf277c5596004fac 100644 (file)
@@ -28,7 +28,8 @@ macro_rules! impl_zeroable_for_pointer_types {
             unsafe impl<T: ?Sized> Zeroable for $Ptr {
                 #[inline]
                 fn is_zero(&self) -> bool {
-                    (*self).is_null()
+                    // Cast because `is_null` is only available on thin pointers
+                    (*self as *mut u8).is_null()
                 }
             }
         )+
index 474658b65a154a0ab8854f17a8f9914a6f835b81..7d0cdc27571f591ecb69b783f57df6a5027c9399 100644 (file)
@@ -476,11 +476,6 @@ 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:
@@ -492,10 +487,8 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    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()
+    pub fn is_null(self) -> bool where T: Sized {
+        self == null()
     }
 
     /// Returns `None` if the pointer is null, or else returns a reference to
@@ -527,7 +520,9 @@ pub fn is_null(self) -> bool {
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
     pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
-        if self.is_null() {
+        // 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)
@@ -1114,11 +1109,6 @@ pub fn align_offset(self, align: usize) -> usize {
 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:
@@ -1130,10 +1120,8 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    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()
+    pub fn is_null(self) -> bool where T: Sized {
+        self == null_mut()
     }
 
     /// Returns `None` if the pointer is null, or else returns a reference to
@@ -1165,7 +1153,9 @@ pub fn is_null(self) -> bool {
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
     pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
-        if self.is_null() {
+        // 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)
@@ -1289,7 +1279,9 @@ pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized {
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
     pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
-        if self.is_null() {
+        // 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)
index 98436f0e1d1cd968d613e70acfe8995c8b8a5257..e93e9be0cd50b378846ffe60fe6a99f3d13050cd 100644 (file)
@@ -62,39 +62,6 @@ fn test_is_null() {
 
     let mq = unsafe { mp.offset(1) };
     assert!(!mq.is_null());
-
-    // Pointers to unsized types -- slices
-    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::<[u8; 3]>();
-    assert!(ncs.is_null());
-
-    let nms: *mut [u8] = null_mut::<[u8; 3]>();
-    assert!(nms.is_null());
-
-    // Pointers to unsized types -- trait objects
-    let ci: *const ToString = &3;
-    assert!(!ci.is_null());
-
-    let mi: *mut ToString = &mut 3;
-    assert!(!mi.is_null());
-
-    let nci: *const ToString = null::<isize>();
-    assert!(nci.is_null());
-
-    let nmi: *mut ToString = null_mut::<isize>();
-    assert!(nmi.is_null());
 }
 
 #[test]