Auto merge of #110585 - JohnTitor:rollup-gfffoiv, r=JohnTitor

Rollup of 7 pull requests

Successful merges:

 - #102341 (Implement `Neg` for signed non-zero integers.)
 - #110424 (Spelling misc)
 - #110448 (cmp doc examples improvements)
 - #110516 (bootstrap: Update linux-raw-sys to 0.3.2)
 - #110548 (Make `impl Debug for Span` not panic on not having session globals.)
 - #110554 (`deny(unsafe_op_in_unsafe_fn)` in `rustc_data_structures`)
 - #110575 (fix lint regression in `non_upper_case_globals`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-04-20 08:33:33 +00:00
commit 13fc33e3f2
14 changed files with 251 additions and 175 deletions

View File

@ -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

View File

@ -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]

View File

@ -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;

View File

@ -13,7 +13,8 @@ pub struct Mmap(Vec<u8>);
impl Mmap {
#[inline]
pub unsafe fn map(file: File) -> io::Result<Self> {
memmap2::Mmap::map(&file).map(Mmap)
// Safety: this is in fact not safe.
unsafe { memmap2::Mmap::map(&file).map(Mmap) }
}
}

View File

@ -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<const LEN: usize>(&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);
// 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;
// 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);
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;
// 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);
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.
// 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;
// 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;
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;
}
// 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;
}
// 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;
}
// 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;
}
// 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]

View File

@ -153,7 +153,7 @@ unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
#[inline]
unsafe fn from_ptr(ptr: NonNull<T>) -> 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<T: ?Sized + Aligned> Pointer for Rc<T> {
#[inline]
unsafe fn from_ptr(ptr: NonNull<T>) -> 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<T: ?Sized + Aligned> Pointer for Arc<T> {
#[inline]
unsafe fn from_ptr(ptr: NonNull<T>) -> 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<T>) -> 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<T>) -> Self {
// Safety:
// `ptr` comes from `into_ptr` which gets the pointer from a reference
ptr.as_mut()
unsafe { ptr.as_mut() }
}
}

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -321,14 +321,11 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
/// ```
/// 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<Self> {
/// # 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<Self> {
/// # 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<Self> {
/// # 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<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # 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<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # 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<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # 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<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// # 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<T: Ord>(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<T, F: FnOnce(&T, &T) -> 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<T, F: FnMut(&T) -> 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<T: Ord>(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<T, F: FnOnce(&T, &T) -> 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]

View File

@ -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")] }
)+
}
}

View File

@ -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);
}

View File

@ -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"

View File

@ -0,0 +1,12 @@
// check-pass
#![deny(warnings)]
pub struct Struct;
impl Struct {
#[allow(non_upper_case_globals)]
pub const Const: () = ();
}
fn main() {}

View File

@ -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();
}