diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index 91c06402ca10a..934312662beb6 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -12,7 +12,7 @@ Tracking issues are for tracking a feature from implementation to stabilization. Make sure to include the relevant RFC for the feature if it has one. If the new feature is small, it may be fine to skip the RFC process. In that -case, you can use use `issue = "none"` in your initial implementation PR. The +case, you can use `issue = "none"` in your initial implementation PR. The reviewer will ask you to open a tracking issue if they agree your feature can be added without an RFC. --> @@ -65,7 +65,7 @@ the rfcbot will ask all the team members to verify they agree with stabilization. Once enough members agree and there are no concerns, the final comment period begins: this issue will be marked as such and will be listed in the next This Week in Rust newsletter. If no blocking concerns are raised in -that period of 10 days, a stabilzation PR can be opened by anyone. +that period of 10 days, a stabilization PR can be opened by anyone. --> ### Unresolved Questions diff --git a/RELEASES.md b/RELEASES.md index b89178a6f68fe..699735de6fb4d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -963,7 +963,7 @@ Compatibility Notes - [rustdoc: doctests are now run on unexported `macro_rules!` macros, matching other private items][96630] - [rustdoc: Remove .woff font files][96279] - [Enforce Copy bounds for repeat elements while considering lifetimes][95819] -- [Windows: Fix potentinal unsoundness by aborting if `File` reads or writes cannot +- [Windows: Fix potential unsoundness by aborting if `File` reads or writes cannot complete synchronously][95469]. Internal Changes @@ -1794,10 +1794,10 @@ Libraries - [impl Default, Copy, Clone for std::io::Sink and std::io::Empty][rust#86744] - [`impl From<[(K, V); N]>` for all collections.][rust#84111] - [Remove `P: Unpin` bound on impl Future for Pin.][rust#81363] -- [Treat invalid environment variable names as non-existent.][rust#86183] +- [Treat invalid environment variable names as nonexistent.][rust#86183] Previously, the environment functions would panic if given a variable name with an internal null character or equal sign (`=`). Now, these functions will - just treat such names as non-existent variables, since the OS cannot represent + just treat such names as nonexistent variables, since the OS cannot represent the existence of a variable with such a name. Stabilised APIs @@ -1990,7 +1990,7 @@ Compatibility Notes kinds of errors could be categorised [into newer more specific `ErrorKind` variants][79965], and that they do not represent a user error. - [Using environment variable names with `process::Command` on Windows now - behaves as expected.][85270] Previously using envionment variables with + behaves as expected.][85270] Previously using environment variables with `Command` would cause them to be ASCII-uppercased. - [Rustdoc will now warn on using rustdoc lints that aren't prefixed with `rustdoc::`][86849] @@ -6367,7 +6367,7 @@ eg. `static MINUTE: Duration = Duration::from_secs(60);` Cargo ----- -- [`cargo new` no longer removes `rust` or `rs` prefixs/suffixs.][cargo/5013] +- [`cargo new` no longer removes `rust` or `rs` prefixes/suffixes.][cargo/5013] - [`cargo new` now defaults to creating a binary crate, instead of a library crate.][cargo/5029] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 405ae99395b31..426d2c4034bd8 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -35,6 +35,7 @@ #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![deny(unsafe_op_in_unsafe_fn)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index ef37a606f313e..ca908671ae530 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -13,7 +13,8 @@ pub struct Mmap(Vec); impl Mmap { #[inline] pub unsafe fn map(file: File) -> io::Result { - memmap2::Mmap::map(&file).map(Mmap) + // Safety: this is in fact not safe. + unsafe { memmap2::Mmap::map(&file).map(Mmap) } } } diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index d849fe0373f28..4a0ed87f77c84 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -96,28 +96,30 @@ macro_rules! compress { unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { debug_assert!(count <= 8); - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); - return; - } + unsafe { + if count == 8 { + ptr::copy_nonoverlapping(src, dst, 8); + return; + } - let mut i = 0; - if i + 3 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i += 4; - } + let mut i = 0; + if i + 3 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); + i += 4; + } - if i + 1 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i += 2 - } + if i + 1 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); + i += 2 + } - if i < count { - *dst.add(i) = *src.add(i); - i += 1; - } + if i < count { + *dst.add(i) = *src.add(i); + i += 1; + } - debug_assert_eq!(i, count); + debug_assert_eq!(i, count); + } } // # Implementation @@ -232,38 +234,40 @@ impl SipHasher128 { // overflow) if it wasn't already. #[inline(never)] unsafe fn short_write_process_buffer(&mut self, bytes: [u8; LEN]) { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN >= BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); + unsafe { + let nbuf = self.nbuf; + debug_assert!(LEN <= 8); + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + LEN >= BUFFER_SIZE); + debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); + + // Copy first part of input into end of buffer, possibly into spill + // element. The memcpy call is optimized away because the size is known. + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); + + // Process buffer. + for i in 0..BUFFER_CAPACITY { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } - // Copy first part of input into end of buffer, possibly into spill - // element. The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - - // Process buffer. - for i in 0..BUFFER_CAPACITY { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; + // Copy remaining input into start of buffer by copying LEN - 1 + // elements from spill (at most LEN - 1 bytes could have overflowed + // into the spill). The memcpy call is optimized away because the size + // is known. And the whole copy is optimized away for LEN == 1. + let dst = self.buf.as_mut_ptr() as *mut u8; + let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; + ptr::copy_nonoverlapping(src, dst, LEN - 1); + + // This function should only be called when the write fills the buffer. + // Therefore, when LEN == 1, the new `self.nbuf` must be zero. + // LEN is statically known, so the branch is optimized away. + self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; + self.processed += BUFFER_SIZE; } - - // Copy remaining input into start of buffer by copying LEN - 1 - // elements from spill (at most LEN - 1 bytes could have overflowed - // into the spill). The memcpy call is optimized away because the size - // is known. And the whole copy is optimized away for LEN == 1. - let dst = self.buf.as_mut_ptr() as *mut u8; - let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, dst, LEN - 1); - - // This function should only be called when the write fills the buffer. - // Therefore, when LEN == 1, the new `self.nbuf` must be zero. - // LEN is statically known, so the branch is optimized away. - self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; - self.processed += BUFFER_SIZE; } // A write function for byte slices. @@ -301,57 +305,59 @@ impl SipHasher128 { // containing the byte offset `self.nbuf`. #[inline(never)] unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + length >= BUFFER_SIZE); - - // Always copy first part of input into current element of buffer. - // This function should only be called when the write fills the buffer, - // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE - valid_in_elem; - - let src = msg.as_ptr(); - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - copy_nonoverlapping_small(src, dst, needed_in_elem); - - // Process buffer. + unsafe { + let length = msg.len(); + let nbuf = self.nbuf; + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + length >= BUFFER_SIZE); + + // Always copy first part of input into current element of buffer. + // This function should only be called when the write fills the buffer, + // so we know that there is enough input to fill the current element. + let valid_in_elem = nbuf % ELEM_SIZE; + let needed_in_elem = ELEM_SIZE - valid_in_elem; + + let src = msg.as_ptr(); + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + copy_nonoverlapping_small(src, dst, needed_in_elem); + + // Process buffer. + + // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / + // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. + // We know that is true, because last step ensured we have a full + // element in the buffer. + let last = nbuf / ELEM_SIZE + 1; + + for i in 0..last { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } - // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / - // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. - // We know that is true, because last step ensured we have a full - // element in the buffer. - let last = nbuf / ELEM_SIZE + 1; + // Process the remaining element-sized chunks of input. + let mut processed = needed_in_elem; + let input_left = length - processed; + let elems_left = input_left / ELEM_SIZE; + let extra_bytes_left = input_left % ELEM_SIZE; + + for _ in 0..elems_left { + let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + processed += ELEM_SIZE; + } - for i in 0..last { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } + // Copy remaining input into start of buffer. + let src = msg.as_ptr().add(processed); + let dst = self.buf.as_mut_ptr() as *mut u8; + copy_nonoverlapping_small(src, dst, extra_bytes_left); - // Process the remaining element-sized chunks of input. - let mut processed = needed_in_elem; - let input_left = length - processed; - let elems_left = input_left / ELEM_SIZE; - let extra_bytes_left = input_left % ELEM_SIZE; - - for _ in 0..elems_left { - let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - processed += ELEM_SIZE; + self.nbuf = extra_bytes_left; + self.processed += nbuf + processed; } - - // Copy remaining input into start of buffer. - let src = msg.as_ptr().add(processed); - let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, extra_bytes_left); - - self.nbuf = extra_bytes_left; - self.processed += nbuf + processed; } #[inline] diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index c26bffac67823..8568aac67c08c 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -153,7 +153,7 @@ unsafe impl Pointer for Box { #[inline] unsafe fn from_ptr(ptr: NonNull) -> Self { // Safety: `ptr` comes from `into_ptr` which calls `Box::into_raw` - Box::from_raw(ptr.as_ptr()) + unsafe { Box::from_raw(ptr.as_ptr()) } } } @@ -169,7 +169,7 @@ unsafe impl Pointer for Rc { #[inline] unsafe fn from_ptr(ptr: NonNull) -> Self { // Safety: `ptr` comes from `into_ptr` which calls `Rc::into_raw` - Rc::from_raw(ptr.as_ptr()) + unsafe { Rc::from_raw(ptr.as_ptr()) } } } @@ -185,7 +185,7 @@ unsafe impl Pointer for Arc { #[inline] unsafe fn from_ptr(ptr: NonNull) -> Self { // Safety: `ptr` comes from `into_ptr` which calls `Arc::into_raw` - Arc::from_raw(ptr.as_ptr()) + unsafe { Arc::from_raw(ptr.as_ptr()) } } } @@ -201,7 +201,7 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T { unsafe fn from_ptr(ptr: NonNull) -> Self { // Safety: // `ptr` comes from `into_ptr` which gets the pointer from a reference - ptr.as_ref() + unsafe { ptr.as_ref() } } } @@ -217,7 +217,7 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { unsafe fn from_ptr(mut ptr: NonNull) -> Self { // Safety: // `ptr` comes from `into_ptr` which gets the pointer from a reference - ptr.as_mut() + unsafe { ptr.as_mut() } } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 648a7c6eed66d..79253cbc8b43c 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -33,6 +33,11 @@ pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext } } +fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool { + let item = cx.tcx.associated_item(ii.owner_id); + item.trait_item_def_id.is_some() +} + declare_lint! { /// The `non_camel_case_types` lint detects types, variants, traits and /// type parameters that don't have camel case names. @@ -177,6 +182,7 @@ impl EarlyLintPass for NonCamelCaseTypes { // trait impls where we should have warned for the trait definition already. ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => { for it in items { + // FIXME: this doesn't respect `#[allow(..)]` on the item itself. if let ast::AssocItemKind::Type(..) = it.kind { self.check_case(cx, "associated type", &it.ident); } @@ -494,15 +500,6 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { hir::ItemKind::Const(..) => { NonUpperCaseGlobals::check_upper_case(cx, "constant", &it.ident); } - // we only want to check inherent associated consts, trait consts - // are linted at def-site. - hir::ItemKind::Impl(hir::Impl { of_trait: None, items, .. }) => { - for it in *items { - if let hir::AssocItemKind::Const = it.kind { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &it.ident); - } - } - } _ => {} } } @@ -513,6 +510,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } } + fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { + if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); + } + } + fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.kind { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 83f4907d51769..8a900ca427ebe 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1044,17 +1044,26 @@ impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Use the global `SourceMap` to print the span. If that's not // available, fall back to printing the raw values. - with_session_globals(|session_globals| { - if let Some(source_map) = &*session_globals.source_map.borrow() { - write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) - } else { - f.debug_struct("Span") - .field("lo", &self.lo()) - .field("hi", &self.hi()) - .field("ctxt", &self.ctxt()) - .finish() - } - }) + + fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() + } + + if SESSION_GLOBALS.is_set() { + with_session_globals(|session_globals| { + if let Some(source_map) = &*session_globals.source_map.borrow() { + write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) + } else { + fallback(*self, f) + } + }) + } else { + fallback(*self, f) + } } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 90825c4ce32e1..87ec35c040fbf 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -321,14 +321,11 @@ pub struct AssertParamIsEq { /// ``` /// use std::cmp::Ordering; /// -/// let result = 1.cmp(&2); -/// assert_eq!(Ordering::Less, result); +/// assert_eq!(1.cmp(&2), Ordering::Less); /// -/// let result = 1.cmp(&1); -/// assert_eq!(Ordering::Equal, result); +/// assert_eq!(1.cmp(&1), Ordering::Equal); /// -/// let result = 2.cmp(&1); -/// assert_eq!(Ordering::Greater, result); +/// assert_eq!(2.cmp(&1), Ordering::Greater); /// ``` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -784,8 +781,8 @@ pub trait Ord: Eq + PartialOrd { /// # Examples /// /// ``` - /// assert_eq!(2, 1.max(2)); - /// assert_eq!(2, 2.max(2)); + /// assert_eq!(1.max(2), 2); + /// assert_eq!(2.max(2), 2); /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] @@ -804,8 +801,8 @@ pub trait Ord: Eq + PartialOrd { /// # Examples /// /// ``` - /// assert_eq!(1, 1.min(2)); - /// assert_eq!(2, 2.min(2)); + /// assert_eq!(1.min(2), 1); + /// assert_eq!(2.min(2), 2); /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] @@ -829,9 +826,9 @@ pub trait Ord: Eq + PartialOrd { /// # Examples /// /// ``` - /// assert!((-3).clamp(-2, 1) == -2); - /// assert!(0.clamp(-2, 1) == 0); - /// assert!(2.clamp(-2, 1) == 1); + /// assert_eq!((-3).clamp(-2, 1), -2); + /// assert_eq!(0.clamp(-2, 1), 0); + /// assert_eq!(2.clamp(-2, 1), 1); /// ``` #[must_use] #[stable(feature = "clamp", since = "1.50.0")] @@ -1060,11 +1057,9 @@ pub trait PartialOrd: PartialEq { /// # Examples /// /// ``` - /// let result = 1.0 < 2.0; - /// assert_eq!(result, true); - /// - /// let result = 2.0 < 1.0; - /// assert_eq!(result, false); + /// assert_eq!(1.0 < 1.0, false); + /// assert_eq!(1.0 < 2.0, true); + /// assert_eq!(2.0 < 1.0, false); /// ``` #[inline] #[must_use] @@ -1079,11 +1074,9 @@ pub trait PartialOrd: PartialEq { /// # Examples /// /// ``` - /// let result = 1.0 <= 2.0; - /// assert_eq!(result, true); - /// - /// let result = 2.0 <= 2.0; - /// assert_eq!(result, true); + /// assert_eq!(1.0 <= 1.0, true); + /// assert_eq!(1.0 <= 2.0, true); + /// assert_eq!(2.0 <= 1.0, false); /// ``` #[inline] #[must_use] @@ -1097,11 +1090,9 @@ pub trait PartialOrd: PartialEq { /// # Examples /// /// ``` - /// let result = 1.0 > 2.0; - /// assert_eq!(result, false); - /// - /// let result = 2.0 > 2.0; - /// assert_eq!(result, false); + /// assert_eq!(1.0 > 1.0, false); + /// assert_eq!(1.0 > 2.0, false); + /// assert_eq!(2.0 > 1.0, true); /// ``` #[inline] #[must_use] @@ -1116,11 +1107,9 @@ pub trait PartialOrd: PartialEq { /// # Examples /// /// ``` - /// let result = 2.0 >= 1.0; - /// assert_eq!(result, true); - /// - /// let result = 2.0 >= 2.0; - /// assert_eq!(result, true); + /// assert_eq!(1.0 >= 1.0, true); + /// assert_eq!(1.0 >= 2.0, false); + /// assert_eq!(2.0 >= 1.0, true); /// ``` #[inline] #[must_use] @@ -1150,8 +1139,8 @@ pub macro PartialOrd($item:item) { /// ``` /// use std::cmp; /// -/// assert_eq!(1, cmp::min(1, 2)); -/// assert_eq!(2, cmp::min(2, 2)); +/// assert_eq!(cmp::min(1, 2), 1); +/// assert_eq!(cmp::min(2, 2), 2); /// ``` #[inline] #[must_use] @@ -1170,8 +1159,11 @@ pub fn min(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1); -/// assert_eq!(cmp::min_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); +/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// assert_eq!(result, 1); +/// +/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// assert_eq!(result, -2); /// ``` #[inline] #[must_use] @@ -1192,8 +1184,11 @@ pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1); -/// assert_eq!(cmp::min_by_key(-2, 2, |x: &i32| x.abs()), -2); +/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs()); +/// assert_eq!(result, 1); +/// +/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs()); +/// assert_eq!(result, -2); /// ``` #[inline] #[must_use] @@ -1213,8 +1208,8 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { /// ``` /// use std::cmp; /// -/// assert_eq!(2, cmp::max(1, 2)); -/// assert_eq!(2, cmp::max(2, 2)); +/// assert_eq!(cmp::max(1, 2), 2); +/// assert_eq!(cmp::max(2, 2), 2); /// ``` #[inline] #[must_use] @@ -1233,8 +1228,11 @@ pub fn max(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); -/// assert_eq!(cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 2); +/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// assert_eq!(result, -2); +/// +/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ; +/// assert_eq!(result, 2); /// ``` #[inline] #[must_use] @@ -1255,8 +1253,11 @@ pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2); -/// assert_eq!(cmp::max_by_key(-2, 2, |x: &i32| x.abs()), 2); +/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs()); +/// assert_eq!(result, -2); +/// +/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs()); +/// assert_eq!(result, 2); /// ``` #[inline] #[must_use] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 54e03067d1c7a..fc9b07d29e266 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,7 +1,7 @@ //! Definitions of integer that is known not to equal zero. use crate::fmt; -use crate::ops::{BitOr, BitOrAssign, Div, Rem}; +use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; use crate::str::FromStr; use super::from_str_radix; @@ -664,8 +664,7 @@ macro_rules! nonzero_signed_operations { /// assert_eq!(pos, pos.wrapping_abs()); /// assert_eq!(pos, neg.wrapping_abs()); /// assert_eq!(min, min.wrapping_abs()); - /// # // FIXME: add once Neg is implemented? - /// # // assert_eq!(max, (-max).wrapping_abs()); + /// assert_eq!(max, (-max).wrapping_abs()); /// # Some(()) /// # } /// ``` @@ -868,6 +867,20 @@ macro_rules! nonzero_signed_operations { unsafe { $Ty::new_unchecked(result) } } } + + #[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] + impl Neg for $Ty { + type Output = $Ty; + + #[inline] + fn neg(self) -> $Ty { + // SAFETY: negation of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().neg()) } + } + } + + forward_ref_unop! { impl Neg, neg for $Ty, + #[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] } )+ } } diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index 96356b728e926..007f844253308 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -336,3 +336,21 @@ fn test_nonzero_uint_rem() { let x: u32 = 42u32 % nz; assert_eq!(x, 2u32); } + +#[test] +fn test_signed_nonzero_neg() { + assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1); + assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1); + assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1); + assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1); + assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1); + assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1); +} diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index a158d1f718e2c..19d67e80a61c5 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -374,9 +374,9 @@ checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "3f508063cc7bb32987c71511216bd5a32be15bccb6a80b52df8b9d7f01fc3aa2" [[package]] name = "log" diff --git a/tests/ui/lint/issue-110573.rs b/tests/ui/lint/issue-110573.rs new file mode 100644 index 0000000000000..d9f0868b7659d --- /dev/null +++ b/tests/ui/lint/issue-110573.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(warnings)] + +pub struct Struct; + +impl Struct { + #[allow(non_upper_case_globals)] + pub const Const: () = (); +} + +fn main() {} diff --git a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs new file mode 100644 index 0000000000000..565b7e86fc4b9 --- /dev/null +++ b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs @@ -0,0 +1,12 @@ +// run-fail +// error-pattern:thread 'main' panicked at 'attempt to negate with overflow' +// ignore-emscripten no processes +// compile-flags: -C debug-assertions + +#![allow(arithmetic_overflow)] + +use std::num::NonZeroI8; + +fn main() { + let _x = -NonZeroI8::new(i8::MIN).unwrap(); +}