Merge pull request #20 from oli-obk/error_reporting
various fixes and refactorings
This commit is contained in:
commit
a8d0812ed1
4 changed files with 228 additions and 292 deletions
|
|
@ -7,11 +7,21 @@ extern crate rustc;
|
|||
extern crate rustc_driver;
|
||||
extern crate env_logger;
|
||||
extern crate log_settings;
|
||||
extern crate log;
|
||||
extern crate syntax;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use miri::interpreter;
|
||||
use miri::{
|
||||
EvalContext,
|
||||
CachedMir,
|
||||
step,
|
||||
EvalError,
|
||||
Frame,
|
||||
};
|
||||
use rustc::session::Session;
|
||||
use rustc_driver::{driver, CompilerCalls};
|
||||
use rustc::ty::{TyCtxt, subst};
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::hir::def_id::DefId;
|
||||
|
||||
struct MiriCompilerCalls;
|
||||
|
||||
|
|
@ -25,13 +35,84 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
|||
|
||||
control.after_analysis.callback = Box::new(|state| {
|
||||
state.session.abort_if_errors();
|
||||
interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
|
||||
interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
|
||||
});
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn interpret_start_points<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir_map: &MirMap<'tcx>,
|
||||
) {
|
||||
let initial_indentation = ::log_settings::settings().indentation;
|
||||
for (&id, mir) in &mir_map.map {
|
||||
for attr in tcx.map.attrs(id) {
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
if attr.check_name("miri_run") {
|
||||
let item = tcx.map.expect_item(id);
|
||||
|
||||
::log_settings::settings().indentation = initial_indentation;
|
||||
|
||||
debug!("Interpreting: {}", item.name);
|
||||
|
||||
let mut ecx = EvalContext::new(tcx, mir_map);
|
||||
let substs = tcx.mk_substs(subst::Substs::empty());
|
||||
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs);
|
||||
|
||||
ecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr);
|
||||
|
||||
loop {
|
||||
match (step(&mut ecx), return_ptr) {
|
||||
(Ok(true), _) => {},
|
||||
(Ok(false), Some(ptr)) => if log_enabled!(::log::LogLevel::Debug) {
|
||||
ecx.memory().dump(ptr.alloc_id);
|
||||
break;
|
||||
},
|
||||
(Ok(false), None) => {
|
||||
warn!("diverging function returned");
|
||||
break;
|
||||
},
|
||||
// FIXME: diverging functions can end up here in some future miri
|
||||
(Err(e), _) => {
|
||||
report(tcx, &ecx, e);
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
|
||||
let frame = ecx.stack().last().expect("stackframe was empty");
|
||||
let block = frame.mir.basic_block_data(frame.next_block);
|
||||
let span = if frame.stmt < block.statements.len() {
|
||||
block.statements[frame.stmt].span
|
||||
} else {
|
||||
block.terminator().span
|
||||
};
|
||||
let mut err = tcx.sess.struct_span_err(span, &e.to_string());
|
||||
for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
|
||||
// FIXME(solson): Find a way to do this without this Display impl hack.
|
||||
use rustc::util::ppaux;
|
||||
use std::fmt;
|
||||
struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
|
||||
impl<'tcx> fmt::Display for Instance<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
|
||||
|tcx| tcx.lookup_item_type(self.0).generics)
|
||||
}
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn main() {
|
||||
init_logger();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc::ty::subst::{self, Subst, Substs};
|
|||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::util::nodemap::DefIdMap;
|
||||
use std::cell::RefCell;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::{iter, mem};
|
||||
use syntax::ast;
|
||||
|
|
@ -24,7 +24,11 @@ use std::collections::HashMap;
|
|||
|
||||
mod stepper;
|
||||
|
||||
struct GlobalEvalContext<'a, 'tcx: 'a> {
|
||||
pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<bool> {
|
||||
stepper::Stepper::new(ecx).step()
|
||||
}
|
||||
|
||||
pub struct EvalContext<'a, 'tcx: 'a> {
|
||||
/// The results of the type checker, from rustc.
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
|
|
@ -39,61 +43,44 @@ struct GlobalEvalContext<'a, 'tcx: 'a> {
|
|||
|
||||
/// Precomputed statics, constants and promoteds
|
||||
statics: HashMap<ConstantId<'tcx>, Pointer>,
|
||||
}
|
||||
|
||||
struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> {
|
||||
gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
|
||||
|
||||
/// The virtual call stack.
|
||||
stack: Vec<Frame<'mir, 'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> Deref for FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
type Target = GlobalEvalContext<'b, 'tcx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.gecx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> DerefMut for FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.gecx
|
||||
}
|
||||
stack: Vec<Frame<'a, 'tcx>>,
|
||||
}
|
||||
|
||||
/// A stack frame.
|
||||
struct Frame<'a, 'tcx: 'a> {
|
||||
pub struct Frame<'a, 'tcx: 'a> {
|
||||
/// The def_id of the current function
|
||||
def_id: DefId,
|
||||
pub def_id: DefId,
|
||||
|
||||
/// The span of the call site
|
||||
span: codemap::Span,
|
||||
pub span: codemap::Span,
|
||||
|
||||
/// type substitutions for the current function invocation
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
|
||||
/// The MIR for the function called on this frame.
|
||||
mir: CachedMir<'a, 'tcx>,
|
||||
pub mir: CachedMir<'a, 'tcx>,
|
||||
|
||||
/// The block that is currently executed (or will be executed after the above call stacks return)
|
||||
next_block: mir::BasicBlock,
|
||||
pub next_block: mir::BasicBlock,
|
||||
|
||||
/// A pointer for writing the return value of the current call if it's not a diverging call.
|
||||
return_ptr: Option<Pointer>,
|
||||
pub return_ptr: Option<Pointer>,
|
||||
|
||||
/// The list of locals for the current function, stored in order as
|
||||
/// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
|
||||
/// and the temporaries at `self.temp_offset`.
|
||||
locals: Vec<Pointer>,
|
||||
pub locals: Vec<Pointer>,
|
||||
|
||||
/// The offset of the first variable in `self.locals`.
|
||||
var_offset: usize,
|
||||
pub var_offset: usize,
|
||||
|
||||
/// The offset of the first temporary in `self.locals`.
|
||||
temp_offset: usize,
|
||||
pub temp_offset: usize,
|
||||
|
||||
/// The index of the currently evaluated statment
|
||||
stmt: usize,
|
||||
pub stmt: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -111,23 +98,11 @@ enum LvalueExtra {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum CachedMir<'mir, 'tcx: 'mir> {
|
||||
pub enum CachedMir<'mir, 'tcx: 'mir> {
|
||||
Ref(&'mir mir::Mir<'tcx>),
|
||||
Owned(Rc<mir::Mir<'tcx>>)
|
||||
}
|
||||
|
||||
/// Represents the action to be taken in the main loop as a result of executing a terminator.
|
||||
enum TerminatorTarget {
|
||||
/// Make a local jump to the next block
|
||||
Block,
|
||||
|
||||
/// Start executing from the new current frame. (For function calls.)
|
||||
Call,
|
||||
|
||||
/// Stop executing the current frame and resume the previous frame.
|
||||
Return,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
/// Uniquely identifies a specific constant or static
|
||||
struct ConstantId<'tcx> {
|
||||
|
|
@ -148,9 +123,9 @@ enum ConstantKind {
|
|||
Global,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
||||
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
|
||||
GlobalEvalContext {
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
|
||||
EvalContext {
|
||||
tcx: tcx,
|
||||
mir_map: mir_map,
|
||||
mir_cache: RefCell::new(DefIdMap()),
|
||||
|
|
@ -160,24 +135,11 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
|||
.bit_width()
|
||||
.expect("Session::target::uint_type was usize")/8),
|
||||
statics: HashMap::new(),
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult<Option<Pointer>> {
|
||||
let substs = self.tcx.mk_substs(subst::Substs::empty());
|
||||
let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs);
|
||||
|
||||
let mut nested_fecx = FnEvalContext::new(self);
|
||||
|
||||
nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None);
|
||||
|
||||
nested_fecx.frame_mut().return_ptr = return_ptr;
|
||||
|
||||
nested_fecx.run()?;
|
||||
Ok(return_ptr)
|
||||
}
|
||||
|
||||
fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
|
||||
pub fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
|
||||
match output_ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size(ty, substs);
|
||||
|
|
@ -187,6 +149,14 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn memory(&self) -> &Memory {
|
||||
&self.memory
|
||||
}
|
||||
|
||||
pub fn stack(&self) -> &[Frame] {
|
||||
&self.stack
|
||||
}
|
||||
|
||||
// TODO(solson): Try making const_to_primval instead.
|
||||
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
|
||||
use rustc::middle::const_val::ConstVal::*;
|
||||
|
|
@ -349,57 +319,8 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
|||
ty.layout(&infcx).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
fn new(gecx: &'a mut GlobalEvalContext<'b, 'tcx>) -> Self {
|
||||
FnEvalContext {
|
||||
gecx: gecx,
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn report(&self, e: &EvalError) {
|
||||
let stmt = self.frame().stmt;
|
||||
let block = self.basic_block();
|
||||
let span = if stmt < block.statements.len() {
|
||||
block.statements[stmt].span
|
||||
} else {
|
||||
block.terminator().span
|
||||
};
|
||||
let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
|
||||
for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() {
|
||||
// FIXME(solson): Find a way to do this without this Display impl hack.
|
||||
use rustc::util::ppaux;
|
||||
use std::fmt;
|
||||
struct Instance<'tcx>(DefId, &'tcx Substs<'tcx>);
|
||||
impl<'tcx> fmt::Display for Instance<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
|
||||
|tcx| tcx.lookup_item_type(self.0).generics)
|
||||
}
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn maybe_report<T>(&self, r: EvalResult<T>) -> EvalResult<T> {
|
||||
if let Err(ref e) = r {
|
||||
self.report(e);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn run(&mut self) -> EvalResult<()> {
|
||||
let mut stepper = stepper::Stepper::new(self);
|
||||
while stepper.step()? {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>,
|
||||
pub fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>,
|
||||
return_ptr: Option<Pointer>)
|
||||
{
|
||||
let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
|
||||
|
|
@ -411,11 +332,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
::log_settings::settings().indentation += 1;
|
||||
|
||||
let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
|
||||
let size = self.type_size(ty, substs);
|
||||
self.memory.allocate(size)
|
||||
}).collect();
|
||||
|
||||
self.stack.push(Frame {
|
||||
mir: mir.clone(),
|
||||
next_block: mir::START_BLOCK,
|
||||
return_ptr: return_ptr,
|
||||
locals: Vec::new(),
|
||||
locals: locals,
|
||||
var_offset: num_args,
|
||||
temp_offset: num_args + num_vars,
|
||||
span: span,
|
||||
|
|
@ -423,13 +349,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
substs: substs,
|
||||
stmt: 0,
|
||||
});
|
||||
|
||||
let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
|
||||
let size = self.type_size(ty);
|
||||
self.memory.allocate(size)
|
||||
}).collect();
|
||||
|
||||
self.frame_mut().locals = locals;
|
||||
}
|
||||
|
||||
fn pop_stack_frame(&mut self) {
|
||||
|
|
@ -439,27 +358,25 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
|
||||
-> EvalResult<TerminatorTarget> {
|
||||
-> EvalResult<()> {
|
||||
use rustc::mir::repr::TerminatorKind::*;
|
||||
let target = match terminator.kind {
|
||||
Return => TerminatorTarget::Return,
|
||||
match terminator.kind {
|
||||
Return => self.pop_stack_frame(),
|
||||
|
||||
Goto { target } => {
|
||||
self.frame_mut().next_block = target;
|
||||
TerminatorTarget::Block
|
||||
},
|
||||
|
||||
If { ref cond, targets: (then_target, else_target) } => {
|
||||
let cond_ptr = self.eval_operand(cond)?;
|
||||
let cond_val = self.memory.read_bool(cond_ptr)?;
|
||||
self.frame_mut().next_block = if cond_val { then_target } else { else_target };
|
||||
TerminatorTarget::Block
|
||||
}
|
||||
|
||||
SwitchInt { ref discr, ref values, ref targets, .. } => {
|
||||
let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
|
||||
let discr_size = self
|
||||
.type_layout(self.lvalue_ty(discr))
|
||||
.type_layout(self.lvalue_ty(discr), self.substs())
|
||||
.size(&self.tcx.data_layout)
|
||||
.bytes() as usize;
|
||||
let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
|
||||
|
|
@ -477,7 +394,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
|
||||
self.frame_mut().next_block = target_block;
|
||||
TerminatorTarget::Block
|
||||
}
|
||||
|
||||
Switch { ref discr, ref targets, adt_def } => {
|
||||
|
|
@ -490,7 +406,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
match matching {
|
||||
Some(i) => {
|
||||
self.frame_mut().next_block = targets[i];
|
||||
TerminatorTarget::Block
|
||||
},
|
||||
None => return Err(EvalError::InvalidDiscriminant),
|
||||
}
|
||||
|
|
@ -512,7 +427,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
let name = self.tcx.item_name(def_id).as_str();
|
||||
match fn_ty.sig.0.output {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
let ret = return_ptr.unwrap();
|
||||
self.call_intrinsic(&name, substs, args, ret, size)?
|
||||
}
|
||||
|
|
@ -523,7 +438,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
Abi::C => {
|
||||
match fn_ty.sig.0.output {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
self.call_c_abi(def_id, args, return_ptr.unwrap(), size)?
|
||||
}
|
||||
ty::FnDiverging => unimplemented!(),
|
||||
|
|
@ -553,7 +468,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
let last_arg = args.last().unwrap();
|
||||
let last = self.eval_operand(last_arg)?;
|
||||
let last_ty = self.operand_ty(last_arg);
|
||||
let last_layout = self.type_layout(last_ty);
|
||||
let last_layout = self.type_layout(last_ty, self.substs());
|
||||
match (&last_ty.sty, last_layout) {
|
||||
(&ty::TyTuple(fields),
|
||||
&Layout::Univariant { ref variant, .. }) => {
|
||||
|
|
@ -576,8 +491,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
let dest = self.frame().locals[i];
|
||||
self.move_(src, dest, src_ty)?;
|
||||
}
|
||||
|
||||
TerminatorTarget::Call
|
||||
}
|
||||
|
||||
abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
|
||||
|
|
@ -593,13 +506,12 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
let ty = self.lvalue_ty(value);
|
||||
self.drop(ptr, ty)?;
|
||||
self.frame_mut().next_block = target;
|
||||
TerminatorTarget::Block
|
||||
}
|
||||
|
||||
Resume => unimplemented!(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(target)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
|
||||
|
|
@ -638,7 +550,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
// Filling drop.
|
||||
// FIXME(solson): Trait objects (with no static size) probably get filled, too.
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
self.memory.drop_fill(ptr, size)?;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -646,7 +558,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
let adt_layout = self.type_layout(adt_ty);
|
||||
let adt_layout = self.type_layout(adt_ty, self.substs());
|
||||
|
||||
let discr_val = match *adt_layout {
|
||||
General { discr, .. } | CEnum { discr, .. } => {
|
||||
|
|
@ -689,7 +601,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest_size: usize
|
||||
) -> EvalResult<TerminatorTarget> {
|
||||
) -> EvalResult<()> {
|
||||
let args_res: EvalResult<Vec<Pointer>> = args.iter()
|
||||
.map(|arg| self.eval_operand(arg))
|
||||
.collect();
|
||||
|
|
@ -699,7 +611,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
// 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 size = self.type_size(ty, self.substs());
|
||||
let left = self.memory.read_int(args[0], size)?;
|
||||
let right = self.memory.read_int(args[1], size)?;
|
||||
let (n, overflowed) = unsafe {
|
||||
|
|
@ -713,7 +625,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
"copy_nonoverlapping" => {
|
||||
let elem_ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let elem_size = self.type_size(elem_ty);
|
||||
let elem_size = self.type_size(elem_ty, self.substs());
|
||||
let src = self.memory.read_ptr(args[0])?;
|
||||
let dest = self.memory.read_ptr(args[1])?;
|
||||
let count = self.memory.read_isize(args[2])?;
|
||||
|
|
@ -729,7 +641,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
"forget" => {
|
||||
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, self.substs());
|
||||
self.memory.drop_fill(args[0], arg_size)?;
|
||||
}
|
||||
|
||||
|
|
@ -748,7 +660,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
// FIXME(solson): Handle different integer types correctly.
|
||||
"mul_with_overflow" => {
|
||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
let left = self.memory.read_int(args[0], size)?;
|
||||
let right = self.memory.read_int(args[1], size)?;
|
||||
let (n, overflowed) = unsafe {
|
||||
|
|
@ -760,7 +672,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
"offset" => {
|
||||
let pointee_ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let pointee_size = self.type_size(pointee_ty) as isize;
|
||||
let pointee_size = self.type_size(pointee_ty, self.substs()) as isize;
|
||||
let ptr_arg = args[0];
|
||||
let offset = self.memory.read_isize(args[1])?;
|
||||
|
||||
|
|
@ -781,7 +693,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
// FIXME(solson): Handle different integer types correctly. Use primvals?
|
||||
"overflowing_sub" => {
|
||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
let left = self.memory.read_int(args[0], size)?;
|
||||
let right = self.memory.read_int(args[1], size)?;
|
||||
let n = left.wrapping_sub(right);
|
||||
|
|
@ -790,20 +702,20 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
"size_of" => {
|
||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let size = self.type_size(ty) as u64;
|
||||
let size = self.type_size(ty, self.substs()) as u64;
|
||||
self.memory.write_uint(dest, size, dest_size)?;
|
||||
}
|
||||
|
||||
"size_of_val" => {
|
||||
let ty = *substs.types.get(subst::FnSpace, 0);
|
||||
if self.type_is_sized(ty) {
|
||||
let size = self.type_size(ty) as u64;
|
||||
let size = self.type_size(ty, self.substs()) as u64;
|
||||
self.memory.write_uint(dest, size, dest_size)?;
|
||||
} else {
|
||||
match ty.sty {
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
let elem_ty = ty.sequence_element_type(self.tcx);
|
||||
let elem_size = self.type_size(elem_ty) as u64;
|
||||
let elem_size = self.type_size(elem_ty, self.substs()) as u64;
|
||||
let ptr_size = self.memory.pointer_size as isize;
|
||||
let n = self.memory.read_usize(args[0].offset(ptr_size))?;
|
||||
self.memory.write_uint(dest, n * elem_size, dest_size)?;
|
||||
|
|
@ -826,7 +738,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
// Since we pushed no stack frame, the main loop will act
|
||||
// as if the call just completed and it's returning to the
|
||||
// current frame.
|
||||
Ok(TerminatorTarget::Call)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_c_abi(
|
||||
|
|
@ -835,7 +747,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest_size: usize,
|
||||
) -> EvalResult<TerminatorTarget> {
|
||||
) -> EvalResult<()> {
|
||||
let name = self.tcx.item_name(def_id);
|
||||
let attrs = self.tcx.get_attrs(def_id);
|
||||
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
|
||||
|
|
@ -888,7 +800,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
// Since we pushed no stack frame, the main loop will act
|
||||
// as if the call just completed and it's returning to the
|
||||
// current frame.
|
||||
Ok(TerminatorTarget::Call)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assign_fields<I: IntoIterator<Item = u64>>(
|
||||
|
|
@ -911,7 +823,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
{
|
||||
let dest = self.eval_lvalue(lvalue)?.to_ptr();
|
||||
let dest_ty = self.lvalue_ty(lvalue);
|
||||
let dest_layout = self.type_layout(dest_ty);
|
||||
let dest_layout = self.type_layout(dest_ty, self.substs());
|
||||
|
||||
use rustc::mir::repr::Rvalue::*;
|
||||
match *rvalue {
|
||||
|
|
@ -951,7 +863,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
Array { .. } => {
|
||||
let elem_size = match dest_ty.sty {
|
||||
ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64,
|
||||
ty::TyArray(elem_ty, _) => self.type_size(elem_ty, self.substs()) as u64,
|
||||
_ => panic!("tried to assign {:?} to non-array type {:?}",
|
||||
kind, dest_ty),
|
||||
};
|
||||
|
|
@ -1029,7 +941,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
|
||||
Repeat(ref operand, _) => {
|
||||
let (elem_size, length) = match dest_ty.sty {
|
||||
ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n),
|
||||
ty::TyArray(elem_ty, n) => (self.type_size(elem_ty, self.substs()), n),
|
||||
_ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty),
|
||||
};
|
||||
|
||||
|
|
@ -1070,7 +982,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
|
||||
Box(ty) => {
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
let ptr = self.memory.allocate(size);
|
||||
self.memory.write_ptr(dest, ptr)?;
|
||||
}
|
||||
|
|
@ -1164,7 +1076,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
|
||||
let layout = self.type_layout(ty);
|
||||
let layout = self.type_layout(ty, self.substs());
|
||||
|
||||
use rustc::ty::layout::Layout::*;
|
||||
match *layout {
|
||||
|
|
@ -1229,13 +1141,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
substs: substs,
|
||||
kind: ConstantKind::Global,
|
||||
};
|
||||
*self.gecx.statics.get(&cid).expect("static should have been cached (lvalue)")
|
||||
*self.statics.get(&cid).expect("static should have been cached (lvalue)")
|
||||
},
|
||||
|
||||
Projection(ref proj) => {
|
||||
let base = self.eval_lvalue(&proj.base)?;
|
||||
let base_ty = self.lvalue_ty(&proj.base);
|
||||
let base_layout = self.type_layout(base_ty);
|
||||
let base_layout = self.type_layout(base_ty, self.substs());
|
||||
|
||||
use rustc::mir::repr::ProjectionElem::*;
|
||||
match proj.elem {
|
||||
|
|
@ -1296,7 +1208,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
Index(ref operand) => {
|
||||
let elem_size = match base_ty.sty {
|
||||
ty::TyArray(elem_ty, _) |
|
||||
ty::TySlice(elem_ty) => self.type_size(elem_ty),
|
||||
ty::TySlice(elem_ty) => self.type_size(elem_ty, self.substs()),
|
||||
_ => panic!("indexing expected an array or slice, got {:?}", base_ty),
|
||||
};
|
||||
let n_ptr = self.eval_operand(operand)?;
|
||||
|
|
@ -1313,19 +1225,15 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
|
||||
self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx))
|
||||
self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx), self.substs())
|
||||
}
|
||||
|
||||
fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
|
||||
self.monomorphize(self.mir().operand_ty(self.tcx, operand))
|
||||
}
|
||||
|
||||
fn monomorphize(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.gecx.monomorphize(ty, self.substs())
|
||||
self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
|
||||
}
|
||||
|
||||
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
|
||||
let size = self.type_size(ty);
|
||||
let size = self.type_size(ty, self.substs());
|
||||
self.memory.copy(src, dest, size)?;
|
||||
if self.type_needs_drop(ty) {
|
||||
self.memory.drop_fill(src, size)?;
|
||||
|
|
@ -1333,14 +1241,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn type_size(&self, ty: Ty<'tcx>) -> usize {
|
||||
self.gecx.type_size(ty, self.substs())
|
||||
}
|
||||
|
||||
fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
|
||||
self.gecx.type_layout(ty, self.substs())
|
||||
}
|
||||
|
||||
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
|
||||
use syntax::ast::{IntTy, UintTy};
|
||||
let val = match (self.memory.pointer_size, &ty.sty) {
|
||||
|
|
@ -1380,20 +1280,15 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
Ok(val)
|
||||
}
|
||||
|
||||
fn frame(&self) -> &Frame<'mir, 'tcx> {
|
||||
fn frame(&self) -> &Frame<'a, 'tcx> {
|
||||
self.stack.last().expect("no call frames exist")
|
||||
}
|
||||
|
||||
fn basic_block(&self) -> &mir::BasicBlockData<'tcx> {
|
||||
let frame = self.frame();
|
||||
frame.mir.basic_block_data(frame.next_block)
|
||||
}
|
||||
|
||||
fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
|
||||
fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
|
||||
self.stack.last_mut().expect("no call frames exist")
|
||||
}
|
||||
|
||||
fn mir(&self) -> CachedMir<'mir, 'tcx> {
|
||||
fn mir(&self) -> CachedMir<'a, 'tcx> {
|
||||
self.frame().mir.clone()
|
||||
}
|
||||
|
||||
|
|
@ -1472,37 +1367,6 @@ pub fn get_impl_method<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn interpret_start_points<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir_map: &MirMap<'tcx>,
|
||||
) {
|
||||
let initial_indentation = ::log_settings::settings().indentation;
|
||||
for (&id, mir) in &mir_map.map {
|
||||
for attr in tcx.map.attrs(id) {
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
if attr.check_name("miri_run") {
|
||||
let item = tcx.map.expect_item(id);
|
||||
|
||||
::log_settings::settings().indentation = initial_indentation;
|
||||
|
||||
debug!("Interpreting: {}", item.name);
|
||||
|
||||
let mut gecx = GlobalEvalContext::new(tcx, mir_map);
|
||||
match gecx.call(mir, tcx.map.local_def_id(id)) {
|
||||
Ok(Some(return_ptr)) => if log_enabled!(::log::LogLevel::Debug) {
|
||||
gecx.memory.dump(return_ptr.alloc_id);
|
||||
},
|
||||
Ok(None) => warn!("diverging function returned"),
|
||||
Err(_e) => {
|
||||
// TODO(solson): Detect whether the error was already reported or not.
|
||||
// tcx.sess.err(&e.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(solson): Upstream these methods into rustc::ty::layout.
|
||||
|
||||
trait IntegerExt {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use super::{
|
||||
FnEvalContext,
|
||||
CachedMir,
|
||||
TerminatorTarget,
|
||||
ConstantId,
|
||||
GlobalEvalContext,
|
||||
EvalContext,
|
||||
ConstantKind,
|
||||
};
|
||||
use error::EvalResult;
|
||||
|
|
@ -13,138 +11,117 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::mir::visit::{Visitor, LvalueContext};
|
||||
use syntax::codemap::Span;
|
||||
use std::rc::Rc;
|
||||
use memory::Pointer;
|
||||
|
||||
pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
|
||||
fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
|
||||
|
||||
// a cache of the constants to be computed before the next statement/terminator
|
||||
// this is an optimization, so we don't have to allocate a new vector for every statement
|
||||
constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
|
||||
pub(super) struct Stepper<'ecx, 'a: 'ecx, 'tcx: 'a>{
|
||||
ecx: &'ecx mut EvalContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
|
||||
pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
|
||||
impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
|
||||
pub(super) fn new(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> Self {
|
||||
Stepper {
|
||||
fncx: fncx,
|
||||
constants: Vec::new(),
|
||||
ecx: ecx,
|
||||
}
|
||||
}
|
||||
|
||||
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> {
|
||||
trace!("{:?}", stmt);
|
||||
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
|
||||
let result = self.fncx.eval_assignment(lvalue, rvalue);
|
||||
self.fncx.maybe_report(result)?;
|
||||
self.fncx.frame_mut().stmt += 1;
|
||||
self.ecx.eval_assignment(lvalue, rvalue)?;
|
||||
self.ecx.frame_mut().stmt += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> {
|
||||
// after a terminator we go to a new block
|
||||
self.fncx.frame_mut().stmt = 0;
|
||||
let term = {
|
||||
trace!("{:?}", terminator.kind);
|
||||
let result = self.fncx.eval_terminator(terminator);
|
||||
self.fncx.maybe_report(result)?
|
||||
};
|
||||
match term {
|
||||
TerminatorTarget::Return => {
|
||||
self.fncx.pop_stack_frame();
|
||||
},
|
||||
TerminatorTarget::Block |
|
||||
TerminatorTarget::Call => trace!("// {:?}", self.fncx.frame().next_block),
|
||||
self.ecx.frame_mut().stmt = 0;
|
||||
trace!("{:?}", terminator.kind);
|
||||
self.ecx.eval_terminator(terminator)?;
|
||||
if !self.ecx.stack.is_empty() {
|
||||
trace!("// {:?}", self.ecx.frame().next_block);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// returns true as long as there are more things to do
|
||||
pub fn step(&mut self) -> EvalResult<bool> {
|
||||
if self.fncx.stack.is_empty() {
|
||||
pub(super) fn step(&mut self) -> EvalResult<bool> {
|
||||
if self.ecx.stack.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let block = self.fncx.frame().next_block;
|
||||
let stmt = self.fncx.frame().stmt;
|
||||
let mir = self.fncx.mir();
|
||||
let block = self.ecx.frame().next_block;
|
||||
let stmt = self.ecx.frame().stmt;
|
||||
let mir = self.ecx.mir();
|
||||
let basic_block = mir.basic_block_data(block);
|
||||
|
||||
if let Some(ref stmt) = basic_block.statements.get(stmt) {
|
||||
assert!(self.constants.is_empty());
|
||||
let current_stack = self.ecx.stack.len();
|
||||
ConstantExtractor {
|
||||
span: stmt.span,
|
||||
substs: self.fncx.substs(),
|
||||
def_id: self.fncx.frame().def_id,
|
||||
gecx: self.fncx.gecx,
|
||||
constants: &mut self.constants,
|
||||
substs: self.ecx.substs(),
|
||||
def_id: self.ecx.frame().def_id,
|
||||
ecx: self.ecx,
|
||||
mir: &mir,
|
||||
}.visit_statement(block, stmt);
|
||||
if self.constants.is_empty() {
|
||||
if current_stack == self.ecx.stack.len() {
|
||||
self.statement(stmt)?;
|
||||
} else {
|
||||
self.extract_constants()?;
|
||||
// ConstantExtractor added some new frames for statics/constants/promoteds
|
||||
// self.step() can't be "done", so it can't return false
|
||||
assert!(self.step()?);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let terminator = basic_block.terminator();
|
||||
assert!(self.constants.is_empty());
|
||||
let current_stack = self.ecx.stack.len();
|
||||
ConstantExtractor {
|
||||
span: terminator.span,
|
||||
substs: self.fncx.substs(),
|
||||
def_id: self.fncx.frame().def_id,
|
||||
gecx: self.fncx.gecx,
|
||||
constants: &mut self.constants,
|
||||
substs: self.ecx.substs(),
|
||||
def_id: self.ecx.frame().def_id,
|
||||
ecx: self.ecx,
|
||||
mir: &mir,
|
||||
}.visit_terminator(block, terminator);
|
||||
if self.constants.is_empty() {
|
||||
if current_stack == self.ecx.stack.len() {
|
||||
self.terminator(terminator)?;
|
||||
} else {
|
||||
self.extract_constants()?;
|
||||
// ConstantExtractor added some new frames for statics/constants/promoteds
|
||||
// self.step() can't be "done", so it can't return false
|
||||
assert!(self.step()?);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn extract_constants(&mut self) -> EvalResult<()> {
|
||||
assert!(!self.constants.is_empty());
|
||||
for (cid, span, return_ptr, mir) in self.constants.drain(..) {
|
||||
trace!("queuing a constant");
|
||||
self.fncx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr));
|
||||
}
|
||||
// self.step() can't be "done", so it can't return false
|
||||
assert!(self.step()?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> {
|
||||
// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
|
||||
// this includes any method that might access the stack
|
||||
// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame`
|
||||
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
|
||||
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
span: Span,
|
||||
// FIXME: directly push the new stackframes instead of doing this intermediate caching
|
||||
constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
|
||||
gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
|
||||
ecx: &'a mut EvalContext<'b, 'tcx>,
|
||||
mir: &'a mir::Mir<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: &'tcx subst::Substs<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
|
||||
impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
|
||||
fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) {
|
||||
let cid = ConstantId {
|
||||
def_id: def_id,
|
||||
substs: substs,
|
||||
kind: ConstantKind::Global,
|
||||
};
|
||||
if self.gecx.statics.contains_key(&cid) {
|
||||
if self.ecx.statics.contains_key(&cid) {
|
||||
return;
|
||||
}
|
||||
let mir = self.gecx.load_mir(def_id);
|
||||
let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
|
||||
self.gecx.statics.insert(cid.clone(), ptr);
|
||||
self.constants.push((cid, span, ptr, mir));
|
||||
let mir = self.ecx.load_mir(def_id);
|
||||
let ptr = self.ecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
|
||||
self.ecx.statics.insert(cid.clone(), ptr);
|
||||
self.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> {
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
|
||||
self.super_constant(constant);
|
||||
match constant.literal {
|
||||
|
|
@ -165,15 +142,15 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx>
|
|||
substs: self.substs,
|
||||
kind: ConstantKind::Promoted(index),
|
||||
};
|
||||
if self.gecx.statics.contains_key(&cid) {
|
||||
if self.ecx.statics.contains_key(&cid) {
|
||||
return;
|
||||
}
|
||||
let mir = self.mir.promoted[index].clone();
|
||||
let return_ty = mir.return_ty;
|
||||
let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static");
|
||||
let return_ptr = self.ecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static");
|
||||
let mir = CachedMir::Owned(Rc::new(mir));
|
||||
self.gecx.statics.insert(cid.clone(), return_ptr);
|
||||
self.constants.push((cid, constant.span, return_ptr, mir));
|
||||
self.ecx.statics.insert(cid.clone(), return_ptr);
|
||||
self.ecx.push_stack_frame(self.def_id, constant.span, mir, self.substs, Some(return_ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +158,7 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx>
|
|||
fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) {
|
||||
self.super_lvalue(lvalue, context);
|
||||
if let mir::Lvalue::Static(def_id) = *lvalue {
|
||||
let substs = self.gecx.tcx.mk_substs(subst::Substs::empty());
|
||||
let substs = self.ecx.tcx.mk_substs(subst::Substs::empty());
|
||||
let span = self.span;
|
||||
self.global_item(def_id, substs, span);
|
||||
}
|
||||
|
|
|
|||
16
src/lib.rs
16
src/lib.rs
|
|
@ -20,6 +20,20 @@ extern crate log_settings;
|
|||
extern crate byteorder;
|
||||
|
||||
mod error;
|
||||
pub mod interpreter;
|
||||
mod interpreter;
|
||||
mod memory;
|
||||
mod primval;
|
||||
|
||||
pub use error::{
|
||||
EvalError,
|
||||
EvalResult,
|
||||
};
|
||||
|
||||
pub use interpreter::{
|
||||
EvalContext,
|
||||
step,
|
||||
Frame,
|
||||
CachedMir,
|
||||
};
|
||||
|
||||
pub use memory::Memory;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue