Allow writing mutable statics in miri by adding them to the Machine

This commit is contained in:
Oliver Schneider 2018-01-25 08:06:53 +01:00
parent d3e2f48c8c
commit 34772aad63
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
4 changed files with 47 additions and 42 deletions

View file

@ -1,6 +1,7 @@
use rustc::hir;
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
use rustc::traits;
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf};
@ -326,6 +327,27 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
Ok(false)
}
fn init_static<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId> {
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
// ensure the static is computed
if let Err(err) = ecx.tcx.const_eval(param_env.and(cid)) {
match err.kind {
ErrKind::Miri(miri) => return Err(miri),
ErrKind::TypeckError => return err!(TypeckError),
other => bug!("const eval returned {:?}", other),
}
};
Ok(ecx
.tcx
.interpret_interner
.borrow()
.get_cached(cid.instance.def_id())
.expect("uncached static"))
}
fn box_alloc<'a>(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_ty: Ty<'tcx>,

View file

@ -1264,14 +1264,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?,
)),
ty::TySlice(..) | ty::TyStr => {
match p.primval {
PrimVal::Bytes(b) => bug!("slice ptr: {:x}", b),
PrimVal::Undef => bug!("undef slice ptr"),
_ => {},
}
Ok(
p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64),
)
let len = self
.memory
.read_ptr_sized_unsigned(extra, ptr_align)?
.to_bytes()?;
Ok(p.to_value_with_len(len as u64))
},
_ => bug!("unsized primval ptr read from {:?}", pointee_ty),
}
@ -1621,16 +1618,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
block.terminator().source_info.span
});
trace!("reporting const eval failure at {:?}", span);
let node_id = self
.stack()
.iter()
.rev()
.filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
.next()
.expect("some part of a failing const eval must be local");
let mut err = if as_err {
::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error")
} else {
let node_id = self
.stack()
.iter()
.rev()
.filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
.next()
.expect("some part of a failing const eval must be local");
self.tcx.struct_span_lint_node(
::rustc::lint::builtin::CONST_ERR,
node_id,

View file

@ -2,7 +2,7 @@
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.
use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind};
use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind, GlobalId};
use super::{EvalContext, Place, ValTy, Memory};
use rustc::mir;
@ -66,6 +66,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
_mutability: Mutability,
) -> EvalResult<'tcx, bool>;
/// Called when requiring a pointer to a static. Non const eval can
/// create a mutable memory location for `static mut`
fn init_static<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
cid: GlobalId<'tcx>,
) -> EvalResult<'tcx, AllocId>;
/// Heap allocations via the `box` keyword
///
/// Returns a pointer to the allocated memory

View file

@ -1,13 +1,11 @@
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc::traits;
use rustc_data_structures::indexed_vec::Idx;
use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer};
use super::{EvalContext, Machine, ValTy};
use interpret::memory::HasMemory;
use rustc::middle::const_val::ErrKind;
#[derive(Copy, Clone, Debug)]
pub enum Place {
@ -105,14 +103,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
Local(mir::RETURN_PLACE) => err!(ReadFromReturnPointer),
// Directly reading a local will always succeed
Local(local) => self.frame().get_local(local).map(Some),
// Directly reading a static will always succeed
Static(ref static_) => {
let instance = ty::Instance::mono(self.tcx, static_.def_id);
self.read_global_as_value(GlobalId {
instance,
promoted: None,
}, self.place_ty(place)).map(Some)
}
// No fast path for statics. Reading from statics is rare and would require another
// Machine function to handle differently in miri.
Static(_) => Ok(None),
Projection(ref proj) => self.try_read_place_projection(proj),
}
}
@ -219,21 +212,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
instance,
promoted: None
};
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
// ensure the static is computed
if let Err(err) = self.tcx.const_eval(param_env.and(cid)) {
match err.kind {
ErrKind::Miri(miri) => return Err(miri),
ErrKind::TypeckError => return err!(TypeckError),
other => bug!("const eval returned {:?}", other),
}
};
let alloc = self
.tcx
.interpret_interner
.borrow()
.get_cached(static_.def_id)
.expect("uncached static");
let alloc = Machine::init_static(self, cid)?;
Place::Ptr {
ptr: MemoryPointer::new(alloc, 0).into(),
align: layout.align,