Handle discriminant_value intrinsic.
This commit is contained in:
parent
2d32503409
commit
f63206ed2f
3 changed files with 63 additions and 56 deletions
|
@ -297,35 +297,14 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||||
|
|
||||||
Switch { ref discr, ref targets, adt_def } => {
|
Switch { ref discr, ref targets, adt_def } => {
|
||||||
let adt_ptr = self.eval_lvalue(discr)?.to_ptr();
|
let adt_ptr = self.eval_lvalue(discr)?.to_ptr();
|
||||||
let adt_layout = self.type_layout(self.lvalue_ty(discr));
|
let adt_ty = self.lvalue_ty(discr);
|
||||||
|
let discr_val = self.read_discriminant_value(adt_ptr, adt_ty)?;
|
||||||
|
let matching = adt_def.variants.iter()
|
||||||
|
.position(|v| discr_val == v.disr_val.to_u64_unchecked());
|
||||||
|
|
||||||
match *adt_layout {
|
match matching {
|
||||||
Layout::General { discr, .. } | Layout::CEnum { discr, .. } => {
|
Some(i) => TerminatorTarget::Block(targets[i]),
|
||||||
let discr_size = discr.size().bytes();
|
None => return Err(EvalError::InvalidDiscriminant),
|
||||||
let discr_val = self.memory.read_uint(adt_ptr, discr_size as usize)?;
|
|
||||||
|
|
||||||
let matching = adt_def.variants.iter()
|
|
||||||
.position(|v| discr_val == v.disr_val.to_u64_unchecked());
|
|
||||||
|
|
||||||
match matching {
|
|
||||||
Some(i) => TerminatorTarget::Block(targets[i]),
|
|
||||||
None => return Err(EvalError::InvalidDiscriminant),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Layout::RawNullablePointer { nndiscr, .. } => {
|
|
||||||
let is_null = match self.memory.read_usize(adt_ptr) {
|
|
||||||
Ok(0) => true,
|
|
||||||
Ok(_) | Err(EvalError::ReadPointerAsBytes) => false,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(nndiscr == 0 || nndiscr == 1);
|
|
||||||
let target = if is_null { 1 - nndiscr } else { nndiscr };
|
|
||||||
TerminatorTarget::Block(targets[target as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => panic!("attempted to switch on non-aggregate type"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,6 +456,36 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: ty::Ty<'tcx>) -> EvalResult<u64> {
|
||||||
|
use rustc::ty::layout::Layout::*;
|
||||||
|
let adt_layout = self.type_layout(adt_ty);
|
||||||
|
|
||||||
|
let discr_val = match *adt_layout {
|
||||||
|
General { discr, .. } | CEnum { discr, .. } => {
|
||||||
|
let discr_size = discr.size().bytes();
|
||||||
|
self.memory.read_uint(adt_ptr, discr_size as usize)?
|
||||||
|
}
|
||||||
|
|
||||||
|
RawNullablePointer { nndiscr, .. } => {
|
||||||
|
let not_null = match self.memory.read_usize(adt_ptr) {
|
||||||
|
Ok(0) => false,
|
||||||
|
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
assert!(nndiscr == 0 || nndiscr == 1);
|
||||||
|
if not_null { nndiscr } else { 1 - nndiscr }
|
||||||
|
}
|
||||||
|
|
||||||
|
StructWrappedNullablePointer { .. } => unimplemented!(),
|
||||||
|
|
||||||
|
// The discriminant_value intrinsic returns 0 for non-sum types.
|
||||||
|
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
|
||||||
|
Vector { .. } => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(discr_val)
|
||||||
|
}
|
||||||
|
|
||||||
fn call_intrinsic(
|
fn call_intrinsic(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -491,6 +500,19 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||||
let args = args_res?;
|
let args = args_res?;
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
|
// FIXME(solson): Handle different integer types correctly.
|
||||||
|
"add_with_overflow" => {
|
||||||
|
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||||
|
let size = self.type_size(ty);
|
||||||
|
let left = self.memory.read_int(args[0], size)?;
|
||||||
|
let right = self.memory.read_int(args[1], size)?;
|
||||||
|
let (n, overflowed) = unsafe {
|
||||||
|
::std::intrinsics::add_with_overflow::<i64>(left, right)
|
||||||
|
};
|
||||||
|
self.memory.write_int(dest, n, size)?;
|
||||||
|
self.memory.write_bool(dest.offset(size as isize), overflowed)?;
|
||||||
|
}
|
||||||
|
|
||||||
"assume" => {}
|
"assume" => {}
|
||||||
|
|
||||||
"copy_nonoverlapping" => {
|
"copy_nonoverlapping" => {
|
||||||
|
@ -502,6 +524,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||||
self.memory.copy(src, dest, count as usize * elem_size)?;
|
self.memory.copy(src, dest, count as usize * elem_size)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"discriminant_value" => {
|
||||||
|
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||||
|
let adt_ptr = self.memory.read_ptr(args[0])?;
|
||||||
|
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
|
||||||
|
self.memory.write_uint(dest, discr_val, dest_size)?;
|
||||||
|
}
|
||||||
|
|
||||||
"forget" => {
|
"forget" => {
|
||||||
let arg_ty = *substs.types.get(subst::FnSpace, 0);
|
let arg_ty = *substs.types.get(subst::FnSpace, 0);
|
||||||
let arg_size = self.type_size(arg_ty);
|
let arg_size = self.type_size(arg_ty);
|
||||||
|
@ -520,19 +549,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||||
self.move_(args[1], ptr, ty)?;
|
self.move_(args[1], ptr, ty)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(solson): Handle different integer types correctly.
|
|
||||||
"add_with_overflow" => {
|
|
||||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
|
||||||
let size = self.type_size(ty);
|
|
||||||
let left = self.memory.read_int(args[0], size)?;
|
|
||||||
let right = self.memory.read_int(args[1], size)?;
|
|
||||||
let (n, overflowed) = unsafe {
|
|
||||||
::std::intrinsics::add_with_overflow::<i64>(left, right)
|
|
||||||
};
|
|
||||||
self.memory.write_int(dest, n, size)?;
|
|
||||||
self.memory.write_bool(dest.offset(size as isize), overflowed)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(solson): Handle different integer types correctly.
|
// FIXME(solson): Handle different integer types correctly.
|
||||||
"mul_with_overflow" => {
|
"mul_with_overflow" => {
|
||||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#![feature(custom_attribute)]
|
|
||||||
#![allow(dead_code, unused_attributes)]
|
|
||||||
|
|
||||||
// error-pattern:can't handle intrinsic: discriminant_value
|
|
||||||
|
|
||||||
#[miri_run]
|
|
||||||
fn main() {
|
|
||||||
assert_eq!(None::<i32>, None);
|
|
||||||
}
|
|
|
@ -57,12 +57,12 @@ fn two_nones() -> (Option<i16>, Option<i16>) {
|
||||||
|
|
||||||
#[miri_run]
|
#[miri_run]
|
||||||
fn main() {
|
fn main() {
|
||||||
//assert_eq!(two_nones(), (None, None));
|
assert_eq!(two_nones(), (None, None));
|
||||||
assert_eq!(match_opt_some(), 13);
|
assert_eq!(match_opt_some(), 13);
|
||||||
assert_eq!(match_opt_none(), 42);
|
assert_eq!(match_opt_none(), 42);
|
||||||
//assert_eq!(return_some(), Some(42));
|
assert_eq!(return_some(), Some(42));
|
||||||
//assert_eq!(return_none(), None);
|
assert_eq!(return_none(), None);
|
||||||
//assert_eq!(return_false(), MyBool::False);
|
assert_eq!(return_false(), MyBool::False(()));
|
||||||
//assert_eq!(return_true(), MyBool::True);
|
assert_eq!(return_true(), MyBool::True(()));
|
||||||
//assert_eq!(return_unit(), Unit::Unit);
|
assert_eq!(return_unit(), Unit::Unit(()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue