diff options
| author | bors <bors@rust-lang.org> | 2019-10-01 02:31:48 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-10-01 02:31:48 +0000 |
| commit | 42ec6831b019114a4b6f6b58bfb5bc2927d70388 (patch) | |
| tree | be392b01361811cd2585d4e763fd671fce9ac991 /src/liballoc | |
| parent | 22bc9e1d9ca49ee4f5cd953088ab09c238a6dd26 (diff) | |
| parent | 913c095bcf97177d030e4bde9a45a0bb68873eaf (diff) | |
| download | rust-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.rs | 48 | ||||
| -rw-r--r-- | src/liballoc/vec.rs | 29 |
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 |
