diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 51b2d0272a597..ce04cca96e0f9 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -235,17 +235,17 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { { assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes()); let offset = ptr.offset.bytes() as usize; - match self.bytes[offset..].iter().position(|&c| c == 0) { + Ok(match self.bytes[offset..].iter().position(|&c| c == 0) { Some(size) => { let size_with_null = Size::from_bytes((size + 1) as u64); // Go through `get_bytes` for checks and AllocationExtra hooks. // We read the null, so we include it in the request, but we want it removed // from the result, so we do subslicing. - Ok(&self.get_bytes(cx, ptr, size_with_null)?[..size]) + &self.get_bytes(cx, ptr, size_with_null)?[..size] } // This includes the case where `offset` is out-of-bounds to begin with. - None => err!(UnterminatedCString(ptr.erase_tag())), - } + None => throw_unsup!(UnterminatedCString(ptr.erase_tag())), + }) } /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a @@ -446,7 +446,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { if self.relocations(cx, ptr, size).is_empty() { Ok(()) } else { - err!(ReadPointerAsBytes) + throw_unsup!(ReadPointerAsBytes) } } @@ -516,7 +516,7 @@ impl<'tcx, Tag, Extra> Allocation { self.undef_mask.is_range_defined( ptr.offset, ptr.offset + size, - ).or_else(|idx| err!(ReadUndefBytes(idx))) + ).or_else(|idx| throw_unsup!(ReadUndefBytes(idx))) } pub fn mark_definedness( diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 5309d5b039e9e..8d41b019c221a 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -138,10 +138,12 @@ impl<'tcx> ConstEvalErr<'tcx> { lint_root: Option, ) -> Result, ErrorHandled> { match self.error { - InterpError::Layout(LayoutError::Unknown(_)) | - InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric), - InterpError::Layout(LayoutError::SizeOverflow(_)) | - InterpError::TypeckError => return Err(ErrorHandled::Reported), + err_inval!(Layout(LayoutError::Unknown(_))) | + err_inval!(TooGeneric) => + return Err(ErrorHandled::TooGeneric), + err_inval!(Layout(LayoutError::SizeOverflow(_))) | + err_inval!(TypeckError) => + return Err(ErrorHandled::Reported), _ => {}, } trace!("reporting const eval failure at {:?}", self.span); @@ -181,8 +183,8 @@ pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<' /// Packages the kind of error we got from the const code interpreter /// up with a Rust-level backtrace of where the error occured. /// Thsese should always be constructed by calling `.into()` on -/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!` -/// macro for this. +/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*` +/// macros for this. #[derive(Debug, Clone)] pub struct InterpErrorInfo<'tcx> { pub kind: InterpError<'tcx>, @@ -234,7 +236,7 @@ impl<'tcx> From> for InterpErrorInfo<'tcx> { } #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum PanicMessage { +pub enum PanicInfo { Panic { msg: Symbol, line: u32, @@ -254,14 +256,14 @@ pub enum PanicMessage { } /// Type for MIR `Assert` terminator error messages. -pub type AssertMessage<'tcx> = PanicMessage>; +pub type AssertMessage<'tcx> = PanicInfo>; -impl PanicMessage { +impl PanicInfo { /// Getting a description does not require `O` to be printable, and does not /// require allocation. /// The caller is expected to handle `Panic` and `BoundsCheck` separately. pub fn description(&self) -> &'static str { - use PanicMessage::*; + use PanicInfo::*; match self { Overflow(mir::BinOp::Add) => "attempt to add with overflow", @@ -290,14 +292,14 @@ impl PanicMessage { GeneratorResumedAfterPanic => "generator resumed after panicking", Panic { .. } | BoundsCheck { .. } => - bug!("Unexpected PanicMessage"), + bug!("Unexpected PanicInfo"), } } } -impl fmt::Debug for PanicMessage { +impl fmt::Debug for PanicInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use PanicMessage::*; + use PanicInfo::*; match self { Panic { ref msg, line, col, ref file } => write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col), @@ -310,20 +312,64 @@ impl fmt::Debug for PanicMessage { } #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum InterpError<'tcx> { - /// This variant is used by machines to signal their own errors that do not - /// match an existing variant. - MachineError(String), +pub enum InvalidProgramInfo<'tcx> { + /// Resolution can fail if we are in a too generic context. + TooGeneric, + /// Cannot compute this constant because it depends on another one + /// which already produced an error. + ReferencedConstant, + /// Abort in case type errors are reached. + TypeckError, + /// An error occurred during layout computation. + Layout(layout::LayoutError<'tcx>), +} - /// Not actually an interpreter error -- used to signal that execution has exited - /// with the given status code. Used by Miri, but not by CTFE. - Exit(i32), +impl fmt::Debug for InvalidProgramInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InvalidProgramInfo::*; + match self { + TooGeneric => + write!(f, "encountered overly generic constant"), + ReferencedConstant => + write!(f, "referenced constant has errors"), + TypeckError => + write!(f, "encountered constants with type errors, stopping evaluation"), + Layout(ref err) => + write!(f, "rustc layout computation failed: {:?}", err), + } + } +} +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +pub enum UndefinedBehaviourInfo { + /// Handle cases which for which we do not have a fixed variant. + Ub(String), + /// Unreachable code was executed. + Unreachable, +} + +impl fmt::Debug for UndefinedBehaviourInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use UndefinedBehaviourInfo::*; + match self { + Ub(ref msg) => + write!(f, "{}", msg), + Unreachable => + write!(f, "entered unreachable code"), + } + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +pub enum UnsupportedOpInfo<'tcx> { + /// Handle cases which for which we do not have a fixed variant. + Unimplemented(String), + + // -- Everything below is not classified yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>), FunctionArgCountMismatch, - NoMirFor(String), UnterminatedCString(Pointer), DanglingPointerDeref, DoubleFree, @@ -344,12 +390,17 @@ pub enum InterpError<'tcx> { ReadUndefBytes(Size), DeadLocal, InvalidBoolOp(mir::BinOp), - Unimplemented(String), + InlineAsm, + UnimplementedTraitSelection, + CalledClosureAsFunction, + NoMirFor(String), + /// This variant is used by machines to signal their own errors that do not + /// match an existing variant. + MachineError(String), DerefFunctionPointer, ExecuteMemory, Intrinsic(String), InvalidChar(u128), - StackFrameLimitReached, OutOfTls, TlsOutOfBounds, AbiViolation(String), @@ -358,49 +409,26 @@ pub enum InterpError<'tcx> { has: Align, }, ValidationFailure(String), - CalledClosureAsFunction, VtableForArgumentlessMethod, ModifiedConstantMemory, ModifiedStatic, AssumptionNotHeld, - InlineAsm, TypeNotPrimitive(Ty<'tcx>), ReallocatedWrongMemoryKind(String, String), DeallocatedWrongMemoryKind(String, String), ReallocateNonBasePtr, DeallocateNonBasePtr, IncorrectAllocationInformation(Size, Size, Align, Align), - Layout(layout::LayoutError<'tcx>), HeapAllocZeroBytes, HeapAllocNonPowerOfTwoAlignment(u64), - Unreachable, - Panic(PanicMessage), ReadFromReturnPointer, PathNotFound(Vec), - UnimplementedTraitSelection, - /// Abort in case type errors are reached - TypeckError, - /// Resolution can fail if we are in a too generic context - TooGeneric, - /// Cannot compute this constant because it depends on another one - /// which already produced an error - ReferencedConstant, - InfiniteLoop, -} - -pub type InterpResult<'tcx, T = ()> = Result>; - -impl fmt::Display for InterpError<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Forward `Display` to `Debug` - write!(f, "{:?}", self) - } } -impl fmt::Debug for InterpError<'_> { +impl fmt::Debug for UnsupportedOpInfo<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InterpError::*; - match *self { + use UnsupportedOpInfo::*; + match self { PointerOutOfBounds { ptr, msg, allocation_size } => { write!(f, "{} failed: pointer must be in-bounds at offset {}, \ but is outside bounds of allocation {} which has size {}", @@ -434,8 +462,6 @@ impl fmt::Debug for InterpError<'_> { has.bytes(), required.bytes()), TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty), - Layout(ref err) => - write!(f, "rustc layout computation failed: {:?}", err), PathNotFound(ref path) => write!(f, "Cannot find path {:?}", path), IncorrectAllocationInformation(size, size2, align, align2) => @@ -444,8 +470,6 @@ impl fmt::Debug for InterpError<'_> { size.bytes(), align.bytes(), size2.bytes(), align2.bytes()), InvalidDiscriminant(val) => write!(f, "encountered invalid enum discriminant {}", val), - Exit(code) => - write!(f, "exited with status code {}", code), InvalidMemoryAccess => write!(f, "tried to access memory through an invalid pointer"), DanglingPointerDeref => @@ -474,8 +498,6 @@ impl fmt::Debug for InterpError<'_> { write!(f, "tried to dereference a function pointer"), ExecuteMemory => write!(f, "tried to treat a memory pointer as a function pointer"), - StackFrameLimitReached => - write!(f, "reached the configured maximum number of stack frames"), OutOfTls => write!(f, "reached the maximum number of representable TLS keys"), TlsOutOfBounds => @@ -501,21 +523,10 @@ impl fmt::Debug for InterpError<'_> { existing object"), HeapAllocZeroBytes => write!(f, "tried to re-, de- or allocate zero bytes on the heap"), - Unreachable => - write!(f, "entered unreachable code"), ReadFromReturnPointer => write!(f, "tried to read from the return pointer"), UnimplementedTraitSelection => write!(f, "there were unresolved type arguments during trait selection"), - TypeckError => - write!(f, "encountered constants with type errors, stopping evaluation"), - TooGeneric => - write!(f, "encountered overly generic constant"), - ReferencedConstant => - write!(f, "referenced constant has errors"), - InfiniteLoop => - write!(f, "duplicate interpreter state observed here, const evaluation will never \ - terminate"), InvalidBoolOp(_) => write!(f, "invalid boolean operation"), UnterminatedCString(_) => @@ -531,8 +542,75 @@ impl fmt::Debug for InterpError<'_> { AbiViolation(ref msg) | Intrinsic(ref msg) => write!(f, "{}", msg), + } + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +pub enum ResourceExhaustionInfo { + /// The stack grew too big. + StackFrameLimitReached, + /// The program ran into an infinite loop. + InfiniteLoop, +} + +impl fmt::Debug for ResourceExhaustionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ResourceExhaustionInfo::*; + match self { + StackFrameLimitReached => + write!(f, "reached the configured maximum number of stack frames"), + InfiniteLoop => + write!(f, "duplicate interpreter state observed here, const evaluation will never \ + terminate"), + } + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +pub enum InterpError<'tcx> { + /// The program panicked. + Panic(PanicInfo), + /// The program caused undefined behavior. + UndefinedBehaviour(UndefinedBehaviourInfo), + /// The program did something the interpreter does not support (some of these *might* be UB + /// but the interpreter is not sure). + Unsupported(UnsupportedOpInfo<'tcx>), + /// The program was invalid (ill-typed, not sufficiently monomorphized, ...). + InvalidProgram(InvalidProgramInfo<'tcx>), + /// The program exhausted the interpreter's resources (stack/heap too big, + /// execution takes too long, ..). + ResourceExhaustion(ResourceExhaustionInfo), + /// Not actually an interpreter error -- used to signal that execution has exited + /// with the given status code. Used by Miri, but not by CTFE. + Exit(i32), +} + +pub type InterpResult<'tcx, T = ()> = Result>; + +impl fmt::Display for InterpError<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Forward `Display` to `Debug` + write!(f, "{:?}", self) + } +} + +impl fmt::Debug for InterpError<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InterpError::*; + match *self { + Unsupported(ref msg) => + write!(f, "{:?}", msg), + InvalidProgram(ref msg) => + write!(f, "{:?}", msg), + UndefinedBehaviour(ref msg) => + write!(f, "{:?}", msg), + ResourceExhaustion(ref msg) => + write!(f, "{:?}", msg), Panic(ref msg) => write!(f, "{:?}", msg), + Exit(code) => + write!(f, "exited with status code {}", code), } } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 121b6ac0ac88c..723a30792fddc 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -1,8 +1,73 @@ //! An interpreter for MIR used in CTFE and by miri #[macro_export] -macro_rules! err { - ($($tt:tt)*) => { Err($crate::mir::interpret::InterpError::$($tt)*.into()) }; +macro_rules! err_unsup { + ($($tt:tt)*) => { + $crate::mir::interpret::InterpError::Unsupported( + $crate::mir::interpret::UnsupportedOpInfo::$($tt)* + ) + }; +} + +#[macro_export] +macro_rules! err_inval { + ($($tt:tt)*) => { + $crate::mir::interpret::InterpError::InvalidProgram( + $crate::mir::interpret::InvalidProgramInfo::$($tt)* + ) + }; +} + +#[macro_export] +macro_rules! err_ub { + ($($tt:tt)*) => { + $crate::mir::interpret::InterpError::UndefinedBehaviour( + $crate::mir::interpret::UndefinedBehaviourInfo::$($tt)* + ) + }; +} + +#[macro_export] +macro_rules! err_panic { + ($($tt:tt)*) => { + $crate::mir::interpret::InterpError::Panic( + $crate::mir::interpret::PanicInfo::$($tt)* + ) + }; +} + +#[macro_export] +macro_rules! err_exhaust { + ($($tt:tt)*) => { + $crate::mir::interpret::InterpError::ResourceExhaustion( + $crate::mir::interpret::ResourceExhaustionInfo::$($tt)* + ) + }; +} + +#[macro_export] +macro_rules! throw_unsup { + ($($tt:tt)*) => { return Err(err_unsup!($($tt)*).into()) }; +} + +#[macro_export] +macro_rules! throw_inval { + ($($tt:tt)*) => { return Err(err_inval!($($tt)*).into()) }; +} + +#[macro_export] +macro_rules! throw_ub { + ($($tt:tt)*) => { return Err(err_ub!($($tt)*).into()) }; +} + +#[macro_export] +macro_rules! throw_panic { + ($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) }; +} + +#[macro_export] +macro_rules! throw_exhaust { + ($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) }; } mod error; @@ -12,7 +77,8 @@ mod pointer; pub use self::error::{ InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error, - FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicMessage + FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, PanicInfo, UnsupportedOpInfo, + InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviourInfo, }; pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue}; diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 0e3b8459115e3..0a99851337994 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -4,9 +4,7 @@ use crate::mir; use crate::ty::layout::{self, HasDataLayout, Size}; use rustc_macros::HashStable; -use super::{ - AllocId, InterpResult, PanicMessage -}; +use super::{AllocId, InterpResult}; /// Used by `check_in_alloc` to indicate context of check #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] @@ -76,13 +74,13 @@ pub trait PointerArithmetic: layout::HasDataLayout { #[inline] fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> { let (res, over) = self.overflowing_offset(val, i); - if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) } + if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) } } #[inline] fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> { let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); - if over { err!(Panic(PanicMessage::Overflow(mir::BinOp::Add))) } else { Ok(res) } + if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) } } } @@ -198,11 +196,7 @@ impl<'tcx, Tag> Pointer { msg: CheckInAllocMsg, ) -> InterpResult<'tcx, ()> { if self.offset > allocation_size { - err!(PointerOutOfBounds { - ptr: self.erase_tag(), - msg, - allocation_size, - }) + throw_unsup!(PointerOutOfBounds { ptr: self.erase_tag(), msg, allocation_size }) } else { Ok(()) } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 4a59d845b3b42..607bcea7fe801 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -360,7 +360,7 @@ impl<'tcx, Tag> Scalar { Scalar::check_data(data, size); Ok(data) } - Scalar::Ptr(_) => err!(ReadPointerAsBytes), + Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), } } @@ -373,8 +373,8 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { match self { - Scalar::Raw { data: 0, .. } => err!(InvalidNullPointerUsage), - Scalar::Raw { .. } => err!(ReadBytesAsPointer), + Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage), + Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer), Scalar::Ptr(p) => Ok(p), } } @@ -406,7 +406,7 @@ impl<'tcx, Tag> Scalar { match self { Scalar::Raw { data: 0, size: 1 } => Ok(false), Scalar::Raw { data: 1, size: 1 } => Ok(true), - _ => err!(InvalidBool), + _ => throw_unsup!(InvalidBool), } } @@ -414,7 +414,7 @@ impl<'tcx, Tag> Scalar { let val = self.to_u32()?; match ::std::char::from_u32(val) { Some(c) => Ok(c), - None => err!(InvalidChar(val as u128)), + None => throw_unsup!(InvalidChar(val as u128)), } } @@ -537,7 +537,7 @@ impl<'tcx, Tag> ScalarMaybeUndef { pub fn not_undef(self) -> InterpResult<'static, Scalar> { match self { ScalarMaybeUndef::Scalar(scalar) => Ok(scalar), - ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))), + ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::from_bytes(0))), } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 50f16858c0486..1e2ec08301cf9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -7,7 +7,7 @@ use crate::hir::def::{CtorKind, Namespace}; use crate::hir::def_id::DefId; use crate::hir::{self, InlineAsm as HirInlineAsm}; -use crate::mir::interpret::{ConstValue, PanicMessage, Scalar}; +use crate::mir::interpret::{ConstValue, PanicInfo, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -3152,7 +3152,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } } Assert { ref cond, expected, ref msg, target, cleanup } => { - use PanicMessage::*; + use PanicInfo::*; let msg = match msg { BoundsCheck { ref len, ref index } => BoundsCheck { @@ -3200,7 +3200,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } Assert { ref cond, ref msg, .. } => { if cond.visit_with(visitor) { - use PanicMessage::*; + use PanicInfo::*; match msg { BoundsCheck { ref len, ref index } => len.visit_with(visitor) || index.visit_with(visitor), diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 7562981f94f61..ee4ecb6762c96 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -514,7 +514,7 @@ macro_rules! make_mir_visitor { fn super_assert_message(&mut self, msg: & $($mutability)? AssertMessage<'tcx>, location: Location) { - use crate::mir::interpret::PanicMessage::*; + use crate::mir::interpret::PanicInfo::*; match msg { BoundsCheck { len, index } => { self.visit_operand(len, location); diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 18611c3e167d2..006ebcbdec672 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -2,7 +2,7 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; -use rustc::mir::interpret::PanicMessage; +use rustc::mir::interpret::PanicInfo; use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; use rustc_target::spec::abi::Abi; use crate::base; @@ -368,7 +368,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked operation, just a comparison with the minimum // value, so we have to check for the assert message. if !bx.check_overflow() { - if let PanicMessage::OverflowNeg = *msg { + if let PanicInfo::OverflowNeg = *msg { const_cond = Some(expected); } } @@ -403,7 +403,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match msg { - PanicMessage::BoundsCheck { ref len, ref index } => { + PanicInfo::BoundsCheck { ref len, ref index } => { let len = self.codegen_operand(&mut bx, len).immediate(); let index = self.codegen_operand(&mut bx, index).immediate(); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 92774bbb7a6b4..2be39799b5273 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -733,8 +733,8 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx cleanup: _, } => { self.consume_operand(loc, (cond, span), flow_state); - use rustc::mir::interpret::PanicMessage; - if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { + use rustc::mir::interpret::PanicInfo; + if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(loc, (len, span), flow_state); self.consume_operand(loc, (index, span), flow_state); } diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index aa9e68bd7de44..631a81421131c 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -207,8 +207,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { cleanup: _, } => { self.consume_operand(location, cond); - use rustc::mir::interpret::PanicMessage; - if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { + use rustc::mir::interpret::PanicInfo; + if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(location, len); self.consume_operand(location, index); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 50c0640f885f2..f10d505fe8983 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -26,7 +26,7 @@ use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::mir::interpret::{ConstValue, PanicMessage}; +use rustc::mir::interpret::{ConstValue, PanicInfo}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext}; use rustc::mir::*; @@ -1632,7 +1632,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } - if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { + if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { if len.ty(body, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 7a428a2ec9f36..7005f274e0e7d 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -4,7 +4,7 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; -use rustc::mir::interpret::{PanicMessage::BoundsCheck}; +use rustc::mir::interpret::{PanicInfo::BoundsCheck}; use rustc::mir::*; use rustc::ty::{CanonicalUserTypeAnnotation, Variance}; diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 92daf06e6f8fe..ec061e7453577 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -7,7 +7,7 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::PanicMessage; +use rustc::mir::interpret::PanicInfo; use rustc::mir::*; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts}; use syntax_pos::Span; @@ -101,7 +101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Operand::Move(is_min), false, - PanicMessage::OverflowNeg, + PanicInfo::OverflowNeg, expr_span, ); } @@ -401,7 +401,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val = result_value.clone().field(val_fld, ty); let of = result_value.field(of_fld, bool_ty); - let err = PanicMessage::Overflow(op); + let err = PanicInfo::Overflow(op); block = self.assert(block, Operand::Move(of), false, err, span); @@ -412,11 +412,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // and 2. there are two possible failure cases, divide-by-zero and overflow. let zero_err = if op == BinOp::Div { - PanicMessage::DivisionByZero + PanicInfo::DivisionByZero } else { - PanicMessage::RemainderByZero + PanicInfo::RemainderByZero }; - let overflow_err = PanicMessage::Overflow(op); + let overflow_err = PanicInfo::Overflow(op); // Check for / 0 let is_zero = self.temp(bool_ty, span); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 37d4c5b2f09ce..1b92e4992ffb1 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -22,7 +22,7 @@ use syntax::source_map::{Span, DUMMY_SP}; 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, }; @@ -183,7 +183,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( impl<'tcx> Into> for ConstEvalError { fn into(self) -> InterpErrorInfo<'tcx> { - InterpError::MachineError(self.to_string()).into() + err_unsup!(MachineError(self.to_string())).into() } } @@ -352,7 +352,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx.goto_block(ret)?; // fully evaluated and done Ok(None) } else { - err!(MachineError(format!("calling non-const function `{}`", instance))) + throw_unsup!(MachineError(format!("calling non-const function `{}`", instance))) }; } } @@ -360,7 +360,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Ok(Some(match ecx.load_mir(instance.def) { Ok(body) => body, Err(err) => { - if let InterpError::NoMirFor(ref path) = err.kind { + if let err_unsup!(NoMirFor(ref path)) = err.kind { return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -412,7 +412,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _tcx: TyCtxt<'tcx>, _def_id: DefId, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - err!(ReadForeignStatic) + throw_unsup!(ReadForeignStatic) } #[inline(always)] @@ -698,7 +698,7 @@ pub fn const_eval_raw_provider<'tcx>( // any other kind of error will be reported to the user as a deny-by-default lint _ => if let Some(p) = cid.promoted { let span = tcx.promoted_mir(def_id)[p].span; - if let InterpError::ReferencedConstant = err.error { + if let err_inval!(ReferencedConstant) = err.error { err.report_as_error( tcx.at(span), "evaluation of constant expression failed", diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 980697360eb75..a481a3b37b717 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -7,7 +7,7 @@ use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::{Float, FloatConvert}; use rustc::mir::interpret::{ - Scalar, InterpResult, Pointer, PointerArithmetic, InterpError, + Scalar, InterpResult, Pointer, PointerArithmetic, }; use rustc::mir::CastKind; @@ -80,13 +80,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if self.tcx.has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); } - let instance: InterpResult<'tcx, _> = ty::Instance::resolve( + let instance = ty::Instance::resolve( *self.tcx, self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric.into()); - let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance?)); + ).ok_or_else(|| err_inval!(TooGeneric))?; + let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; } _ => bug!("reify fn pointer on {:?}", src.layout.ty), @@ -199,7 +199,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }, // Casts to bool are not permitted by rustc, no need to handle them here. - _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))), + _ => throw_unsup!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))), } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 007ec8cb2db5c..f10d7fb965116 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -16,8 +16,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use rustc::mir::interpret::{ ErrorHandled, GlobalId, Scalar, Pointer, FrameInfo, AllocId, - InterpResult, InterpError, - truncate, sign_extend, + InterpResult, truncate, sign_extend, }; use rustc_data_structures::fx::FxHashMap; @@ -135,7 +134,7 @@ pub enum LocalValue { impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { pub fn access(&self) -> InterpResult<'tcx, Operand> { match self.value { - LocalValue::Dead => err!(DeadLocal), + LocalValue::Dead => throw_unsup!(DeadLocal), LocalValue::Uninitialized => bug!("The type checker should prevent reading from a never-written local"), LocalValue::Live(val) => Ok(val), @@ -148,7 +147,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { &mut self, ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { match self.value { - LocalValue::Dead => err!(DeadLocal), + LocalValue::Dead => throw_unsup!(DeadLocal), LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), ref mut local @ LocalValue::Live(Operand::Immediate(_)) | ref mut local @ LocalValue::Uninitialized => { @@ -190,8 +189,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { #[inline] fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { - self.tcx.layout_of(self.param_env.and(ty)) - .map_err(|layout| InterpError::Layout(layout).into()) + self.tcx + .layout_of(self.param_env.and(ty)) + .map_err(|layout| err_inval!(Layout(layout)).into()) } } @@ -302,7 +302,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &substs, )), None => if substs.needs_subst() { - err!(TooGeneric).into() + throw_inval!(TooGeneric) } else { Ok(substs) }, @@ -323,7 +323,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric.into()) + ).ok_or_else(|| err_inval!(TooGeneric).into()) } pub fn load_mir( @@ -336,14 +336,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors { - return err!(TypeckError); + throw_inval!(TypeckError) } trace!("load mir {:?}", instance); match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) } else { - err!(NoMirFor(self.tcx.def_path_str(def_id))) + throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id))) }, _ => Ok(self.tcx.instance_mir(instance)), } @@ -356,7 +356,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match self.stack.last() { Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), None => if t.needs_subst() { - err!(TooGeneric).into() + throw_inval!(TooGeneric) } else { Ok(t) }, @@ -373,7 +373,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let substituted = t.subst(*self.tcx, substs); if substituted.needs_subst() { - return err!(TooGeneric); + throw_inval!(TooGeneric) } Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) @@ -572,7 +572,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit { - err!(StackFrameLimitReached) + throw_exhaust!(StackFrameLimitReached) } else { Ok(()) } @@ -620,7 +620,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } else { // Uh, that shouldn't happen... the function did not intend to return - return err!(Unreachable); + throw_ub!(Unreachable) } // Jump to new block -- *after* validation so that the spans make more sense. match frame.return_to_block { @@ -694,8 +694,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| { match err { - ErrorHandled::Reported => InterpError::ReferencedConstant, - ErrorHandled::TooGeneric => InterpError::TooGeneric, + ErrorHandled::Reported => + err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => + err_inval!(TooGeneric), } })?; self.raw_const_to_mplace(val) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index bcd36ac547c73..e9bba7889119a 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -4,9 +4,7 @@ //! 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, -}; +use rustc::mir::interpret::{InterpResult, ErrorHandled}; use rustc::hir; use rustc::hir::def_id::DefId; use super::validity::RefTracking; @@ -16,7 +14,7 @@ use syntax::ast::Mutability; 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}; @@ -293,7 +291,7 @@ pub fn intern_const_alloc_recursive( 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::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) => { @@ -328,9 +326,7 @@ pub fn intern_const_alloc_recursive( } } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) { // dangling pointer - return err!(ValidationFailure( - "encountered dangling pointer in final constant".into(), - )) + throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into())) } } Ok(()) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 6a5b933e4a530..97866adcfa333 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -6,9 +6,7 @@ use syntax::symbol::Symbol; use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; use rustc::mir::BinOp; -use rustc::mir::interpret::{ - InterpResult, InterpError, Scalar, PanicMessage, -}; +use rustc::mir::interpret::{InterpResult, Scalar}; use super::{ Machine, PlaceTy, OpTy, InterpCx, Immediate, @@ -100,11 +98,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?, + _ => Err(err_unsup!(TypeNotPrimitive(ty)))?, }; let out_val = if intrinsic_name.ends_with("_nonzero") { if bits == 0 { - return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); + throw_unsup!(Intrinsic(format!("{} called on 0", intrinsic_name))) } numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)? } else { @@ -190,9 +188,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflowed { let layout = self.layout_of(substs.type_at(0))?; let r_val = r.to_scalar()?.to_bits(layout.size)?; - return err!(Intrinsic( - format!("Overflowing shift by {} in {}", r_val, intrinsic_name), - )); + throw_unsup!( + Intrinsic(format!("Overflowing shift by {} in {}", r_val, intrinsic_name)) + ) } self.write_scalar(val, dest)?; } @@ -250,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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(PanicMessage::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) @@ -268,7 +266,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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(PanicMessage::Panic { msg, file, line, col }).into()); + throw_panic!(Panic { msg, file, line, col }) } else { return Ok(false); } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index e3f16a3c9ea45..78902b1016634 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -10,7 +10,7 @@ use rustc::mir; use rustc::ty::{self, TyCtxt}; use super::{ - Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra, + Allocation, AllocId, InterpResult, Scalar, AllocationExtra, InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, }; @@ -240,9 +240,9 @@ pub trait Machine<'mir, 'tcx>: Sized { int: u64, ) -> InterpResult<'tcx, Pointer> { Err((if int == 0 { - InterpError::InvalidNullPointerUsage + err_unsup!(InvalidNullPointerUsage) } else { - InterpError::ReadBytesAsPointer + err_unsup!(ReadBytesAsPointer) }).into()) } @@ -251,6 +251,6 @@ pub trait Machine<'mir, 'tcx>: Sized { _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, ) -> InterpResult<'tcx, u64> { - err!(ReadPointerAsBytes) + throw_unsup!(ReadPointerAsBytes) } } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 87dd7738410ee..a1574cd5935e9 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -18,7 +18,7 @@ use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, - InterpResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic, + InterpResult, Scalar, GlobalAlloc, PointerArithmetic, Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, }; @@ -66,10 +66,9 @@ impl<'tcx, Other> FnVal<'tcx, Other> { match self { FnVal::Instance(instance) => Ok(instance), - FnVal::Other(_) => - err!(MachineError( - format!("Expected instance function pointer, got 'other' pointer") - )), + FnVal::Other(_) => throw_unsup!(MachineError(format!( + "Expected instance function pointer, got 'other' pointer" + ))), } } } @@ -203,7 +202,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { kind: MemoryKind, ) -> InterpResult<'tcx, Pointer> { if ptr.offset.bytes() != 0 { - return err!(ReallocateNonBasePtr); + throw_unsup!(ReallocateNonBasePtr) } // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". @@ -244,41 +243,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { trace!("deallocating: {}", ptr.alloc_id); if ptr.offset.bytes() != 0 { - return err!(DeallocateNonBasePtr); + throw_unsup!(DeallocateNonBasePtr) } let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) { Some(alloc) => alloc, None => { // Deallocating static memory -- always an error - return match self.tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err!(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(..)) => err!(DeallocatedWrongMemoryKind( - "static".to_string(), - format!("{:?}", kind), - )), - None => err!(DoubleFree) + Some(GlobalAlloc::Static(..)) | Some(GlobalAlloc::Memory(..)) => err_unsup!( + DeallocatedWrongMemoryKind("static".to_string(), format!("{:?}", kind)) + ), + None => err_unsup!(DoubleFree), } + .into()); } }; if alloc_kind != kind { - return err!(DeallocatedWrongMemoryKind( + throw_unsup!(DeallocatedWrongMemoryKind( format!("{:?}", alloc_kind), format!("{:?}", kind), - )); + )) } if let Some((size, align)) = old_size_and_align { if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align { let bytes = Size::from_bytes(alloc.bytes.len() as u64); - return err!(IncorrectAllocationInformation(size, - bytes, - align, - alloc.align)); + throw_unsup!(IncorrectAllocationInformation(size, bytes, align, alloc.align)) } } @@ -323,7 +318,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } else { // The biggest power of two through which `offset` is divisible. let offset_pow2 = 1 << offset.trailing_zeros(); - err!(AlignmentCheckFailed { + throw_unsup!(AlignmentCheckFailed { has: Align::from_bytes(offset_pow2).unwrap(), required: align, }) @@ -345,7 +340,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { assert!(size.bytes() == 0); // Must be non-NULL and aligned. if bits == 0 { - return err!(InvalidNullPointerUsage); + throw_unsup!(InvalidNullPointerUsage) } check_offset_align(bits, align)?; None @@ -366,10 +361,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // got picked we might be aligned even if this check fails. // We instead have to fall back to converting to an integer and checking // the "real" alignment. - return err!(AlignmentCheckFailed { + throw_unsup!(AlignmentCheckFailed { has: alloc_align, required: align, - }); + }) } check_offset_align(ptr.offset.bytes(), align)?; @@ -417,9 +412,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(GlobalAlloc::Memory(mem)) => Cow::Borrowed(mem), Some(GlobalAlloc::Function(..)) => - return err!(DerefFunctionPointer), + throw_unsup!(DerefFunctionPointer), None => - return err!(DanglingPointerDeref), + throw_unsup!(DanglingPointerDeref), Some(GlobalAlloc::Static(def_id)) => { // We got a "lazy" static that has not been computed yet. if tcx.is_foreign_item(def_id) { @@ -440,8 +435,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // for statics assert!(tcx.is_static(def_id)); match err { - ErrorHandled::Reported => InterpError::ReferencedConstant, - ErrorHandled::TooGeneric => InterpError::TooGeneric, + ErrorHandled::Reported => + err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => + err_inval!(TooGeneric), } })?; // Make sure we use the ID of the resolved memory, not the lazy one! @@ -505,11 +502,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // to give us a cheap reference. let alloc = Self::get_static_alloc(memory_extra, tcx, id)?; if alloc.mutability == Mutability::Immutable { - return err!(ModifiedConstantMemory); + throw_unsup!(ModifiedConstantMemory) } match M::STATIC_KIND { Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())), - None => err!(ModifiedStatic), + None => throw_unsup!(ModifiedStatic), } }); // Unpack the error type manually because type inference doesn't @@ -519,7 +516,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Ok(a) => { let a = &mut a.1; if a.mutability == Mutability::Immutable { - return err!(ModifiedConstantMemory); + throw_unsup!(ModifiedConstantMemory) } Ok(a) } @@ -548,7 +545,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if let Ok(_) = self.get_fn_alloc(id) { return if let AllocCheck::Dereferencable = liveness { // The caller requested no function pointers. - err!(DerefFunctionPointer) + throw_unsup!(DerefFunctionPointer) } else { Ok((Size::ZERO, Align::from_bytes(1).unwrap())) }; @@ -579,7 +576,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { .expect("deallocated pointers should all be recorded in \ `dead_alloc_map`")) } else { - err!(DanglingPointerDeref) + throw_unsup!(DanglingPointerDeref) }, } } @@ -591,7 +588,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } else { match self.tcx.alloc_map.lock().get(id) { Some(GlobalAlloc::Function(instance)) => Ok(FnVal::Instance(instance)), - _ => Err(InterpError::ExecuteMemory.into()), + _ => throw_unsup!(ExecuteMemory), } } } @@ -602,7 +599,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { let ptr = self.force_ptr(ptr)?; // We definitely need a pointer value. if ptr.offset.bytes() != 0 { - return err!(InvalidFunctionPointer); + throw_unsup!(InvalidFunctionPointer) } self.get_fn_alloc(ptr.alloc_id) } @@ -837,9 +834,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if (src.offset <= dest.offset && src.offset + size > dest.offset) || (dest.offset <= src.offset && dest.offset + size > src.offset) { - return err!(Intrinsic( + throw_unsup!(Intrinsic( "copy_nonoverlapping called on overlapping ranges".to_string(), - )); + )) } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 1816171d7b127..e64a474b4ca71 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,8 +11,7 @@ use rustc::ty::layout::{ use rustc::mir::interpret::{ GlobalId, AllocId, ConstValue, Pointer, Scalar, - InterpResult, InterpError, - sign_extend, truncate, + InterpResult, sign_extend, truncate, }; use super::{ InterpCx, Machine, @@ -331,8 +330,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, &str> { 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::ValidationFailure(err.to_string()))?; + let str = ::std::str::from_utf8(bytes).map_err(|err| { + err_unsup!(ValidationFailure(err.to_string())) + })?; Ok(str) } @@ -459,7 +459,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { mir_place.iterate(|place_base, place_projection| { let mut op = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), + PlaceBase::Local(mir::RETURN_PLACE) => + throw_unsup!(ReadFromReturnPointer), PlaceBase::Local(local) => { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. @@ -530,7 +531,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. match val.val { - ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize + ConstValue::Param(_) => + // FIXME(oli-obk): try to monomorphize + throw_inval!(TooGeneric), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(OpTy::from(self.const_eval_raw(GlobalId { @@ -604,7 +607,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout::DiscriminantKind::Tag => { let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { Ok(raw_discr) => raw_discr, - Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())), + Err(_) => + throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag())), }; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type @@ -630,7 +634,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .discriminants(*def_id, self.tcx.tcx) .find(|(_, var)| var.val == real_discr), _ => bug!("tagged layout for non-adt non-generator"), - }.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?; + }.ok_or_else( + || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())) + )?; (real_discr, index.0) }, layout::DiscriminantKind::Niche { @@ -640,15 +646,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } => { 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::InvalidDiscriminant(ScalarMaybeUndef::Undef))?; + let raw_discr = raw_discr.not_undef().map_err(|_| { + err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef)) + })?; match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { 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.ptr_may_be_null(ptr); if !ptr_valid { - return err!(InvalidDiscriminant(raw_discr.erase_tag().into())); + throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag().into())) } (dataful_variant.as_u32() as u128, dataful_variant) }, diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index b4edee72a4d19..a942da5771b00 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::ty::{self, layout::TyLayout}; use syntax::ast::FloatTy; use rustc_apfloat::Float; -use rustc::mir::interpret::{InterpResult, PanicMessage, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar}; use super::{InterpCx, PlaceTy, Immediate, Machine, ImmTy}; @@ -155,7 +155,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r, right_layout.ty ); - return err!(Unimplemented(msg)); + throw_unsup!(Unimplemented(msg)) } // Operations that need special treatment for signed integers @@ -173,8 +173,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok((Scalar::from_bool(op(&l, &r)), false)); } let op: Option (i128, bool)> = match bin_op { - Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)), - Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)), + Div if r == 0 => throw_panic!(DivisionByZero), + Rem if r == 0 => throw_panic!(RemainderByZero), Div => Some(i128::overflowing_div), Rem => Some(i128::overflowing_rem), Add => Some(i128::overflowing_add), @@ -231,8 +231,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Add => u128::overflowing_add, Sub => u128::overflowing_sub, Mul => u128::overflowing_mul, - Div if r == 0 => return err!(Panic(PanicMessage::DivisionByZero)), - Rem if r == 0 => return err!(Panic(PanicMessage::RemainderByZero)), + Div if r == 0 => throw_panic!(DivisionByZero), + Rem if r == 0 => throw_panic!(RemainderByZero), Div => u128::overflowing_div, Rem => u128::overflowing_rem, _ => bug!(), @@ -250,7 +250,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r, right_layout.ty, ); - return err!(Unimplemented(msg)); + throw_unsup!(Unimplemented(msg)) } }; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8fe882934dfb5..f66c4adf76397 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -13,8 +13,8 @@ use rustc::ty::TypeFoldable; use super::{ GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic, - InterpCx, Machine, AllocMap, AllocationExtra, PanicMessage, - RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue + InterpCx, Machine, AllocMap, AllocationExtra, + RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -356,7 +356,7 @@ where // This can be violated because this runs during promotion on code where the // type system has not yet ensured that such things don't happen. debug!("tried to access element {} of array/slice with length {}", field, len); - return err!(Panic(PanicMessage::BoundsCheck { len, index: field })); + throw_panic!(BoundsCheck { len, index: field }); } stride * field } @@ -622,7 +622,7 @@ where .layout_of(self.monomorphize(self.frame().body.return_ty())?)?, } } - None => return err!(InvalidNullPointerUsage), + None => throw_unsup!(InvalidNullPointerUsage), }, PlaceBase::Local(local) => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index ad631793a0827..70a297c866280 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -11,8 +11,7 @@ use rustc::ich::StableHashingContextProvider; use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, - Relocations, Allocation, UndefMask, - InterpResult, InterpError, + Relocations, Allocation, UndefMask, InterpResult, }; use rustc::ty::{self, TyCtxt}; @@ -77,7 +76,7 @@ impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> { } // Second cycle - Err(InterpError::InfiniteLoop.into()) + throw_exhaust!(InfiniteLoop) } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 246c90ba48e3a..95824d0ebc166 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -121,7 +121,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // size of MIR constantly. Nop => {} - InlineAsm { .. } => return err!(InlineAsm), + InlineAsm { .. } => throw_unsup!(InlineAsm), } self.stack[frame_idx].stmt += 1; diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 27bd0f8889634..d4bc8f460e894 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - InterpResult, PointerArithmetic, InterpError, Scalar, + InterpResult, PointerArithmetic, Scalar, InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; @@ -19,7 +19,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.frame_mut().stmt = 0; Ok(()) } else { - err!(Unreachable) + throw_ub!(Unreachable) } } @@ -89,7 +89,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }, _ => { let msg = format!("can't handle callee of type {:?}", func.layout.ty); - return err!(Unimplemented(msg)); + throw_unsup!(Unimplemented(msg)) } }; let args = self.eval_operands(args)?; @@ -135,32 +135,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.goto_block(Some(target))?; } else { // Compute error message - use rustc::mir::interpret::PanicMessage::*; - return match msg { + use rustc::mir::interpret::PanicInfo::*; + 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; - err!(Panic(BoundsCheck { len, index })) + err_panic!(BoundsCheck { len, index }) } - 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"), - }; + 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()); } } @@ -173,7 +171,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { `simplify_branches` mir pass"), FalseUnwind { .. } => bug!("should have been eliminated by\ `simplify_branches` mir pass"), - Unreachable => return err!(Unreachable), + Unreachable => throw_ub!(Unreachable), } Ok(()) @@ -220,13 +218,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(()); } let caller_arg = caller_arg.next() - .ok_or_else(|| InterpError::FunctionArgCountMismatch)?; + .ok_or_else(|| err_unsup!(FunctionArgCountMismatch)) ?; if rust_abi { debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } // Now, check if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { - return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)); + throw_unsup!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)) } // We allow some transmutes here self.copy_op_transmute(caller_arg, callee_arg) @@ -254,13 +252,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(..) => { if caller_abi != Abi::RustIntrinsic { - return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic)); + throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic)) } // The intrinsic itself cannot diverge, so if we got here without a return // place... (can happen e.g., for transmute returning `!`) let dest = match dest { Some(dest) => dest, - None => return err!(Unreachable) + None => throw_ub!(Unreachable) }; M::call_intrinsic(self, instance, args, dest)?; // No stack frame gets pushed, the main loop will just act as if the @@ -295,7 +293,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { abi, }; if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - return err!(FunctionAbiMismatch(caller_abi, callee_abi)); + throw_unsup!(FunctionAbiMismatch(caller_abi, callee_abi)) } } @@ -390,7 +388,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Now we should have no more caller args if caller_iter.next().is_some() { trace!("Caller has passed too many args"); - return err!(FunctionArgCountMismatch); + throw_unsup!(FunctionArgCountMismatch) } // Don't forget to check the return type! if let Some(caller_ret) = dest { @@ -402,15 +400,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_ret.layout, callee_ret.layout, ) { - return err!(FunctionRetMismatch( - caller_ret.layout.ty, callee_ret.layout.ty - )); + throw_unsup!( + FunctionRetMismatch(caller_ret.layout.ty, callee_ret.layout.ty) + ) } } else { let local = mir::RETURN_PLACE; let ty = self.frame().body.local_decls[local].ty; if !self.tcx.is_ty_uninhabited_from_any_module(ty) { - return err!(FunctionRetMismatch(self.tcx.types.never, ty)); + throw_unsup!(FunctionRetMismatch(self.tcx.types.never, ty)) } } Ok(()) diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index e7363f6876c28..e55b0d0fb1f2a 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,8 +1,8 @@ use rustc::ty::{self, Ty, Instance}; use rustc::ty::layout::{Size, Align, LayoutOf}; -use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic}; +use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,}; -use super::{InterpCx, InterpError, Machine, MemoryKind, FnVal}; +use super::{InterpCx, Machine, MemoryKind, FnVal}; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -83,7 +83,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, def_id, substs, - ).ok_or_else(|| InterpError::TooGeneric)?; + ).ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?; self.memory diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index da9780ac0a305..072c9afc50ae0 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -10,11 +10,11 @@ use rustc_data_structures::fx::FxHashSet; use std::hash::Hash; use super::{ - GlobalAlloc, InterpResult, InterpError, + 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() { @@ -22,7 +22,7 @@ macro_rules! validation_failure { } else { format!(" at {}", where_) }; - err!(ValidationFailure(format!( + throw_unsup!(ValidationFailure(format!( "encountered {}{}, but expected {}", $what, where_, $details, ))) @@ -34,7 +34,7 @@ macro_rules! validation_failure { } else { format!(" at {}", where_) }; - err!(ValidationFailure(format!( + throw_unsup!(ValidationFailure(format!( "encountered {}{}", $what, where_, ))) @@ -45,14 +45,14 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr, $details:expr) => {{ match $e { Ok(x) => x, - Err(_) => return validation_failure!($what, $where, $details), + Err(_) => throw_validation_failure!($what, $where, $details), } }}; ($e:expr, $what:expr, $where:expr) => {{ match $e { Ok(x) => x, - Err(_) => return validation_failure!($what, $where), + Err(_) => throw_validation_failure!($what, $where), } }} } @@ -297,12 +297,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { - InterpError::InvalidDiscriminant(val) => - validation_failure!( + err_unsup!(InvalidDiscriminant(val)) => + throw_validation_failure!( val, self.path, "a valid enum discriminant" ), - InterpError::ReadPointerAsBytes => - validation_failure!( + err_unsup!(ReadPointerAsBytes) => + throw_validation_failure!( "a pointer", self.path, "plain (non-pointer) bytes" ), _ => Err(err), @@ -406,19 +406,19 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ptr, size, align ); match err.kind { - InterpError::InvalidNullPointerUsage => - return validation_failure!("NULL reference", self.path), - InterpError::AlignmentCheckFailed { required, has } => - return 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::ReadBytesAsPointer => - return validation_failure!( + err_unsup!(ReadBytesAsPointer) => + throw_validation_failure!( "dangling reference (created from integer)", self.path ), _ => - return validation_failure!( + throw_validation_failure!( "dangling reference (not entirely in bounds)", self.path ), @@ -478,7 +478,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> 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( @@ -511,27 +511,27 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> 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) { - return validation_failure!( + throw_validation_failure!( "a potentially NULL pointer", self.path, format!( "something that cannot possibly fail to be {}", wrapping_range_format(&layout.valid_range, max_hi) ) - ); + ) } return Ok(()); } else { // Conservatively, we reject, because the pointer *could* have a bad // value. - return validation_failure!( + throw_validation_failure!( "a pointer", self.path, format!( "something that cannot possibly fail to be {}", wrapping_range_format(&layout.valid_range, max_hi) ) - ); + ) } } Ok(data) => @@ -541,7 +541,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> 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)) @@ -608,16 +608,14 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Err(err) => { // For some errors we might be able to provide extra information match err.kind { - InterpError::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)); - return validation_failure!( - "undefined bytes", self.path - ) + throw_validation_failure!("undefined bytes", self.path) }, // Other errors shouldn't be possible _ => return Err(err), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 7a2d78b2e986b..a450ec32e1a47 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -13,7 +13,7 @@ use rustc::mir::{ use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, }; -use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, InterpError, PanicMessage}; +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; @@ -258,87 +258,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let diagnostic = error_to_const_error(&self.ecx, error); use rustc::mir::interpret::InterpError::*; match diagnostic.error { - // don't report these, they make no sense in a const prop context - | MachineError(_) - | Exit(_) - // at runtime these transformations might make sense - // FIXME: figure out the rules and start linting - | FunctionAbiMismatch(..) - | FunctionArgMismatch(..) - | FunctionRetMismatch(..) - | FunctionArgCountMismatch - // fine at runtime, might be a register address or sth - | ReadBytesAsPointer - // fine at runtime - | ReadForeignStatic - | Unimplemented(_) - // don't report const evaluator limits - | StackFrameLimitReached - | NoMirFor(..) - | InlineAsm - => {}, - - | InvalidMemoryAccess - | DanglingPointerDeref - | DoubleFree - | InvalidFunctionPointer - | InvalidBool - | InvalidDiscriminant(..) - | PointerOutOfBounds { .. } - | InvalidNullPointerUsage - | ValidationFailure(..) - | InvalidPointerMath - | ReadUndefBytes(_) - | DeadLocal - | InvalidBoolOp(_) - | DerefFunctionPointer - | ExecuteMemory - | Intrinsic(..) - | InvalidChar(..) - | AbiViolation(_) - | AlignmentCheckFailed{..} - | CalledClosureAsFunction - | VtableForArgumentlessMethod - | ModifiedConstantMemory - | ModifiedStatic - | AssumptionNotHeld - // FIXME: should probably be removed and turned into a bug! call - | TypeNotPrimitive(_) - | ReallocatedWrongMemoryKind(_, _) - | DeallocatedWrongMemoryKind(_, _) - | ReallocateNonBasePtr - | DeallocateNonBasePtr - | IncorrectAllocationInformation(..) - | UnterminatedCString(_) - | HeapAllocZeroBytes - | HeapAllocNonPowerOfTwoAlignment(_) - | Unreachable - | ReadFromReturnPointer - | ReferencedConstant - | InfiniteLoop - => { - // FIXME: report UB here - }, - - | OutOfTls - | TlsOutOfBounds - | PathNotFound(_) - => bug!("these should not be in rustc, but in miri's machine errors"), - - | Layout(_) - | UnimplementedTraitSelection - | TypeckError - | TooGeneric - // these are just noise - => {}, - - // non deterministic - | ReadPointerAsBytes - // FIXME: implement - => {}, - - | Panic(_) - => { + Exit(_) => bug!("the CTFE program cannot exit"), + Unsupported(_) + | UndefinedBehaviour(_) + | InvalidProgram(_) + | ResourceExhaustion(_) => { + // Ignore these errors. + } + Panic(_) => { diagnostic.report_as_lint( self.ecx.tcx, "this expression will panic at runtime", @@ -515,7 +442,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Need to do overflow check here: For actual CTFE, MIR // generation emits code that does this before calling the op. if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - return err!(Panic(PanicMessage::OverflowNeg)); + throw_panic!(OverflowNeg) } } UnOp::Not => { @@ -593,7 +520,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) } else { if overflow { - let err = InterpError::Panic(PanicMessage::Overflow(op)).into(); + let err = err_panic!(Overflow(op)).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None; } @@ -830,12 +757,12 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .as_local_hir_id(self.source.def_id()) .expect("some part of a failing const eval must be local"); let msg = match msg { - PanicMessage::Overflow(_) | - PanicMessage::OverflowNeg | - PanicMessage::DivisionByZero | - PanicMessage::RemainderByZero => + PanicInfo::Overflow(_) | + PanicInfo::OverflowNeg | + PanicInfo::DivisionByZero | + PanicInfo::RemainderByZero => msg.description().to_owned(), - PanicMessage::BoundsCheck { ref len, ref index } => { + PanicInfo::BoundsCheck { ref len, ref index } => { let len = self .eval_operand(len, source_info) .expect("len must be const"); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5461a2e470c7e..94bb70e10aa53 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -1016,7 +1016,7 @@ fn create_generator_resume_function<'tcx>( let mut cases = create_cases(body, &transform, |point| Some(point.resume)); - use rustc::mir::interpret::PanicMessage::{ + use rustc::mir::interpret::PanicInfo::{ GeneratorResumedAfterPanic, GeneratorResumedAfterReturn, };