diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 5d0333d5226d2..1b06baeb711c2 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -1,5 +1,7 @@ //! Memory allocation APIs +// ignore-tidy-undocumented-unsafe + #![stable(feature = "alloc_module", since = "1.28.0")] use crate::cmp; diff --git a/src/libcore/any.rs b/src/libcore/any.rs index e2704e807d104..39a5dd7263ccf 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -182,6 +182,7 @@ impl dyn Any { #[inline] pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { + // SAFETY: just checked whether we are pointing to the correct type unsafe { Some(&*(self as *const dyn Any as *const T)) } @@ -217,6 +218,7 @@ impl dyn Any { #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { + // SAFETY: just checked whether we are pointing to the correct type unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) } @@ -424,7 +426,11 @@ impl TypeId { #[rustc_const_unstable(feature="const_type_id")] pub const fn of() -> TypeId { TypeId { + #[cfg(bootstrap)] + // SAFETY: going away soon t: unsafe { intrinsics::type_id::() }, + #[cfg(not(bootstrap))] + t: intrinsics::type_id::(), } } } diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs index 11803238407c8..307e9b90ee2c0 100644 --- a/src/libcore/array/iter.rs +++ b/src/libcore/array/iter.rs @@ -51,7 +51,7 @@ where /// iterator (either via `IntoIterator` for arrays or via another way). #[unstable(feature = "array_value_iter", issue = "65798")] pub fn new(array: [T; N]) -> Self { - // The transmute here is actually safe. The docs of `MaybeUninit` + // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit` // promise: // // > `MaybeUninit` is guaranteed to have the same size and alignment @@ -84,10 +84,10 @@ where /// Returns an immutable slice of all elements that have not been yielded /// yet. fn as_slice(&self) -> &[T] { - // This transmute is safe. As mentioned in `new`, `MaybeUninit` retains + let slice = &self.data[self.alive.clone()]; + // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains // the size and alignment of `T`. Furthermore, we know that all // elements within `alive` are properly initialized. - let slice = &self.data[self.alive.clone()]; unsafe { mem::transmute::<&[MaybeUninit], &[T]>(slice) } @@ -117,7 +117,8 @@ where let idx = self.alive.start; self.alive.start += 1; - // Read the element from the array. This is safe: `idx` is an index + // Read the element from the array. + // SAFETY: This is safe: `idx` is an index // into the "alive" region of the array. Reading this element means // that `data[idx]` is regarded as dead now (i.e. do not touch). As // `idx` was the start of the alive-zone, the alive zone is now @@ -163,7 +164,8 @@ where // + 1]`. self.alive.end -= 1; - // Read the element from the array. This is safe: `alive.end` is an + // Read the element from the array. + // SAFETY: This is safe: `alive.end` is an // index into the "alive" region of the array. Compare the previous // comment that states that the alive region is // `data[alive.start..alive.end + 1]`. Reading this element means that @@ -226,6 +228,7 @@ where [T; N]: LengthAtMost32, { fn clone(&self) -> Self { + // SAFETY: each point of unsafety is documented inside the unsafe block unsafe { // This creates a new uninitialized array. Note that the `assume_init` // refers to the array, not the individual elements. And it is Ok if diff --git a/src/libcore/array/mod.rs b/src/libcore/array/mod.rs index e1ec8b795d04c..74a7d062d3f4a 100644 --- a/src/libcore/array/mod.rs +++ b/src/libcore/array/mod.rs @@ -156,6 +156,7 @@ where fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_ptr() as *const [T; N]; + // SAFETY: ok because we just checked that the length fits unsafe { Ok(&*ptr) } } else { Err(TryFromSliceError(())) @@ -173,6 +174,7 @@ where fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_mut_ptr() as *mut [T; N]; + // SAFETY: ok because we just checked that the length fits unsafe { Ok(&mut *ptr) } } else { Err(TryFromSliceError(())) diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 4087333e2cf6d..9b588525bd698 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -135,6 +135,7 @@ impl FusedIterator for EscapeDefault {} #[stable(feature = "ascii_escape_display", since = "1.39.0")] impl fmt::Display for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: ok because `escape_default` created only valid utf-8 data f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) }) } } diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index a337c46713133..e921dd1ba0636 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -118,6 +118,7 @@ benches! { } fn case07_fake_simd_u32(bytes: &mut [u8]) { + // SAFETY: transmuting a sequence of `u8` to `u32` is always fine let (before, aligned, after) = unsafe { bytes.align_to_mut::() }; @@ -142,6 +143,7 @@ benches! { } fn case08_fake_simd_u64(bytes: &mut [u8]) { + // SAFETY: transmuting a sequence of `u8` to `u64` is always fine let (before, aligned, after) = unsafe { bytes.align_to_mut::() }; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index fda103a52d8bc..31d7514133e1e 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -182,6 +182,8 @@ //! ``` //! +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] use crate::cmp::Ordering; diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index c456e14db12d4..28f5207449561 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -224,6 +224,7 @@ impl TryFrom for char { if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { Err(CharTryFromError(())) } else { + // SAFETY: checked that it's a legal unicode value Ok(unsafe { from_u32_unchecked(i) }) } } diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index b71c9c2c40b37..ae09251c776de 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -87,7 +87,7 @@ impl> Iterator for DecodeUtf16 { }; if u < 0xD800 || 0xDFFF < u { - // not a surrogate + // SAFETY: not a surrogate Some(Ok(unsafe { from_u32_unchecked(u as u32) })) } else if u >= 0xDC00 { // a trailing surrogate @@ -107,6 +107,7 @@ impl> Iterator for DecodeUtf16 { // all ok, so lets decode it. let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; + // SAFETY: we checked that it's a legal unicode value Some(Ok(unsafe { from_u32_unchecked(c) })) } } diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 971d89e004446..c048bab287dd2 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -438,6 +438,7 @@ impl char { #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { let code = self as u32; + // SAFETY: each arm checks the size of the slice and only uses `get_unchecked` unsafe ops unsafe { let len = if code < MAX_ONE_B && !dst.is_empty() { *dst.get_unchecked_mut(0) = code as u8; @@ -507,6 +508,7 @@ impl char { #[inline] pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { let mut code = self as u32; + // SAFETY: each arm checks whether there are enough bits to write into unsafe { if (code & 0xFFFF) == code && !dst.is_empty() { // The BMP falls through (assuming non-surrogate, as it should) diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index 569c667ac0a54..499dd0facd38c 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -315,6 +315,7 @@ impl<'f> Clone for VaListImpl<'f> { #[inline] fn clone(&self) -> Self { let mut dest = crate::mem::MaybeUninit::uninit(); + // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal unsafe { va_copy(dest.as_mut_ptr(), self); dest.assume_init() diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index a2fff913ac720..b52b56b1bdbc2 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -2,6 +2,8 @@ use crate::fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; use crate::mem::MaybeUninit; use crate::num::flt2dec; +// ignore-tidy-undocumented-unsafe + // Don't inline this so callers don't use the stack space this function // requires unless they have to. #[inline(never)] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0e83a282b18f7..5a039144f667f 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1,5 +1,7 @@ //! Utilities for formatting and printing strings. +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] use crate::cell::{UnsafeCell, Cell, RefCell, Ref, RefMut}; diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 3b5c9fbff250a..3c7aefc090f8e 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -1,5 +1,7 @@ //! Integer and floating-point number formatting +// ignore-tidy-undocumented-unsafe + use crate::fmt; use crate::ops::{Div, Rem, Sub}; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 020e085abf8a8..0082363692df6 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -79,6 +79,8 @@ //! } //! ``` +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 19aeafd882ef1..194d9e6e2f8ad 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -1,5 +1,7 @@ //! An implementation of SipHash. +// ignore-tidy-undocumented-unsafe + #![allow(deprecated)] // the types in this module are deprecated use crate::marker::PhantomData; diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 368a2f16b281e..f68a3e5a76fd7 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -2,6 +2,8 @@ //! Hints to compiler that affects how code should be emitted or optimized. +// ignore-tidy-undocumented-unsafe + use crate::intrinsics; /// Informs the compiler that this point in the code is not reachable, enabling diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index 3b8edc2ad6177..39d571006e66a 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -517,8 +517,18 @@ impl Iterator for StepBy where I: Iterator { // overflow handling loop { let mul = n.checked_mul(step); - if unsafe { intrinsics::likely(mul.is_some()) } { - return self.iter.nth(mul.unwrap() - 1); + #[cfg(bootstrap)] + { + // SAFETY: going away soon + if unsafe { intrinsics::likely(mul.is_some()) } { + return self.iter.nth(mul.unwrap() - 1); + } + } + #[cfg(not(bootstrap))] + { + if intrinsics::likely(mul.is_some()) { + return self.iter.nth(mul.unwrap() - 1); + } } let div_n = usize::MAX / n; let div_step = usize::MAX / step; diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs index 430ceacdd9fab..14d9d5499b880 100644 --- a/src/libcore/iter/adapters/zip.rs +++ b/src/libcore/iter/adapters/zip.rs @@ -1,3 +1,5 @@ +// ignore-tidy-undocumented-unsafe + use crate::cmp; use super::super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 51ba260589f62..9f2948dcb0310 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -1,6 +1,8 @@ use crate::intrinsics; use crate::mem::ManuallyDrop; +// ignore-tidy-undocumented-unsafe + /// A wrapper type to construct uninitialized instances of `T`. /// /// # Initialization invariant diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index c7da56aad309a..26909be949664 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -93,6 +93,8 @@ pub fn forget(t: T) { #[inline] #[unstable(feature = "forget_unsized", issue = "0")] pub fn forget_unsized(t: T) { + // SAFETY: the forget intrinsic could be safe, but there's no point in making it safe since + // we'll be implementing this function soon via `ManuallyDrop` unsafe { intrinsics::forget(t) } } @@ -266,7 +268,11 @@ pub const fn size_of() -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(val: &T) -> usize { + #[cfg(bootstrap)] + // SAFETY: going away soon unsafe { intrinsics::size_of_val(val) } + #[cfg(not(bootstrap))] + intrinsics::size_of_val(val) } /// Returns the [ABI]-required minimum alignment of a type. @@ -310,7 +316,11 @@ pub fn min_align_of() -> usize { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] pub fn min_align_of_val(val: &T) -> usize { + #[cfg(bootstrap)] + // SAFETY: going away soon unsafe { intrinsics::min_align_of_val(val) } + #[cfg(not(bootstrap))] + intrinsics::min_align_of_val(val) } /// Returns the [ABI]-required minimum alignment of a type. @@ -350,8 +360,9 @@ pub const fn align_of() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub fn align_of_val(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } + min_align_of_val(val) } /// Returns `true` if dropping values of type `T` matters. @@ -508,6 +519,8 @@ pub unsafe fn uninitialized() -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { + // SAFETY: the raw pointers have been created from safe mutable references satisfying all the + // constraints on `ptr::swap_nonoverlapping_one` unsafe { ptr::swap_nonoverlapping_one(x, y); } @@ -822,7 +835,11 @@ impl fmt::Debug for Discriminant { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] pub fn discriminant(v: &T) -> Discriminant { + #[cfg(bootstrap)] + // SAFETY: going away soon unsafe { Discriminant(intrinsics::discriminant_value(v), PhantomData) } + #[cfg(not(bootstrap))] + Discriminant(intrinsics::discriminant_value(v), PhantomData) } diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index ed89852dc48da..641463026261d 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -58,6 +58,8 @@ mod fpu_precision { pub struct FPUControlWord(u16); fn set_cw(cw: u16) { + // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with + // any `u16` unsafe { asm!("fldcw $0" :: "m" (cw) :: "volatile") } } @@ -74,6 +76,8 @@ mod fpu_precision { // Get the original value of the control word to restore it later, when the // `FPUControlWord` structure is dropped + // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with + // any `u16` unsafe { asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") } // Set the control word to the desired precision. This is achieved by masking away the old diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 5730088c4d9a9..7662bba6b5e13 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -414,6 +414,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { + // SAFETY: `u32` is a plain old datatype so we can always transmute to it unsafe { mem::transmute(self) } } @@ -456,6 +457,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { + // SAFETY: `u32` is a plain old datatype so we can always transmute from it // It turns out the safety issues with sNaN were overblown! Hooray! unsafe { mem::transmute(v) } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 2bdeda340dce0..4a2a35dfb0999 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -427,6 +427,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { + // SAFETY: `u64` is a plain old datatype so we can always transmute to it unsafe { mem::transmute(self) } } @@ -469,6 +470,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { + // SAFETY: `u64` is a plain old datatype so we can always transmute from it // It turns out the safety issues with sNaN were overblown! Hooray! unsafe { mem::transmute(v) } } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index b4ade70414462..4b9e82c7cfee9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -71,6 +71,7 @@ assert_eq!(size_of::>(), size_of::<", s #[inline] pub fn new(n: $Int) -> Option { if n != 0 { + // SAFETY: we just checked that there's no `0` Some(unsafe { $Ty(n) }) } else { None @@ -703,6 +704,7 @@ $EndFeature, " if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { + // SAFETY: div by zero and by INT_MIN have been checked above Some(unsafe { intrinsics::unchecked_div(self, rhs) }) } } @@ -759,6 +761,7 @@ $EndFeature, " if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { + // SAFETY: div by zero and by INT_MIN have been checked above Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) } } @@ -1329,6 +1332,8 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds unsafe { intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) } @@ -1358,6 +1363,8 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds unsafe { intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) } @@ -2113,6 +2120,8 @@ assert_eq!( #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes unsafe { mem::transmute(self) } } } @@ -2221,6 +2230,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them unsafe { mem::transmute(bytes) } } } @@ -2748,6 +2758,8 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " pub fn checked_div(self, rhs: Self) -> Option { match rhs { 0 => None, + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division rhs => Some(unsafe { intrinsics::unchecked_div(self, rhs) }), } } @@ -2799,6 +2811,8 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " if rhs == 0 { None } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) } } @@ -3248,6 +3262,8 @@ assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds unsafe { intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) } @@ -3279,6 +3295,8 @@ assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds unsafe { intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) } @@ -3775,11 +3793,11 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " fn one_less_than_next_power_of_two(self) -> Self { if self <= 1 { return 0; } - // Because `p > 0`, it cannot consist entirely of leading zeros. + let p = self - 1; + // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. // That means the shift is always in-bounds, and some processors // (such as intel pre-haswell) have more efficient ctlz // intrinsics when the argument is non-zero. - let p = self - 1; let z = unsafe { intrinsics::ctlz_nonzero(p) }; <$SelfT>::max_value() >> z } @@ -3925,6 +3943,8 @@ assert_eq!( #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes unsafe { mem::transmute(self) } } } @@ -4033,6 +4053,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them unsafe { mem::transmute(bytes) } } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index f0ac5e749f6b3..958f31c0fd22a 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -133,6 +133,8 @@ //! [`Box`]: ../../std/boxed/struct.Box.html //! [`i32`]: ../../std/primitive.i32.html +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{FromIterator, FusedIterator, TrustedLen}; diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 685b749776b1d..b88dc336097f3 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -20,6 +20,8 @@ //! one function. Currently, the actual symbol is declared in the standard //! library, but the location of this may change over time. +// ignore-tidy-undocumented-unsafe + #![allow(dead_code, missing_docs)] #![unstable(feature = "core_panic", reason = "internal details of the implementation of the `panic!` \ diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index be057ed6d59a7..1219fd09a9dfa 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -552,6 +552,7 @@ impl Pin

