diff options
| author | Stefan Lankes <slankes@eonerc.rwth-aachen.de> | 2019-11-13 00:24:37 +0100 |
|---|---|---|
| committer | Stefan Lankes <slankes@eonerc.rwth-aachen.de> | 2019-11-13 00:24:37 +0100 |
| commit | 88717319142e162ae2f48124d94f33d2c21bc2ce (patch) | |
| tree | e50a968f836c55007e9bc8f305d4f0f80aca042c /src/libcore | |
| parent | 969b74144641bf1c8ae5aba0581f4b52a4c15bac (diff) | |
| parent | 4f03f4a989d1c8346c19dfb417a77c09b34408b8 (diff) | |
| download | rust-88717319142e162ae2f48124d94f33d2c21bc2ce.tar.gz rust-88717319142e162ae2f48124d94f33d2c21bc2ce.zip | |
Merge remote-tracking branch 'rust-lang/master' into hermit
Diffstat (limited to 'src/libcore')
44 files changed, 460 insertions, 80 deletions
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 5d0333d5226..1b06baeb711 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 e2704e807d1..39a5dd7263c 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -182,6 +182,7 @@ impl dyn Any { #[inline] pub fn downcast_ref<T: Any>(&self) -> Option<&T> { if self.is::<T>() { + // 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<T: Any>(&mut self) -> Option<&mut T> { if self.is::<T>() { + // 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<T: ?Sized + 'static>() -> TypeId { TypeId { + #[cfg(bootstrap)] + // SAFETY: going away soon t: unsafe { intrinsics::type_id::<T>() }, + #[cfg(not(bootstrap))] + t: intrinsics::type_id::<T>(), } } } diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs index 11803238407..307e9b90ee2 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<T>` 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>], &[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 e1ec8b795d0..74a7d062d3f 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 4087333e2cf..9b588525bd6 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 a337c467131..e921dd1ba06 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::<u32>() }; @@ -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::<u64>() }; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index fda103a52d8..87d8e7aff05 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -137,9 +137,11 @@ //! use std::cell::Cell; //! use std::ptr::NonNull; //! use std::intrinsics::abort; +//! use std::marker::PhantomData; //! //! struct Rc<T: ?Sized> { -//! ptr: NonNull<RcBox<T>> +//! ptr: NonNull<RcBox<T>>, +//! phantom: PhantomData<RcBox<T>>, //! } //! //! struct RcBox<T: ?Sized> { @@ -151,7 +153,10 @@ //! impl<T: ?Sized> Clone for Rc<T> { //! fn clone(&self) -> Rc<T> { //! self.inc_strong(); -//! Rc { ptr: self.ptr } +//! Rc { +//! ptr: self.ptr, +//! phantom: PhantomData, +//! } //! } //! } //! @@ -182,6 +187,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 c456e14db12..28f52074495 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -224,6 +224,7 @@ impl TryFrom<u32> 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 b71c9c2c40b..ae09251c776 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -87,7 +87,7 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { }; 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<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { // 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 971d89e0044..c048bab287d 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/convert.rs b/src/libcore/convert.rs index 16045f64d46..5058e58d0eb 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -205,11 +205,12 @@ pub trait AsMut<T: ?Sized> { /// A value-to-value conversion that consumes the input value. The /// opposite of [`From`]. /// -/// One should only implement [`Into`] if a conversion to a type outside the current crate is -/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because -/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to -/// the blanket implementation in the standard library. [`From`] cannot do these type of -/// conversions because of Rust's orphaning rules. +/// One should avoid implementing [`Into`] and implement [`From`] instead. +/// Implementing [`From`] automatically provides one with an implementation of [`Into`] +/// thanks to the blanket implementation in the standard library. +/// +/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function +/// to ensure that types that only implement [`Into`] can be used as well. /// /// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`]. /// @@ -218,13 +219,13 @@ pub trait AsMut<T: ?Sized> { /// - [`From`]`<T> for U` implies `Into<U> for T` /// - [`Into`] is reflexive, which means that `Into<T> for T` is implemented /// -/// # Implementing [`Into`] for conversions to external types +/// # Implementing [`Into`] for conversions to external types in old versions of Rust /// -/// If the destination type is not part of the current crate -/// then you can't implement [`From`] directly. +/// Prior to Rust 1.40, if the destination type was not part of the current crate +/// then you couldn't implement [`From`] directly. /// For example, take this code: /// -/// ```compile_fail +/// ``` /// struct Wrapper<T>(Vec<T>); /// impl<T> From<Wrapper<T>> for Vec<T> { /// fn from(w: Wrapper<T>) -> Vec<T> { @@ -232,9 +233,8 @@ pub trait AsMut<T: ?Sized> { /// } /// } /// ``` -/// This will fail to compile because we cannot implement a trait for a type -/// if both the trait and the type are not defined by the current crate. -/// This is due to Rust's orphaning rules. To bypass this, you can implement [`Into`] directly: +/// This will fail to compile in older versions of the language because Rust's orphaning rules +/// used to be a little bit more strict. To bypass this, you could implement [`Into`] directly: /// /// ``` /// struct Wrapper<T>(Vec<T>); @@ -249,9 +249,6 @@ pub trait AsMut<T: ?Sized> { /// (as [`From`] does with [`Into`]). Therefore, you should always try to implement [`From`] /// and then fall back to [`Into`] if [`From`] can't be implemented. /// -/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function -/// to ensure that types that only implement [`Into`] can be used as well. -/// /// # Examples /// /// [`String`] implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>`: diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index 569c667ac0a..499dd0facd3 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 a2fff913ac7..b52b56b1bdb 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 0e83a282b18..5a039144f66 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 3b5c9fbff25..3c7aefc090f 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 020e085abf8..0082363692d 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 19aeafd882e..194d9e6e2f8 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 368a2f16b28..f68a3e5a76f 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 3b8edc2ad61..39d571006e6 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -517,8 +517,18 @@ impl<I> Iterator for StepBy<I> 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 430ceacdd9f..14d9d5499b8 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/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 00a86417058..bbdb169cac0 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -205,6 +205,7 @@ pub trait FromIterator<A>: Sized { /// .collect() /// } /// ``` +#[rustc_diagnostic_item = "IntoIterator"] #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated over. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1b67b05c730..ca431627147 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -89,7 +89,7 @@ #![feature(nll)] #![feature(exhaustive_patterns)] #![feature(no_core)] -#![feature(on_unimplemented)] +#![cfg_attr(bootstrap, feature(on_unimplemented))] #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 8ccd31c95d5..726d187d2e9 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -26,31 +26,29 @@ macro_rules! panic { /// For details, see `std::macros`. #[cfg(not(bootstrap))] #[macro_export] -#[allow_internal_unstable(core_panic, panic_internals)] +#[allow_internal_unstable(core_panic, + // FIXME(anp, eddyb) `core_intrinsics` is used here to allow calling + // the `caller_location` intrinsic, but once `#[track_caller]` is implemented, + // `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument. + core_intrinsics, +)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( $crate::panic!("explicit panic") ); - ($msg:expr) => ({ - const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor( - $crate::file!(), - $crate::line!(), - $crate::column!(), - ); - $crate::panicking::panic($msg, LOC) - }); + ($msg:expr) => ( + $crate::panicking::panic($msg, $crate::intrinsics::caller_location()) + ); ($msg:expr,) => ( $crate::panic!($msg) ); - ($fmt:expr, $($arg:tt)+) => ({ - const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor( - $crate::file!(), - $crate::line!(), - $crate::column!(), - ); - $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC) - }); + ($fmt:expr, $($arg:tt)+) => ( + $crate::panicking::panic_fmt( + $crate::format_args!($fmt, $($arg)+), + $crate::intrinsics::caller_location(), + ) + ); } /// Asserts that two expressions are equal to each other (using [`PartialEq`]). @@ -1276,6 +1274,10 @@ pub(crate) mod builtin { } /// Inline assembly. + /// + /// Read the [unstable book] for the usage. + /// + /// [unstable book]: ../unstable-book/library-features/asm.html #[unstable(feature = "asm", issue = "29722", reason = "inline assembly is not stable enough for use and is subject to change")] #[rustc_builtin_macro] diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 792ce9dfad4..e05b40052ee 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 @@ -254,10 +256,48 @@ impl<T> MaybeUninit<T> { /// [type]: union.MaybeUninit.html #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] + #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "maybe_uninit_uninit")] pub const fn uninit() -> MaybeUninit<T> { MaybeUninit { uninit: () } } + /// Create a new array of `MaybeUninit<T>` items, in an uninitialized state. + /// + /// Note: in a future Rust version this method may become unnecessary + /// when array literal syntax allows + /// [repeating const expressions](https://github.com/rust-lang/rust/issues/49147). + /// The example below could then use `let mut buf = [MaybeUninit::<u8>::uninit(); 32];`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice_assume_init)] + /// + /// use std::mem::MaybeUninit; + /// + /// extern "C" { + /// fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize; + /// } + /// + /// /// Returns a (possibly smaller) slice of data that was actually read + /// fn read(buf: &mut [MaybeUninit<u8>]) -> &[u8] { + /// unsafe { + /// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); + /// MaybeUninit::slice_get_ref(&buf[..len]) + /// } + /// } + /// + /// let mut buf: [MaybeUninit<u8>; 32] = MaybeUninit::uninit_array(); + /// let data = read(&mut buf); + /// ``` + #[unstable(feature = "maybe_uninit_uninit_array", issue = "0")] + #[inline(always)] + pub fn uninit_array<const LEN: usize>() -> [Self; LEN] { + unsafe { + MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() + } + } + /// A promotable constant, equivalent to `uninit()`. #[unstable(feature = "internal_uninit_const", issue = "0", reason = "hack to work around promotability")] @@ -300,6 +340,7 @@ impl<T> MaybeUninit<T> { /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline] + #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "maybe_uninit_zeroed")] pub fn zeroed() -> MaybeUninit<T> { let mut u = MaybeUninit::<T>::uninit(); unsafe { @@ -440,6 +481,7 @@ impl<T> MaybeUninit<T> { /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] + #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "assume_init")] pub unsafe fn assume_init(self) -> T { intrinsics::panic_if_uninhabited::<T>(); ManuallyDrop::into_inner(self.value) @@ -509,35 +551,212 @@ impl<T> MaybeUninit<T> { self.as_ptr().read() } - /// Gets a reference to the contained value. + /// Gets a shared reference to the contained value. + /// + /// This can be useful when we want to access a `MaybeUninit` that has been + /// initialized but don't have ownership of the `MaybeUninit` (preventing the use + /// of `.assume_init()`). /// /// # Safety /// - /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really + /// is in an initialized state. + /// + /// # Examples + /// + /// ### Correct usage of this method: + /// + /// ```rust + /// #![feature(maybe_uninit_ref)] + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); + /// // Initialize `x`: + /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); } + /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to + /// // create a shared reference to it: + /// let x: &Vec<u32> = unsafe { + /// // Safety: `x` has been initialized. + /// x.get_ref() + /// }; + /// assert_eq!(x, &vec![1, 2, 3]); + /// ``` + /// + /// ### *Incorrect* usages of this method: + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::<Vec<u32>>::uninit(); + /// let x_vec: &Vec<u32> = unsafe { x.get_ref() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] + /// use std::{cell::Cell, mem::MaybeUninit}; + /// + /// let b = MaybeUninit::<Cell<bool>>::uninit(); + /// // Initialize the `MaybeUninit` using `Cell::set`: + /// unsafe { + /// b.get_ref().set(true); + /// // ^^^^^^^^^^^ + /// // Reference to an uninitialized `Cell<bool>`: UB! + /// } + /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_ref(&self) -> &T { + intrinsics::panic_if_uninhabited::<T>(); &*self.value } - /// Gets a mutable reference to the contained value. + /// Gets a mutable (unique) reference to the contained value. + /// + /// This can be useful when we want to access a `MaybeUninit` that has been + /// initialized but don't have ownership of the `MaybeUninit` (preventing the use + /// of `.assume_init()`). /// /// # Safety /// - /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really + /// is in an initialized state. For instance, `.get_mut()` cannot be used to + /// initialize a `MaybeUninit`. + /// + /// # Examples + /// + /// ### Correct usage of this method: + /// + /// ```rust + /// #![feature(maybe_uninit_ref)] + /// use std::mem::MaybeUninit; + /// + /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] } + /// # #[cfg(FALSE)] + /// extern "C" { + /// /// Initializes *all* the bytes of the input buffer. + /// fn initialize_buffer(buf: *mut [u8; 2048]); + /// } + /// + /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit(); + /// + /// // Initialize `buf`: + /// unsafe { initialize_buffer(buf.as_mut_ptr()); } + /// // Now we know that `buf` has been initialized, so we could `.assume_init()` it. + /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes. + /// // To assert our buffer has been initialized without copying it, we upgrade + /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: + /// let buf: &mut [u8; 2048] = unsafe { + /// // Safety: `buf` has been initialized. + /// buf.get_mut() + /// }; + /// + /// // Now we can use `buf` as a normal slice: + /// buf.sort_unstable(); + /// assert!( + /// buf.chunks(2).all(|chunk| chunk[0] <= chunk[1]), + /// "buffer is sorted", + /// ); + /// ``` + /// + /// ### *Incorrect* usages of this method: + /// + /// You cannot use `.get_mut()` to initialize a value: + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] + /// use std::mem::MaybeUninit; + /// + /// let mut b = MaybeUninit::<bool>::uninit(); + /// unsafe { + /// *b.get_mut() = true; + /// // We have created a (mutable) reference to an uninitialized `bool`! + /// // This is undefined behavior. + /// } + /// ``` + /// + /// For instance, you cannot [`Read`] into an uninitialized buffer: + /// + /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] + /// use std::{io, mem::MaybeUninit}; + /// + /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> + /// { + /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); + /// reader.read_exact(unsafe { buffer.get_mut() })?; + /// // ^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// Ok(unsafe { buffer.assume_init() }) + /// } + /// ``` + /// + /// Nor can you use direct field access to do field-by-field gradual initialization: + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] + /// use std::{mem::MaybeUninit, ptr}; + /// + /// struct Foo { + /// a: u32, + /// b: u8, + /// } + /// + /// let foo: Foo = unsafe { + /// let mut foo = MaybeUninit::<Foo>::uninit(); + /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337); + /// // ^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// ptr::write(&mut foo.get_mut().b as *mut u8, 42); + /// // ^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// foo.assume_init() + /// }; + /// ``` // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_mut(&mut self) -> &mut T { + intrinsics::panic_if_uninhabited::<T>(); &mut *self.value } + /// Assuming all the elements are initialized, get a slice to them. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit<T>` elements + /// really are in an initialized state. + /// Calling this when the content is not yet fully initialized causes undefined behavior. + #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "0")] + #[inline(always)] + pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] { + &*(slice as *const [Self] as *const [T]) + } + + /// Assuming all the elements are initialized, get a mutable slice to them. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit<T>` elements + /// really are in an initialized state. + /// Calling this when the content is not yet fully initialized causes undefined behavior. + #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "0")] + #[inline(always)] + pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] { + &mut *(slice as *mut [Self] as *mut [T]) + } + /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index c7da56aad30..dc7c36ff03c 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -93,6 +93,8 @@ pub fn forget<T>(t: T) { #[inline] #[unstable(feature = "forget_unsized", issue = "0")] pub fn forget_unsized<T: ?Sized>(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<T>() -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val<T: ?Sized>(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<T>() -> 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<T: ?Sized>(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<T>() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub fn align_of_val<T: ?Sized>(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } + min_align_of_val(val) } /// Returns `true` if dropping values of type `T` matters. @@ -457,6 +468,7 @@ pub const fn needs_drop<T>() -> bool { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated_in_future)] #[allow(deprecated)] +#[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "mem_zeroed")] pub unsafe fn zeroed<T>() -> T { intrinsics::panic_if_uninhabited::<T>(); intrinsics::init() @@ -485,6 +497,7 @@ pub unsafe fn zeroed<T>() -> T { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated_in_future)] #[allow(deprecated)] +#[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "mem_uninitialized")] pub unsafe fn uninitialized<T>() -> T { intrinsics::panic_if_uninhabited::<T>(); intrinsics::uninit() @@ -508,6 +521,8 @@ pub unsafe fn uninitialized<T>() -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap<T>(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 +837,11 @@ impl<T> fmt::Debug for Discriminant<T> { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] pub fn discriminant<T>(v: &T) -> Discriminant<T> { + #[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 ed89852dc48..64146302626 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 5730088c4d9..7662bba6b5e 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 2bdeda340dc..4a2a35dfb09 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 b4ade704144..b5d61a3fd4e 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -71,6 +71,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s #[inline] pub fn new(n: $Int) -> Option<Self> { if n != 0 { + // SAFETY: we just checked that there's no `0` Some(unsafe { $Ty(n) }) } else { None @@ -234,7 +235,6 @@ depending on the target pointer size. "} } -// `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, @@ -703,6 +703,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 +760,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 +1331,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 +1362,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 +2119,8 @@ assert_eq!( #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes unsafe { mem::transmute(self) } } } @@ -2221,6 +2229,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>()]) -> Self { + // SAFETY: integers are plain old datatypes so we can always transmute to them unsafe { mem::transmute(bytes) } } } @@ -2293,7 +2302,6 @@ impl isize { usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } -// `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, @@ -2748,6 +2756,8 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " pub fn checked_div(self, rhs: Self) -> Option<Self> { 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 +2809,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 +3260,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 +3293,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 +3791,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 +3941,8 @@ assert_eq!( #[rustc_const_unstable(feature = "const_int_conversion")] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] { + // SAFETY: integers are plain old datatypes so we can always transmute them to + // arrays of bytes unsafe { mem::transmute(self) } } } @@ -4033,6 +4051,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>()]) -> 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 f0ac5e749f6..958f31c0fd2 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -133,6 +133,8 @@ //! [`Box<T>`]: ../../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 685b749776b..b88dc336097 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 be057ed6d59..1219fd09a9d 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -552,6 +552,7 @@ impl<P: Deref> Pin<P> { #[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<P: DerefMut> Pin<P> { #[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 1355ce1aa43..5a75730cf2b 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -18,6 +18,10 @@ //! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. //! * All pointers (except for the null pointer) are valid for all operations of //! [size zero][zst]. +//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer +//! be *dereferencable*: the memory range of the given size starting at the pointer must all be +//! within the bounds of a single allocated object. Note that in Rust, +//! every (stack-allocated) variable is considered a separate allocated object. //! * All accesses performed by functions in this module are *non-atomic* in the sense //! of [atomic operations] used to synchronize between threads. This means it is //! undefined behavior to perform two concurrent accesses to the same location from different @@ -61,6 +65,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; @@ -221,10 +227,15 @@ pub(crate) struct FatPtr<T> { pub(crate) len: usize, } -/// Forms a slice from a pointer and a length. +/// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. /// +/// This function is safe, but actually using the return value is unsafe. +/// See the documentation of [`from_raw_parts`] for slice safety requirements. +/// +/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +/// /// # Examples /// /// ```rust @@ -243,12 +254,16 @@ pub fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { unsafe { Repr { raw: FatPtr { data, len } }.rust } } -/// Performs the same functionality as [`from_raw_parts`], except that a -/// mutable slice is returned. +/// Performs the same functionality as [`slice_from_raw_parts`], except that a +/// raw mutable slice is returned, as opposed to a raw immutable slice. /// -/// See the documentation of [`from_raw_parts`] for more details. +/// See the documentation of [`slice_from_raw_parts`] for more details. /// -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +/// This function is safe, but actually using the return value is unsafe. +/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements. +/// +/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html +/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html #[inline] #[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")] pub fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index 7dcd57f1f98..7599991f0f1 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 3521dd79979..11a3aed1ab4 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<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`. diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 45ab016c496..2a2169dd348 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 cdada1252d2..c8fe9f98613 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. //! @@ -5272,18 +5273,24 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// /// # Safety /// -/// This function is unsafe as there is no guarantee that the given pointer is -/// valid for `len` elements, nor whether the lifetime inferred is a suitable -/// lifetime for the returned slice. +/// Behavior is undefined if any of the following conditions are violated: /// -/// `data` must be non-null and aligned, even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. +/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes, +/// and it must be properly aligned. This means in particular: /// -/// The total size of the slice must be no larger than `isize::MAX` **bytes** -/// in memory. See the safety documentation of [`pointer::offset`]. +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. /// /// # Caveat /// @@ -5305,6 +5312,7 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// assert_eq!(slice[0], 42); /// ``` /// +/// [valid]: ../../std/ptr/index.html#safety /// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset #[inline] @@ -5312,28 +5320,45 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering half the address space"); + "attempt to create slice covering at least half the address space"); &*ptr::slice_from_raw_parts(data, len) } /// Performs the same functionality as [`from_raw_parts`], except that a /// mutable slice is returned. /// -/// This function is unsafe for the same reasons as [`from_raw_parts`], as well -/// as not being able to provide a non-aliasing guarantee of the returned -/// mutable slice. `data` must be non-null and aligned even for zero-length -/// slices as with [`from_raw_parts`]. The total size of the slice must be no -/// larger than `isize::MAX` **bytes** in memory. +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for writes for `len * mem::size_of::<T>()` many bytes, +/// and it must be properly aligned. This means in particular: /// -/// See the documentation of [`from_raw_parts`] for more details. +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. /// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ../../std/ptr/index.html#safety +/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset /// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering half the address space"); + "attempt to create slice covering at least half the address space"); &mut *ptr::slice_from_raw_parts_mut(data, len) } diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 2f2170f7ff1..a719a51b616 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 e8f747f1a67..762de0489a9 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 1968919f554..25b7eec5b33 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 ad9d956fda1..a494274118a 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 73d5abf1aed..d311cb16b64 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 c41d35efced..a35897e9bc1 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 5a0e4388e03..57fc1a7b760 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]) |
