about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-02-12 20:36:55 +0100
committerGitHub <noreply@github.com>2020-02-12 20:36:55 +0100
commit29dd5df791bb70d6c5d3d1118c1289d4f3d51899 (patch)
treebe69c58038568bd2ac24cc8e76858ab08d83f32b
parent2a3c1a30c84d66ad9bde8aef7727dfd6b60c40c9 (diff)
parentc561d23a6105122a517c14394a46c3faab8e01b6 (diff)
downloadrust-29dd5df791bb70d6c5d3d1118c1289d4f3d51899.tar.gz
rust-29dd5df791bb70d6c5d3d1118c1289d4f3d51899.zip
Rollup merge of #69002 - RalfJung:miri-op-overflow, r=oli-obk,wesleywiser
miri: improve and simplify overflow detection

This simplifies the overflow detection for signed binary operators, and adds overflow detection to unary operators so that const-prop doesn't have to crudely hand-roll that.

It also fixes some bugs in the operator implementation that however, I think, were not observable.

r? @oli-obk @wesleywiser
-rw-r--r--src/librustc_mir/interpret/operator.rs74
-rw-r--r--src/librustc_mir/transform/const_prop.rs34
-rw-r--r--src/test/ui/consts/const-err2.rs8
-rw-r--r--src/test/ui/consts/const-err2.stderr22
-rw-r--r--src/test/ui/consts/const-err3.rs6
-rw-r--r--src/test/ui/consts/const-err3.stderr22
-rw-r--r--src/test/ui/consts/const-int-arithmetic-overflow.rs26
-rw-r--r--src/test/ui/consts/const-int-arithmetic.rs21
-rw-r--r--src/test/ui/issues/issue-8460-const.rs12
-rw-r--r--src/test/ui/issues/issue-8460-const.stderr78
-rw-r--r--src/test/ui/issues/issue-8460-const2.rs10
-rw-r--r--src/test/ui/issues/issue-8460-const2.stderr56
12 files changed, 272 insertions, 97 deletions
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 5050fe49064..2e8c94903ca 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -134,9 +134,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             let mut r = r as u32;
             let size = left_layout.size;
             oflo |= r >= size.bits() as u32;
-            if oflo {
-                r %= size.bits() as u32;
-            }
+            r %= size.bits() as u32;
             let result = if signed {
                 let l = self.sign_extend(l, left_layout) as i128;
                 let result = match bin_op {
@@ -168,6 +166,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )
         }
 
