message: &str,
lint_root: Option<hir::HirId>,
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
- use InvalidProgramInfo::*;
match self.error {
- InterpError::InvalidProgram(Layout(LayoutError::Unknown(_))) |
- InterpError::InvalidProgram(TooGeneric) =>
+ err_inval!(Layout(LayoutError::Unknown(_))) |
+ err_inval!(TooGeneric) =>
return Err(ErrorHandled::TooGeneric),
- InterpError::InvalidProgram(Layout(LayoutError::SizeOverflow(_))) |
- InterpError::InvalidProgram(TypeckError) =>
+ err_inval!(Layout(LayoutError::SizeOverflow(_))) |
+ err_inval!(TypeckError) =>
return Err(ErrorHandled::Reported),
_ => {},
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum ResourceExhaustionInfo {
+ /// The stack grew too big.
StackFrameLimitReached,
+ /// The program ran into an infinite loop.
InfiniteLoop,
}
#[macro_export]
macro_rules! throw_panic {
- ($($tt:tt)*) => {
- return Err($crate::mir::interpret::InterpError::Panic(
- $crate::mir::interpret::PanicInfo::$($tt)*
- ).into())
- };
+ ($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) };
}
#[macro_export]
macro_rules! throw_exhaust {
- ($($tt:tt)*) => {
- return Err($crate::mir::interpret::InterpError::ResourceExhaustion(
- $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
- ).into())
- };
+ ($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) };
}
#[macro_export]
};
}
+#[macro_export]
+macro_rules! err_exhaust {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::ResourceExhaustion(
+ $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
+ )
+ };
+}
+
+#[macro_export]
+macro_rules! err_panic {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::Panic(
+ $crate::mir::interpret::PanicInfo::$($tt)*
+ )
+ };
+}
+
mod error;
mod value;
mod allocation;
use crate::interpret::{self,
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar,
RawConst, ConstValue,
- InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpCx, StackPopCleanup,
+ InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
Allocation, AllocId, MemoryKind,
- snapshot, RefTracking, intern_const_alloc_recursive, UnsupportedOpInfo,
+ snapshot, RefTracking, intern_const_alloc_recursive,
};
/// Number of steps until the detector even starts doing anything.
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
fn into(self) -> InterpErrorInfo<'tcx> {
- InterpError::Unsupported(UnsupportedOpInfo::MachineError(self.to_string())).into()
+ err_unsup!(MachineError(self.to_string())).into()
}
}
Ok(Some(match ecx.load_mir(instance.def) {
Ok(body) => body,
Err(err) => {
- if let InterpError::Unsupported(UnsupportedOpInfo::NoMirFor(ref path)) = err.kind {
+ if let err_unsup!(NoMirFor(ref path)) = err.kind {
return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(),
// promoting runtime code is only allowed to error if it references broken constants
// any other kind of error will be reported to the user as a deny-by-default lint
_ => if let Some(p) = cid.promoted {
- use crate::interpret::InvalidProgramInfo::ReferencedConstant;
let span = tcx.promoted_mir(def_id)[p].span;
- if let InterpError::InvalidProgram(ReferencedConstant) = err.error {
+ if let err_inval!(ReferencedConstant) = err.error {
err.report_as_error(
tcx.at(span),
"evaluation of constant expression failed",
use rustc::mir::interpret::{
ErrorHandled,
GlobalId, Scalar, Pointer, FrameInfo, AllocId,
- InterpResult, InterpError,
- truncate, sign_extend, InvalidProgramInfo,
+ InterpResult, truncate, sign_extend,
};
use rustc_data_structures::fx::FxHashMap;
self.tcx
.layout_of(self.param_env.and(ty))
.map_err(|layout| {
- InterpError::InvalidProgram(InvalidProgramInfo::Layout(layout)).into()
+ err_inval!(Layout(layout)).into()
})
}
}
let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
match err {
ErrorHandled::Reported =>
- InterpError::InvalidProgram(InvalidProgramInfo::ReferencedConstant),
+ err_inval!(ReferencedConstant),
ErrorHandled::TooGeneric =>
- InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric),
+ err_inval!(TooGeneric),
}
})?;
self.raw_const_to_mplace(val)
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
-use rustc::mir::interpret::{
- InterpResult, ErrorHandled, UnsupportedOpInfo,
-};
+use rustc::mir::interpret::{InterpResult, ErrorHandled};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use syntax_pos::Span;
use super::{
- ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
+ ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
if let Err(error) = interned {
// This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
// to read enum discriminants in order to find references in enum variant fields.
- if let InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_)) = error.kind {
+ if let err_unsup!(ValidationFailure(_)) = error.kind {
let err = crate::const_eval::error_to_const_error(&ecx, error);
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
Ok(mut diag) => {
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
-use rustc::mir::interpret::{
- InterpResult, InterpError, Scalar, PanicInfo, UnsupportedOpInfo,
-};
+use rustc::mir::interpret::{InterpResult, Scalar};
use super::{
Machine, PlaceTy, OpTy, InterpCx, Immediate,
let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
let kind = match layout_of.abi {
ty::layout::Abi::Scalar(ref scalar) => scalar.value,
- _ => Err(InterpError::Unsupported(UnsupportedOpInfo::TypeNotPrimitive(ty)))?,
+ _ => Err(err_unsup!(TypeNotPrimitive(ty)))?,
};
let out_val = if intrinsic_name.ends_with("_nonzero") {
if bits == 0 {
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic(PanicInfo::Panic { msg, file, line, col }).into());
+ throw_panic!(Panic { msg, file, line, col })
} else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
assert!(args.len() == 2);
// &'static str, &(&'static str, u32, u32)
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
- return Err(InterpError::Panic(PanicInfo::Panic { msg, file, line, col }).into());
+ throw_panic!(Panic { msg, file, line, col })
} else {
return Ok(false);
}
use rustc::ty::{self, TyCtxt};
use super::{
- Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra,
- InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, UnsupportedOpInfo,
+ Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
+ InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
};
/// Whether this kind of memory is allowed to leak
int: u64,
) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
Err((if int == 0 {
- InterpError::Unsupported(UnsupportedOpInfo::InvalidNullPointerUsage)
+ err_unsup!(InvalidNullPointerUsage)
} else {
- InterpError::Unsupported(UnsupportedOpInfo::ReadBytesAsPointer)
+ err_unsup!(ReadBytesAsPointer)
}).into())
}
use super::{
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
- InterpResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic,
- Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, InvalidProgramInfo,
+ InterpResult, Scalar, GlobalAlloc, PointerArithmetic,
+ Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg,
};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
Some(alloc) => alloc,
None => {
// Deallocating static memory -- always an error
- match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
- Some(GlobalAlloc::Function(..)) => throw_unsup!(DeallocatedWrongMemoryKind(
+ return Err(match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
+ Some(GlobalAlloc::Function(..)) => err_unsup!(DeallocatedWrongMemoryKind(
"function".to_string(),
format!("{:?}", kind),
)),
- Some(GlobalAlloc::Static(..)) |
- Some(GlobalAlloc::Memory(..)) => throw_unsup!(DeallocatedWrongMemoryKind(
- "static".to_string(),
- format!("{:?}", kind),
- )),
- None => throw_unsup!(DoubleFree)
+ Some(GlobalAlloc::Static(..)) | Some(GlobalAlloc::Memory(..)) => err_unsup!(
+ DeallocatedWrongMemoryKind("static".to_string(), format!("{:?}", kind))
+ ),
+ None => err_unsup!(DoubleFree),
}
+ .into());
}
};
assert!(tcx.is_static(def_id));
match err {
ErrorHandled::Reported =>
- InterpError::InvalidProgram(
- InvalidProgramInfo::ReferencedConstant
- ),
+ err_inval!(ReferencedConstant),
ErrorHandled::TooGeneric =>
- InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric),
+ err_inval!(TooGeneric),
}
})?;
// Make sure we use the ID of the resolved memory, not the lazy one!
use rustc::mir::interpret::{
GlobalId, AllocId,
ConstValue, Pointer, Scalar,
- InterpResult, InterpError,
- sign_extend, truncate, UnsupportedOpInfo,
+ InterpResult, sign_extend, truncate,
};
use super::{
InterpCx, Machine,
let len = mplace.len(self)?;
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
let str = ::std::str::from_utf8(bytes).map_err(|err| {
- InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(err.to_string()))
+ err_unsup!(ValidationFailure(err.to_string()))
})?;
Ok(str)
}
let raw_discr = discr_val.to_scalar_or_undef();
trace!("discr value: {:?}", raw_discr);
// post-process
- use rustc::mir::interpret::UnsupportedOpInfo::InvalidDiscriminant;
Ok(match *discr_kind {
layout::DiscriminantKind::Tag => {
let bits_discr = match raw_discr.to_bits(discr_val.layout.size) {
let variants_start = niche_variants.start().as_u32() as u128;
let variants_end = niche_variants.end().as_u32() as u128;
let raw_discr = raw_discr.not_undef().map_err(|_| {
- InterpError::Unsupported(InvalidDiscriminant(ScalarMaybeUndef::Undef))
+ err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
})?;
match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
Err(ptr) => {
use rustc::mir;
use rustc::mir::interpret::{
AllocId, Pointer, Scalar,
- Relocations, Allocation, UndefMask,
- InterpResult, InterpError, ResourceExhaustionInfo,
+ Relocations, Allocation, UndefMask, InterpResult,
};
use rustc::ty::{self, TyCtxt};
}
// Second cycle
- Err(InterpError::ResourceExhaustion(ResourceExhaustionInfo::InfiniteLoop).into())
+ throw_exhaust!(InfiniteLoop)
}
}
} else {
// Compute error message
use rustc::mir::interpret::PanicInfo::*;
- match msg {
+ return Err(match msg {
BoundsCheck { ref len, ref index } => {
- let len = self.read_immediate(self.eval_operand(len, None)?)
- .expect("can't eval len").to_scalar()?
+ let len = self
+ .read_immediate(self.eval_operand(len, None)?)
+ .expect("can't eval len")
+ .to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- let index = self.read_immediate(self.eval_operand(index, None)?)
- .expect("can't eval index").to_scalar()?
+ let index = self
+ .read_immediate(self.eval_operand(index, None)?)
+ .expect("can't eval index")
+ .to_scalar()?
.to_bits(self.memory().pointer_size())? as u64;
- throw_panic!(BoundsCheck { len, index })
+ err_panic!(BoundsCheck { len, index })
}
- Overflow(op) =>
- throw_panic!(Overflow(*op)),
- OverflowNeg =>
- throw_panic!(OverflowNeg),
- DivisionByZero =>
- throw_panic!(DivisionByZero),
- RemainderByZero =>
- throw_panic!(RemainderByZero),
- GeneratorResumedAfterReturn =>
- throw_panic!(GeneratorResumedAfterReturn),
- GeneratorResumedAfterPanic =>
- throw_panic!(GeneratorResumedAfterPanic),
- Panic { .. } =>
- bug!("`Panic` variant cannot occur in MIR"),
- };
+ Overflow(op) => err_panic!(Overflow(*op)),
+ OverflowNeg => err_panic!(OverflowNeg),
+ DivisionByZero => err_panic!(DivisionByZero),
+ RemainderByZero => err_panic!(RemainderByZero),
+ GeneratorResumedAfterReturn => err_panic!(GeneratorResumedAfterReturn),
+ GeneratorResumedAfterPanic => err_panic!(GeneratorResumedAfterPanic),
+ Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
+ }
+ .into());
}
}
use std::hash::Hash;
use super::{
- GlobalAlloc, InterpResult, InterpError,
- OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, UnsupportedOpInfo,
+ GlobalAlloc, InterpResult,
+ OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
};
-macro_rules! validation_failure {
+macro_rules! throw_validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let where_ = path_format(&$where);
let where_ = if where_.is_empty() {
($e:expr, $what:expr, $where:expr, $details:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => validation_failure!($what, $where, $details),
+ Err(_) => throw_validation_failure!($what, $where, $details),
}
}};
($e:expr, $what:expr, $where:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => validation_failure!($what, $where),
+ Err(_) => throw_validation_failure!($what, $where),
}
}}
}
match self.walk_value(op) {
Ok(()) => Ok(()),
Err(err) => match err.kind {
- InterpError::Unsupported(UnsupportedOpInfo::InvalidDiscriminant(val)) =>
- validation_failure!(
+ err_unsup!(InvalidDiscriminant(val)) =>
+ throw_validation_failure!(
val, self.path, "a valid enum discriminant"
),
- InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes) =>
- validation_failure!(
+ err_unsup!(ReadPointerAsBytes) =>
+ throw_validation_failure!(
"a pointer", self.path, "plain (non-pointer) bytes"
),
_ => Err(err),
"{:?} did not pass access check for size {:?}, align {:?}",
ptr, size, align
);
- use super::UnsupportedOpInfo::*;
match err.kind {
- InterpError::Unsupported(InvalidNullPointerUsage) =>
- validation_failure!("NULL reference", self.path),
- InterpError::Unsupported(AlignmentCheckFailed { required, has }) =>
- validation_failure!(format!("unaligned reference \
+ err_unsup!(InvalidNullPointerUsage) =>
+ throw_validation_failure!("NULL reference", self.path),
+ err_unsup!(AlignmentCheckFailed { required, has }) =>
+ throw_validation_failure!(format!("unaligned reference \
(required {} byte alignment but found {})",
required.bytes(), has.bytes()), self.path),
- InterpError::Unsupported(ReadBytesAsPointer) =>
- validation_failure!(
+ err_unsup!(ReadBytesAsPointer) =>
+ throw_validation_failure!(
"dangling reference (created from integer)",
self.path
),
_ =>
- validation_failure!(
+ throw_validation_failure!(
"dangling reference (not entirely in bounds)",
self.path
),
fn visit_uninhabited(&mut self) -> InterpResult<'tcx>
{
- validation_failure!("a value of an uninhabited type", self.path)
+ throw_validation_failure!("a value of an uninhabited type", self.path)
}
fn visit_scalar(
if lo == 1 && hi == max_hi {
// Only NULL is the niche. So make sure the ptr is NOT NULL.
if self.ecx.memory.ptr_may_be_null(ptr) {
- validation_failure!(
+ throw_validation_failure!(
"a potentially NULL pointer",
self.path,
format!(
} else {
// Conservatively, we reject, because the pointer *could* have a bad
// value.
- validation_failure!(
+ throw_validation_failure!(
"a pointer",
self.path,
format!(
if wrapping_range_contains(&layout.valid_range, bits) {
Ok(())
} else {
- validation_failure!(
+ throw_validation_failure!(
bits,
self.path,
format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
Err(err) => {
// For some errors we might be able to provide extra information
match err.kind {
- InterpError::Unsupported(UnsupportedOpInfo::ReadUndefBytes(offset)) => {
+ err_unsup!(ReadUndefBytes(offset)) => {
// Some byte was undefined, determine which
// element that byte belongs to so we can
// provide an index.
let i = (offset.bytes() / ty_size.bytes()) as usize;
self.path.push(PathElem::ArrayElem(i));
- validation_failure!("undefined bytes", self.path)
+ throw_validation_failure!("undefined bytes", self.path)
},
// Other errors shouldn't be possible
_ => return Err(err),
use rustc::mir::visit::{
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
};
-use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, InterpError, PanicInfo};
+use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, PanicInfo};
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
)
} else {
if overflow {
- let err = InterpError::Panic(PanicInfo::Overflow(op)).into();
+ let err = err_panic!(Overflow(op)).into();
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}