Value::ScalarPair(self.into(), Scalar::Ptr(vtable).into())
}
- pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
- match self {
- ScalarMaybeUndef::Scalar(scalar) => {
- scalar.ptr_signed_offset(i, cx).map(ScalarMaybeUndef::Scalar)
- },
- ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
- }
- }
-
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
match self {
ScalarMaybeUndef::Scalar(scalar) => {
ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
}
}
-
- pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
- match self {
- ScalarMaybeUndef::Scalar(scalar) => {
- ScalarMaybeUndef::Scalar(scalar.ptr_wrapping_signed_offset(i, cx))
- },
- ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef
- }
- }
}
impl<'tcx> Scalar {
use rustc::mir::interpret::{ConstEvalErr, ScalarMaybeUndef};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
-use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout};
+use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout, Size};
use rustc::ty::subst::Subst;
use rustc_data_structures::indexed_vec::IndexVec;
pub fn value_to_const_value<'tcx>(
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
val: Value,
- ty: Ty<'tcx>,
+ layout: TyLayout<'tcx>,
) -> &'tcx ty::Const<'tcx> {
- let layout = ecx.layout_of(ty).unwrap();
match (val, &layout.abi) {
(Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size: 0, ..})), _) if layout.is_zst() => {},
(Value::ByRef(..), _) |
}
})();
match val {
- Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty),
- Err(err) => {
- let (frames, span) = ecx.generate_stacktrace(None);
- let err = ConstEvalErr {
- span,
- error: err,
- stacktrace: frames,
- };
- err.report_as_error(
- ecx.tcx,
- "failed to convert Value to ConstValue, this is a bug",
- );
- span_bug!(span, "miri error occured when converting Value to ConstValue")
+ Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, layout.ty),
+ Err(error) => {
+ let (stacktrace, span) = ecx.generate_stacktrace(None);
+ let err = ConstEvalErr { span, error, stacktrace };
+ if let Some(mut err) = err.struct_error(ecx.tcx, "failed to convert Value to ConstValue") {
+ err.delay_as_bug();
+ } else {
+ span_bug!(span, "failed to convert Value to ConstValue")
+ }
+ let alloc = Allocation::undef(layout.size, layout.align);
+ let alloc = ecx.tcx.intern_const_alloc(alloc);
+ let val = ConstValue::ByRef(alloc, Size::ZERO);
+ ty::Const::from_const_value(ecx.tcx.tcx, val, layout.ty)
}
}
}
),
_ => {},
}
- Ok(value_to_const_value(&ecx, new_value, layout.ty))
+ Ok(value_to_const_value(&ecx, new_value, layout))
})();
result.map_err(|err| {
let (trace, span) = ecx.generate_stacktrace(None);
if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
val = ecx.try_read_by_ref(val, layout.ty)?;
}
- Ok(value_to_const_value(&ecx, val, layout.ty))
+ Ok(value_to_const_value(&ecx, val, layout))
}).map_err(|err| {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ConstEvalErr {
},
_ => false,
};
- self.memory.write_scalar(dest, dest_align, scalar, layout.size, signed)
+ self.memory.write_scalar(dest, dest_align, scalar, layout.size, layout.align, signed)
}
Value::ScalarPair(a_val, b_val) => {
trace!("write_value_to_ptr valpair: {:#?}", layout);
_ => bug!("write_value_to_ptr: invalid ScalarPair layout: {:#?}", layout)
};
let (a_size, b_size) = (a.size(&self), b.size(&self));
+ let (a_align, b_align) = (a.align(&self), b.align(&self));
let a_ptr = dest;
- let b_offset = a_size.abi_align(b.align(&self));
+ let b_offset = a_size.abi_align(b_align);
let b_ptr = dest.ptr_offset(b_offset, &self)?.into();
// TODO: What about signedess?
- self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, false)?;
- self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, false)
+ self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, a_align, false)?;
+ self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, b_align, false)
}
}
}
fn validate_scalar(
&self,
- value: Scalar,
+ value: ScalarMaybeUndef,
size: Size,
scalar: &layout::Scalar,
path: &str,
trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
let (lo, hi) = scalar.valid_range.clone().into_inner();
+ let value = match value {
+ ScalarMaybeUndef::Scalar(scalar) => scalar,
+ ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
+ };
+
let bits = match value {
Scalar::Bits { bits, size: value_size } => {
assert_eq!(value_size as u64, size.bytes());
if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
Ok(())
} else {
- validation_failure!("undefined bytes", path)
+ validation_failure!(
+ bits,
+ path,
+ format!("something in the range {:?} or {:?}", ..=hi, lo..)
+ )
}
} else {
if in_range(scalar.valid_range.clone()) {
Ok(())
} else {
- validation_failure!("undefined bytes", path)
+ validation_failure!(
+ bits,
+ path,
+ format!("something in the range {:?}", scalar.valid_range)
+ )
}
}
}
mir::Field::new(0),
layout,
)?;
- let tag_value = self.value_to_scalar(ValTy {
- value: tag_value,
- ty: tag_layout.ty,
- })?;
+ let tag_value = match self.follow_by_ref_value(tag_value, tag_layout.ty)? {
+ Value::Scalar(val) => val,
+ _ => bug!("tag must be scalar"),
+ };
let path = format!("{}.TAG", path);
self.validate_scalar(tag_value, size, tag, &path, tag_layout.ty)?;
let variant_index = self.read_discriminant_as_variant_index(
// expectation.
layout::Abi::Scalar(ref scalar) => {
let size = scalar.value.size(self);
- let value = self.memory.read_scalar(ptr, ptr_align, size)?.unwrap_or_err()?;
+ let value = self.memory.read_scalar(ptr, ptr_align, size)?;
self.validate_scalar(value, size, scalar, &path, layout.ty)?;
if scalar.value == Primitive::Pointer {
// ignore integer pointers, we can't reason about the final hardware
- if let Scalar::Ptr(ptr) = value {
+ if let Scalar::Ptr(ptr) = value.unwrap_or_err()? {
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(AllocType::Static(did)) = alloc_kind {
// statics from other crates are already checked
self.read_scalar(ptr, ptr_align, self.pointer_size())
}
- pub fn write_scalar(&mut self, ptr: Scalar, ptr_align: Align, val: ScalarMaybeUndef, type_size: Size, signed: bool) -> EvalResult<'tcx> {
+ pub fn write_scalar(
+ &mut self,
+ ptr: Scalar,
+ ptr_align: Align,
+ val: ScalarMaybeUndef,
+ type_size: Size,
+ type_align: Align,
+ signed: bool,
+ ) -> EvalResult<'tcx> {
let endianness = self.endianness();
let val = match val {
let ptr = ptr.to_ptr()?;
{
- let align = self.int_align(type_size);
- let dst = self.get_bytes_mut(ptr, type_size, ptr_align.min(align))?;
+ let dst = self.get_bytes_mut(ptr, type_size, ptr_align.min(type_align))?;
if signed {
write_target_int(endianness, dst, bytes as i128).unwrap();
} else {
pub fn write_ptr_sized_unsigned(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
- self.write_scalar(ptr.into(), ptr_align, val, ptr_size, false)
+ self.write_scalar(ptr.into(), ptr_align, val, ptr_size, ptr_align, false)
}
fn int_align(&self, size: Size) -> Align {
let (ptr, align, _extra) = self.to_ptr_align_extra();
(ptr, align)
}
-/*
+
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
// At this point, we forget about the alignment information -- the place has been turned into a reference,
// and no matter where it came from, it now must be aligned.
- self.to_ptr_align().0.to_ptr()
+ self.to_ptr_align().0.unwrap_or_err()?.to_ptr()
}
-*/
+
pub(super) fn elem_ty_and_len(
self,
ty: Ty<'tcx>,