This commit is contained in:
bjorn3 2018-01-14 18:59:13 +01:00 committed by Oliver Schneider
parent d289c0f464
commit 753da676ba
No known key found for this signature in database
GPG key ID: 1D5CB4FC597C3004
9 changed files with 113 additions and 128 deletions

View file

@ -5,6 +5,7 @@ extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_trans_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
@ -17,7 +18,8 @@ use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{self, MetaItemKind, NestedMetaItemKind};
use rustc_trans_utils::trans_crate::TransCrate;
use syntax::ast;
use std::path::PathBuf;
struct MiriCompilerCalls {
@ -61,6 +63,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
}
fn late_callback(
&mut self,
trans: &TransCrate,
matches: &getopts::Matches,
sess: &Session,
cstore: &CrateStore,
@ -68,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
) -> Compilation {
self.default.late_callback(matches, sess, cstore, input, odir, ofile)
self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile)
}
fn build_controller(
&mut self,
@ -98,11 +101,9 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
state.session.abort_if_errors();
let tcx = state.tcx.unwrap();
let limits = resource_limits_from_attributes(state);
if std::env::args().any(|arg| arg == "--test") {
struct Visitor<'a, 'tcx: 'a>(
miri::ResourceLimits,
TyCtxt<'a, 'tcx, 'tcx>,
&'a CompileState<'a, 'tcx>
);
@ -113,13 +114,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
attr.name().map_or(false, |n| n == "test")
})
{
let did = self.1.hir.body_owner_def_id(body_id);
let did = self.0.hir.body_owner_def_id(body_id);
println!(
"running test: {}",
self.1.def_path_debug_str(did),
self.0.def_path_debug_str(did),
);
miri::eval_main(self.1, did, None, self.0);
self.2.session.abort_if_errors();
miri::eval_main(self.0, did, None);
self.1.session.abort_if_errors();
}
}
}
@ -127,7 +128,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
}
state.hir_crate.unwrap().visit_all_item_likes(
&mut Visitor(limits, tcx, state),
&mut Visitor(tcx, state),
);
} else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
@ -138,7 +139,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
None
}
});
miri::eval_main(tcx, entry_def_id, start_wrapper, limits);
miri::eval_main(tcx, entry_def_id, start_wrapper);
state.session.abort_if_errors();
} else {
@ -146,50 +147,6 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
}
}
fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
let mut limits = miri::ResourceLimits::default();
let krate = state.hir_crate.as_ref().unwrap();
let err_msg = "miri attributes need to be in the form `miri(key = value)`";
let extract_int = |lit: &syntax::ast::Lit| -> u128 {
match lit.node {
syntax::ast::LitKind::Int(i, _) => i,
_ => {
state.session.span_fatal(
lit.span,
"expected an integer literal",
)
}
}
};
for attr in krate.attrs.iter().filter(|a| {
a.name().map_or(false, |n| n == "miri")
})
{
if let Some(items) = attr.meta_item_list() {
for item in items {
if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
if let MetaItemKind::NameValue(ref value) = inner.node {
match &inner.name().as_str()[..] {
"memory_size" => limits.memory_size = extract_int(value) as u64,
"step_limit" => limits.step_limit = extract_int(value) as u64,
"stack_limit" => limits.stack_limit = extract_int(value) as usize,
_ => state.session.span_err(item.span, "unknown miri attribute"),
}
} else {
state.session.span_err(inner.span, err_msg);
}
} else {
state.session.span_err(item.span, err_msg);
}
}
} else {
state.session.span_err(attr.span, err_msg);
}
}
limits
}
fn init_logger() {
let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| {
use std::io::Write;

View file

@ -8,8 +8,6 @@ use syntax::codemap::Span;
use std::mem;
use rustc::traits;
use super::*;
use tls::MemoryExt;
@ -49,7 +47,7 @@ pub trait EvalContextExt<'tcx> {
fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
fn eval_fn_call(
&mut self,
instance: ty::Instance<'tcx>,
@ -385,13 +383,17 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
promoted: None,
};
// compute global if not cached
let val = match self.tcx.interpret_interner.borrow().get_cached(cid) {
Some(ptr) => MemoryPointer::new(ptr, 0).into(),
None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0,
let value: Value = match self.tcx.interpret_interner.get_cached(instance.def_id()) {
Some(ptr) => {
Value::ByRef(MemoryPointer::new(ptr, 0).into(), name_align)
}
None => {
let res: Option<(Value, Pointer, Ty)> = eval_body(self.tcx.tcx, cid, ty::ParamEnv::reveal_all());
res.ok_or_else(||EvalErrorKind::MachineError("<already reported>".to_string()))?.0
},
};
let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align),
ty: args[0].ty })?.to_u64()?;
if val == name {
let value = self.value_to_primval(ValTy { value, ty: args[0].ty })?.to_u64()?;
if value == name {
result = Some(path_value);
break;
}
@ -420,7 +422,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
};
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference)
let key_type = args[0].ty.builtin_deref(true)
.ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
let key_size = self.layout_of(key_type)?.size;
@ -502,7 +504,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
for item in mem::replace(&mut items, Default::default()).iter() {
if item.ident.name == *segment {
if path_it.peek().is_none() {
return Some(ty::Instance::mono(self.tcx, item.def.def_id()));
return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id()));
}
items = self.tcx.item_children(item.def.def_id());

View file

@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> {
) -> EvalResult<'tcx, Pointer>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
fn wrapping_pointer_offset(
&self,
ptr: Pointer,

View file

@ -1,5 +1,4 @@
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{TyLayout, LayoutOf};
use rustc::ty;
@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> {
) -> EvalResult<'tcx>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
fn call_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
@ -349,7 +348,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
match dest {
Place::Local { frame, local } => self.modify_local(frame, local, init)?,
Place::Ptr {
ptr: ptr,
ptr,
align: _align,
extra: PlaceExtra::None,
} => self.memory.write_repeat(ptr, 0, size)?,
@ -381,8 +380,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
"needs_drop" => {
let ty = substs.type_at(0);
let env = ty::ParamEnv::empty(Reveal::All);
let needs_drop = ty.needs_drop(self.tcx, env);
let env = ty::ParamEnv::reveal_all();
let needs_drop = ty.needs_drop(self.tcx.tcx, env);
self.write_primval(
dest,
PrimVal::from_bool(needs_drop),
@ -542,10 +541,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
"transmute" => {
let src_ty = substs.type_at(0);
let src_align = self.layout_of(src_ty)?.align;
let _src_align = self.layout_of(src_ty)?.align;
let ptr = self.force_allocation(dest)?.to_ptr()?;
let dest_align = self.layout_of(substs.type_at(1))?.align;
self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty);
self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap();
}
"unchecked_shl" => {
@ -626,7 +625,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
match dest {
Place::Local { frame, local } => self.modify_local(frame, local, uninit)?,
Place::Ptr {
ptr: ptr,
ptr,
align: _align,
extra: PlaceExtra::None,
} => self.memory.mark_definedness(ptr, size, false)?,

View file

@ -22,7 +22,6 @@ use rustc::ty::{self, TyCtxt};
use rustc::ty::layout::{TyLayout, LayoutOf};
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::traits;
use syntax::ast::Mutability;
use syntax::codemap::Span;
@ -56,14 +55,13 @@ pub fn eval_main<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
main_id: DefId,
start_wrapper: Option<DefId>,
limits: ResourceLimits,
) {
fn run_main<'a, 'tcx: 'a>(
ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Evaluator<'tcx>>,
fn run_main<'a, 'mir: 'a, 'tcx: 'mir>(
ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>,
main_id: DefId,
start_wrapper: Option<DefId>,
) -> EvalResult<'tcx> {
let main_instance = ty::Instance::mono(ecx.tcx, main_id);
let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
let main_mir = ecx.load_mir(main_instance.def)?;
let mut cleanup_ptr = None; // Pointer to be deallocated when we are done
@ -78,8 +76,8 @@ pub fn eval_main<'a, 'tcx: 'a>(
let main_ret_ty = ecx.tcx.fn_sig(main_id).output();
let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap();
let start_instance = ty::Instance::resolve(
ecx.tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ecx.tcx.tcx,
ty::ParamEnv::reveal_all(),
start_id,
ecx.tcx.mk_substs(
::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap();
@ -112,8 +110,8 @@ pub fn eval_main<'a, 'tcx: 'a>(
// First argument: pointer to main()
let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let main_ty = main_instance.ty(ecx.tcx);
let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx));
let main_ty = main_instance.ty(ecx.tcx.tcx);
let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx));
ecx.write_value(
ValTy {
value: Value::ByVal(PrimVal::Ptr(main_ptr)),
@ -136,7 +134,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
let ptr_align = ecx.tcx.data_layout.pointer_align;
let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?;
ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?;
ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?;
ecx.write_ptr(dest, foo_ptr.into(), ty)?;
assert!(args.next().is_none(), "start lang item has more arguments than expected");
@ -166,7 +164,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
Ok(())
}
let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default());
let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default());
match run_main(&mut ecx, main_id, start_wrapper) {
Ok(()) => {
let leaks = ecx.memory().leak_report();
@ -175,7 +173,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
}
}
Err(mut e) => {
ecx.report(&mut e);
ecx.report(&mut e, true, None);
}
}
}
@ -213,13 +211,13 @@ pub struct MemoryData<'tcx> {
locks: HashMap<AllocId, RangeMap<LockInfo<'tcx>>>,
}
impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> {
type MemoryData = MemoryData<'tcx>;
type MemoryKinds = memory::MemoryKind;
/// Returns Ok() when the function was handled, fail otherwise
fn eval_fn_call<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
destination: Option<(Place, mir::BasicBlock)>,
args: &[ValTy<'tcx>],
@ -230,7 +228,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
}
fn call_intrinsic<'a>(
ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Self>,
ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
args: &[ValTy<'tcx>],
dest: Place,
@ -241,7 +239,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
}
fn try_ptr_op<'a>(
ecx: &rustc_mir::interpret::EvalContext<'a, 'tcx, Self>,
ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
left: PrimVal,
left_ty: ty::Ty<'tcx>,
@ -251,17 +249,35 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
ecx.ptr_op(bin_op, left, left_ty, right, right_ty)
}
fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> {
use memory::MemoryKind::*;
fn mark_static_initialized<'a>(
_mem: &mut Memory<'a, 'mir, 'tcx, Self>,
_id: AllocId,
_mutability: Mutability,
) -> EvalResult<'tcx, bool> {
/*use memory::MemoryKind::*;
match m {
// FIXME: This could be allowed, but not for env vars set during miri execution
Env => err!(Unimplemented("statics can't refer to env vars".to_owned())),
_ => Ok(()),
}
_ => Ok(false), // TODO: What does the bool mean?
}*/
Ok(true)
}
fn init_static<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId> {
let def_id = cid.instance.def_id();
let ty = ecx.tcx.type_of(def_id);
let layout = ecx.tcx.layout_of(ty::ParamEnvAnd {
param_env: ty::ParamEnv::reveal_all(),
value: ty
}).expect("Couldn't compute layout for the type of a static");
ecx.memory.allocate(layout.size.bytes(), layout.align, None).map(|mptr|mptr.alloc_id)
}
fn box_alloc<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
ty: ty::Ty<'tcx>,
dest: Place,
) -> EvalResult<'tcx> {
@ -269,7 +285,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
// Call the `exchange_malloc` lang item
let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
let malloc = ty::Instance::mono(ecx.tcx, malloc);
let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
let malloc_mir = ecx.load_mir(malloc.def)?;
ecx.push_stack_frame(
malloc,
@ -311,7 +327,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
}
fn global_item_with_linkage<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
mutability: Mutability,
) -> EvalResult<'tcx> {
@ -325,19 +341,16 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
None,
)?;
ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?;
ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?;
ecx.tcx.interpret_interner.borrow_mut().cache(
GlobalId {
instance,
promoted: None,
},
ecx.memory.mark_static_initialized(ptr.alloc_id, mutability)?;
ecx.tcx.interpret_interner.cache(
instance.def_id(),
ptr.alloc_id,
);
Ok(())
}
fn check_locks<'a>(
mem: &Memory<'a, 'tcx, Self>,
mem: &Memory<'a, 'mir, 'tcx, Self>,
ptr: MemoryPointer,
size: u64,
access: AccessKind,
@ -346,14 +359,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
}
fn add_lock<'a>(
mem: &mut Memory<'a, 'tcx, Self>,
mem: &mut Memory<'a, 'mir, 'tcx, Self>,
id: AllocId,
) {
mem.data.locks.insert(id, RangeMap::new());
}
fn free_lock<'a>(
mem: &mut Memory<'a, 'tcx, Self>,
mem: &mut Memory<'a, 'mir, 'tcx, Self>,
id: AllocId,
len: u64,
) -> EvalResult<'tcx> {
@ -379,14 +392,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> {
}
fn end_region<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
reg: Option<::rustc::middle::region::Scope>,
) -> EvalResult<'tcx> {
ecx.end_region(reg)
}
fn validation_op<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
op: ::rustc::mir::ValidationOp,
operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
) -> EvalResult<'tcx> {

View file

@ -99,7 +99,7 @@ pub trait MemoryExt<'tcx> {
}
impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> {
fn check_locks(
&self,
ptr: MemoryPointer,

View file

@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx> {
) -> EvalResult<'tcx, (PrimVal, bool)>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
fn ptr_op(
&self,
bin_op: mir::BinOp,
@ -42,7 +42,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
match bin_op {
Offset if left_kind == Ptr && right_kind == usize => {
let pointee_ty = left_ty
.builtin_deref(true, ty::LvaluePreference::NoPreference)
.builtin_deref(true)
.expect("Offset called on non-ptr type")
.ty;
let ptr = self.pointer_offset(

View file

@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> {
fn run_tls_dtors(&mut self) -> EvalResult<'tcx>;
}
impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> {
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
let new_key = self.data.next_thread_local;
self.data.next_thread_local += 1;
@ -106,7 +106,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> {
}
}
impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> {
fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
let mut dtor = self.memory.fetch_tls_dtor(None)?;
// FIXME: replace loop by some structure that works with stepping

View file

@ -1,15 +1,16 @@
use rustc::hir::{self, Mutability};
use rustc::hir::Mutability::*;
use rustc::mir::{self, ValidationOp, ValidationOperand};
use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance};
use rustc::ty::layout::LayoutOf;
use rustc::ty::subst::{Substs, Subst};
use rustc::traits;
use rustc::infer::InferCtxt;
use rustc::traits::Reveal;
use rustc::middle::region;
use rustc::middle::const_val::ConstVal;
use rustc_data_structures::indexed_vec::Idx;
use rustc_mir::interpret::HasMemory;
use rustc_mir::interpret::{HasMemory, eval_body};
use super::{EvalContext, Place, PlaceExtra, ValTy};
use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult};
@ -108,7 +109,7 @@ pub(crate) trait EvalContextExt<'tcx> {
) -> EvalResult<'tcx>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> {
use self::mir::ProjectionElem::*;
@ -117,7 +118,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
Field(f, _) => Field(f, ()),
Index(v) => {
let value = self.frame().get_local(v)?;
let ty = self.tcx.types.usize;
let ty = self.tcx.tcx.types.usize;
let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?;
Index(n)
},
@ -152,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
// because other crates may have been compiled with mir-emit-validate > 0. Ignore those
// commands. This makes mir-emit-validate also a flag to control whether miri will do
// validation or not.
if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 {
if self.tcx.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 {
return Ok(());
}
debug_assert!(self.memory.cur_frame == self.cur_frame());
@ -187,7 +188,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
// We need to monomorphize ty *without* erasing lifetimes
trace!("validation_op1: {:?}", operand.ty.sty);
let ty = operand.ty.subst(self.tcx, self.substs());
let ty = operand.ty.subst(self.tcx.tcx, self.substs());
trace!("validation_op2: {:?}", operand.ty.sty);
let place = self.eval_place(&operand.place)?;
let abs_place = self.abstract_place(&operand.place)?;
@ -250,7 +251,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
}
fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
return normalize_associated_type(self.tcx, &ty);
return normalize_associated_type(self.tcx.tcx, &ty);
use syntax::codemap::{Span, DUMMY_SP};
@ -356,7 +357,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
where
T: MyTransNormalize<'tcx>,
{
let param_env = ty::ParamEnv::empty(Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
if !value.has_projections() {
return value.clone();
@ -383,7 +384,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
}
_ => {}
}
let tcx = self.tcx;
let tcx = self.tcx.tcx;
Ok(match layout.ty.sty {
ty::TyBool |
ty::TyChar |
@ -393,6 +394,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
ty::TyFnPtr(_) |
ty::TyNever |
ty::TyFnDef(..) |
ty::TyGeneratorWitness(..) |
ty::TyDynamic(..) |
ty::TyForeign(..) => {
bug!("TyLayout::field_type({:?}): not applicable", layout)
@ -437,7 +439,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
substs.field_tys(def_id, tcx).nth(i).unwrap()
}
ty::TyTuple(tys, _) => tys[i],
ty::TyTuple(tys) => tys[i],
// SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => {
@ -558,6 +560,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
TyAdt(adt, _) if adt.is_box() => true,
TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) |
TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false,
TyGeneratorWitness(..) => bug!("I'm not sure what to return here"),
TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => {
bug!("I got an incomplete/unnormalized type for validation")
}
@ -725,7 +728,18 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
Ok(())
}
TyArray(elem_ty, len) => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
let len_val = match len.val {
ConstVal::Unevaluated(def_id, substs) => {
eval_body(self.tcx.tcx, GlobalId {
instance: Instance::new(def_id, substs),
promoted: None,
}, ty::ParamEnv::reveal_all())
.ok_or_else(||EvalErrorKind::MachineError("<already reported>".to_string()))?
.0
}
ConstVal::Value(val) => val,
};
let len = ConstVal::Value(len_val).unwrap_u64();
for i in 0..len {
let inner_place = self.place_index(query.place.1, query.ty, i as u64)?;
self.validate(
@ -759,7 +773,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
Ok(())
}
TyAdt(adt, _) => {
if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() &&
if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() &&
query.mutbl == MutImmutable
{
// No locks for shared unsafe cells. Also no other validation, the only field is private anyway.
@ -771,8 +785,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'
let discr = self.read_discriminant_value(query.place.1, query.ty)?;
// Get variant index for discriminant
let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| {
variant_discr.to_u128_unchecked() == discr
let variant_idx = adt.discriminants(self.tcx.tcx).position(|variant_discr| {
variant_discr.val == discr
});
let variant_idx = match variant_idx {
Some(val) => val,