allow Machine to hook into foreign statics; remove unused HasMemory trait

This commit is contained in:
Ralf Jung 2018-08-23 21:22:27 +02:00
parent 2592b20347
commit 286fc5caa2
4 changed files with 72 additions and 126 deletions

View File

@ -11,10 +11,10 @@
use std::fmt;
use std::error::Error;
use rustc::hir;
use rustc::hir::{self, def_id::DefId};
use rustc::mir::interpret::ConstEvalErr;
use rustc::mir;
use rustc::ty::{self, ParamEnv, TyCtxt, Instance, query::TyCtxtAt};
use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
use rustc::ty::layout::{LayoutOf, TyLayout};
use rustc::ty::subst::Subst;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@ -325,6 +325,13 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
}
}
fn find_foreign_static<'a>(
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
_def_id: DefId,
) -> EvalResult<'tcx, &'tcx Allocation> {
err!(ReadForeignStatic)
}
fn box_alloc<'a>(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
@ -333,16 +340,6 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
)
}
fn global_item_with_linkage<'a>(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>,
_mutability: Mutability,
) -> EvalResult<'tcx> {
Err(
ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(),
)
}
}
/// Project to a field of a (variant of a) const
@ -481,43 +478,3 @@ pub fn const_eval_provider<'a, 'tcx>(
err.into()
})
}
/// Helper function to obtain the global (tcx) allocation for a static
pub fn static_alloc<'a, 'tcx>(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
id: AllocId,
) -> EvalResult<'tcx, &'tcx Allocation> {
let alloc = tcx.alloc_map.lock().get(id);
let def_id = match alloc {
Some(AllocType::Memory(mem)) => {
return Ok(mem)
}
Some(AllocType::Function(..)) => {
return err!(DerefFunctionPointer)
}
Some(AllocType::Static(did)) => {
did
}
None =>
return err!(DanglingPointerDeref),
};
// We got a "lazy" static that has not been computed yet, do some work
trace!("static_alloc: Need to compute {:?}", def_id);
if tcx.is_foreign_item(def_id) {
return err!(ReadForeignStatic);
}
let instance = Instance::mono(tcx.tcx, def_id);
let gid = GlobalId {
instance,
promoted: None,
};
tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
// no need to report anything, the const_eval call takes care of that for statics
assert!(tcx.is_static(def_id).is_some());
EvalErrorKind::ReferencedConstant(err).into()
}).map(|val| {
// FIXME We got our static (will be a ByRef), now we make a *copy*?!?
tcx.const_to_allocation(val)
})
}

View File

@ -14,12 +14,12 @@
use std::hash::Hash;
use rustc::hir::def_id::DefId;
use rustc::mir::interpret::{AllocId, Allocation, EvalResult, Scalar};
use super::{EvalContext, PlaceTy, OpTy, Memory};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout};
use syntax::ast::Mutability;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
use super::{EvalContext, PlaceTy, OpTy, Memory};
/// Used by the machine to tell if a certain allocation is for static memory
pub trait IsStatic {
@ -62,6 +62,12 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx>;
/// Called for read access to a foreign static item.
fn find_foreign_static<'a>(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> EvalResult<'tcx, &'tcx Allocation>;
/// Called for all binary operations except on float types.
///
/// Returns `None` if the operation should be handled by the integer
@ -91,13 +97,6 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx>;
/// Called when trying to access a global declared with a `linkage` attribute
fn global_item_with_linkage<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
mutability: Mutability,
) -> EvalResult<'tcx>;
/// Execute a validation operation
fn validation_op<'a>(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,

View File

@ -20,21 +20,16 @@ use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
use std::ptr;
use rustc::ty::Instance;
use rustc::ty::query::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
use rustc::mir::interpret::{Pointer, AllocId, Allocation, ScalarMaybeUndef,
use rustc::ty::{self, Instance, query::TyCtxtAt};
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
use rustc::mir::interpret::{Pointer, AllocId, Allocation, ScalarMaybeUndef, GlobalId,
EvalResult, Scalar, EvalErrorKind, AllocType, truncate};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
use syntax::ast::Mutability;
use super::{EvalContext, Machine, IsStatic, static_alloc};
////////////////////////////////////////////////////////////////////////////////
// Allocations and pointers
////////////////////////////////////////////////////////////////////////////////
use super::{Machine, IsStatic};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum MemoryKind<T> {
@ -53,10 +48,6 @@ impl<T: IsStatic> IsStatic for MemoryKind<T> {
}
}
////////////////////////////////////////////////////////////////////////////////
// Top-level interpreter memory
////////////////////////////////////////////////////////////////////////////////
#[derive(Clone)]
pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// Additional data required by the Machine
@ -70,6 +61,13 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
}
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,
'tcx: 'a + 'mir,
@ -122,6 +120,45 @@ impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
}
}
/// Helper function to obtain the global (tcx) allocation for a static
fn const_eval_static<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>>(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
id: AllocId
) -> EvalResult<'tcx, &'tcx Allocation> {
let alloc = tcx.alloc_map.lock().get(id);
let def_id = match alloc {
Some(AllocType::Memory(mem)) => {
return Ok(mem)
}
Some(AllocType::Function(..)) => {
return err!(DerefFunctionPointer)
}
Some(AllocType::Static(did)) => {
did
}
None =>
return err!(DanglingPointerDeref),
};
// We got a "lazy" static that has not been computed yet, do some work
trace!("static_alloc: Need to compute {:?}", def_id);
if tcx.is_foreign_item(def_id) {
return M::find_foreign_static(tcx, def_id);
}
let instance = Instance::mono(tcx.tcx, def_id);
let gid = GlobalId {
instance,
promoted: None,
};
tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
// no need to report anything, the const_eval call takes care of that for statics
assert!(tcx.is_static(def_id).is_some());
EvalErrorKind::ReferencedConstant(err).into()
}).map(|val| {
// FIXME We got our static (will be a ByRef), now we make a *copy*?!?
tcx.const_to_allocation(val)
})
}
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory {
@ -322,7 +359,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
Some(alloc) => Ok(&alloc.1),
// No need to make any copies, just provide read access to the global static
// memory in tcx.
None => static_alloc(self.tcx, id),
None => const_eval_static::<M>(self.tcx, id),
}
}
@ -588,7 +625,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
id: AllocId,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx> {
let alloc = static_alloc(self.tcx, id)?;
let alloc = const_eval_static::<M>(self.tcx, id)?;
if alloc.mutability == Mutability::Immutable {
return err!(ModifiedConstantMemory);
}
@ -980,49 +1017,3 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
Ok(())
}
}
////////////////////////////////////////////////////////////////////////////////
// Unaligned accesses
////////////////////////////////////////////////////////////////////////////////
pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M>;
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>;
}
impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>
{
#[inline]
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
self
}
#[inline]
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
self
}
}
impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>
{
#[inline]
fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
&mut self.memory
}
#[inline]
fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
&self.memory
}
}
impl<'a, 'mir, 'tcx, M> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>
{
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}

View File

@ -30,7 +30,7 @@ pub use self::eval_context::{
pub use self::place::{Place, PlaceExtra, PlaceTy, MemPlace, MPlaceTy};
pub use self::memory::{Memory, MemoryKind, HasMemory};
pub use self::memory::{Memory, MemoryKind};
pub use self::const_eval::{
eval_promoted,
@ -42,7 +42,6 @@ pub use self::const_eval::{
const_field,
const_variant_index,
op_to_const,
static_alloc,
};
pub use self::machine::{Machine, IsStatic};