diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-02-24 22:38:59 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-24 22:38:59 +0100 |
| commit | a189c8962a3a0fb28319790964cf836585b61f9b (patch) | |
| tree | 21003bdaefd81f198dd531a1481a5492635c2ddf /compiler | |
| parent | 59a2cd4de6964b04a5cd07ac70d15070156b97a2 (diff) | |
| parent | f32095cd8d43de470c2d3daa5b3cb8f494cfa770 (diff) | |
| download | rust-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.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. |
