Re-implement support for downcast lvalues.
This commit is contained in:
parent
0f533e3ae0
commit
30f07f3d7f
1 changed files with 38 additions and 36 deletions
|
@ -84,7 +84,8 @@ struct Lvalue {
|
||||||
enum LvalueExtra {
|
enum LvalueExtra {
|
||||||
None,
|
None,
|
||||||
Length(u64),
|
Length(u64),
|
||||||
// Vtable(memory::AllocId),
|
// TODO(tsion): Vtable(memory::AllocId),
|
||||||
|
DowncastVariant(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -231,8 +232,10 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
|
|
||||||
SwitchInt { ref discr, ref values, ref targets, .. } => {
|
SwitchInt { ref discr, ref values, ref targets, .. } => {
|
||||||
let discr_ptr = try!(self.eval_lvalue(discr)).to_ptr();
|
let discr_ptr = try!(self.eval_lvalue(discr)).to_ptr();
|
||||||
let discr_size =
|
let discr_size = self
|
||||||
self.lvalue_layout(discr).size(&self.tcx.data_layout).bytes() as usize;
|
.type_layout(self.lvalue_ty(discr))
|
||||||
|
.size(&self.tcx.data_layout)
|
||||||
|
.bytes() as usize;
|
||||||
let discr_val = try!(self.memory.read_uint(discr_ptr, discr_size));
|
let discr_val = try!(self.memory.read_uint(discr_ptr, discr_size));
|
||||||
|
|
||||||
// Branch to the `otherwise` case by default, if no match is found.
|
// Branch to the `otherwise` case by default, if no match is found.
|
||||||
|
@ -252,7 +255,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
|
|
||||||
Switch { ref discr, ref targets, adt_def } => {
|
Switch { ref discr, ref targets, adt_def } => {
|
||||||
let adt_ptr = try!(self.eval_lvalue(discr)).to_ptr();
|
let adt_ptr = try!(self.eval_lvalue(discr)).to_ptr();
|
||||||
let adt_layout = self.lvalue_layout(discr);
|
let adt_layout = self.type_layout(self.lvalue_ty(discr));
|
||||||
let discr_size = match *adt_layout {
|
let discr_size = match *adt_layout {
|
||||||
Layout::General { discr, .. } => discr.size().bytes(),
|
Layout::General { discr, .. } => discr.size().bytes(),
|
||||||
_ => panic!("attmpted to switch on non-aggregate type"),
|
_ => panic!("attmpted to switch on non-aggregate type"),
|
||||||
|
@ -590,7 +593,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let dest = try!(self.eval_lvalue(lvalue)).to_ptr();
|
let dest = try!(self.eval_lvalue(lvalue)).to_ptr();
|
||||||
let dest_ty = self.lvalue_ty(lvalue);
|
let dest_ty = self.lvalue_ty(lvalue);
|
||||||
let dest_layout = self.lvalue_layout(lvalue);
|
let dest_layout = self.type_layout(dest_ty);
|
||||||
|
|
||||||
use rustc::mir::repr::Rvalue::*;
|
use rustc::mir::repr::Rvalue::*;
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
|
@ -693,6 +696,8 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
let len_ptr = dest.offset(self.memory.pointer_size as isize);
|
let len_ptr = dest.offset(self.memory.pointer_size as isize);
|
||||||
try!(self.memory.write_usize(len_ptr, len));
|
try!(self.memory.write_usize(len_ptr, len));
|
||||||
}
|
}
|
||||||
|
LvalueExtra::DowncastVariant(..) =>
|
||||||
|
panic!("attempted to take a reference to an enum downcast lvalue"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,7 +750,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
match *op {
|
match *op {
|
||||||
Consume(ref lvalue) =>
|
Consume(ref lvalue) =>
|
||||||
Ok(try!(self.eval_lvalue(lvalue)).to_ptr()),
|
Ok(try!(self.eval_lvalue(lvalue)).to_ptr()),
|
||||||
Constant(mir::Constant { ref literal, ty, .. }) => {
|
Constant(mir::Constant { ref literal, .. }) => {
|
||||||
use rustc::mir::repr::Literal::*;
|
use rustc::mir::repr::Literal::*;
|
||||||
match *literal {
|
match *literal {
|
||||||
Value { ref value } => Ok(try!(self.const_to_ptr(value))),
|
Value { ref value } => Ok(try!(self.const_to_ptr(value))),
|
||||||
|
@ -755,22 +760,6 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(tsion): Replace this inefficient hack with a wrapper like LvalueTy (e.g. LvalueLayout).
|
|
||||||
fn lvalue_layout(&self, lvalue: &mir::Lvalue<'tcx>) -> &'tcx Layout {
|
|
||||||
use rustc::mir::tcx::LvalueTy;
|
|
||||||
match self.mir().lvalue_ty(self.tcx, lvalue) {
|
|
||||||
LvalueTy::Ty { ty } => self.type_layout(ty),
|
|
||||||
LvalueTy::Downcast { adt_def, substs, variant_index } => {
|
|
||||||
let field_tys = adt_def.variants[variant_index].fields.iter()
|
|
||||||
.map(|f| f.ty(self.tcx, substs));
|
|
||||||
|
|
||||||
// FIXME(tsion): Handle LvalueTy::Downcast better somehow...
|
|
||||||
unimplemented!();
|
|
||||||
// self.repr_arena.alloc(self.make_aggregate_layout(iter::once(field_tys)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
|
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
|
||||||
use rustc::mir::repr::Lvalue::*;
|
use rustc::mir::repr::Lvalue::*;
|
||||||
let ptr = match *lvalue {
|
let ptr = match *lvalue {
|
||||||
|
@ -783,32 +772,45 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
Static(_def_id) => unimplemented!(),
|
Static(_def_id) => unimplemented!(),
|
||||||
|
|
||||||
Projection(ref proj) => {
|
Projection(ref proj) => {
|
||||||
let base_ptr = try!(self.eval_lvalue(&proj.base)).ptr;
|
let base = try!(self.eval_lvalue(&proj.base));
|
||||||
let base_layout = self.lvalue_layout(&proj.base);
|
|
||||||
let base_ty = self.lvalue_ty(&proj.base);
|
let base_ty = self.lvalue_ty(&proj.base);
|
||||||
|
let base_layout = self.type_layout(base_ty);
|
||||||
|
|
||||||
use rustc::mir::repr::ProjectionElem::*;
|
use rustc::mir::repr::ProjectionElem::*;
|
||||||
match proj.elem {
|
match proj.elem {
|
||||||
Field(field, _) => match *base_layout {
|
Field(field, _) => {
|
||||||
Layout::Univariant { ref variant, .. } => {
|
let variant = match *base_layout {
|
||||||
let offset = variant.field_offset(field.index()).bytes();
|
Layout::Univariant { ref variant, .. } => variant,
|
||||||
base_ptr.offset(offset as isize)
|
Layout::General { ref variants, .. } => {
|
||||||
}
|
if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
|
||||||
_ => panic!("field access on non-product type: {:?}", base_layout),
|
&variants[variant_idx]
|
||||||
|
} else {
|
||||||
|
panic!("field access on enum had no variant index");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("field access on non-product type: {:?}", base_layout),
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = variant.field_offset(field.index()).bytes();
|
||||||
|
base.ptr.offset(offset as isize)
|
||||||
},
|
},
|
||||||
|
|
||||||
Downcast(..) => match *base_layout {
|
Downcast(_, variant) => match *base_layout {
|
||||||
Layout::General { discr, .. } =>
|
Layout::General { discr, .. } => {
|
||||||
base_ptr.offset(discr.size().bytes() as isize),
|
return Ok(Lvalue {
|
||||||
|
ptr: base.ptr.offset(discr.size().bytes() as isize),
|
||||||
|
extra: LvalueExtra::DowncastVariant(variant),
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => panic!("variant downcast on non-aggregate type: {:?}", base_layout),
|
_ => panic!("variant downcast on non-aggregate type: {:?}", base_layout),
|
||||||
},
|
},
|
||||||
|
|
||||||
Deref => {
|
Deref => {
|
||||||
let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer");
|
let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer");
|
||||||
let ptr = try!(self.memory.read_ptr(base_ptr));
|
let ptr = try!(self.memory.read_ptr(base.ptr));
|
||||||
let extra = match pointee_ty.sty {
|
let extra = match pointee_ty.sty {
|
||||||
ty::TySlice(_) | ty::TyStr => {
|
ty::TySlice(_) | ty::TyStr => {
|
||||||
let len_ptr = base_ptr.offset(self.memory.pointer_size as isize);
|
let len_ptr = base.ptr.offset(self.memory.pointer_size as isize);
|
||||||
let len = try!(self.memory.read_usize(len_ptr));
|
let len = try!(self.memory.read_usize(len_ptr));
|
||||||
LvalueExtra::Length(len)
|
LvalueExtra::Length(len)
|
||||||
}
|
}
|
||||||
|
@ -826,7 +828,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
let n_ptr = try!(self.eval_operand(operand));
|
let n_ptr = try!(self.eval_operand(operand));
|
||||||
let n = try!(self.memory.read_usize(n_ptr));
|
let n = try!(self.memory.read_usize(n_ptr));
|
||||||
base_ptr.offset(n as isize * elem_size as isize)
|
base.ptr.offset(n as isize * elem_size as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstantIndex { .. } => unimplemented!(),
|
ConstantIndex { .. } => unimplemented!(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue