about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-10-01 02:31:48 +0000
committerbors <bors@rust-lang.org>2019-10-01 02:31:48 +0000
commit42ec6831b019114a4b6f6b58bfb5bc2927d70388 (patch)
treebe392b01361811cd2585d4e763fd671fce9ac991 /src/liballoc
parent22bc9e1d9ca49ee4f5cd953088ab09c238a6dd26 (diff)
parent913c095bcf97177d030e4bde9a45a0bb68873eaf (diff)
downloadrust-42ec6831b019114a4b6f6b58bfb5bc2927d70388.tar.gz
rust-42ec6831b019114a4b6f6b58bfb5bc2927d70388.zip
Auto merge of #64932 - tmandry:rollup-7t8x1nz, r=tmandry
Rollup of 9 pull requests

Successful merges:

 - #64377 (Add long error explanation for E0493)
 - #64786 (Use https for curl when building for linux)
 - #64828 (Graphviz debug output for generic dataflow analysis)
 - #64838 (Add long error explanation for E0550)
 - #64891 (Fix `vec![x; n]` with null raw fat pointer zeroing the pointer metadata)
 - #64893 (Zero-initialize `vec![None; n]` for `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>`)
 - #64911 (Fixed a misleading documentation issue #64844)
 - #64921 (Add test for issue-64662)
 - #64923 (Add missing links for mem::needs_drop)

Failed merges:

 - #64918 (Add long error explanation for E0551)

r? @ghost
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/tests/vec.rs48
-rw-r--r--src/liballoc/vec.rs29
2 files changed, 75 insertions, 2 deletions
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index 29a22aa0315..98d013dfa2b 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -1281,3 +1281,51 @@ fn test_stable_push_pop() {
     v.pop().unwrap();
     assert_eq!(*v0, 13);
 }
+
+// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
+//
+// ```
+// unsafe impl<T: ?Sized> IsZero for *mut T {
+//     fn is_zero(&self) -> bool {
+//         (*self).is_null()
+//     }
+// }
+// ```
+//
+// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`,
+// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component.
+// That is, a fat pointer can be “null” without being made entirely of zero bits.
+#[test]
+fn vec_macro_repeating_null_raw_fat_pointer() {
+    let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn();
+    let vtable = dbg!(ptr_metadata(raw_dyn));
+    let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable);
+    assert!(null_raw_dyn.is_null());
+
+    let vec = vec![null_raw_dyn; 1];
+    dbg!(ptr_metadata(vec[0]));
+    assert!(vec[0] == null_raw_dyn);
+
+    // Polyfill for https://github.com/rust-lang/rfcs/pull/2580
+
+    fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () {
+        unsafe {
+            std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable
+        }
+    }
+
+    fn ptr_from_raw_parts(data: *mut (), vtable: *mut()) -> *mut dyn Fn() {
+        unsafe {
+            std::mem::transmute::<DynRepr, *mut dyn Fn()>(DynRepr {
+                data,
+                vtable
+            })
+        }
+    }
+
+    #[repr(C)]
+    struct DynRepr {
+        data: *mut (),
+        vtable: *mut (),
+    }
+}
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index e5672f8542f..7c6ded08bba 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -1734,20 +1734,45 @@ impl_is_zero!(char, |x| x == '\0');
 impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
 impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
 
-unsafe impl<T: ?Sized> IsZero for *const T {
+unsafe impl<T> IsZero for *const T {
     #[inline]
     fn is_zero(&self) -> bool {
         (*self).is_null()
     }
 }
 
-unsafe impl<T: ?Sized> IsZero for *mut T {
+unsafe impl<T> IsZero for *mut T {
     #[inline]
     fn is_zero(&self) -> bool {
         (*self).is_null()
     }
 }
 
+// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
+// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
+// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.
+
+unsafe impl<T: ?Sized> IsZero for Option<&T> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // Common trait implementations for Vec