use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
use rustc::mir::interpret::{
- GlobalId, AllocId, InboundsCheck,
+ GlobalId, AllocId, CheckInAllocMsg,
ConstValue, Pointer, Scalar,
- EvalResult, InterpError,
+ EvalResult, InterpError, InboundsCheck,
sign_extend, truncate,
};
use super::{
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
}
- #[inline]
- pub fn erase_tag(self) -> Immediate
- {
- match self {
- Immediate::Scalar(x) => Immediate::Scalar(x.erase_tag()),
- Immediate::ScalarPair(x, y) =>
- Immediate::ScalarPair(x.erase_tag(), y.erase_tag()),
- }
- }
-
pub fn new_slice(
val: Scalar<Tag>,
len: u64,
}
impl<Tag> Operand<Tag> {
- #[inline]
- pub fn erase_tag(self) -> Operand
- {
- match self {
- Operand::Immediate(x) => Operand::Immediate(x.erase_tag()),
- Operand::Indirect(x) => Operand::Indirect(x.erase_tag()),
- }
- }
-
#[inline]
pub fn to_mem_place(self) -> MemPlace<Tag>
where Tag: ::std::fmt::Debug
}
}
-impl<'tcx, Tag> OpTy<'tcx, Tag>
-{
- #[inline]
- pub fn erase_tag(self) -> OpTy<'tcx>
- {
- OpTy {
- op: self.op.erase_tag(),
- layout: self.layout,
- }
- }
-}
-
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
#[inline(always)]
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
- /// Try reading an immediate in memory; this is interesting particularly for ScalarPair.
+ /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
/// Returns `None` if the layout does not permit loading this as a value.
fn try_read_immediate_from_mplace(
&self,
Ok(OpTy { op, layout })
}
- /// Every place can be read from, so we can turm them into an operand
+ /// Every place can be read from, so we can turn them into an operand
#[inline(always)]
pub fn place_to_op(
&self,
PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
PlaceBase::Local(local) => {
// FIXME use place_projection.is_empty() when is available
+ // Do not use the layout passed in as argument if the base we are looking at
+ // here is not the entire place.
let layout = if let Place::Base(_) = mir_place {
layout
} else {
}
/// Evaluate the operand, returning a place where you can then find the data.
- /// if you already know the layout, you can save two some table lookups
+ /// If you already know the layout, you can save two table lookups
/// by passing it in here.
pub fn eval_operand(
&self,
val: &'tcx ty::Const<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- let op = match val.val {
- ConstValue::Param(_) => return err!(TooGeneric),
- ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(),
- ConstValue::ByRef(ptr, alloc) => {
- // We rely on mutability being set correctly in that allocation to prevent writes
- // where none should happen -- and for `static mut`, we copy on demand anyway.
- Operand::Indirect(
- MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
- )
- },
- ConstValue::Slice { data, start, end } =>
- Operand::Immediate(Immediate::ScalarPair(
- Scalar::from(Pointer::new(
- self.tcx.alloc_map.lock().allocate(data),
- Size::from_bytes(start as u64),
- )).with_default_tag().into(),
- Scalar::from_uint(
- (end - start) as u64,
- self.tcx.data_layout.pointer_size,
- ).with_default_tag().into(),
- )),
- ConstValue::Scalar(x) =>
- Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
+ let tag_scalar = |scalar| match scalar {
+ Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)),
+ Scalar::Raw { data, size } => Scalar::Raw { data, size },
+ };
+ // Early-return cases.
+ match val.val {
+ ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize
ConstValue::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
return Ok(OpTy::from(self.const_eval_raw(GlobalId {
instance,
promoted: None,
})?));
- },
- };
+ }
+ _ => {}
+ }
+ // Other cases need layout.
let layout = from_known_layout(layout, || {
self.layout_of(self.monomorphize(val.ty)?)
})?;
- Ok(OpTy {
- op,
- layout,
- })
+ let op = match val.val {
+ ConstValue::ByRef(ptr, _alloc) => {
+ // We rely on mutability being set correctly in that allocation to prevent writes
+ // where none should happen.
+ let ptr = self.tag_static_base_pointer(ptr);
+ Operand::Indirect(MemPlace::from_ptr(ptr, layout.align.abi))
+ },
+ ConstValue::Scalar(x) =>
+ Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())),
+ ConstValue::Slice { data, start, end } => {
+ // We rely on mutability being set correctly in `data` to prevent writes
+ // where none should happen.
+ let ptr = Pointer::new(
+ self.tcx.alloc_map.lock().create_memory_alloc(data),
+ Size::from_bytes(start as u64), // offset: `start`
+ );
+ Operand::Immediate(Immediate::new_slice(
+ self.tag_static_base_pointer(ptr).into(),
+ (end - start) as u64, // len: `end - start`
+ self,
+ ))
+ }
+ ConstValue::Param(..) |
+ ConstValue::Infer(..) |
+ ConstValue::Placeholder(..) |
+ ConstValue::Unevaluated(..) =>
+ bug!("eval_const_to_op: Unexpected ConstValue {:?}", val),
+ };
+ Ok(OpTy { op, layout })
}
/// Read discriminant, return the runtime value as well as the variant index.
Err(ptr) => {
// The niche must be just 0 (which an inbounds pointer value never is)
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
- self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
+ self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead,
+ CheckInAllocMsg::NullPointerTest).is_ok();
if !ptr_valid {
return err!(InvalidDiscriminant(raw_discr.erase_tag().into()));
}