Skip to content

Commit

Permalink
Fix the miri tool
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Apr 23, 2018
1 parent f5cf1a8 commit 3084c06
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 84 deletions.
15 changes: 3 additions & 12 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/ci/docker/x86_64-gnu-tools/checktools.sh
Expand Up @@ -67,7 +67,7 @@ verify_status rust-by-example src/doc/rust-by-example
verify_status rls src/tool/rls
verify_status rustfmt src/tool/rustfmt
verify_status clippy-driver src/tool/clippy
#verify_status miri src/tool/miri
verify_status miri src/tool/miri

if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
Expand Down
35 changes: 3 additions & 32 deletions src/librustc_mir/hair/pattern/mod.rs
Expand Up @@ -16,7 +16,7 @@ mod check_match;
pub use self::check_match::check_crate;
pub(crate) use self::check_match::check_match;

use interpret::{const_val_field, const_discr, self};
use interpret::{const_val_field, const_variant_index, self};

use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability};
Expand Down Expand Up @@ -835,38 +835,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
match cv.val {
ConstVal::Value(val) => {
let discr_val = const_discr(
let variant_index = const_variant_index(
self.tcx, self.param_env, instance, val, cv.ty
).expect("const_discr failed");
let layout = self
.tcx
.layout_of(self.param_env.and(cv.ty))
.expect("layout of enum not available");
let variant_index = match layout.variants {
ty::layout::Variants::Single { index } => index,
ty::layout::Variants::Tagged { ref discr, .. } => {
// raw discriminants for enums are isize or bigger during
// their computation, but later shrunk to the smallest possible
// representation
let size = discr.value.size(self.tcx).bits();
let amt = 128 - size;
adt_def
.discriminants(self.tcx)
.position(|var| ((var.val << amt) >> amt) == discr_val)
.unwrap_or_else(|| {
bug!("discriminant {} not found in {:#?}",
discr_val,
adt_def
.discriminants(self.tcx)
.collect::<Vec<_>>(),
);
})
}
ty::layout::Variants::NicheFilling { .. } => {
assert_eq!(discr_val as usize as u128, discr_val);
discr_val as usize
},
};
).expect("const_variant_index failed");
let subpatterns = adt_subpatterns(
adt_def.variants[variant_index].fields.len(),
Some(variant_index),
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/interpret/const_eval.rs
Expand Up @@ -400,14 +400,14 @@ pub fn const_val_field<'a, 'tcx>(
}
}

pub fn const_discr<'a, 'tcx>(
pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
value: Value,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, u128> {
trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
) -> EvalResult<'tcx, usize> {
trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
Expand All @@ -421,7 +421,7 @@ pub fn const_discr<'a, 'tcx>(
Value::ByRef(ptr, align) => (ptr, align),
};
let place = Place::from_primval_ptr(ptr, align);
ecx.read_discriminant_value(place, ty)
ecx.read_discriminant_as_variant_index(place, ty)
}

pub fn const_eval_provider<'a, 'tcx>(
Expand Down
87 changes: 60 additions & 27 deletions src/librustc_mir/interpret/eval_context.rs
Expand Up @@ -743,28 +743,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M

Discriminant(ref place) => {
let ty = self.place_ty(place);
let layout = self.layout_of(ty)?;
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, ty)?;
match layout.variants {
layout::Variants::Single { index } => {
assert_eq!(discr_val, index as u128);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {
if let ty::TyAdt(adt_def, _) = ty.sty {
trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
if adt_def.discriminants(*self.tcx).all(|v| {
discr_val != v.val
})
{
return err!(InvalidDiscriminant);
}
} else {
bug!("rustc only generates Rvalue::Discriminant for enums");
}
}
}
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
}
}
Expand Down Expand Up @@ -837,13 +817,39 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
}
}

/// reads a tag and produces the corresponding variant index
pub fn read_discriminant_as_variant_index(
&mut self,
place: Place,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, usize> {
let layout = self.layout_of(ty)?;
match layout.variants {
ty::layout::Variants::Single { index } => Ok(index),
ty::layout::Variants::Tagged { .. } => {
let discr_val = self.read_discriminant_value(place, ty)?;
ty
.ty_adt_def()
.expect("tagged layout for non adt")
.discriminants(self.tcx.tcx)
.position(|var| var.val == discr_val)
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into())
}
ty::layout::Variants::NicheFilling { .. } => {
let discr_val = self.read_discriminant_value(place, ty)?;
assert_eq!(discr_val as usize as u128, discr_val);
Ok(discr_val as usize)
},
}
}

