promotion: don't promote int::MIN / -1
This commit is contained in:
parent
8f359beca4
commit
f32095cd8d
8 changed files with 265 additions and 734 deletions
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue