diff --git a/ci/miri.sh b/ci/miri.sh index 9d845d833b..8ea3e52db0 100644 --- a/ci/miri.sh +++ b/ci/miri.sh @@ -9,4 +9,4 @@ rustup toolchain install nightly --component miri rustup override set nightly cargo miri setup -MIRIFLAGS='-Zmiri-retag-fields' cargo miri test +MIRIFLAGS='-Zmiri-strict-provenance' cargo miri test --features nightly diff --git a/src/lib.rs b/src/lib.rs index e43165dd63..8de2700fb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,8 @@ slice_ptr_get, nonnull_slice_from_raw_parts, maybe_uninit_array_assume_init, - build_hasher_simple_hash_one + build_hasher_simple_hash_one, + strict_provenance ) )] #![allow( @@ -37,6 +38,7 @@ )] #![warn(missing_docs)] #![warn(rust_2018_idioms)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] #[cfg(test)] #[macro_use] diff --git a/src/raw/mod.rs b/src/raw/mod.rs index e86bd239a2..b47b0734b4 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -69,6 +69,16 @@ fn unlikely(b: bool) -> bool { b } +// Use strict provenance functions if available. +#[cfg(feature = "nightly")] +use core::ptr::invalid_mut; +// Implement it with a cast otherwise. +#[cfg(not(feature = "nightly"))] +#[inline(always)] +fn invalid_mut(addr: usize) -> *mut T { + addr as *mut T +} + #[inline] unsafe fn offset_from(to: *const T, from: *const T) -> usize { to.offset_from(from) as usize @@ -371,7 +381,7 @@ impl Bucket { // won't overflow because index must be less than length (bucket_mask) // and bucket_mask is guaranteed to be less than `isize::MAX` // (see TableLayout::calculate_layout_for method) - (index + 1) as *mut T + invalid_mut(index + 1) } else { base.as_ptr().sub(index) }; @@ -507,7 +517,8 @@ impl Bucket { pub fn as_ptr(&self) -> *mut T { if Self::IS_ZERO_SIZED_TYPE { // Just return an arbitrary ZST pointer which is properly aligned - mem::align_of::() as *mut T + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) } else { unsafe { self.ptr.as_ptr().sub(1) } } @@ -553,7 +564,8 @@ impl Bucket { #[inline] unsafe fn next_n(&self, offset: usize) -> Self { let ptr = if Self::IS_ZERO_SIZED_TYPE { - (self.ptr.as_ptr() as usize + offset) as *mut T + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) } else { self.ptr.as_ptr().sub(offset) }; diff --git a/src/set.rs b/src/set.rs index 9cb5f1f0c4..f5670d160d 100644 --- a/src/set.rs +++ b/src/set.rs @@ -2907,4 +2907,11 @@ mod test_set { set.insert(i); } } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } }