Skip to content

Commit

Permalink
address nits
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Aug 28, 2018
1 parent 6c78fa8 commit f96208c
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 128 deletions.
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Expand Up @@ -517,7 +517,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
InvalidMemoryAccess |
InvalidFunctionPointer |
InvalidBool |
InvalidDiscriminant |
InvalidNullPointerUsage |
ReadPointerAsBytes |
ReadBytesAsPointer |
Expand Down Expand Up @@ -550,6 +549,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
GeneratorResumedAfterReturn |
GeneratorResumedAfterPanic |
InfiniteLoop => {}
InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
Panic { ref msg, ref file, line, col } => {
msg.hash_stable(hcx, hasher);
file.hash_stable(hcx, hasher);
Expand Down
8 changes: 5 additions & 3 deletions src/librustc/mir/interpret/error.rs
Expand Up @@ -190,7 +190,7 @@ pub enum EvalErrorKind<'tcx, O> {
InvalidMemoryAccess,
InvalidFunctionPointer,
InvalidBool,
InvalidDiscriminant,
InvalidDiscriminant(u128),
PointerOutOfBounds {
ptr: Pointer,
access: bool,
Expand Down Expand Up @@ -302,8 +302,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
"tried to use a function pointer after offsetting it",
InvalidBool =>
"invalid boolean value read",
InvalidDiscriminant =>
"invalid enum discriminant value read or written",
InvalidDiscriminant(..) =>
"invalid enum discriminant value read",
PointerOutOfBounds { .. } =>
"pointer offset outside bounds of allocation",
InvalidNullPointerUsage =>
Expand Down Expand Up @@ -488,6 +488,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
Panic { ref msg, line, col, ref file } =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
InvalidDiscriminant(val) =>
write!(f, "encountered invalid enum discriminant {}", val),
_ => write!(f, "{}", self.description()),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/structural_impls.rs
Expand Up @@ -498,7 +498,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
InvalidMemoryAccess => InvalidMemoryAccess,
InvalidFunctionPointer => InvalidFunctionPointer,
InvalidBool => InvalidBool,
InvalidDiscriminant => InvalidDiscriminant,
InvalidDiscriminant(val) => InvalidDiscriminant(val),
PointerOutOfBounds {
ptr,
access,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/operand.rs
Expand Up @@ -585,7 +585,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
.expect("tagged layout for non adt")
.discriminants(self.tcx.tcx)
.position(|var| var.val == real_discr)
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant)?;
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
(real_discr, index)
},
layout::Variants::NicheFilling {
Expand Down
251 changes: 149 additions & 102 deletions src/librustc_mir/interpret/operator.rs
Expand Up @@ -48,111 +48,100 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
}

impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
/// Returns the result of the specified operation and whether it overflowed.
pub fn binary_op(
fn binary_char_op(
&self,
bin_op: mir::BinOp,
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
l: char,
r: char,
) -> EvalResult<'tcx, (Scalar, bool)> {
use rustc::mir::BinOp::*;

let left = left.to_scalar()?;
let right = right.to_scalar()?;
let res = match bin_op {
Eq => l == r,
Ne => l != r,
Lt => l < r,
Le => l <= r,
Gt => l > r,
Ge => l >= r,
_ => bug!("Invalid operation on char: {:?}", bin_op),
};
return Ok((Scalar::from_bool(res), false));
}

trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
fn binary_bool_op(
&self,
bin_op: mir::BinOp,
l: bool,
r: bool,
) -> EvalResult<'tcx, (Scalar, bool)> {
use rustc::mir::BinOp::*;

// Handle non-integer operations
if let ty::Char = left_layout.ty.sty {
assert_eq!(right_layout.ty.sty, ty::Char);
let l = left.to_char()?;
let r = right.to_char()?;
let res = match bin_op {
Eq => l == r,
Ne => l != r,
Lt => l < r,
Le => l <= r,
Gt => l > r,
Ge => l >= r,
_ => bug!("Invalid operation on char: {:?}", bin_op),
};
return Ok((Scalar::from_bool(res), false));
}
if let ty::Bool = left_layout.ty.sty {
assert_eq!(right_layout.ty.sty, ty::Bool);
let l = left.to_bool()?;
let r = right.to_bool()?;
let res = match bin_op {
Eq => l == r,
Ne => l != r,
Lt => l < r,
Le => l <= r,
Gt => l > r,
Ge => l >= r,
BitAnd => l & r,
BitOr => l | r,
BitXor => l ^ r,
_ => bug!("Invalid operation on bool: {:?}", bin_op),
};
return Ok((Scalar::from_bool(res), false));
}
if let ty::Float(fty) = left_layout.ty.sty {
let l = left.to_bits(left_layout.size)?;
let r = right.to_bits(right_layout.size)?;
assert_eq!(right_layout.ty.sty, ty::Float(fty));
macro_rules! float_math {
($ty:path, $size:expr) => {{
let l = <$ty>::from_bits(l);
let r = <$ty>::from_bits(r);
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
bits: res.value.to_bits(),
size: $size,
};
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
Lt => Scalar::from_bool(l < r),
Le => Scalar::from_bool(l <= r),
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
Add => bitify(l + r),
Sub => bitify(l - r),
Mul => bitify(l * r),
Div => bitify(l / r),
Rem => bitify(l % r),
_ => bug!("invalid float op: `{:?}`", bin_op),
};
return Ok((val, false));
}};
}
match fty {
FloatTy::F32 => float_math!(Single, 4),
FloatTy::F64 => float_math!(Double, 8),
}
}
// Only integers left
#[inline]
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
match ty.sty {
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
_ => false,
}
let res = match bin_op {
Eq => l == r,
Ne => l != r,
Lt => l < r,
Le => l <= r,
Gt => l > r,
Ge => l >= r,
BitAnd => l & r,
BitOr => l | r,
BitXor => l ^ r,
_ => bug!("Invalid operation on bool: {:?}", bin_op),
};
return Ok((Scalar::from_bool(res), false));
}