pub fn read_discriminant_value(
&mut self,
place: Place,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, u128> {
let layout = self.layout_of(ty)?;
//trace!("read_discriminant_value {:#?}", layout);
trace!("read_discriminant_value {:#?}", layout);

match layout.variants {
layout::Variants::Single { index } => {
Expand All @@ -854,13 +860,34 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
}

let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
trace!("discr place: {:?}, {:?}", discr_place, discr);
let raw_discr = self.value_to_primval(ValTy {
value: self.read_place(discr_place)?,
ty: discr.ty
})?;
let discr_val = match layout.variants {
layout::Variants::Single { .. } => bug!(),
layout::Variants::Tagged { .. } => raw_discr.to_bytes()?,
// FIXME: should we catch invalid discriminants here?
layout::Variants::Tagged { .. } => {
if discr.ty.is_signed() {
let i = raw_discr.to_bytes()? as i128;
// going from layout tag type to typeck discriminant type
// requires first sign extending with the layout discriminant
let amt = 128 - discr.size.bits();
let sexted = (i << amt) >> amt;
// and then zeroing with the typeck discriminant type
let discr_ty = ty
.ty_adt_def().expect("tagged layout corresponds to adt")
.repr
.discr_type();
let discr_ty = layout::Integer::from_attr(self.tcx.tcx, discr_ty);
let amt = 128 - discr_ty.size().bits();
let truncatee = sexted as u128;
(truncatee << amt) >> amt
} else {
raw_discr.to_bytes()?
}
},
layout::Variants::NicheFilling {
dataful_variant,
ref niche_variants,
Expand Down Expand Up @@ -910,11 +937,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
layout::Abi::Uninhabited);
}
}
layout::Variants::Tagged { .. } => {
layout::Variants::Tagged { ref discr, .. } => {
let discr_val = dest_ty.ty_adt_def().unwrap()
.discriminant_for_variant(*self.tcx, variant_index)
.val;

// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
let size = discr.value.size(self.tcx.tcx).bits();
let amt = 128 - size;
let discr_val = (discr_val << amt) >> amt;

let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
}
Expand Down Expand Up @@ -1145,19 +1179,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
_ if primval.is_undef() => false,
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
};
self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
self.memory.write_primval(dest, dest_align, primval, layout.size.bytes(), signed)
}
Value::ByValPair(a_val, b_val) => {
let ptr = dest.to_ptr()?;
trace!("write_value_to_ptr valpair: {:#?}", layout);
let (a, b) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
_ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
};
let (a_size, b_size) = (a.size(&self), b.size(&self));
let a_ptr = ptr;
let a_ptr = dest;
let b_offset = a_size.abi_align(b.align(&self));
let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
let b_ptr = dest.offset(b_offset.bytes(), &self)?.into();
// TODO: What about signedess?
self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
Expand Down
9 changes: 6 additions & 3 deletions src/librustc_mir/interpret/memory.rs
Expand Up @@ -691,7 +691,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
self.read_primval(ptr, ptr_align, self.pointer_size())
}

pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
let endianness = self.endianness();

let bytes = match val {
Expand All @@ -703,11 +703,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
PrimVal::Bytes(bytes) => bytes,

PrimVal::Undef => {
self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;
self.check_align(ptr.into(), ptr_align)?;
self.mark_definedness(ptr, size, false)?;
return Ok(());
}
};

let ptr = ptr.to_ptr()?;

{
let align = self.int_align(size);
let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?;
Expand All @@ -734,7 +737,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {

pub fn write_ptr_sized_unsigned(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
self.write_primval(ptr, ptr_align, val, ptr_size, false)
self.write_primval(ptr.into(), ptr_align, val, ptr_size, false)
}

fn int_align(&self, size: u64) -> Align {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/mod.rs
Expand Up @@ -25,7 +25,7 @@ pub use self::const_eval::{
CompileTimeEvaluator,
const_eval_provider,
const_val_field,
const_discr,
const_variant_index,
};

pub use self::machine::Machine;
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_mir/interpret/terminator/mod.rs
Expand Up @@ -37,16 +37,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
ref targets,
..
} => {
// FIXME(CTFE): forbid branching
let discr_val = self.eval_operand(discr)?;
let discr_prim = self.value_to_primval(discr_val)?;

// Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets[targets.len() - 1];

for (index, &const_int) in values.iter().enumerate() {
let prim = PrimVal::Bytes(const_int);
if discr_prim.to_bytes()? == prim.to_bytes()? {
if discr_prim.to_bytes()? == const_int {
target_block = targets[index];
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri
Submodule miri updated from d4712c to f48fed

0 comments on commit 3084c06

Please sign in to comment.