{ #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_ref(&self) -> Pin<&P::Target> { + // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&*self.pointer) } } @@ -610,6 +611,7 @@ impl Pin

{ #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut P::Target> { + // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&mut *self.pointer) } } diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 1355ce1aa43b7..cb2fe7bc8bd58 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -61,6 +61,8 @@ //! [`write_volatile`]: ./fn.write_volatile.html //! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] use crate::intrinsics; diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index 7dcd57f1f9858..7599991f0f15a 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -7,6 +7,8 @@ use crate::mem; use crate::ptr::Unique; use crate::cmp::Ordering; +// ignore-tidy-undocumented-unsafe + /// `*mut T` but non-zero and covariant. /// /// This is often the correct thing to use when building data structures using diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs index 3521dd7997956..11a3aed1ab41b 100644 --- a/src/libcore/ptr/unique.rs +++ b/src/libcore/ptr/unique.rs @@ -5,6 +5,8 @@ use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ptr::NonNull; +// ignore-tidy-undocumented-unsafe + /// A wrapper around a raw non-null `*mut T` that indicates that the possessor /// of this wrapper owns the referent. Useful for building abstractions like /// `Box`, `Vec`, `String`, and `HashMap`. diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 45ab016c49628..2a2169dd348c2 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -1,6 +1,8 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +// ignore-tidy-undocumented-unsafe + use crate::cmp; use crate::mem; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index cdada1252d2bf..88e367fe40c74 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1,4 +1,5 @@ // ignore-tidy-filelength +// ignore-tidy-undocumented-unsafe //! Slice management and manipulation. //! diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 2f2170f7ff14c..a719a51b61605 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -6,6 +6,8 @@ //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. +// ignore-tidy-undocumented-unsafe + use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs index e8f747f1a67d5..762de0489a975 100644 --- a/src/libcore/str/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -3,6 +3,8 @@ use crate::str as core_str; use crate::fmt::{self, Write}; use crate::mem; +// ignore-tidy-undocumented-unsafe + /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "0")] pub struct Utf8Lossy { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1968919f5541c..25b7eec5b3343 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1,4 +1,5 @@ // ignore-tidy-filelength +// ignore-tidy-undocumented-unsafe //! String manipulation. //! diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index ad9d956fda1c8..a494274118a74 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -3,6 +3,8 @@ //! For more details, see the traits [`Pattern`], [`Searcher`], //! [`ReverseSearcher`], and [`DoubleEndedSearcher`]. +// ignore-tidy-undocumented-unsafe + #![unstable(feature = "pattern", reason = "API not fully fleshed out and ready to be stabilized", issue = "27721")] diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 73d5abf1aed23..d311cb16b64d3 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -112,6 +112,8 @@ //! println!("live threads: {}", old_thread_count + 1); //! ``` +// ignore-tidy-undocumented-unsafe + #![stable(feature = "rust1", since = "1.0.0")] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))] diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index c41d35efced6c..a35897e9bc1ac 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -85,6 +85,8 @@ fn ldexp_f64(a: f64, b: i32) -> f64 { extern { fn ldexp(x: f64, n: i32) -> f64; } + // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly + // cause undefined behavior unsafe { ldexp(a, b) } } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 5a0e4388e0325..57fc1a7b76075 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -920,7 +920,7 @@ impl fmt::Debug for Duration { if end == 0 { write!(f, "{}", integer_part) } else { - // We are only writing ASCII digits into the buffer and it was + // SAFETY: We are only writing ASCII digits into the buffer and it was // initialized with '0's, so it contains valid UTF8. let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index d5e7ac19263a0..b3ef3217ec6a0 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -76,7 +76,10 @@ pub fn encode_with_shorthand(encoder: &mut E, // The shorthand encoding uses the same usize as the // discriminant, with an offset so they can't conflict. + #[cfg(bootstrap)] let discriminant = unsafe { intrinsics::discriminant_value(variant) }; + #[cfg(not(bootstrap))] + let discriminant = intrinsics::discriminant_value(variant); assert!(discriminant < SHORTHAND_OFFSET as u64); let shorthand = start + SHORTHAND_OFFSET; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 33dc85fc68a2e..693f6f05fab28 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -67,11 +67,13 @@ fn equate_intrinsic_type<'tcx>( pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { match intrinsic { "size_of" | "min_align_of" | "needs_drop" | "caller_location" | + "size_of_val" | "min_align_of_val" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add" | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | + "discriminant_value" | "type_id" | "likely" | "unlikely" | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, diff --git a/src/test/ui/enum-discriminant/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs index b7000015c71db..32d2d40241c82 100644 --- a/src/test/ui/enum-discriminant/discriminant_value.rs +++ b/src/test/ui/enum-discriminant/discriminant_value.rs @@ -51,34 +51,31 @@ enum Mixed { } pub fn main() { - unsafe { + assert_eq!(discriminant_value(&CLike1::A), 0); + assert_eq!(discriminant_value(&CLike1::B), 1); + assert_eq!(discriminant_value(&CLike1::C), 2); + assert_eq!(discriminant_value(&CLike1::D), 3); - assert_eq!(discriminant_value(&CLike1::A), 0); - assert_eq!(discriminant_value(&CLike1::B), 1); - assert_eq!(discriminant_value(&CLike1::C), 2); - assert_eq!(discriminant_value(&CLike1::D), 3); + assert_eq!(discriminant_value(&CLike2::A), 5); + assert_eq!(discriminant_value(&CLike2::B), 2); + assert_eq!(discriminant_value(&CLike2::C), 19); + assert_eq!(discriminant_value(&CLike2::D), 20); - assert_eq!(discriminant_value(&CLike2::A), 5); - assert_eq!(discriminant_value(&CLike2::B), 2); - assert_eq!(discriminant_value(&CLike2::C), 19); - assert_eq!(discriminant_value(&CLike2::D), 20); + assert_eq!(discriminant_value(&CLike3::A), 5); + assert_eq!(discriminant_value(&CLike3::B), 6); + assert_eq!(discriminant_value(&CLike3::C), -1_i8 as u64); + assert_eq!(discriminant_value(&CLike3::D), 0); - assert_eq!(discriminant_value(&CLike3::A), 5); - assert_eq!(discriminant_value(&CLike3::B), 6); - assert_eq!(discriminant_value(&CLike3::C), -1_i8 as u64); - assert_eq!(discriminant_value(&CLike3::D), 0); + assert_eq!(discriminant_value(&ADT::First(0,0)), 0); + assert_eq!(discriminant_value(&ADT::Second(5)), 1); - assert_eq!(discriminant_value(&ADT::First(0,0)), 0); - assert_eq!(discriminant_value(&ADT::Second(5)), 1); + assert_eq!(discriminant_value(&NullablePointer::Nothing), 1); + assert_eq!(discriminant_value(&NullablePointer::Something(&CONST)), 0); - assert_eq!(discriminant_value(&NullablePointer::Nothing), 1); - assert_eq!(discriminant_value(&NullablePointer::Something(&CONST)), 0); + assert_eq!(discriminant_value(&10), 0); + assert_eq!(discriminant_value(&"test"), 0); - assert_eq!(discriminant_value(&10), 0); - assert_eq!(discriminant_value(&"test"), 0); - - assert_eq!(3, discriminant_value(&Mixed::Unit)); - assert_eq!(2, discriminant_value(&Mixed::Tuple(5))); - assert_eq!(1, discriminant_value(&Mixed::Struct{a: 7, b: 11})); - } + assert_eq!(3, discriminant_value(&Mixed::Unit)); + assert_eq!(2, discriminant_value(&Mixed::Tuple(5))); + assert_eq!(1, discriminant_value(&Mixed::Struct{a: 7, b: 11})); } diff --git a/src/test/ui/issues/issue-43398.rs b/src/test/ui/issues/issue-43398.rs index ae52e8f3f6b43..f0b762c6254a3 100644 --- a/src/test/ui/issues/issue-43398.rs +++ b/src/test/ui/issues/issue-43398.rs @@ -7,9 +7,7 @@ enum Big { A, B } fn main() { - unsafe { - println!("{} {:?}", - std::intrinsics::discriminant_value(&Big::A), - std::mem::discriminant(&Big::B)); - } + println!("{} {:?}", + std::intrinsics::discriminant_value(&Big::A), + std::mem::discriminant(&Big::B)); } diff --git a/src/test/ui/issues/issue-51582.rs b/src/test/ui/issues/issue-51582.rs index 63ef05729bc56..40a70c623a741 100644 --- a/src/test/ui/issues/issue-51582.rs +++ b/src/test/ui/issues/issue-51582.rs @@ -14,5 +14,5 @@ fn main() { assert_eq!(1, make_b() as u8); assert_eq!(1, make_b() as i32); assert_eq!(1, make_b() as u32); - assert_eq!(1, unsafe { std::intrinsics::discriminant_value(&make_b()) }); + assert_eq!(1, std::intrinsics::discriminant_value(&make_b())); } diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 9302909968615..5abe481368df5 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -160,6 +160,8 @@ pub fn check(path: &Path, bad: &mut bool) { let can_contain = contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-"); let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr"); + let mut skip_undocumented_unsafe = + contains_ignore_directive(can_contain, &contents, "undocumented-unsafe"); let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab"); let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength"); let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength"); @@ -171,6 +173,7 @@ pub fn check(path: &Path, bad: &mut bool) { let mut leading_new_lines = false; let mut trailing_new_lines = 0; let mut lines = 0; + let mut last_safety_comment = false; for (i, line) in contents.split('\n').enumerate() { let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); @@ -200,6 +203,20 @@ pub fn check(path: &Path, bad: &mut bool) { err("XXX is deprecated; use FIXME") } } + let is_test = || file.components().any(|c| c.as_os_str() == "tests"); + // for now we just check libcore + if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment { + if file.components().any(|c| c.as_os_str() == "libcore") && !is_test() { + suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); + } + } + if line.contains("// SAFETY: ") || line.contains("// Safety: ") { + last_safety_comment = true; + } else if line.trim().starts_with("//") || line.trim().is_empty() { + // keep previous value + } else { + last_safety_comment = false; + } if (line.starts_with("// Copyright") || line.starts_with("# Copyright") || line.starts_with("Copyright"))