]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/mir/interpret/error.rs
Rollup merge of #63203 - spastorino:is-mutable-use-place-ref, r=oli-obk
[rust.git] / src / librustc / mir / interpret / error.rs
index 6ab07c9679e7a0eb05472797093e737c18d0362e..8d41b019c221a4719d578556a47fa74c9398dfcf 100644 (file)
@@ -47,7 +47,7 @@ pub fn assert_reported(self) {
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub error: crate::mir::interpret::InterpError<'tcx, u64>,
+    pub error: crate::mir::interpret::InterpError<'tcx>,
     pub stacktrace: Vec<FrameInfo<'tcx>>,
 }
 
@@ -138,10 +138,12 @@ fn struct_generic(
         lint_root: Option<hir::HirId>,
     ) -> Result<DiagnosticBuilder<'tcx>, 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,15 +183,22 @@ 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, u64>,
+    pub kind: InterpError<'tcx>,
     backtrace: Option<Box<Backtrace>>,
 }
 
-impl<'tcx> InterpErrorInfo<'tcx> {
+
+impl fmt::Display for InterpErrorInfo<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.kind)
+    }
+}
+
+impl InterpErrorInfo<'_> {
     pub fn print_backtrace(&mut self) {
         if let Some(ref mut backtrace) = self.backtrace {
             print_backtrace(&mut *backtrace);
@@ -202,8 +211,8 @@ fn print_backtrace(backtrace: &mut Backtrace) {
     eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
 }
 
-impl<'tcx> From<InterpError<'tcx, u64>> for InterpErrorInfo<'tcx> {
-    fn from(kind: InterpError<'tcx, u64>) -> Self {
+impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
+    fn from(kind: InterpError<'tcx>) -> Self {
         let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
             // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
             Ok(ref val) if val != "0" => {
@@ -226,10 +235,8 @@ fn from(kind: InterpError<'tcx, u64>) -> Self {
     }
 }
 
-pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
-
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum PanicMessage<O> {
+pub enum PanicInfo<O> {
     Panic {
         msg: Symbol,
         line: u32,
@@ -244,23 +251,125 @@ pub enum PanicMessage<O> {
     OverflowNeg,
     DivisionByZero,
     RemainderByZero,
+    GeneratorResumedAfterReturn,
+    GeneratorResumedAfterPanic,
+}
+
+/// Type for MIR `Assert` terminator error messages.
+pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
+
+impl<O> PanicInfo<O> {
+    /// 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 PanicInfo::*;
+        match self {
+            Overflow(mir::BinOp::Add) =>
+                "attempt to add with overflow",
+            Overflow(mir::BinOp::Sub) =>
+                "attempt to subtract with overflow",
+            Overflow(mir::BinOp::Mul) =>
+                "attempt to multiply with overflow",
+            Overflow(mir::BinOp::Div) =>
+                "attempt to divide with overflow",
+            Overflow(mir::BinOp::Rem) =>
+                "attempt to calculate the remainder with overflow",
+            OverflowNeg =>
+                "attempt to negate with overflow",
+            Overflow(mir::BinOp::Shr) =>
+                "attempt to shift right with overflow",
+            Overflow(mir::BinOp::Shl) =>
+                "attempt to shift left with overflow",
+            Overflow(op) =>
+                bug!("{:?} cannot overflow", op),
+            DivisionByZero =>
+                "attempt to divide by zero",
+            RemainderByZero =>
+                "attempt to calculate the remainder with a divisor of zero",
+            GeneratorResumedAfterReturn =>
+                "generator resumed after completion",
+            GeneratorResumedAfterPanic =>
+                "generator resumed after panicking",
+            Panic { .. } | BoundsCheck { .. } =>
+                bug!("Unexpected PanicInfo"),
+        }
+    }
+}
+
+impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use PanicInfo::*;
+        match self {
+            Panic { ref msg, line, col, ref file } =>
+                write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
+            BoundsCheck { ref len, ref index } =>
+                write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
+            _ =>
+                write!(f, "{}", self.description()),
+        }
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub enum InterpError<'tcx, O> {
-    /// 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,
@@ -281,12 +390,17 @@ pub enum InterpError<'tcx, O> {
     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),
@@ -295,201 +409,26 @@ pub enum InterpError<'tcx, O> {
         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<O>),
     ReadFromReturnPointer,
     PathNotFound(Vec<String>),
-    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,
-    GeneratorResumedAfterReturn,
-    GeneratorResumedAfterPanic,
-    InfiniteLoop,
-}
-
-pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
-
-impl<'tcx, O> InterpError<'tcx, O> {
-    pub fn description(&self) -> &str {
-        use self::InterpError::*;
-        match *self {
-            MachineError(ref inner) => inner,
-            Exit(..) =>
-                "exited",
-            FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
-            | FunctionArgCountMismatch =>
-                "tried to call a function through a function pointer of incompatible type",
-            InvalidMemoryAccess =>
-                "tried to access memory through an invalid pointer",
-            DanglingPointerDeref =>
-                "dangling pointer was dereferenced",
-            DoubleFree =>
-                "tried to deallocate dangling pointer",
-            InvalidFunctionPointer =>
-                "tried to use a function pointer after offsetting it",
-            InvalidBool =>
-                "invalid boolean value read",
-            InvalidDiscriminant(..) =>
-                "invalid enum discriminant value read",
-            PointerOutOfBounds { .. } =>
-                "pointer offset outside bounds of allocation",
-            InvalidNullPointerUsage =>
-                "invalid use of NULL pointer",
-            ValidationFailure(..) =>
-                "type validation failed",
-            ReadPointerAsBytes =>
-                "a raw memory access tried to access part of a pointer value as raw bytes",
-            ReadBytesAsPointer =>
-                "a memory access tried to interpret some bytes as a pointer",
-            ReadForeignStatic =>
-                "tried to read from foreign (extern) static",
-            InvalidPointerMath =>
-                "attempted to do invalid arithmetic on pointers that would leak base addresses, \
-                e.g., comparing pointers into different allocations",
-            ReadUndefBytes(_) =>
-                "attempted to read undefined bytes",
-            DeadLocal =>
-                "tried to access a dead local variable",
-            InvalidBoolOp(_) =>
-                "invalid boolean operation",
-            Unimplemented(ref msg) => msg,
-            DerefFunctionPointer =>
-                "tried to dereference a function pointer",
-            ExecuteMemory =>
-                "tried to treat a memory pointer as a function pointer",
-            Intrinsic(..) =>
-                "intrinsic failed",
-            NoMirFor(..) =>
-                "mir not found",
-            InvalidChar(..) =>
-                "tried to interpret an invalid 32-bit value as a char",
-            StackFrameLimitReached =>
-                "reached the configured maximum number of stack frames",
-            OutOfTls =>
-                "reached the maximum number of representable TLS keys",
-            TlsOutOfBounds =>
-                "accessed an invalid (unallocated) TLS key",
-            AbiViolation(ref msg) => msg,
-            AlignmentCheckFailed{..} =>
-                "tried to execute a misaligned read or write",
-            CalledClosureAsFunction =>
-                "tried to call a closure through a function pointer",
-            VtableForArgumentlessMethod =>
-                "tried to call a vtable function without arguments",
-            ModifiedConstantMemory =>
-                "tried to modify constant memory",
-            ModifiedStatic =>
-                "tried to modify a static's initial value from another static's initializer",
-            AssumptionNotHeld =>
-                "`assume` argument was false",
-            InlineAsm =>
-                "miri does not support inline assembly",
-            TypeNotPrimitive(_) =>
-                "expected primitive type, got nonprimitive",
-            ReallocatedWrongMemoryKind(_, _) =>
-                "tried to reallocate memory from one kind to another",
-            DeallocatedWrongMemoryKind(_, _) =>
-                "tried to deallocate memory of the wrong kind",
-            ReallocateNonBasePtr =>
-                "tried to reallocate with a pointer not to the beginning of an existing object",
-            DeallocateNonBasePtr =>
-                "tried to deallocate with a pointer not to the beginning of an existing object",
-            IncorrectAllocationInformation(..) =>
-                "tried to deallocate or reallocate using incorrect alignment or size",
-            Layout(_) =>
-                "rustc layout computation failed",
-            UnterminatedCString(_) =>
-                "attempted to get length of a null terminated string, but no null found before end \
-                of allocation",
-            HeapAllocZeroBytes =>
-                "tried to re-, de- or allocate zero bytes on the heap",
-            HeapAllocNonPowerOfTwoAlignment(_) =>
-                "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
-                two",
-            Unreachable =>
-                "entered unreachable code",
-            Panic(PanicMessage::Panic{..}) =>
-                "the evaluated program panicked",
-            Panic(PanicMessage::BoundsCheck{..}) =>
-                "array index out of bounds",
-            Panic(PanicMessage::Overflow(mir::BinOp::Add)) =>
-                "attempt to add with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Sub)) =>
-                "attempt to subtract with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Mul)) =>
-                "attempt to multiply with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Div)) =>
-                "attempt to divide with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Rem)) =>
-                "attempt to calculate the remainder with overflow",
-            Panic(PanicMessage::OverflowNeg) =>
-                "attempt to negate with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Shr)) =>
-                "attempt to shift right with overflow",
-            Panic(PanicMessage::Overflow(mir::BinOp::Shl)) =>
-                "attempt to shift left with overflow",
-            Panic(PanicMessage::Overflow(op)) =>
-                bug!("{:?} cannot overflow", op),
-            Panic(PanicMessage::DivisionByZero) =>
-                "attempt to divide by zero",
-            Panic(PanicMessage::RemainderByZero) =>
-                "attempt to calculate the remainder with a divisor of zero",
-            ReadFromReturnPointer =>
-                "tried to read from the return pointer",
-            PathNotFound(_) =>
-                "a path could not be resolved, maybe the crate is not loaded",
-            UnimplementedTraitSelection =>
-                "there were unresolved type arguments during trait selection",
-            TypeckError =>
-                "encountered constants with type errors, stopping evaluation",
-            TooGeneric =>
-                "encountered overly generic constant",
-            ReferencedConstant =>
-                "referenced constant has errors",
-            GeneratorResumedAfterReturn => "generator resumed after completion",
-            GeneratorResumedAfterPanic => "generator resumed after panicking",
-            InfiniteLoop =>
-                "duplicate interpreter state observed here, const evaluation will never terminate",
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for InterpErrorInfo<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.kind)
-    }
-}
-
-impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self)
-    }
 }
 
-impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
+impl fmt::Debug for UnsupportedOpInfo<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use self::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 {}",
@@ -516,8 +455,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 write!(f, "tried to reallocate memory from {} to {}", old, new),
             DeallocatedWrongMemoryKind(ref old, ref new) =>
                 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
-            Intrinsic(ref err) =>
-                write!(f, "{}", err),
             InvalidChar(c) =>
                 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
             AlignmentCheckFailed { required, has } =>
@@ -525,25 +462,155 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                       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),
-            MachineError(ref inner) =>
-                write!(f, "{}", inner),
             IncorrectAllocationInformation(size, size2, align, align2) =>
                 write!(f, "incorrect alloc info: expected size {} and align {}, \
                            got size {} and align {}",
                     size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
-            Panic(PanicMessage::Panic { ref msg, line, col, ref file }) =>
-                write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
-            Panic(PanicMessage::BoundsCheck { ref len, ref index }) =>
-                write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
             InvalidDiscriminant(val) =>
                 write!(f, "encountered invalid enum discriminant {}", val),
+            InvalidMemoryAccess =>
+                write!(f, "tried to access memory through an invalid pointer"),
+            DanglingPointerDeref =>
+                write!(f, "dangling pointer was dereferenced"),
+            DoubleFree =>
+                write!(f, "tried to deallocate dangling pointer"),
+            InvalidFunctionPointer =>
+                write!(f, "tried to use a function pointer after offsetting it"),
+            InvalidBool =>
+                write!(f, "invalid boolean value read"),
+            InvalidNullPointerUsage =>
+                write!(f, "invalid use of NULL pointer"),
+            ReadPointerAsBytes =>
+                write!(f, "a raw memory access tried to access part of a pointer value as raw \
+                    bytes"),
+            ReadBytesAsPointer =>
+                write!(f, "a memory access tried to interpret some bytes as a pointer"),
+            ReadForeignStatic =>
+                write!(f, "tried to read from foreign (extern) static"),
+            InvalidPointerMath =>
+                write!(f, "attempted to do invalid arithmetic on pointers that would leak base \
+                    addresses, e.g., comparing pointers into different allocations"),
+            DeadLocal =>
+                write!(f, "tried to access a dead local variable"),
+            DerefFunctionPointer =>
+                write!(f, "tried to dereference a function pointer"),
+            ExecuteMemory =>
+                write!(f, "tried to treat a memory pointer as a function pointer"),
+            OutOfTls =>
+                write!(f, "reached the maximum number of representable TLS keys"),
+            TlsOutOfBounds =>
+                write!(f, "accessed an invalid (unallocated) TLS key"),
+            CalledClosureAsFunction =>
+                write!(f, "tried to call a closure through a function pointer"),
+            VtableForArgumentlessMethod =>
+                write!(f, "tried to call a vtable function without arguments"),
+            ModifiedConstantMemory =>
+                write!(f, "tried to modify constant memory"),
+            ModifiedStatic =>
+                write!(f, "tried to modify a static's initial value from another static's \
+                    initializer"),
+            AssumptionNotHeld =>
+                write!(f, "`assume` argument was false"),
+            InlineAsm =>
+                write!(f, "miri does not support inline assembly"),
+            ReallocateNonBasePtr =>
+                write!(f, "tried to reallocate with a pointer not to the beginning of an \
+                    existing object"),
+            DeallocateNonBasePtr =>
+                write!(f, "tried to deallocate with a pointer not to the beginning of an \
+                    existing object"),
+            HeapAllocZeroBytes =>
+                write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
+            ReadFromReturnPointer =>
+                write!(f, "tried to read from the return pointer"),
+            UnimplementedTraitSelection =>
+                write!(f, "there were unresolved type arguments during trait selection"),
+            InvalidBoolOp(_) =>
+                write!(f, "invalid boolean operation"),
+            UnterminatedCString(_) =>
+                write!(f, "attempted to get length of a null terminated string, but no null \
+                    found before end of allocation"),
+            ReadUndefBytes(_) =>
+                write!(f, "attempted to read undefined bytes"),
+            HeapAllocNonPowerOfTwoAlignment(_) =>
+                write!(f, "tried to re-, de-, or allocate heap memory with alignment that is \
+                    not a power of two"),
+            MachineError(ref msg) |
+            Unimplemented(ref msg) |
+            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<u64>),
+    /// 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<T, InterpErrorInfo<'tcx>>;
+
+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),
-            _ => write!(f, "{}", self.description()),
         }
     }
 }