+        let size = left_layout.size;
+
         // Operations that need special treatment for signed integers
         if left_layout.abi.is_signed() {
             let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
@@ -195,32 +195,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if let Some(op) = op {
                 let l128 = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
-                let size = left_layout.size;
+                // We need a special check for overflowing remainder:
+                // "int_min % -1" overflows and returns 0, but after casting things to a larger int
+                // type it does *not* overflow nor give an unrepresentable result!
                 match bin_op {
-                    Rem | Div => {
-                        // int_min / -1
+                    Rem => {
                         if r == -1 && l == (1 << (size.bits() - 1)) {
-                            return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
+                            return Ok((Scalar::from_int(0, size), true, left_layout.ty));
                         }
                     }
                     _ => {}
                 }
-                trace!("{}, {}, {}", l, l128, r);
-                let (result, mut oflo) = op(l128, r);
-                trace!("{}, {}", result, oflo);
-                if !oflo && size.bits() != 128 {
-                    let max = 1 << (size.bits() - 1);
-                    oflo = result >= max || result < -max;
-                }
-                // this may be out-of-bounds for the result type, so we have to truncate ourselves
+
+                let (result, oflo) = op(l128, r);
+                // This may be out-of-bounds for the result type, so we have to truncate ourselves.
+                // If that truncation loses any information, we have an overflow.
                 let result = result as u128;
                 let truncated = self.truncate(result, left_layout);
-                return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
+                return Ok((
+                    Scalar::from_uint(truncated, size),
+                    oflo || self.sign_extend(truncated, left_layout) != result,
+                    left_layout.ty,
+                ));
             }
         }
 
-        let size = left_layout.size;
-
         let (val, ty) = match bin_op {
             Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
             Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
@@ -247,6 +246,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     _ => bug!(),
                 };
                 let (result, oflo) = op(l, r);
+                // Truncate to target type.
+                // If that truncation loses any information, we have an overflow.
                 let truncated = self.truncate(result, left_layout);
                 return Ok((
                     Scalar::from_uint(truncated, size),
@@ -341,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    /// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
+    /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows.
     #[inline]
     pub fn binary_op(
         &self,
@@ -353,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
     }
 
-    pub fn unary_op(
+    /// Returns the result of the specified operation, whether it overflowed, and
+    /// the result type.
+    pub fn overflowing_unary_op(
         &self,
         un_op: mir::UnOp,
         val: ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         use rustc::mir::UnOp::*;
 
         let layout = val.layout;
@@ -371,7 +374,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Not => !val,
                     _ => bug!("Invalid bool op {:?}", un_op),
                 };
-                Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
+                Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
             }
             ty::Float(fty) => {
                 let res = match (un_op, fty) {
@@ -379,21 +382,36 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
                     _ => bug!("Invalid float op {:?}", un_op),
                 };
-                Ok(ImmTy::from_scalar(res, layout))
+                Ok((res, false, layout.ty))
             }
             _ => {
                 assert!(layout.ty.is_integral());
                 let val = self.force_bits(val, layout.size)?;
-                let res = match un_op {
-                    Not => !val,
+                let (res, overflow) = match un_op {
+                    Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate
                     Neg => {
+                        // arithmetic negation
                         assert!(layout.abi.is_signed());
-                        (-(val as i128)) as u128
+                        let val = self.sign_extend(val, layout) as i128;
+                        let (res, overflow) = val.overflowing_neg();
+                        let res = res as u128;
+                        // Truncate to target type.
+                        // If that truncation loses any information, we have an overflow.
+                        let truncated = self.truncate(res, layout);
+                        (truncated, overflow || self.sign_extend(truncated, layout) != res)
                     }
                 };
-                // res needs tuncating
-                Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
+                Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
             }
         }
     }
+
+    pub fn unary_op(
+        &self,
+        un_op: mir::UnOp,
+        val: ImmTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+        let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
+        Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
+    }
 }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 14c0db2def2..a7da4f7c164 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -518,18 +518,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn check_unary_op(&mut self, arg: &Operand<'tcx>, source_info: SourceInfo) -> Option<()> {
+    fn check_unary_op(
+        &mut self,
+        op: UnOp,
+        arg: &Operand<'tcx>,
+        source_info: SourceInfo,
+    ) -> Option<()> {
         self.use_ecx(source_info, |this| {
-            let ty = arg.ty(&this.local_decls, this.tcx);
-
-            if ty.is_integral() {
-                let arg = this.ecx.eval_operand(arg, None)?;
-                let prim = this.ecx.read_immediate(arg)?;
-                // Need to do overflow check here: For actual CTFE, MIR
-                // generation emits code that does this before calling the op.
-                if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
-                    throw_panic!(OverflowNeg)
-                }
+            let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
+            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
+
+            if overflow {
+                assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
+                throw_panic!(OverflowNeg);
             }
 
             Ok(())
@@ -576,11 +577,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if !overflow_check {
             self.use_ecx(source_info, |this| {
                 let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
-                let (_, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
+                let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
 
                 if overflow {
-                    let err = err_panic!(Overflow(op)).into();
-                    return Err(err);
+                    throw_panic!(Overflow(op));
                 }
 
                 Ok(())
@@ -620,9 +620,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // Additional checking: if overflow checks are disabled (which is usually the case in
             // release mode), then we need to do additional checking here to give lints to the user
             // if an overflow would occur.
-            Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => {
-                trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
-                self.check_unary_op(arg, source_info)?;
+            Rvalue::UnaryOp(op, arg) if !overflow_check => {
+                trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
+                self.check_unary_op(*op, arg, source_info)?;
             }
 
             // Additional checking: check for overflows on integer binary operations and report
diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index 351dfd2e0f5..7c5aaedda35 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -17,16 +17,22 @@ fn black_box<T>(_: T) {
 fn main() {
     let a = -std::i8::MIN;
     //~^ ERROR const_err
+    let a_i128 = -std::i128::MIN;
+    //~^ ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
     //~^ ERROR const_err
+    let b_i128 = std::i128::MIN - std::i128::MAX;
+    //~^ ERROR const_err
     let c = 200u8 * 4;
     //~^ ERROR const_err
     let d = 42u8 - (42u8 + 1);
     //~^ ERROR const_err
     let _e = [5u8][1];
-    //~^ ERROR index out of bounds
+    //~^ ERROR const_err
     black_box(a);
+    black_box(a_i128);
     black_box(b);
+    black_box(b_i128);
     black_box(c);
     black_box(d);
 }
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index a76b6d1775f..f135bf0b06c 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -11,28 +11,40 @@ LL | #![deny(const_err)]
    |         ^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:20:13
+  --> $DIR/const-err2.rs:20:18
+   |
+LL |     let a_i128 = -std::i128::MIN;
+   |                  ^^^^^^^^^^^^^^^ attempt to negate with overflow
+
+error: this expression will panic at runtime
+  --> $DIR/const-err2.rs:22:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
    |             ^^^^^^^^^^^^^ attempt to add with overflow
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:22:13
+  --> $DIR/const-err2.rs:24:18
+   |
+LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+
+error: this expression will panic at runtime
+  --> $DIR/const-err2.rs:26:13
    |
 LL |     let c = 200u8 * 4;
    |             ^^^^^^^^^ attempt to multiply with overflow
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:24:13
+  --> $DIR/const-err2.rs:28:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
    |             ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 error: index out of bounds: the len is 1 but the index is 1
-  --> $DIR/const-err2.rs:26:14
+  --> $DIR/const-err2.rs:30:14
    |
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index ab3823efd30..43aba4a8b01 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -17,8 +17,12 @@ fn black_box<T>(_: T) {
 fn main() {
     let a = -std::i8::MIN;
     //~^ ERROR const_err
+    let a_i128 = -std::i128::MIN;
+    //~^ ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
     //~^ ERROR const_err
+    let b_i128 = std::i128::MIN - std::i128::MAX;
+    //~^ ERROR const_err
     let c = 200u8 * 4;
     //~^ ERROR const_err
     let d = 42u8 - (42u8 + 1);
@@ -26,7 +30,9 @@ fn main() {
     let _e = [5u8][1];
     //~^ ERROR const_err
     black_box(a);
+    black_box(a_i128);
     black_box(b);
+    black_box(b_i128);
     black_box(c);
     black_box(d);
 }
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 02b912e928c..05f64b87fcc 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -10,29 +10,41 @@ note: the lint level is defined here
 LL | #![deny(const_err)]
    |         ^^^^^^^^^
 
+error: attempt to negate with overflow
+  --> $DIR/const-err3.rs:20:18
+   |
+LL |     let a_i128 = -std::i128::MIN;
+   |                  ^^^^^^^^^^^^^^^
+
 error: attempt to add with overflow
-  --> $DIR/const-err3.rs:20:13
+  --> $DIR/const-err3.rs:22:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
    |             ^^^^^^^^^^^^^
 
+error: attempt to subtract with overflow
+  --> $DIR/const-err3.rs:24:18
+   |
+LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: attempt to multiply with overflow
-  --> $DIR/const-err3.rs:22:13
+  --> $DIR/const-err3.rs:26:13
    |
 LL |     let c = 200u8 * 4;
    |             ^^^^^^^^^
 
 error: attempt to subtract with overflow
-  --> $DIR/const-err3.rs:24:13
+  --> $DIR/const-err3.rs:28:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
    |             ^^^^^^^^^^^^^^^^^
 
 error: index out of bounds: the len is 1 but the index is 1
-  --> $DIR/const-err3.rs:26:14
+  --> $DIR/const-err3.rs:30:14
    |
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/consts/const-int-arithmetic-overflow.rs b/src/test/ui/consts/const-int-arithmetic-overflow.rs
new file mode 100644
index 00000000000..75dac812f1e
--- /dev/null
+++ b/src/test/ui/consts/const-int-arithmetic-overflow.rs
@@ -0,0 +1,26 @@
+// run-pass
+// compile-flags: -O
+#![allow(const_err)]
+
+// Make sure arithmetic unary/binary ops actually return the right result, even when overflowing.
+// We have to put them in `const fn` and turn on optimizations to avoid overflow checks.
+
+const fn add(x: i8, y: i8) -> i8 { x+y }
+const fn sub(x: i8, y: i8) -> i8 { x-y }
+const fn mul(x: i8, y: i8) -> i8 { x*y }
+// div and rem are always checked, so we cannot test their result in case of oveflow.
+const fn neg(x: i8) -> i8 { -x }
+
+fn main() {
+    const ADD_OFLOW: i8 = add(100, 100);
+    assert_eq!(ADD_OFLOW, -56);
+
+    const SUB_OFLOW: i8 = sub(100, -100);
+    assert_eq!(SUB_OFLOW, -56);
+
+    const MUL_OFLOW: i8 = mul(-100, -2);
+    assert_eq!(MUL_OFLOW, -56);
+
+    const NEG_OFLOW: i8 = neg(-128);
+    assert_eq!(NEG_OFLOW, -128);
+}
diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs
index cfa2873c68b..2c3421b7a8d 100644
--- a/src/test/ui/consts/const-int-arithmetic.rs
+++ b/src/test/ui/consts/const-int-arithmetic.rs
@@ -7,7 +7,7 @@
 #![feature(const_saturating_int_methods)]
 #![feature(const_wrapping_int_methods)]
 
-use std::i8;
+use std::{i8, i128};
 
 macro_rules! suite {
     ($(
@@ -65,6 +65,10 @@ suite!(
         C26: 5i8.checked_rem_euclid(0), None;
         C27: i8::MIN.checked_rem_euclid(-1), None;
     }
+    checked_i128 -> Option<i128> {
+        CHK_ADD_I128: i128::MAX.checked_add(1), None;
+        CHK_MUL_I128: i128::MIN.checked_mul(-1), None;
+    }
 
     saturating_and_wrapping -> i8 {
         // `const_saturating_int_methods`
@@ -104,6 +108,13 @@ suite!(
         C47: 100i8.wrapping_rem_euclid(10), 0;
         C48: (-128i8).wrapping_rem_euclid(-1), 0;
     }
+    saturating_and_wrapping_i128 -> i128 {
+        SAT_ADD_I128: i128::MAX.saturating_add(1), i128::MAX;
+        SAT_MUL_I128: i128::MAX.saturating_mul(2), i128::MAX;
+
+        WRP_ADD_I128: i128::MAX.wrapping_add(1), i128::MIN;
+        WRP_MUL_I128: i128::MAX.wrapping_mul(3), i128::MAX-2;
+    }
 
     overflowing -> (i8, bool) {
         // `const_overflowing_int_methods`
@@ -119,12 +130,18 @@ suite!(
 
         C55: 5i8.overflowing_rem_euclid(2), (1, false);
         C56: i8::MIN.overflowing_rem_euclid(-1), (0, true);
-
+    }
+    overflowing_i128 -> (i128, bool) {
+        OFL_ADD_I128: i128::MAX.overflowing_add(1), (i128::MIN, true);
+        OFL_MUL_I128: i128::MAX.overflowing_mul(3), (i128::MAX-2, true);
     }
 );
 
 fn main() {
    checked();
+   checked_i128();
    saturating_and_wrapping();
+   saturating_and_wrapping_i128();
    overflowing();
+   overflowing_i128();
 }
diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs
index c18a0d4d6cb..5866cef2d2c 100644
--- a/src/test/ui/issues/issue-8460-const.rs
+++ b/src/test/ui/issues/issue-8460-const.rs
@@ -3,7 +3,7 @@
 
 #![deny(const_err)]
 
-use std::{isize, i8, i16, i32, i64};
+use std::{isize, i8, i16, i32, i64, i128};
 use std::thread;
 
 fn main() {
@@ -22,6 +22,9 @@ fn main() {
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
     //~| ERROR this expression will panic at runtime
+    assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+    //~^ ERROR attempt to divide with overflow
+    //~| ERROR this expression will panic at runtime
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
@@ -32,6 +35,8 @@ fn main() {
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+    //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     //~| ERROR this expression will panic at runtime
@@ -47,6 +52,9 @@ fn main() {
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     //~| ERROR this expression will panic at runtime
+    assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR this expression will panic at runtime
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
@@ -57,4 +65,6 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with a divisor of zero
 }
diff --git a/src/test/ui/issues/issue-8460-const.stderr b/src/test/ui/issues/issue-8460-const.stderr
index 6b1d74094a1..d7373948cb9 100644
--- a/src/test/ui/issues/issue-8460-const.stderr
+++ b/src/test/ui/issues/issue-8460-const.stderr
@@ -64,125 +64,161 @@ error: this expression will panic at runtime
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
 
-error: attempt to divide by zero
+error: attempt to divide with overflow
+  --> $DIR/issue-8460-const.rs:25:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: this expression will panic at runtime
   --> $DIR/issue-8460-const.rs:25:36
    |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^ attempt to divide with overflow
+
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const.rs:28:36
+   |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:27:36
+  --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:29:36
+  --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:31:36
+  --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:33:36
+  --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const.rs:38:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:35:36
+  --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:35:36
+  --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:38:36
+  --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:38:36
+  --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:41:36
+  --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:41:36
+  --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:44:36
+  --> $DIR/issue-8460-const.rs:49:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:44:36
+  --> $DIR/issue-8460-const.rs:49:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:47:36
+  --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:47:36
+  --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
+error: attempt to calculate the remainder with overflow
+  --> $DIR/issue-8460-const.rs:55:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: this expression will panic at runtime
+  --> $DIR/issue-8460-const.rs:55:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:50:36
+  --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:52:36
+  --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:54:36
+  --> $DIR/issue-8460-const.rs:62:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:56:36
+  --> $DIR/issue-8460-const.rs:64:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:58:36
+  --> $DIR/issue-8460-const.rs:66:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
-error: aborting due to 30 previous errors
+error: attempt to calculate the remainder with a divisor of zero
+  --> $DIR/issue-8460-const.rs:68:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
+error: aborting due to 36 previous errors
 
diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs
index 0ca850abc1b..afea859bb65 100644
--- a/src/test/ui/issues/issue-8460-const2.rs
+++ b/src/test/ui/issues/issue-8460-const2.rs
@@ -3,7 +3,7 @@
 
 #![deny(const_err)]
 
-use std::{isize, i8, i16, i32, i64};
+use std::{isize, i8, i16, i32, i64, i128};
 use std::thread;
 
 fn main() {
@@ -17,6 +17,8 @@ fn main() {
     //~^ ERROR attempt to divide with overflow
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+    //~^ ERROR attempt to divide with overflow
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
@@ -27,6 +29,8 @@ fn main() {
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+    //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
@@ -37,6 +41,8 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
@@ -47,4 +53,6 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with a divisor of zero
 }
diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr
index 63b9123e950..e25d560fe0c 100644
--- a/src/test/ui/issues/issue-8460-const2.stderr
+++ b/src/test/ui/issues/issue-8460-const2.stderr
@@ -34,95 +34,119 @@ error: attempt to divide with overflow
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
-error: attempt to divide by zero
+error: attempt to divide with overflow
   --> $DIR/issue-8460-const2.rs:20:36
    |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const2.rs:22:36
+   |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:22:36
+  --> $DIR/issue-8460-const2.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:24:36
+  --> $DIR/issue-8460-const2.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:26:36
+  --> $DIR/issue-8460-const2.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:28:36
+  --> $DIR/issue-8460-const2.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const2.rs:32:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:30:36
+  --> $DIR/issue-8460-const2.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:32:36
+  --> $DIR/issue-8460-const2.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:34:36
+  --> $DIR/issue-8460-const2.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:36:36
+  --> $DIR/issue-8460-const2.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:38:36
+  --> $DIR/issue-8460-const2.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
+error: attempt to calculate the remainder with overflow
+  --> $DIR/issue-8460-const2.rs:44:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:40:36
+  --> $DIR/issue-8460-const2.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:42:36
+  --> $DIR/issue-8460-const2.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:44:36
+  --> $DIR/issue-8460-const2.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:46:36
+  --> $DIR/issue-8460-const2.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:48:36
+  --> $DIR/issue-8460-const2.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
-error: aborting due to 20 previous errors
+error: attempt to calculate the remainder with a divisor of zero
+  --> $DIR/issue-8460-const2.rs:56:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
+error: aborting due to 24 previous errors