From 6739299d18a16851140bc6b24b8eeae31e3d5878 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Tue, 1 Mar 2022 20:02:59 -0500
Subject: [PATCH] Miri/CTFE: properly treat overflow in (signed) division/rem
 as UB

---
 .../src/interpret/intrinsics.rs               | 12 ++------
 .../src/interpret/operator.rs                 | 18 +++++++-----
 .../rustc_middle/src/mir/interpret/error.rs   |  6 ++++
 .../rustc_mir_transform/src/const_prop.rs     | 11 +++++++-
 library/core/tests/num/wrapping.rs            | 10 +++++++
 src/test/ui/consts/const-int-unchecked.stderr |  4 +--
 .../issue-8460-const.noopt.stderr             | 28 +++++++++----------
 .../issue-8460-const.opt.stderr               | 28 +++++++++----------
 ...8460-const.opt_with_overflow_checks.stderr | 28 +++++++++----------
 .../ui/numbers-arithmetic/issue-8460-const.rs | 24 ++++++++--------
 10 files changed, 93 insertions(+), 76 deletions(-)

diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index d6f856a6f0a70..bf7e811c76f8e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -500,15 +500,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
         // First, check x % y != 0 (or if that computation overflows).
         let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
-        if overflow || res.assert_bits(a.layout.size) != 0 {
-            // Then, check if `b` is -1, which is the "MIN / -1" case.
-            let minus1 = Scalar::from_int(-1, dest.layout.size);
-            let b_scalar = b.to_scalar().unwrap();
-            if b_scalar == minus1 {
-                throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented")
-            } else {
-                throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,)
-            }
+        assert!(!overflow); // All overflow is UB, so this should never return on overflow.
+        if res.assert_bits(a.layout.size) != 0 {
+            throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b)
         }
         // `Rem` says this is all right, so we can let `Div` do its job.
         self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 48c90e1881a9a..079ce9f07b8e1 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -196,16 +196,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 _ => None,
             };
             if let Some(op) = op {
+                let l = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
-                // 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!
-                if bin_op == Rem {
-                    if r == -1 && l == (1 << (size.bits() - 1)) {
-                        return Ok((Scalar::from_int(0, size), true, left_layout.ty));
+
+                // We need a special check for overflowing Rem and Div since they are *UB*
+                // on overflow, which can happen with "int_min $OP -1".
+                if matches!(bin_op, Rem | Div) {
+                    if l == size.signed_int_min() && r == -1 {
+                        if bin_op == Rem {
+                            throw_ub!(RemainderOverflow)
+                        } else {
+                            throw_ub!(DivisionOverflow)
+                        }
                     }
                 }
-                let l = self.sign_extend(l, left_layout) as i128;
 
                 let (result, oflo) = op(l, r);
                 // This may be out-of-bounds for the result type, so we have to truncate ourselves.
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 31468ce73bfc5..389d31ea0c472 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -233,6 +233,10 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     DivisionByZero,
     /// Something was "remainded" by 0 (x % 0).
     RemainderByZero,
+    /// Signed division overflowed (INT_MIN / -1).
+    DivisionOverflow,
+    /// Signed remainder overflowed (INT_MIN % -1).
+    RemainderOverflow,
     /// Overflowing inbounds pointer arithmetic.
     PointerArithOverflow,
     /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
@@ -310,6 +314,8 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             }
             DivisionByZero => write!(f, "dividing by zero"),
             RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
+            DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
+            RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
             PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
             InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
             InvalidVtableDropFn(sig) => write!(
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 6075f572a651c..b724b527c7dfb 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -1200,12 +1200,21 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
                             AssertKind::RemainderByZero(op) => {
                                 Some(AssertKind::RemainderByZero(eval_to_int(op)))
                             }
+                            AssertKind::Overflow(bin_op @ (BinOp::Div | BinOp::Rem), op1, op2) => {
+                                // Division overflow is *UB* in the MIR, and different than the
+                                // other overflow checks.
+                                Some(AssertKind::Overflow(
+                                    *bin_op,
+                                    eval_to_int(op1),
+                                    eval_to_int(op2),
+                                ))
+                            }
                             AssertKind::BoundsCheck { ref len, ref index } => {
                                 let len = eval_to_int(len);
                                 let index = eval_to_int(index);
                                 Some(AssertKind::BoundsCheck { len, index })
                             }
-                            // Overflow is are already covered by checks on the binary operators.
+                            // Remaining overflow errors are already covered by checks on the binary operators.
                             AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => None,
                             // Need proper const propagator for these.
                             _ => None,
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
index c4fb321ef26cf..8ded139a1809f 100644
--- a/library/core/tests/num/wrapping.rs
+++ b/library/core/tests/num/wrapping.rs
@@ -308,3 +308,13 @@ fn wrapping_int_api() {
         }
     }
 }
+
+#[test]
+fn wrapping_const() {
+    // Specifically the wrapping behavior of division and remainder is subtle,
+    // see https://github.com/rust-lang/rust/pull/94512.
+    const _: () = {
+        assert!(i32::MIN.wrapping_div(-1) == i32::MIN);
+        assert!(i32::MIN.wrapping_rem(-1) == 0);
+    };
+}
diff --git a/src/test/ui/consts/const-int-unchecked.stderr b/src/test/ui/consts/const-int-unchecked.stderr
index 22e8c8dabc970..ad880d56d904d 100644
--- a/src/test/ui/consts/const-int-unchecked.stderr
+++ b/src/test/ui/consts/const-int-unchecked.stderr
@@ -266,7 +266,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:134:25
    |
 LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_div`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:137:25
@@ -278,7 +278,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:139:25
    |
 LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_rem`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:144:25
diff --git a/src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr
index d94c7742de301..e2eee1ccdc98c 100644
--- a/src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr
+++ b/src/test/ui/numbers-arithmetic/issue-8460-const.noopt.stderr
@@ -1,36 +1,36 @@
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:13:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
-   = note: `#[deny(arithmetic_overflow)]` on by default
+   = note: `#[deny(unconditional_panic)]` on by default
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:15:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:17:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:19:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:21:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:23:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
@@ -41,8 +41,6 @@ error: this operation will panic at runtime
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:27:36
@@ -74,37 +72,37 @@ error: this operation will panic at runtime
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
    |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:37:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:39:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:41:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:45:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:47:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
diff --git a/src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr
index d94c7742de301..e2eee1ccdc98c 100644
--- a/src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr
+++ b/src/test/ui/numbers-arithmetic/issue-8460-const.opt.stderr
@@ -1,36 +1,36 @@
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:13:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
-   = note: `#[deny(arithmetic_overflow)]` on by default
+   = note: `#[deny(unconditional_panic)]` on by default
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:15:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:17:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:19:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:21:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:23:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
@@ -41,8 +41,6 @@ error: this operation will panic at runtime
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:27:36
@@ -74,37 +72,37 @@ error: this operation will panic at runtime
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
    |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:37:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:39:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:41:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:45:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:47:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
diff --git a/src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr
index d94c7742de301..e2eee1ccdc98c 100644
--- a/src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr
+++ b/src/test/ui/numbers-arithmetic/issue-8460-const.opt_with_overflow_checks.stderr
@@ -1,36 +1,36 @@
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:13:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
-   = note: `#[deny(arithmetic_overflow)]` on by default
+   = note: `#[deny(unconditional_panic)]` on by default
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:15:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:17:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:19:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:21:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:23:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
@@ -41,8 +41,6 @@ error: this operation will panic at runtime
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:27:36
@@ -74,37 +72,37 @@ error: this operation will panic at runtime
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
    |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:37:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:39:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:41:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:45:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
-error: this arithmetic operation will overflow
+error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:47:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
diff --git a/src/test/ui/numbers-arithmetic/issue-8460-const.rs b/src/test/ui/numbers-arithmetic/issue-8460-const.rs
index dc754666c8e1f..8cad6deb3db5e 100644
--- a/src/test/ui/numbers-arithmetic/issue-8460-const.rs
+++ b/src/test/ui/numbers-arithmetic/issue-8460-const.rs
@@ -11,17 +11,17 @@ use std::thread;
 
 fn main() {
     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
@@ -35,17 +35,17 @@ fn main() {
     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
     //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-    //~^ ERROR arithmetic operation will overflow
+    //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR operation will panic
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());