diff options
| author | Ralf Jung <post@ralfj.de> | 2024-02-23 18:00:51 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2024-02-24 12:17:37 +0100 |
| commit | f32095cd8d43de470c2d3daa5b3cb8f494cfa770 (patch) | |
| tree | 73f652262eae71d1392ea74205feadcf2655de9b /compiler/rustc_mir_transform/src | |
| parent | 8f359beca4e58bc3ae795a666301a8f47023044c (diff) | |
| download | rust-f32095cd8d43de470c2d3daa5b3cb8f494cfa770.tar.gz rust-f32095cd8d43de470c2d3daa5b3cb8f494cfa770.zip | |
promotion: don't promote int::MIN / -1
Diffstat (limited to 'compiler/rustc_mir_transform/src')
| -rw-r--r-- | compiler/rustc_mir_transform/src/promote_consts.rs | 29 |
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. |
