1
Fork 0

Rollup merge of #98888 - RalfJung:interpret-checked-bin, r=oli-obk

interpret: fix CheckedBinOp behavior when overflow checking is disabled

Adjusts the interpreter to https://github.com/rust-lang/rust/pull/98738.

r? `@oli-obk`
This commit is contained in:
Matthias Krüger 2022-07-05 17:08:11 +02:00 committed by GitHub
commit cca43fe8e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 26 additions and 4 deletions

View file

@ -217,7 +217,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::mul_with_overflow => BinOp::Mul, sym::mul_with_overflow => BinOp::Mul,
_ => bug!(), _ => bug!(),
}; };
self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?; self.binop_with_overflow(
bin_op, /*force_overflow_checks*/ true, &lhs, &rhs, dest,
)?;
} }
sym::saturating_add | sym::saturating_sub => { sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(&args[0])?; let l = self.read_immediate(&args[0])?;

View file

@ -144,6 +144,9 @@ pub trait Machine<'mir, 'tcx>: Sized {
true true
} }
/// Whether CheckedBinOp MIR statements should actually check for overflow.
fn check_binop_checks_overflow(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Entry point for obtaining the MIR of anything that should get evaluated. /// Entry point for obtaining the MIR of anything that should get evaluated.
/// So not just functions and shims, but also const/static initializers, anonymous /// So not just functions and shims, but also const/static initializers, anonymous
/// constants, ... /// constants, ...
@ -468,6 +471,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
true true
} }
#[inline(always)]
fn check_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
true
}
#[inline(always)] #[inline(always)]
fn call_extra_fn( fn call_extra_fn(
_ecx: &mut InterpCx<$mir, $tcx, Self>, _ecx: &mut InterpCx<$mir, $tcx, Self>,

View file

@ -12,9 +12,13 @@ use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Applies the binary operation `op` to the two operands and writes a tuple of the result /// Applies the binary operation `op` to the two operands and writes a tuple of the result
/// and a boolean signifying the potential overflow to the destination. /// and a boolean signifying the potential overflow to the destination.
///
/// `force_overflow_checks` indicates whether overflow checks should be done even when
/// `tcx.sess.overflow_checks()` is `false`.
pub fn binop_with_overflow( pub fn binop_with_overflow(
&mut self, &mut self,
op: mir::BinOp, op: mir::BinOp,
force_overflow_checks: bool,
left: &ImmTy<'tcx, M::PointerTag>, left: &ImmTy<'tcx, M::PointerTag>,
right: &ImmTy<'tcx, M::PointerTag>, right: &ImmTy<'tcx, M::PointerTag>,
dest: &PlaceTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>,
@ -26,6 +30,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
"type mismatch for result of {:?}", "type mismatch for result of {:?}",
op, op,
); );
// As per https://github.com/rust-lang/rust/pull/98738, we always return `false` in the 2nd
// component when overflow checking is disabled.
let overflowed =
overflowed && (force_overflow_checks || M::check_binop_checks_overflow(self));
// Write the result to `dest`.
if let Abi::ScalarPair(..) = dest.layout.abi { if let Abi::ScalarPair(..) = dest.layout.abi {
// We can use the optimized path and avoid `place_field` (which might do // We can use the optimized path and avoid `place_field` (which might do
// `force_allocation`). // `force_allocation`).

View file

@ -185,7 +185,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let left = self.read_immediate(&self.eval_operand(left, None)?)?; let left = self.read_immediate(&self.eval_operand(left, None)?)?;
let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
let right = self.read_immediate(&self.eval_operand(right, layout)?)?; let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
self.binop_with_overflow(bin_op, &left, &right, &dest)?; self.binop_with_overflow(
bin_op, /*force_overflow_checks*/ false, &left, &right, &dest,
)?;
} }
UnaryOp(un_op, ref operand) => { UnaryOp(un_op, ref operand) => {

View file

@ -993,8 +993,9 @@ pub enum Rvalue<'tcx> {
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
/// ///
/// When overflow checking is disabled, the error condition is false. Otherwise, the error /// When overflow checking is disabled and we are generating run-time code, the error condition
/// condition is determined as described below. /// is false. Otherwise, and always during CTFE, the error condition is determined as described
/// below.
/// ///
/// For addition, subtraction, and multiplication on integers the error condition is set when /// For addition, subtraction, and multiplication on integers the error condition is set when
/// the infinite precision result would be unequal to the actual result. /// the infinite precision result would be unequal to the actual result.