make both unary_op and binary_op fully typed, including a return type
This commit is contained in:
parent
0a2a517fe6
commit
3edf099266
@ -11,9 +11,8 @@ use rustc::hir::def::DefKind;
|
|||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
|
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
|
||||||
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
|
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
|
||||||
use rustc::ty::subst::Subst;
|
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
|
||||||
@ -415,7 +414,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||||||
_bin_op: mir::BinOp,
|
_bin_op: mir::BinOp,
|
||||||
_left: ImmTy<'tcx>,
|
_left: ImmTy<'tcx>,
|
||||||
_right: ImmTy<'tcx>,
|
_right: ImmTy<'tcx>,
|
||||||
) -> InterpResult<'tcx, (Scalar, bool)> {
|
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
|
||||||
Err(
|
Err(
|
||||||
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
||||||
)
|
)
|
||||||
|
@ -137,7 +137,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let l = self.read_immediate(args[0])?;
|
let l = self.read_immediate(args[0])?;
|
||||||
let r = self.read_immediate(args[1])?;
|
let r = self.read_immediate(args[1])?;
|
||||||
let is_add = intrinsic_name == "saturating_add";
|
let is_add = intrinsic_name == "saturating_add";
|
||||||
let (val, overflowed) = self.binary_op(if is_add {
|
let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
|
||||||
BinOp::Add
|
BinOp::Add
|
||||||
} else {
|
} else {
|
||||||
BinOp::Sub
|
BinOp::Sub
|
||||||
@ -184,7 +184,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
"unchecked_shr" => BinOp::Shr,
|
"unchecked_shr" => BinOp::Shr,
|
||||||
_ => bug!("Already checked for int ops")
|
_ => bug!("Already checked for int ops")
|
||||||
};
|
};
|
||||||
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
|
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
|
||||||
if overflowed {
|
if overflowed {
|
||||||
let layout = self.layout_of(substs.type_at(0))?;
|
let layout = self.layout_of(substs.type_at(0))?;
|
||||||
let r_val = r.to_scalar()?.to_bits(layout.size)?;
|
let r_val = r.to_scalar()?.to_bits(layout.size)?;
|
||||||
|
@ -7,7 +7,7 @@ use std::hash::Hash;
|
|||||||
|
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
|
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
|
||||||
@ -176,7 +176,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: ImmTy<'tcx, Self::PointerTag>,
|
left: ImmTy<'tcx, Self::PointerTag>,
|
||||||
right: ImmTy<'tcx, Self::PointerTag>,
|
right: ImmTy<'tcx, Self::PointerTag>,
|
||||||
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
|
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
|
||||||
|
|
||||||
/// Heap allocations via the `box` keyword.
|
/// Heap allocations via the `box` keyword.
|
||||||
fn box_alloc(
|
fn box_alloc(
|
||||||
|
@ -108,7 +108,7 @@ impl<'tcx, Tag> Immediate<Tag> {
|
|||||||
// as input for binary and cast operations.
|
// as input for binary and cast operations.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ImmTy<'tcx, Tag=()> {
|
pub struct ImmTy<'tcx, Tag=()> {
|
||||||
pub imm: Immediate<Tag>,
|
pub(crate) imm: Immediate<Tag>,
|
||||||
pub layout: TyLayout<'tcx>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ impl<Tag> Operand<Tag> {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct OpTy<'tcx, Tag=()> {
|
pub struct OpTy<'tcx, Tag=()> {
|
||||||
op: Operand<Tag>,
|
op: Operand<Tag>, // Keep this private, it helps enforce invariants
|
||||||
pub layout: TyLayout<'tcx>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, layout::TyLayout};
|
use rustc::ty::{self, Ty, layout::{TyLayout, LayoutOf}};
|
||||||
use syntax::ast::FloatTy;
|
use syntax::ast::FloatTy;
|
||||||
use rustc_apfloat::Float;
|
use rustc_apfloat::Float;
|
||||||
use rustc::mir::interpret::{InterpResult, Scalar};
|
use rustc::mir::interpret::{InterpResult, Scalar};
|
||||||
@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
right: ImmTy<'tcx, M::PointerTag>,
|
right: ImmTy<'tcx, M::PointerTag>,
|
||||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let (val, overflowed) = self.binary_op(op, left, right)?;
|
let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
|
||||||
|
debug_assert_eq!(
|
||||||
|
self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
|
||||||
|
dest.layout.ty,
|
||||||
|
"type mismatch for result of {:?}", op,
|
||||||
|
);
|
||||||
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
||||||
self.write_immediate(val, dest)
|
self.write_immediate(val, dest)
|
||||||
}
|
}
|
||||||
@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
right: ImmTy<'tcx, M::PointerTag>,
|
right: ImmTy<'tcx, M::PointerTag>,
|
||||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let (val, _overflowed) = self.binary_op(op, left, right)?;
|
let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
|
||||||
|
assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
|
||||||
self.write_scalar(val, dest)
|
self.write_scalar(val, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
l: char,
|
l: char,
|
||||||
r: char,
|
r: char,
|
||||||
) -> (Scalar<M::PointerTag>, bool) {
|
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
|
|
||||||
let res = match bin_op {
|
let res = match bin_op {
|
||||||
@ -54,7 +60,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Ge => l >= r,
|
Ge => l >= r,
|
||||||
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
||||||
};
|
};
|
||||||
return (Scalar::from_bool(res), false);
|
return (Scalar::from_bool(res), false, self.tcx.types.bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_bool_op(
|
fn binary_bool_op(
|
||||||
@ -62,7 +68,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
l: bool,
|
l: bool,
|
||||||
r: bool,
|
r: bool,
|
||||||
) -> (Scalar<M::PointerTag>, bool) {
|
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
|
|
||||||
let res = match bin_op {
|
let res = match bin_op {
|
||||||
@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
BitXor => l ^ r,
|
BitXor => l ^ r,
|
||||||
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
||||||
};
|
};
|
||||||
return (Scalar::from_bool(res), false);
|
return (Scalar::from_bool(res), false, self.tcx.types.bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
|
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
|
||||||
&self,
|
&self,
|
||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
l: F,
|
l: F,
|
||||||
r: F,
|
r: F,
|
||||||
) -> (Scalar<M::PointerTag>, bool) {
|
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
|
||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
|
|
||||||
let val = match bin_op {
|
let (val, ty) = match bin_op {
|
||||||
Eq => Scalar::from_bool(l == r),
|
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||||
Ne => Scalar::from_bool(l != r),
|
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||||
Lt => Scalar::from_bool(l < r),
|
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||||
Le => Scalar::from_bool(l <= r),
|
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||||
Gt => Scalar::from_bool(l > r),
|
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||||
Ge => Scalar::from_bool(l >= r),
|
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||||
Add => (l + r).value.into(),
|
Add => ((l + r).value.into(), ty),
|
||||||
Sub => (l - r).value.into(),
|
Sub => ((l - r).value.into(), ty),
|
||||||
Mul => (l * r).value.into(),
|
Mul => ((l * r).value.into(), ty),
|
||||||
Div => (l / r).value.into(),
|
Div => ((l / r).value.into(), ty),
|
||||||
Rem => (l % r).value.into(),
|
Rem => ((l % r).value.into(), ty),
|
||||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||||
};
|
};
|
||||||
return (val, false);
|
return (val, false, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_int_op(
|
fn binary_int_op(
|
||||||
@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
left_layout: TyLayout<'tcx>,
|
left_layout: TyLayout<'tcx>,
|
||||||
r: u128,
|
r: u128,
|
||||||
right_layout: TyLayout<'tcx>,
|
right_layout: TyLayout<'tcx>,
|
||||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
|
||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
|
|
||||||
// Shift ops can have an RHS with a different numeric type.
|
// Shift ops can have an RHS with a different numeric type.
|
||||||
@ -142,7 +149,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let truncated = self.truncate(result, left_layout);
|
let truncated = self.truncate(result, left_layout);
|
||||||
return Ok((Scalar::from_uint(truncated, size), oflo));
|
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the remaining ops, the types must be the same on both sides
|
// For the remaining ops, the types must be the same on both sides
|
||||||
@ -167,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
if let Some(op) = op {
|
if let Some(op) = op {
|
||||||
let l = self.sign_extend(l, left_layout) as i128;
|
let l = self.sign_extend(l, left_layout) as i128;
|
||||||
let r = self.sign_extend(r, right_layout) as i128;
|
let r = self.sign_extend(r, right_layout) as i128;
|
||||||
return Ok((Scalar::from_bool(op(&l, &r)), false));
|
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
|
||||||
}
|
}
|
||||||
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
||||||
Div if r == 0 => throw_panic!(DivisionByZero),
|
Div if r == 0 => throw_panic!(DivisionByZero),
|
||||||
@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Rem | Div => {
|
Rem | Div => {
|
||||||
// int_min / -1
|
// int_min / -1
|
||||||
if r == -1 && l == (1 << (size.bits() - 1)) {
|
if r == -1 && l == (1 << (size.bits() - 1)) {
|
||||||
return Ok((Scalar::from_uint(l, size), true));
|
return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// this may be out-of-bounds for the result type, so we have to truncate ourselves
|
// this may be out-of-bounds for the result type, so we have to truncate ourselves
|
||||||
let result = result as u128;
|
let result = result as u128;
|
||||||
let truncated = self.truncate(result, left_layout);
|
let truncated = self.truncate(result, left_layout);
|
||||||
return Ok((Scalar::from_uint(truncated, size), oflo));
|
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = left_layout.size;
|
let size = left_layout.size;
|
||||||
|
|
||||||
// only ints left
|
let (val, ty) = match bin_op {
|
||||||
let val = match bin_op {
|
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||||
Eq => Scalar::from_bool(l == r),
|
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||||
Ne => Scalar::from_bool(l != r),
|
|
||||||
|
|
||||||
Lt => Scalar::from_bool(l < r),
|
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||||
Le => Scalar::from_bool(l <= r),
|
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||||
Gt => Scalar::from_bool(l > r),
|
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||||
Ge => Scalar::from_bool(l >= r),
|
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||||
|
|
||||||
BitOr => Scalar::from_uint(l | r, size),
|
BitOr => (Scalar::from_uint(l | r, size), left_layout.ty),
|
||||||
BitAnd => Scalar::from_uint(l & r, size),
|
BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
|
||||||
BitXor => Scalar::from_uint(l ^ r, size),
|
BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
|
||||||
|
|
||||||
Add | Sub | Mul | Rem | Div => {
|
Add | Sub | Mul | Rem | Div => {
|
||||||
debug_assert!(!left_layout.abi.is_signed());
|
debug_assert!(!left_layout.abi.is_signed());
|
||||||
@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
};
|
};
|
||||||
let (result, oflo) = op(l, r);
|
let (result, oflo) = op(l, r);
|
||||||
let truncated = self.truncate(result, left_layout);
|
let truncated = self.truncate(result, left_layout);
|
||||||
return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
|
return Ok((
|
||||||
|
Scalar::from_uint(truncated, size),
|
||||||
|
oflo || truncated != result,
|
||||||
|
left_layout.ty,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@ -250,17 +260,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((val, false))
|
Ok((val, false, ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the result of the specified operation and whether it overflowed.
|
/// Returns the result of the specified operation, whether it overflowed, and
|
||||||
#[inline]
|
/// the result type.
|
||||||
pub fn binary_op(
|
pub fn overflowing_binary_op(
|
||||||
&self,
|
&self,
|
||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: ImmTy<'tcx, M::PointerTag>,
|
left: ImmTy<'tcx, M::PointerTag>,
|
||||||
right: ImmTy<'tcx, M::PointerTag>,
|
right: ImmTy<'tcx, M::PointerTag>,
|
||||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
|
||||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||||
bin_op, *left, left.layout.ty, *right, right.layout.ty);
|
bin_op, *left, left.layout.ty, *right, right.layout.ty);
|
||||||
|
|
||||||
@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
ty::Float(fty) => {
|
ty::Float(fty) => {
|
||||||
assert_eq!(left.layout.ty, right.layout.ty);
|
assert_eq!(left.layout.ty, right.layout.ty);
|
||||||
|
let ty = left.layout.ty;
|
||||||
let left = left.to_scalar()?;
|
let left = left.to_scalar()?;
|
||||||
let right = right.to_scalar()?;
|
let right = right.to_scalar()?;
|
||||||
Ok(match fty {
|
Ok(match fty {
|
||||||
FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?),
|
FloatTy::F32 =>
|
||||||
FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?),
|
self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?),
|
||||||
|
FloatTy::F64 =>
|
||||||
|
self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ if left.layout.ty.is_integral() => {
|
_ if left.layout.ty.is_integral() => {
|
||||||
@ -312,11 +325,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
|
||||||
|
#[inline]
|
||||||
|
pub fn binary_op(
|
||||||
|
&self,
|
||||||
|
bin_op: mir::BinOp,
|
||||||
|
left: ImmTy<'tcx, M::PointerTag>,
|
||||||
|
right: ImmTy<'tcx, M::PointerTag>,
|
||||||
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||||
|
let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
|
||||||
|
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unary_op(
|
pub fn unary_op(
|
||||||
&self,
|
&self,
|
||||||
un_op: mir::UnOp,
|
un_op: mir::UnOp,
|
||||||
val: ImmTy<'tcx, M::PointerTag>,
|
val: ImmTy<'tcx, M::PointerTag>,
|
||||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||||
use rustc::mir::UnOp::*;
|
use rustc::mir::UnOp::*;
|
||||||
|
|
||||||
let layout = val.layout;
|
let layout = val.layout;
|
||||||
@ -330,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Not => !val,
|
Not => !val,
|
||||||
_ => bug!("Invalid bool op {:?}", un_op)
|
_ => bug!("Invalid bool op {:?}", un_op)
|
||||||
};
|
};
|
||||||
Ok(Scalar::from_bool(res))
|
Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
|
||||||
}
|
}
|
||||||
ty::Float(fty) => {
|
ty::Float(fty) => {
|
||||||
let res = match (un_op, fty) {
|
let res = match (un_op, fty) {
|
||||||
@ -338,7 +363,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||||
_ => bug!("Invalid float op {:?}", un_op)
|
_ => bug!("Invalid float op {:?}", un_op)
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(ImmTy::from_scalar(res, layout))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
assert!(layout.ty.is_integral());
|
assert!(layout.ty.is_integral());
|
||||||
@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// res needs tuncating
|
// res needs tuncating
|
||||||
Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
|
Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ pub enum Place<Tag=(), Id=AllocId> {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct PlaceTy<'tcx, Tag=()> {
|
pub struct PlaceTy<'tcx, Tag=()> {
|
||||||
place: Place<Tag>,
|
place: Place<Tag>, // Keep this private, it helps enforce invariants
|
||||||
pub layout: TyLayout<'tcx>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +177,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// The operand always has the same type as the result.
|
// The operand always has the same type as the result.
|
||||||
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
|
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
|
||||||
let val = self.unary_op(un_op, val)?;
|
let val = self.unary_op(un_op, val)?;
|
||||||
self.write_scalar(val, dest)?;
|
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
|
||||||
|
self.write_immediate(*val, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Aggregate(ref kind, ref operands) => {
|
Aggregate(ref kind, ref operands) => {
|
||||||
|
@ -50,10 +50,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
|
|
||||||
for (index, &const_int) in values.iter().enumerate() {
|
for (index, &const_int) in values.iter().enumerate() {
|
||||||
// Compare using binary_op, to also support pointer values
|
// Compare using binary_op, to also support pointer values
|
||||||
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
let res = self.overflowing_binary_op(mir::BinOp::Eq,
|
||||||
discr,
|
discr,
|
||||||
ImmTy::from_uint(const_int, discr.layout),
|
ImmTy::from_uint(const_int, discr.layout),
|
||||||
)?;
|
)?.0;
|
||||||
if res.to_bool()? {
|
if res.to_bool()? {
|
||||||
target_block = targets[index];
|
target_block = targets[index];
|
||||||
break;
|
break;
|
||||||
|
@ -452,11 +452,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
// Now run the actual operation.
|
// Now run the actual operation.
|
||||||
this.ecx.unary_op(op, prim)
|
this.ecx.unary_op(op, prim)
|
||||||
})?;
|
})?;
|
||||||
let res = ImmTy {
|
Some(val.into())
|
||||||
imm: Immediate::Scalar(val.into()),
|
|
||||||
layout: place_layout,
|
|
||||||
};
|
|
||||||
Some(res.into())
|
|
||||||
}
|
}
|
||||||
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
||||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||||
@ -510,8 +506,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
this.ecx.read_immediate(left)
|
this.ecx.read_immediate(left)
|
||||||
})?;
|
})?;
|
||||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||||
let (val, overflow) = self.use_ecx(source_info, |this| {
|
let (val, overflow, _ty) = self.use_ecx(source_info, |this| {
|
||||||
this.ecx.binary_op(op, l, r)
|
this.ecx.overflowing_binary_op(op, l, r)
|
||||||
})?;
|
})?;
|
||||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||||
Immediate::ScalarPair(
|
Immediate::ScalarPair(
|
||||||
|
Loading…
Reference in New Issue
Block a user