about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJohn Millikin <john@john-millikin.com>2022-09-27 11:40:39 +0900
committerJohn Millikin <john@john-millikin.com>2023-04-20 14:27:29 +0900
commit4e2797dd76363370eac74cc9480e7d8c0ff17b4b (patch)
tree509fe2f357fc7270af5aa2a9cd9f65a6c2410c72
parentdc730521efad6acf9b31fcc99c8a26789fa9a654 (diff)
downloadrust-4e2797dd76363370eac74cc9480e7d8c0ff17b4b.tar.gz
rust-4e2797dd76363370eac74cc9480e7d8c0ff17b4b.zip
Implement `Neg` for signed non-zero integers.
Negating a non-zero integer currently requires unpacking to a
primitive and re-wrapping. Since negation of non-zero signed
integers always produces a non-zero result, it is safe to
implement `Neg` for `NonZeroI{N}`.

The new `impl` is marked as stable because trait implementations
for two stable types can't be marked unstable.
-rw-r--r--library/core/src/num/nonzero.rs19
-rw-r--r--library/core/tests/nonzero.rs18
-rw-r--r--tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs12
3 files changed, 46 insertions, 3 deletions
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 54e03067d1c..fc9b07d29e2 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 96356b728e9..007f8442533 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/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
new file mode 100644
index 00000000000..565b7e86fc4
--- /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();
+}