diff options
Diffstat (limited to 'library/core/src')
25 files changed, 368 insertions, 160 deletions
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index a93b94867ce..65ae4831839 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -927,7 +927,7 @@ impl char { #[must_use] #[inline] pub(crate) fn is_grapheme_extended(self) -> bool { - unicode::Grapheme_Extend(self) + self > '\x7f' && unicode::Grapheme_Extend(self) } /// Returns `true` if this `char` has one of the general categories for numbers. diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 85740dce866..63fd23ea9a9 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -466,10 +466,10 @@ pub trait Into<T>: Sized { /// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function. /// This way, types that directly implement [`Into`] can be used as arguments as well. /// -/// The `From` is also very useful when performing error handling. When constructing a function +/// The `From` trait is also very useful when performing error handling. When constructing a function /// that is capable of failing, the return type will generally be of the form `Result<T, E>`. -/// The `From` trait simplifies error handling by allowing a function to return a single error type -/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more +/// `From` simplifies error handling by allowing a function to return a single error type +/// that encapsulates multiple error types. See the "Examples" section and [the book][book] for more /// details. /// /// **Note: This trait must not fail**. The `From` trait is intended for perfect conversions. diff --git a/library/core/src/error.rs b/library/core/src/error.rs index ded17e69bd9..a3f2b767054 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -183,6 +183,7 @@ pub trait Error: Debug + Display { #[allow(unused_variables)] fn provide<'a>(&'a self, request: &mut Request<'a>) {} } + mod private { // This is a hack to prevent `type_id` from being overridden by `Error` // implementations, since that can enable unsound downcasting. diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 20186a2de0f..0825281090c 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -428,10 +428,13 @@ impl CStr { unsafe { &*(bytes as *const [u8] as *const CStr) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The const and runtime versions have identical behavior // unless the safety contract of `from_bytes_with_nul_unchecked` is // violated, which is UB. - unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) } + unsafe { + intrinsics::const_eval_select((bytes,), const_impl, rt_impl) + } } /// Returns the inner pointer to this C string. @@ -719,6 +722,9 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize { unsafe { strlen(s) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: the two functions always provide equivalent functionality - unsafe { intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) } + unsafe { + intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) + } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e1b7b46a1ed..25a2d410c45 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -633,6 +633,23 @@ pub use macros::Debug; /// [tostring]: ../../std/string/trait.ToString.html /// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string /// +/// # Internationalization +/// +/// Because a type can only have one `Display` implementation, it is often preferable +/// to only implement `Display` when there is a single most "obvious" way that +/// values can be formatted as text. This could mean formatting according to the +/// "invariant" culture and "undefined" locale, or it could mean that the type +/// display is designed for a specific culture/locale, such as developer logs. +/// +/// If not all values have a justifiably canonical textual format or if you want +/// to support alternative formats not covered by the standard set of possible +/// [formatting traits], the most flexible approach is display adapters: methods +/// like [`str::escape_default`] or [`Path::display`] which create a wrapper +/// implementing `Display` to output the specific display format. +/// +/// [formatting traits]: ../../std/fmt/index.html#formatting-traits +/// [`Path::display`]: ../../std/path/struct.Path.html#method.display +/// /// # Examples /// /// Implementing `Display` on a type: @@ -1102,8 +1119,14 @@ pub trait UpperExp { /// ``` /// /// [`write!`]: crate::write! +#[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { + if let Some(s) = args.as_str() { output.write_str(s) } else { write_internal(output, args) } +} + +/// Actual implementation of the [`write()`], but without the simple string optimization. +fn write_internal(output: &mut dyn Write, args: Arguments<'_>) -> Result { let mut formatter = Formatter::new(output); let mut idx = 0; diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index af2e422e8a0..6dd3069034d 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -30,8 +30,7 @@ use crate::task::{Context, Poll}; #[lang = "future_trait"] #[diagnostic::on_unimplemented( label = "`{Self}` is not a future", - message = "`{Self}` is not a future", - note = "{Self} must be a future or must implement `IntoFuture` to be awaited" + message = "`{Self}` is not a future" )] pub trait Future { /// The type of value produced on completion. diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index 38c654e76b4..eb5a9b72dd0 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -100,6 +100,11 @@ use crate::future::Future; /// ``` #[stable(feature = "into_future", since = "1.64.0")] #[rustc_diagnostic_item = "IntoFuture"] +#[diagnostic::on_unimplemented( + label = "`{Self}` is not a future", + message = "`{Self}` is not a future", + note = "{Self} must be a future or must implement `IntoFuture` to be awaited" +)] pub trait IntoFuture { /// The output that the future will produce on completion. #[stable(feature = "into_future", since = "1.64.0")] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 96e667d63c5..aff1c589e62 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2499,9 +2499,8 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn black_box<T>(dummy: T) -> T; - /// `ptr` must point to a vtable. - /// The intrinsic will return the size stored in that vtable. #[rustc_nounwind] + #[cfg(bootstrap)] pub fn vtable_size(ptr: *const ()) -> usize; /// `ptr` must point to a vtable. @@ -2515,6 +2514,8 @@ extern "rust-intrinsic" { /// intrinsic will be replaced with a call to `called_in_const`. It gets /// replaced with a call to `called_at_rt` otherwise. /// + /// This function is safe to call, but note the stability concerns below. + /// /// # Type Requirements /// /// The two functions must be both function items. They cannot be function @@ -2524,45 +2525,47 @@ extern "rust-intrinsic" { /// the two functions, therefore, both functions must accept the same type of /// arguments. Both functions must return RET. /// - /// # Safety + /// # Stability concerns /// - /// The two functions must behave observably equivalent. Safe code in other - /// crates may assume that calling a `const fn` at compile-time and at run-time - /// produces the same result. A function that produces a different result when - /// evaluated at run-time, or has any other observable side-effects, is - /// *unsound*. + /// Rust has not yet decided that `const fn` are allowed to tell whether + /// they run at compile-time or at runtime. Therefore, when using this + /// intrinsic anywhere that can be reached from stable, it is crucial that + /// the end-to-end behavior of the stable `const fn` is the same for both + /// modes of execution. (Here, Undefined Behavior is considered "the same" + /// as any other behavior, so if the function exhibits UB at runtime then + /// it may do whatever it wants at compile-time.) /// /// Here is an example of how this could cause a problem: /// ```no_run /// #![feature(const_eval_select)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] - /// use std::hint::unreachable_unchecked; + /// # #![cfg_attr(bootstrap, allow(unused))] /// use std::intrinsics::const_eval_select; /// - /// // Crate A + /// // Standard library + /// # #[cfg(not(bootstrap))] /// pub const fn inconsistent() -> i32 { /// fn runtime() -> i32 { 1 } /// const fn compiletime() -> i32 { 2 } /// - /// unsafe { - // // ⚠ This code violates the required equivalence of `compiletime` - /// // and `runtime`. - /// const_eval_select((), compiletime, runtime) - /// } + // // ⚠ This code violates the required equivalence of `compiletime` + /// // and `runtime`. + /// const_eval_select((), compiletime, runtime) /// } + /// # #[cfg(bootstrap)] + /// # pub const fn inconsistent() -> i32 { 0 } /// - /// // Crate B + /// // User Crate /// const X: i32 = inconsistent(); /// let x = inconsistent(); - /// if x != X { unsafe { unreachable_unchecked(); }} + /// assert_eq!(x, X); /// ``` /// - /// This code causes Undefined Behavior when being run, since the - /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, - /// which violates the principle that a `const fn` must behave the same at - /// compile-time and at run-time. The unsafe code in crate B is fine. + /// Currently such an assertion would always succeed; until Rust decides + /// otherwise, that principle should not be violated. #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] + #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)] pub fn const_eval_select<ARG: Tuple, F, G, RET>( arg: ARG, called_in_const: F, @@ -2681,6 +2684,17 @@ pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 { #[cfg_attr(bootstrap, inline)] pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} +/// `ptr` must point to a vtable. +/// The intrinsic will return the size stored in that vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_must_be_overridden)] +#[cfg(not(bootstrap))] +pub unsafe fn vtable_size(_ptr: *const ()) -> usize { + unreachable!() +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>. // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 0d1cf7941fb..d89801bce2b 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -236,6 +236,49 @@ pub trait FromIterator<A>: Sized { /// ``` #[rustc_diagnostic_item = "IntoIterator"] #[rustc_skip_array_during_method_dispatch] +#[rustc_on_unimplemented( + on( + _Self = "core::ops::range::RangeTo<Idx>", + label = "if you meant to iterate until a value, add a starting value", + note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ + bounded `Range`: `0..end`" + ), + on( + _Self = "core::ops::range::RangeToInclusive<Idx>", + label = "if you meant to iterate until a value (including it), add a starting value", + note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ + to have a bounded `RangeInclusive`: `0..=end`" + ), + on( + _Self = "[]", + label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" + ), + on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), + on( + _Self = "alloc::vec::Vec<T, A>", + label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" + ), + on( + _Self = "&str", + label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" + ), + on( + _Self = "alloc::string::String", + label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" + ), + on( + _Self = "{integral}", + note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ + syntax `start..end` or the inclusive range syntax `start..=end`" + ), + on( + _Self = "{float}", + note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ + syntax `start..end` or the inclusive range syntax `start..=end`" + ), + label = "`{Self}` is not an iterator", + message = "`{Self}` is not an iterator" +)] #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated over. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 3267cea38b7..e1904ed220c 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -28,42 +28,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[rustc_on_unimplemented( on( _Self = "core::ops::range::RangeTo<Idx>", - label = "if you meant to iterate until a value, add a starting value", - note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ - bounded `Range`: `0..end`" + note = "you might have meant to use a bounded `Range`" ), on( _Self = "core::ops::range::RangeToInclusive<Idx>", - label = "if you meant to iterate until a value (including it), add a starting value", - note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ - to have a bounded `RangeInclusive`: `0..=end`" - ), - on( - _Self = "[]", - label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" - ), - on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), - on( - _Self = "alloc::vec::Vec<T, A>", - label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" - ), - on( - _Self = "&str", - label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" - ), - on( - _Self = "alloc::string::String", - label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" - ), - on( - _Self = "{integral}", - note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ - syntax `start..end` or the inclusive range syntax `start..=end`" - ), - on( - _Self = "{float}", - note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ - syntax `start..end` or the inclusive range syntax `start..=end`" + note = "you might have meant to use a bounded `RangeInclusive`" ), label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d818889f364..643968c35e8 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -112,16 +112,19 @@ macro_rules! assert_ne { }; } -/// Asserts that an expression matches any of the given patterns. +/// Asserts that an expression matches the provided pattern. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// This macro is generally preferable to `assert!(matches!(value, pattern))`, because it can print +/// the debug representation of the actual value shape that did not meet expectations. In contrast, +/// using [`assert!`] will only print that expectations were not met, but not why. /// -/// On panic, this macro will print the value of the expression with its -/// debug representation. +/// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The +/// optional if guard can be used to add additional checks that must be true for the matched value, +/// otherwise this macro will panic. /// -/// Like [`assert!`], this macro has a second form, where a custom -/// panic message can be provided. +/// On panic, this macro will print the value of the expression with its debug representation. +/// +/// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. /// /// # Examples /// @@ -130,13 +133,20 @@ macro_rules! assert_ne { /// /// use std::assert_matches::assert_matches; /// -/// let a = 1u32.checked_add(2); -/// let b = 1u32.checked_sub(2); +/// let a = Some(345); +/// let b = Some(56); /// assert_matches!(a, Some(_)); -/// assert_matches!(b, None); +/// assert_matches!(b, Some(_)); +/// +/// assert_matches!(a, Some(345)); +/// assert_matches!(a, Some(345) | None); +/// +/// // assert_matches!(a, None); // panics +/// // assert_matches!(b, Some(345)); // panics +/// // assert_matches!(b, Some(345) | None); // panics /// -/// let c = Ok("abc".to_string()); -/// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); +/// assert_matches!(a, Some(x) if x > 100); +/// // assert_matches!(a, Some(x) if x < 100); // panics /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(panic_internals)] @@ -369,21 +379,25 @@ macro_rules! debug_assert_ne { }; } -/// Asserts that an expression matches any of the given patterns. +/// Asserts that an expression matches the provided pattern. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// This macro is generally preferable to `debug_assert!(matches!(value, pattern))`, because it can +/// print the debug representation of the actual value shape that did not meet expectations. In +/// contrast, using [`debug_assert!`] will only print that expectations were not met, but not why. /// -/// On panic, this macro will print the value of the expression with its -/// debug representation. +/// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The +/// optional if guard can be used to add additional checks that must be true for the matched value, +/// otherwise this macro will panic. /// -/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only -/// enabled in non optimized builds by default. An optimized build will not -/// execute `debug_assert_matches!` statements unless `-C debug-assertions` is -/// passed to the compiler. This makes `debug_assert_matches!` useful for -/// checks that are too expensive to be present in a release build but may be -/// helpful during development. The result of expanding `debug_assert_matches!` -/// is always type checked. +/// On panic, this macro will print the value of the expression with its debug representation. +/// +/// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. +/// +/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only enabled in non optimized +/// builds by default. An optimized build will not execute `debug_assert_matches!` statements unless +/// `-C debug-assertions` is passed to the compiler. This makes `debug_assert_matches!` useful for +/// checks that are too expensive to be present in a release build but may be helpful during +/// development. The result of expanding `debug_assert_matches!` is always type checked. /// /// # Examples /// @@ -392,13 +406,20 @@ macro_rules! debug_assert_ne { /// /// use std::assert_matches::debug_assert_matches; /// -/// let a = 1u32.checked_add(2); -/// let b = 1u32.checked_sub(2); +/// let a = Some(345); +/// let b = Some(56); /// debug_assert_matches!(a, Some(_)); -/// debug_assert_matches!(b, None); +/// debug_assert_matches!(b, Some(_)); +/// +/// debug_assert_matches!(a, Some(345)); +/// debug_assert_matches!(a, Some(345) | None); /// -/// let c = Ok("abc".to_string()); -/// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); +/// // debug_assert_matches!(a, None); // panics +/// // debug_assert_matches!(b, Some(345)); // panics +/// // debug_assert_matches!(b, Some(345) | None); // panics +/// +/// debug_assert_matches!(a, Some(x) if x > 100); +/// // debug_assert_matches!(a, Some(x) if x < 100); // panics /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] @@ -409,10 +430,15 @@ pub macro debug_assert_matches($($arg:tt)*) { } } -/// Returns whether the given expression matches any of the given patterns. +/// Returns whether the given expression matches the provided pattern. +/// +/// The pattern syntax is exactly the same as found in a match arm. The optional if guard can be +/// used to add additional checks that must be true for the matched value, otherwise this macro will +/// return `false`. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// When testing that a value matches a pattern, it's generally preferable to use +/// [`assert_matches!`] as it will print the debug representation of the value if the assertion +/// fails. /// /// # Examples /// diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index f5cc86e7767..0687874a258 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -6,10 +6,10 @@ use crate::marker::ConstParamTy; /// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`, /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] -#[lang = "transmute_trait"] +#[cfg_attr(not(bootstrap), lang = "transmute_trait")] #[rustc_deny_explicit_impl(implement_via_object = false)] #[rustc_coinductive] -pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> +pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOTHING }> where Src: ?Sized, { @@ -28,8 +28,9 @@ pub struct Assume { /// that violates Rust's memory model. pub lifetimes: bool, - /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the - /// type and field privacy of the destination type (and sometimes of the source type, too). + /// When `true`, the compiler assumes that *you* have ensured that no + /// unsoundness will arise from violating the safety invariants of the + /// destination type (and sometimes of the source type, too). pub safety: bool, /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index b9a1924d668..835ab9d73af 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -3,7 +3,7 @@ //! This module is "publicly exported" through the `FromStr` implementations //! below. -use crate::convert::TryInto; +use crate::convert::{TryFrom, TryInto}; use crate::error::Error; use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; @@ -104,36 +104,66 @@ impl<'a> Parser<'a> { // Read a number off the front of the input in the given radix, stopping // at the first non-digit character or eof. Fails if the number has more // digits than max_digits or if there is no number. - fn read_number<T: ReadNumberHelper>( + // + // INVARIANT: `max_digits` must be less than the number of digits that `u32` + // can represent. + fn read_number<T: ReadNumberHelper + TryFrom<u32>>( &mut self, radix: u32, max_digits: Option<usize>, allow_zero_prefix: bool, ) -> Option<T> { - self.read_atomically(move |p| { - let mut result = T::ZERO; - let mut digit_count = 0; - let has_leading_zero = p.peek_char() == Some('0'); - - while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { - result = result.checked_mul(radix)?; - result = result.checked_add(digit)?; - digit_count += 1; - if let Some(max_digits) = max_digits { + // If max_digits.is_some(), then we are parsing a `u8` or `u16` and + // don't need to use checked arithmetic since it fits within a `u32`. + if let Some(max_digits) = max_digits { + // u32::MAX = 4_294_967_295u32, which is 10 digits long. + // `max_digits` must be less than 10 to not overflow a `u32`. + debug_assert!(max_digits < 10); + + self.read_atomically(move |p| { + let mut result = 0_u32; + let mut digit_count = 0; + let has_leading_zero = p.peek_char() == Some('0'); + + while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { + result *= radix; + result += digit; + digit_count += 1; + if digit_count > max_digits { return None; } } - } - if digit_count == 0 { - None - } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { - None - } else { - Some(result) - } - }) + if digit_count == 0 { + None + } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { + None + } else { + result.try_into().ok() + } + }) + } else { + self.read_atomically(move |p| { + let mut result = T::ZERO; + let mut digit_count = 0; + let has_leading_zero = p.peek_char() == Some('0'); + + while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { + result = result.checked_mul(radix)?; + result = result.checked_add(digit)?; + digit_count += 1; + } + + if digit_count == 0 { + None + } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { + None + } else { + Some(result) + } + }) + } } /// Read an IPv4 address. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 47e16018a47..abdcb7099ca 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1153,8 +1153,11 @@ impl f32 { // Stability concerns. unsafe { mem::transmute(x) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: We use internal implementations that either always work or fail at compile time. - unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } + unsafe { + intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) + } } /// Raw transmutation from `u32`. @@ -1245,8 +1248,11 @@ impl f32 { // Stability concerns. unsafe { mem::transmute(x) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: We use internal implementations that either always work or fail at compile time. - unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) } + unsafe { + intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) + } } /// Return the memory representation of this floating point number as a byte array in diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index cd69e758d28..f4d2a4f2167 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1146,8 +1146,11 @@ impl f64 { // Stability concerns. unsafe { mem::transmute::<f64, u64>(rt) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: We use internal implementations that either always work or fail at compile time. - unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } + unsafe { + intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) + } } /// Raw transmutation from `u64`. @@ -1243,8 +1246,11 @@ impl f64 { // Stability concerns. unsafe { mem::transmute::<u64, f64>(rt) } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: We use internal implementations that either always work or fail at compile time. - unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) } + unsafe { + intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) + } } /// Return the memory representation of this floating point number as a byte array in diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 295b88361cf..9e34c0d240d 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -24,13 +24,17 @@ mod private { /// A marker trait for primitive types which can be zero. /// /// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time. +/// +/// # Safety +/// +/// Types implementing this trait must be primitves that are valid when zeroed. #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] #[const_trait] -pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {} +pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {} macro_rules! impl_zeroable_primitive { ($primitive:ty) => { @@ -46,7 +50,7 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const ZeroablePrimitive for $primitive {} + unsafe impl const ZeroablePrimitive for $primitive {} }; } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 0819334b600..9e1184c8f5b 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -117,6 +117,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo panic_fmt(fmt); } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: const panic does not care about unwinding unsafe { super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime); diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bd58c167c2e..3eea065eef6 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -234,15 +234,9 @@ impl Default for Alignment { } #[cfg(target_pointer_width = "16")] -type AlignmentEnum = AlignmentEnum16; -#[cfg(target_pointer_width = "32")] -type AlignmentEnum = AlignmentEnum32; -#[cfg(target_pointer_width = "64")] -type AlignmentEnum = AlignmentEnum64; - #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u16)] -enum AlignmentEnum16 { +enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, @@ -261,9 +255,10 @@ enum AlignmentEnum16 { _Align1Shl15 = 1 << 15, } +#[cfg(target_pointer_width = "32")] #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u32)] -enum AlignmentEnum32 { +enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, @@ -298,9 +293,10 @@ enum AlignmentEnum32 { _Align1Shl31 = 1 << 31, } +#[cfg(target_pointer_width = "64")] #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u64)] -enum AlignmentEnum64 { +enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 85a56d37ab7..f2566fe9bcc 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -48,8 +48,11 @@ impl<T: ?Sized> *const T { } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The two versions are equivalent at runtime. - unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) } + unsafe { + const_eval_select((self as *const u8,), const_impl, runtime_impl) + } } /// Casts to a pointer of another type. @@ -806,6 +809,7 @@ impl<T: ?Sized> *const T { where T: Sized, { + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The comparison has no side-effects, and the intrinsic // does this check internally in the CTFE implementation. unsafe { @@ -1623,8 +1627,11 @@ impl<T: ?Sized> *const T { ptr.align_offset(align) == 0 } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The two versions are equivalent at runtime. - unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) } + unsafe { + const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + } } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fc5b08c9801..2bf486062fe 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -574,6 +574,8 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T { /// Creates a pointer with the given address and no provenance. /// +/// This is equivalent to `ptr::null().with_addr(addr)`. +/// /// Without provenance, this pointer is not associated with any actual allocation. Such a /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are @@ -616,6 +618,8 @@ pub const fn dangling<T>() -> *const T { /// Creates a pointer with the given address and no provenance. /// +/// This is equivalent to `ptr::null_mut().with_addr(addr)`. +/// /// Without provenance, this pointer is not associated with any actual allocation. Such a /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are @@ -991,6 +995,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { }; } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: the caller must guarantee that `x` and `y` are // valid for writes and properly aligned. unsafe { @@ -2071,11 +2076,16 @@ impl<F: FnPtr> fmt::Debug for F { /// as all other references. This macro can create a raw pointer *without* creating /// a reference first. /// -/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads -/// from the place or requires the place to be dereferenceable. This means that -/// `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned. -/// Note however that `addr_of!((*ptr).field)` still requires the projection to -/// `field` to be in-bounds, using the same rules as [`offset`]. +/// See [`addr_of_mut`] for how to create a pointer to uninitialized data. +/// Doing that with `addr_of` would not make much sense since one could only +/// read the data, and that would be Undefined Behavior. +/// +/// # Safety +/// +/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads from the +/// place or requires the place to be dereferenceable. This means that `addr_of!((*ptr).field)` +/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`]. +/// However, `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned. /// /// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside /// `addr_of!` like everywhere else, in which case a reference is created to call `Deref::deref` or @@ -2086,6 +2096,8 @@ impl<F: FnPtr> fmt::Debug for F { /// /// # Example /// +/// **Correct usage: Creating a pointer to unaligned data** +/// /// ``` /// use std::ptr; /// @@ -2101,9 +2113,27 @@ impl<F: FnPtr> fmt::Debug for F { /// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); /// ``` /// -/// See [`addr_of_mut`] for how to create a pointer to uninitialized data. -/// Doing that with `addr_of` would not make much sense since one could only -/// read the data, and that would be Undefined Behavior. +/// **Incorrect usage: Out-of-bounds fields projection** +/// +/// ```rust,no_run +/// use std::ptr; +/// +/// #[repr(C)] +/// struct MyStruct { +/// field1: i32, +/// field2: i32, +/// } +/// +/// let ptr: *const MyStruct = ptr::null(); +/// let fieldptr = unsafe { ptr::addr_of!((*ptr).field2) }; // Undefined Behavior ⚠️ +/// ``` +/// +/// The field projection `.field2` would offset the pointer by 4 bytes, +/// but the pointer is not in-bounds of an allocation for 4 bytes, +/// so this offset is Undefined Behavior. +/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the +/// same requirements apply to field projections, even inside `addr_of!`. (In particular, it makes +/// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)] @@ -2120,11 +2150,12 @@ pub macro addr_of($place:expr) { /// as all other references. This macro can create a raw pointer *without* creating /// a reference first. /// -/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads -/// from the place or requires the place to be dereferenceable. This means that -/// `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned. -/// Note however that `addr_of_mut!((*ptr).field)` still requires the projection to -/// `field` to be in-bounds, using the same rules as [`offset`]. +/// # Safety +/// +/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads from the +/// place or requires the place to be dereferenceable. This means that `addr_of_mut!((*ptr).field)` +/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`]. +/// However, `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned. /// /// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside /// `addr_of_mut!` like everywhere else, in which case a reference is created to call `Deref::deref` @@ -2135,7 +2166,7 @@ pub macro addr_of($place:expr) { /// /// # Examples /// -/// **Creating a pointer to unaligned data:** +/// **Correct usage: Creating a pointer to unaligned data** /// /// ``` /// use std::ptr; @@ -2153,7 +2184,7 @@ pub macro addr_of($place:expr) { /// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. /// ``` /// -/// **Creating a pointer to uninitialized data:** +/// **Correct usage: Creating a pointer to uninitialized data** /// /// ```rust /// use std::{ptr, mem::MaybeUninit}; @@ -2169,6 +2200,28 @@ pub macro addr_of($place:expr) { /// unsafe { f1_ptr.write(true); } /// let init = unsafe { uninit.assume_init() }; /// ``` +/// +/// **Incorrect usage: Out-of-bounds fields projection** +/// +/// ```rust,no_run +/// use std::ptr; +/// +/// #[repr(C)] +/// struct MyStruct { +/// field1: i32, +/// field2: i32, +/// } +/// +/// let ptr: *mut MyStruct = ptr::null_mut(); +/// let fieldptr = unsafe { ptr::addr_of_mut!((*ptr).field2) }; // Undefined Behavior ⚠️ +/// ``` +/// +/// The field projection `.field2` would offset the pointer by 4 bytes, +/// but the pointer is not in-bounds of an allocation for 4 bytes, +/// so this offset is Undefined Behavior. +/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the +/// same requirements apply to field projections, even inside `addr_of_mut!`. (In particular, it +/// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 28ba26f5c16..8b0b22a02f2 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -48,8 +48,11 @@ impl<T: ?Sized> *mut T { } } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The two versions are equivalent at runtime. - unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) } + unsafe { + const_eval_select((self as *mut u8,), const_impl, runtime_impl) + } } /// Casts to a pointer of another type. @@ -1896,8 +1899,11 @@ impl<T: ?Sized> *mut T { ptr.align_offset(align) == 0 } + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: The two versions are equivalent at runtime. - unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) } + unsafe { + const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + } } } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 0e2d45c4ada..c771ea70472 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -35,6 +35,7 @@ where #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: we are just panicking here unsafe { const_eval_select( @@ -63,6 +64,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: we are just panicking here unsafe { const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt) @@ -87,8 +89,11 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { #[track_caller] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] const fn slice_index_order_fail(index: usize, end: usize) -> ! { + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: we are just panicking here - unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) } + unsafe { + const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) + } } // FIXME const-hack diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1ad81fcfcfe..aaedbed0d55 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2519,7 +2519,7 @@ impl<T> [T] { cmp::SliceContains::slice_contains(x, self) } - /// Returns `true` if `needle` is a prefix of the slice. + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. /// /// # Examples /// @@ -2527,6 +2527,7 @@ impl<T> [T] { /// let v = [10, 40, 30]; /// assert!(v.starts_with(&[10])); /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); /// assert!(!v.starts_with(&[50])); /// assert!(!v.starts_with(&[10, 50])); /// ``` @@ -2549,7 +2550,7 @@ impl<T> [T] { self.len() >= n && needle == &self[..n] } - /// Returns `true` if `needle` is a suffix of the slice. + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. /// /// # Examples /// @@ -2557,6 +2558,7 @@ impl<T> [T] { /// let v = [10, 40, 30]; /// assert!(v.ends_with(&[30])); /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); /// assert!(!v.ends_with(&[50])); /// assert!(!v.ends_with(&[50, 30])); /// ``` @@ -2582,7 +2584,8 @@ impl<T> [T] { /// Returns a subslice with the prefix removed. /// /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. - /// If `prefix` is empty, simply returns the original slice. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. /// /// If the slice does not start with `prefix`, returns `None`. /// @@ -2592,6 +2595,7 @@ impl<T> [T] { /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); /// assert_eq!(v.strip_prefix(&[50]), None); /// assert_eq!(v.strip_prefix(&[10, 50]), None); /// @@ -2620,7 +2624,8 @@ impl<T> [T] { /// Returns a subslice with the suffix removed. /// /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. - /// If `suffix` is empty, simply returns the original slice. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. /// /// If the slice does not end with `suffix`, returns `None`. /// @@ -2630,6 +2635,7 @@ impl<T> [T] { /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); /// assert_eq!(v.strip_suffix(&[50]), None); /// assert_eq!(v.strip_suffix(&[50, 30]), None); /// ``` diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index f965a50058b..4943bbc45d0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -86,6 +86,7 @@ use iter::{MatchesInternal, SplitNInternal}; #[rustc_allow_const_fn_unstable(const_eval_select)] #[cfg(not(feature = "panic_immediate_abort"))] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { + #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block // SAFETY: panics for both branches unsafe { crate::intrinsics::const_eval_select( diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 45193c11e1d..00e75ec9a25 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1092,7 +1092,7 @@ impl AtomicBool { /// Returns a mutable pointer to the underlying [`bool`]. /// - /// Doing non-atomic reads and writes on the resulting integer can be a data race. + /// Doing non-atomic reads and writes on the resulting boolean can be a data race. /// This method is mostly useful for FFI, where the function signature may use /// `*mut bool` instead of `&AtomicBool`. /// @@ -2031,7 +2031,7 @@ impl<T> AtomicPtr<T> { /// Returns a mutable pointer to the underlying pointer. /// - /// Doing non-atomic reads and writes on the resulting integer can be a data race. + /// Doing non-atomic reads and writes on the resulting pointer can be a data race. /// This method is mostly useful for FFI, where the function signature may use /// `*mut *mut T` instead of `&AtomicPtr<T>`. /// |
