1
Fork 0

promotion: don't promote int::MIN / -1

This commit is contained in:
Ralf Jung 2024-02-23 18:00:51 +01:00
parent 8f359beca4
commit f32095cd8d
8 changed files with 265 additions and 734 deletions

View file

@ -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.