Indirect(MemPlace<Tag, Id>),
}
-impl<Tag> Operand<Tag> {
- #[inline]
- pub fn assert_mem_place(self) -> MemPlace<Tag>
- where
- Tag: ::std::fmt::Debug,
- {
- match self {
- Operand::Indirect(mplace) => mplace,
- _ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self),
- }
- }
-
- #[inline]
- pub fn assert_immediate(self) -> Immediate<Tag>
- where
- Tag: ::std::fmt::Debug,
- {
- match self {
- Operand::Immediate(imm) => imm,
- _ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self),
- }
- }
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct OpTy<'tcx, Tag = ()> {
op: Operand<Tag>, // Keep this private; it helps enforce invariants.
&self,
op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- match op.try_as_mplace() {
+ match op.try_as_mplace(self) {
Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
Err(imm) => Ok(imm.into()), // Nothing to cast/force
}
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
- Ok(match src.try_as_mplace() {
+ Ok(match src.try_as_mplace(self) {
Ok(mplace) => {
if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
Ok(val)
op: OpTy<'tcx, M::PointerTag>,
field: u64,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- let base = match op.try_as_mplace() {
+ let base = match op.try_as_mplace(self) {
Ok(mplace) => {
// The easy case
let field = self.mplace_field(mplace, field)?;
variant: VariantIdx,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
- Ok(match op.try_as_mplace() {
+ Ok(match op.try_as_mplace(self) {
Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
Err(..) => {
let layout = op.layout.for_variant(self, variant);
Field(field, _) => self.operand_field(base, field.index() as u64)?,
Downcast(_, variant) => self.operand_downcast(base, variant)?,
Deref => self.deref_operand(base)?.into(),
- ConstantIndex { .. } | Index(_) if base.layout.is_zst() => {
- OpTy {
- op: Operand::Immediate(Scalar::zst().into()),
- // the actual index doesn't matter, so we just pick a convenient one like 0
- layout: base.layout.field(self, 0)?,
- }
- }
- Subslice { from, to, from_end } if base.layout.is_zst() => {
- let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind {
- elem_ty
- } else {
- bug!("slices shouldn't be zero-sized");
- };
- assert!(!from_end, "arrays shouldn't be subsliced from the end");
-
- OpTy {
- op: Operand::Immediate(Scalar::zst().into()),
- layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?,
- }
- }
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
// The rest should only occur as mplace, we do not use Immediates for types
// allowing such operations. This matches place_projection forcing an allocation.
- let mplace = base.assert_mem_place();
+ let mplace = base.assert_mem_place(self);
self.mplace_projection(mplace, proj_elem)?.into()
}
})
place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- use rustc::mir::PlaceBase;
-
- let base_op = match &place.base {
- PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer),
- PlaceBase::Local(local) => {
+ let base_op = match place.local {
+ mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer),
+ local => {
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
- // FIXME use place_projection.is_empty() when is available
let layout = if place.projection.is_empty() { layout } else { None };
- self.access_local(self.frame(), *local, layout)?
+ self.access_local(self.frame(), local, layout)?
}
- PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
};
let op = place
// Early-return cases.
let val_val = match val.val {
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
- ty::ConstKind::Unevaluated(def_id, substs) => {
+ ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
let instance = self.resolve(def_id, substs)?;
- return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None })?));
+ // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
+ // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
+ // validation, because validation automatically reads through any references, thus
+ // potentially requiring the current static to be evaluated again. This is not a
+ // problem here, because we are building an operand which means an actual read is
+ // happening.
+ return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?));
}
ty::ConstKind::Infer(..)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..) => {
bug!("eval_const_to_op: Unexpected ConstKind {:?}", val)
}
- ty::ConstKind::Value(val_val) => val_val,
+ ty::ConstKind::Value(val_val) => {
+ val_val
+ }
};
// Other cases need layout.
let layout = from_known_layout(layout, || self.layout_of(val.ty))?;
let variant_index = variants_start
.checked_add(variant_index_relative)
.expect("oveflow computing absolute variant idx");
- assert!(
- (variant_index as usize)
- < rval
- .layout
- .ty
- .ty_adt_def()
- .expect("tagged layout for non adt")
- .variants
- .len()
- );
+ let variants_len = rval
+ .layout
+ .ty
+ .ty_adt_def()
+ .expect("tagged layout for non adt")
+ .variants
+ .len();
+ assert!((variant_index as usize) < variants_len);
(u128::from(variant_index), VariantIdx::from_u32(variant_index))
} else {
(u128::from(dataful_variant.as_u32()), dataful_variant)