about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-24 22:38:59 +0100
committerGitHub <noreply@github.com>2024-02-24 22:38:59 +0100
commita189c8962a3a0fb28319790964cf836585b61f9b (patch)
tree21003bdaefd81f198dd531a1481a5492635c2ddf /compiler
parent59a2cd4de6964b04a5cd07ac70d15070156b97a2 (diff)
parentf32095cd8d43de470c2d3daa5b3cb8f494cfa770 (diff)
downloadrust-a189c8962a3a0fb28319790964cf836585b61f9b.tar.gz
rust-a189c8962a3a0fb28319790964cf836585b61f9b.zip
Rollup merge of #121515 - RalfJung:fallible-promotion, r=oli-obk
promotion: don't promote int::MIN / -1

Looks like I entirely forgot about this case when adding the div-by-zero check, which was supposed to ensure that we never promote operations that can fail...
Cc https://github.com/rust-lang/rust/issues/80619

This is a breaking change, so needs a crater run.
r? ``@oli-obk``
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs29
1 files changed, 26 insertions, 3 deletions
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 577b8f2080f..2e11da4d585 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -482,17 +482,40 @@ impl<'tcx> Validator<'_, 'tcx> {
                 match op {
                     BinOp::Div | BinOp::Rem => {
                         if lhs_ty.is_integral() {
+                            let sz = lhs_ty.primitive_size(self.tcx);
                             // Integer division: the RHS must be a non-zero const.
-                            let const_val = match rhs {
+                            let rhs_val = match rhs {
                                 Operand::Constant(c) => {
-                                    c.const_.try_eval_bits(self.tcx, self.param_env)
+                                    c.const_.try_eval_scalar_int(self.tcx, self.param_env)
                                 }
                                 _ => None,
                             };
-                            match const_val {
+                            match rhs_val.map(|x| x.try_to_uint(sz).unwrap()) {
+                                // for the zero test, int vs uint does not matter
                                 Some(x) if x != 0 => {}        // okay
                                 _ => return Err(Unpromotable), // value not known or 0 -- not okay
                             }
+                            // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`.
+                            if lhs_ty.is_signed() {
+                                match rhs_val.map(|x| x.try_to_int(sz).unwrap()) {
+                                    Some(-1) | None => {
+                                        // The RHS is -1 or unknown, so we have to be careful.
+                                        // But is the LHS int::MIN?
+                                        let lhs_val = match lhs {
+                                            Operand::Constant(c) => c
+                                                .const_
+                                                .try_eval_scalar_int(self.tcx, self.param_env),
+                                            _ => None,
+                                        };
+                                        let lhs_min = sz.signed_int_min();
+                                        match lhs_val.map(|x| x.try_to_int(sz).unwrap()) {
+                                            Some(x) if x != lhs_min => {}  // okay
+                                            _ => return Err(Unpromotable), // value not known or int::MIN -- not okay
+                                        }
+                                    }
+                                    _ => {}
+                                }
+                            }
                         }
                     }
                     // The remaining operations can never fail.