fn binary_float_op(
&self,
bin_op: mir::BinOp,
fty: FloatTy,
// passing in raw bits
l: u128,
r: u128,
) -> EvalResult<'tcx, (Scalar, bool)> {
use rustc::mir::BinOp::*;

macro_rules! float_math {
($ty:path, $size:expr) => {{
let l = <$ty>::from_bits(l);
let r = <$ty>::from_bits(r);
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
bits: res.value.to_bits(),
size: $size,
};
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
Lt => Scalar::from_bool(l < r),
Le => Scalar::from_bool(l <= r),
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
Add => bitify(l + r),
Sub => bitify(l - r),
Mul => bitify(l * r),
Div => bitify(l / r),
Rem => bitify(l % r),
_ => bug!("invalid float op: `{:?}`", bin_op),
};
return Ok((val, false));
}};
}
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));

// Handle operations that support pointers
if let Some(handled) =
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
{
return Ok(handled);
match fty {
FloatTy::F32 => float_math!(Single, 4),
FloatTy::F64 => float_math!(Double, 8),
}
}

// From now on, everything must be bytes, no pointer values
// (this is independent of the type)
let l = left.to_bits(left_layout.size)?;
let r = right.to_bits(right_layout.size)?;
fn binary_int_op(
&self,
bin_op: mir::BinOp,
// passing in raw bits
l: u128,
left_layout: TyLayout<'tcx>,
r: u128,
right_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
use rustc::mir::BinOp::*;

// Shift ops can have an RHS with a different numeric type.
if bin_op == Shl || bin_op == Shr {
Expand Down Expand Up @@ -189,11 +178,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
// For the remaining ops, the types must be the same on both sides
if left_layout.ty != right_layout.ty {
let msg = format!(
"unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
"unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op,
left,
l,
left_layout.ty,
right,
r,
right_layout.ty
);
return err!(Unimplemented(msg));
Expand Down Expand Up @@ -289,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {

_ => {
let msg = format!(
"unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
"unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
bin_op,
left,
left_layout.ty,
right,
l,
r,
right_layout.ty,
);
return err!(Unimplemented(msg));
Expand All @@ -303,6 +291,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
Ok((val, false))
}

/// Returns the result of the specified operation and whether it overflowed.
pub fn binary_op(
&self,
bin_op: mir::BinOp,
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
let left = left.to_scalar()?;
let right = right.to_scalar()?;

trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);

match left_layout.ty.sty {
ty::Char => {
assert_eq!(left_layout.ty, right_layout.ty);
let l = left.to_char()?;
let r = right.to_char()?;
self.binary_char_op(bin_op, l, r)
}
ty::Bool => {
assert_eq!(left_layout.ty, right_layout.ty);
let l = left.to_bool()?;
let r = right.to_bool()?;
self.binary_bool_op(bin_op, l, r)
}
ty::Float(fty) => {
assert_eq!(left_layout.ty, right_layout.ty);
let l = left.to_bits(left_layout.size)?;
let r = right.to_bits(right_layout.size)?;
self.binary_float_op(bin_op, fty, l, r)
}
_ => {
// Must be integer(-like) types
#[inline]
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
match ty.sty {
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
_ => false,
}
}
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));

// Handle operations that support pointer values
if let Some(handled) =
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
{
return Ok(handled);
}

// Everything else only works with "proper" bits
let l = left.to_bits(left_layout.size)?;
let r = right.to_bits(right_layout.size)?;
self.binary_int_op(bin_op, l, left_layout, r, right_layout)
}
}
}

pub fn unary_op(
&self,
un_op: mir::UnOp,
Expand Down
15 changes: 5 additions & 10 deletions src/librustc_mir/interpret/place.rs
Expand Up @@ -660,7 +660,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
// a fake pointer? Are we even called for ZST?

// We need the layout of the local. We can NOT use the layout we got,
// that might e.g. be a downcast variant!
// that might e.g. be an inner field of a struct with `Scalar` layout,
// that has different alignment than the outer field.
let local_layout = self.layout_of_local(frame, local)?;
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
self.write_value_to_mplace(value, ptr)?;
Expand Down Expand Up @@ -695,15 +696,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
) -> EvalResult<'tcx> {
match dest.layout.variants {
layout::Variants::Single { index } => {
if index != variant_index {
return err!(InvalidDiscriminant);
}
assert_eq!(index, variant_index);
}
layout::Variants::Tagged { ref tag, .. } => {
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
if variant_index >= adt_def.variants.len() {
return err!(InvalidDiscriminant);
}
assert!(variant_index < adt_def.variants.len());
let discr_val = adt_def
.discriminant_for_variant(*self.tcx, variant_index)
.val;
Expand All @@ -727,9 +724,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
niche_start,
..
} => {
if variant_index >= dest.layout.ty.ty_adt_def().unwrap().variants.len() {
return err!(InvalidDiscriminant);
}
assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
if variant_index != dataful_variant {
let niche_dest =
self.place_field(dest, 0)?;
Expand Down

0 comments on commit f96208c

Please sign in to comment.