1
Fork 0
This commit is contained in:
Oliver Schneider 2017-02-24 10:39:55 +01:00
parent 1af2c397bf
commit 35502fd47d
5 changed files with 27 additions and 36 deletions

View file

@ -456,7 +456,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
General { discr, ref variants, .. } => { General { discr, ref variants, .. } => {
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
let discr_val = adt_def.variants[variant].disr_val.to_u128_unchecked(); let discr_val = adt_def.variants[variant].disr_val;
let discr_size = discr.size().bytes(); let discr_size = discr.size().bytes();
if variants[variant].packed { if variants[variant].packed {
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0; let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
@ -529,7 +529,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
CEnum { .. } => { CEnum { .. } => {
assert_eq!(operands.len(), 0); assert_eq!(operands.len(), 0);
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
let n = adt_def.variants[variant].disr_val.to_u128_unchecked(); let n = adt_def.variants[variant].disr_val;
self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?; self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
} else { } else {
bug!("tried to assign {:?} to Layout::CEnum", kind); bug!("tried to assign {:?} to Layout::CEnum", kind);
@ -661,7 +661,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
} }
InlineAsm { .. } => return Err(EvalError::InlineAsm), Discriminant(ref lvalue) => {
let lval = self.eval_lvalue(lvalue)?;
let ty = self.lvalue_ty(lvalue);
let ptr = self.force_allocation(lval)?.to_ptr();
let discr_val = self.read_discriminant_value(ptr, ty)?;
if let ty::TyAdt(adt_def, _) = ty.sty {
if adt_def.variants.iter().all(|v| discr_val != v.disr_val) {
return Err(EvalError::InvalidDiscriminant);
}
} else {
bug!("rustc only generates Rvalue::Discriminant for enums");
}
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
},
} }
if log_enabled!(::log::LogLevel::Trace) { if log_enabled!(::log::LogLevel::Trace) {

View file

@ -1,7 +1,6 @@
#![feature( #![feature(
btree_range, btree_range,
collections, collections,
field_init_shorthand,
i128_type, i128_type,
pub_restricted, pub_restricted,
rustc_private, rustc_private,

View file

@ -119,6 +119,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// Defined to do nothing. These are added by optimization passes, to avoid changing the // Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly. // size of MIR constantly.
Nop => {} Nop => {}
InlineAsm { .. } => return Err(EvalError::InlineAsm),
} }
self.frame_mut().stmt += 1; self.frame_mut().stmt += 1;

View file

@ -121,7 +121,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Layout::General { .. } => { Layout::General { .. } => {
let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128; let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
let ptr = self.force_allocation(lval)?.to_ptr(); let ptr = self.force_allocation(lval)?.to_ptr();
match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) { match adt_def.variants.iter().position(|v| discr_val == v.disr_val) {
Some(i) => { Some(i) => {
lval = Lvalue::Ptr { lval = Lvalue::Ptr {
ptr, ptr,

View file

@ -35,22 +35,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Goto { target } => self.goto_block(target), Goto { target } => self.goto_block(target),
If { ref cond, targets: (then_target, else_target) } => {
let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?;
self.goto_block(if cond_val { then_target } else { else_target });
}
SwitchInt { ref discr, ref values, ref targets, .. } => { SwitchInt { ref discr, ref values, ref targets, .. } => {
let discr_val = self.eval_and_read_lvalue(discr)?; let discr_val = self.eval_operand(discr)?;
let discr_ty = self.lvalue_ty(discr); let discr_ty = self.operand_ty(discr);
let discr_prim = self.value_to_primval(discr_val, discr_ty)?; let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
// Branch to the `otherwise` case by default, if no match is found. // Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets[targets.len() - 1]; let mut target_block = targets[targets.len() - 1];
for (index, const_val) in values.iter().enumerate() { for (index, const_int) in values.iter().enumerate() {
let val = self.const_to_value(const_val)?; let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
let prim = self.value_to_primval(val, discr_ty)?;
if discr_prim.to_bytes()? == prim.to_bytes()? { if discr_prim.to_bytes()? == prim.to_bytes()? {
target_block = targets[index]; target_block = targets[index];
break; break;
@ -60,23 +54,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.goto_block(target_block); self.goto_block(target_block);
} }
Switch { ref discr, ref targets, adt_def } => {
// FIXME(solson)
let lvalue = self.eval_lvalue(discr)?;
let lvalue = self.force_allocation(lvalue)?;
let adt_ptr = lvalue.to_ptr();
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_u128_unchecked());
match matching {
Some(i) => self.goto_block(targets[i]),
None => return Err(EvalError::InvalidDiscriminant),
}
}
Call { ref func, ref args, ref destination, .. } => { Call { ref func, ref args, ref destination, .. } => {
let destination = match *destination { let destination = match *destination {
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)), Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
@ -216,12 +193,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
trace!("layout({:?}) = {:#?}", dest_ty, dest_layout); trace!("layout({:?}) = {:#?}", dest_ty, dest_layout);
match *dest_layout { match *dest_layout {
Layout::Univariant { .. } => { Layout::Univariant { .. } => {
let disr_val = v.disr_val.to_u128_unchecked(); let disr_val = v.disr_val;
assert_eq!(disr_val, 0); assert_eq!(disr_val, 0);
self.assign_fields(lvalue, dest_ty, args)?; self.assign_fields(lvalue, dest_ty, args)?;
}, },
Layout::General { discr, ref variants, .. } => { Layout::General { discr, ref variants, .. } => {
let disr_val = v.disr_val.to_u128_unchecked(); let disr_val = v.disr_val;
let discr_size = discr.size().bytes(); let discr_size = discr.size().bytes();
self.assign_discr_and_fields( self.assign_discr_and_fields(
lvalue, lvalue,
@ -234,7 +211,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
)?; )?;
}, },
Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
let disr_val = v.disr_val.to_u128_unchecked(); let disr_val = v.disr_val;
if nndiscr as u128 == disr_val { if nndiscr as u128 == disr_val {
self.assign_fields(lvalue, dest_ty, args)?; self.assign_fields(lvalue, dest_ty, args)?;
} else { } else {
@ -325,7 +302,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
} }
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { pub fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
use rustc::ty::layout::Layout::*; use rustc::ty::layout::Layout::*;
let adt_layout = self.type_layout(adt_ty)?; let adt_layout = self.type_layout(adt_ty)?;
trace!("read_discriminant_value {:#?}", adt_layout); trace!("read_discriminant_value {:#?}", adt_layout);