]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/interpret/error.rs
Rollup merge of #68070 - GuillaumeGomez:clean-up-e0185, r=Dylan-DPC
[rust.git] / src / librustc / mir / interpret / error.rs
1 use super::{CheckInAllocMsg, Pointer, RawConst, ScalarMaybeUndef};
2
3 use crate::hir::map::definitions::DefPathData;
4 use crate::mir;
5 use crate::ty::layout::{Align, LayoutError, Size};
6 use crate::ty::query::TyCtxtAt;
7 use crate::ty::{self, layout, Ty};
8
9 use backtrace::Backtrace;
10 use hir::GeneratorKind;
11 use rustc_errors::{struct_span_err, DiagnosticBuilder};
12 use rustc_hir as hir;
13 use rustc_macros::HashStable;
14 use rustc_span::symbol::Symbol;
15 use rustc_span::{Pos, Span};
16 use rustc_target::spec::abi::Abi;
17 use std::{any::Any, env, fmt};
18
19 use rustc_error_codes::*;
20
21 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
22 pub enum ErrorHandled {
23     /// Already reported a lint or an error for this evaluation.
24     Reported,
25     /// Don't emit an error, the evaluation failed because the MIR was generic
26     /// and the substs didn't fully monomorphize it.
27     TooGeneric,
28 }
29
30 impl ErrorHandled {
31     pub fn assert_reported(self) {
32         match self {
33             ErrorHandled::Reported => {}
34             ErrorHandled::TooGeneric => bug!(
35                 "MIR interpretation failed without reporting an error \
36                                               even though it was fully monomorphized"
37             ),
38         }
39     }
40 }
41
42 CloneTypeFoldableImpls! {
43     ErrorHandled,
44 }
45
46 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
47 pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
48
49 #[derive(Debug)]
50 pub struct ConstEvalErr<'tcx> {
51     pub span: Span,
52     pub error: crate::mir::interpret::InterpError<'tcx>,
53     pub stacktrace: Vec<FrameInfo<'tcx>>,
54 }
55
56 #[derive(Debug)]
57 pub struct FrameInfo<'tcx> {
58     /// This span is in the caller.
59     pub call_site: Span,
60     pub instance: ty::Instance<'tcx>,
61     pub lint_root: Option<hir::HirId>,
62 }
63
64 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
65     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66         ty::tls::with(|tcx| {
67             if tcx.def_key(self.instance.def_id()).disambiguated_data.data
68                 == DefPathData::ClosureExpr
69             {
70                 write!(f, "inside call to closure")?;
71             } else {
72                 write!(f, "inside call to `{}`", self.instance)?;
73             }
74             if !self.call_site.is_dummy() {
75                 let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
76                 write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
77             }
78             Ok(())
79         })
80     }
81 }
82
83 impl<'tcx> ConstEvalErr<'tcx> {
84     pub fn struct_error(
85         &self,
86         tcx: TyCtxtAt<'tcx>,
87         message: &str,
88     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
89         self.struct_generic(tcx, message, None)
90     }
91
92     pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
93         let err = self.struct_error(tcx, message);
94         match err {
95             Ok(mut err) => {
96                 err.emit();
97                 ErrorHandled::Reported
98             }
99             Err(err) => err,
100         }
101     }
102
103     pub fn report_as_lint(
104         &self,
105         tcx: TyCtxtAt<'tcx>,
106         message: &str,
107         lint_root: hir::HirId,
108         span: Option<Span>,
109     ) -> ErrorHandled {
110         let lint = self.struct_generic(tcx, message, Some(lint_root));
111         match lint {
112             Ok(mut lint) => {
113                 if let Some(span) = span {
114                     let primary_spans = lint.span.primary_spans().to_vec();
115                     // point at the actual error as the primary span
116                     lint.replace_span_with(span);
117                     // point to the `const` statement as a secondary span
118                     // they don't have any label
119                     for sp in primary_spans {
120                         if sp != span {
121                             lint.span_label(sp, "");
122                         }
123                     }
124                 }
125                 lint.emit();
126                 ErrorHandled::Reported
127             }
128             Err(err) => err,
129         }
130     }
131
132     fn struct_generic(
133         &self,
134         tcx: TyCtxtAt<'tcx>,
135         message: &str,
136         lint_root: Option<hir::HirId>,
137     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
138         let must_error = match self.error {
139             InterpError::MachineStop(_) => bug!("CTFE does not stop"),
140             err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
141                 return Err(ErrorHandled::TooGeneric);
142             }
143             err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
144             err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
145             _ => false,
146         };
147         trace!("reporting const eval failure at {:?}", self.span);
148         let mut err = if let (Some(lint_root), false) = (lint_root, must_error) {
149             let hir_id = self
150                 .stacktrace
151                 .iter()
152                 .rev()
153                 .filter_map(|frame| frame.lint_root)
154                 .next()
155                 .unwrap_or(lint_root);
156             tcx.struct_span_lint_hir(
157                 crate::rustc::lint::builtin::CONST_ERR,
158                 hir_id,
159                 tcx.span,
160                 message,
161             )
162         } else if must_error {
163             struct_error(tcx, &self.error.to_string())
164         } else {
165             struct_error(tcx, message)
166         };
167         if !must_error {
168             err.span_label(self.span, self.error.to_string());
169         }
170         // Skip the last, which is just the environment of the constant.  The stacktrace
171         // is sometimes empty because we create "fake" eval contexts in CTFE to do work
172         // on constant values.
173         if self.stacktrace.len() > 0 {
174             for frame_info in &self.stacktrace[..self.stacktrace.len() - 1] {
175                 err.span_label(frame_info.call_site, frame_info.to_string());
176             }
177         }
178         Ok(err)
179     }
180 }
181
182 pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
183     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
184 }
185
186 /// Packages the kind of error we got from the const code interpreter
187 /// up with a Rust-level backtrace of where the error occurred.
188 /// Thsese should always be constructed by calling `.into()` on
189 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
190 /// macros for this.
191 #[derive(Debug)]
192 pub struct InterpErrorInfo<'tcx> {
193     pub kind: InterpError<'tcx>,
194     backtrace: Option<Box<Backtrace>>,
195 }
196
197 impl fmt::Display for InterpErrorInfo<'_> {
198     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199         write!(f, "{}", self.kind)
200     }
201 }
202
203 impl InterpErrorInfo<'_> {
204     pub fn print_backtrace(&mut self) {
205         if let Some(ref mut backtrace) = self.backtrace {
206             print_backtrace(&mut *backtrace);
207         }
208     }
209 }
210
211 fn print_backtrace(backtrace: &mut Backtrace) {
212     backtrace.resolve();
213     eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
214 }
215
216 impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
217     fn from(err: ErrorHandled) -> Self {
218         match err {
219             ErrorHandled::Reported => err_inval!(ReferencedConstant),
220             ErrorHandled::TooGeneric => err_inval!(TooGeneric),
221         }
222         .into()
223     }
224 }
225
226 impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
227     fn from(kind: InterpError<'tcx>) -> Self {
228         let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
229             // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
230             Ok(ref val) if val != "0" => {
231                 let mut backtrace = Backtrace::new_unresolved();
232
233                 if val == "immediate" {
234                     // Print it now.
235                     print_backtrace(&mut backtrace);
236                     None
237                 } else {
238                     Some(Box::new(backtrace))
239                 }
240             }
241             _ => None,
242         };
243         InterpErrorInfo { kind, backtrace }
244     }
245 }
246
247 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
248 pub enum PanicInfo<O> {
249     Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
250     BoundsCheck { len: O, index: O },
251     Overflow(mir::BinOp),
252     OverflowNeg,
253     DivisionByZero,
254     RemainderByZero,
255     ResumedAfterReturn(GeneratorKind),
256     ResumedAfterPanic(GeneratorKind),
257 }
258
259 /// Type for MIR `Assert` terminator error messages.
260 pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
261
262 impl<O> PanicInfo<O> {
263     /// Getting a description does not require `O` to be printable, and does not
264     /// require allocation.
265     /// The caller is expected to handle `Panic` and `BoundsCheck` separately.
266     pub fn description(&self) -> &'static str {
267         use PanicInfo::*;
268         match self {
269             Overflow(mir::BinOp::Add) => "attempt to add with overflow",
270             Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
271             Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
272             Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
273             Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
274             OverflowNeg => "attempt to negate with overflow",
275             Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
276             Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
277             Overflow(op) => bug!("{:?} cannot overflow", op),
278             DivisionByZero => "attempt to divide by zero",
279             RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
280             ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
281             ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
282             ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
283             ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
284             Panic { .. } | BoundsCheck { .. } => bug!("Unexpected PanicInfo"),
285         }
286     }
287 }
288
289 impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
290     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291         use PanicInfo::*;
292         match self {
293             Panic { ref msg, line, col, ref file } => {
294                 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
295             }
296             BoundsCheck { ref len, ref index } => {
297                 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
298             }
299             _ => write!(f, "{}", self.description()),
300         }
301     }
302 }
303
304 /// Error information for when the program we executed turned out not to actually be a valid
305 /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
306 /// where we work on generic code or execution does not have all information available.
307 pub enum InvalidProgramInfo<'tcx> {
308     /// Resolution can fail if we are in a too generic context.
309     TooGeneric,
310     /// Cannot compute this constant because it depends on another one
311     /// which already produced an error.
312     ReferencedConstant,
313     /// Abort in case type errors are reached.
314     TypeckError,
315     /// An error occurred during layout computation.
316     Layout(layout::LayoutError<'tcx>),
317 }
318
319 impl fmt::Debug for InvalidProgramInfo<'tcx> {
320     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321         use InvalidProgramInfo::*;
322         match self {
323             TooGeneric => write!(f, "encountered overly generic constant"),
324             ReferencedConstant => write!(f, "referenced constant has errors"),
325             TypeckError => write!(f, "encountered constants with type errors, stopping evaluation"),
326             Layout(ref err) => write!(f, "{}", err),
327         }
328     }
329 }
330
331 /// Error information for when the program caused Undefined Behavior.
332 pub enum UndefinedBehaviorInfo {
333     /// Free-form case. Only for errors that are never caught!
334     Ub(String),
335     /// Free-form case for experimental UB. Only for errors that are never caught!
336     UbExperimental(String),
337     /// Unreachable code was executed.
338     Unreachable,
339     /// An enum discriminant was set to a value which was outside the range of valid values.
340     InvalidDiscriminant(ScalarMaybeUndef),
341     /// A slice/array index projection went out-of-bounds.
342     BoundsCheckFailed { len: u64, index: u64 },
343     /// Something was divided by 0 (x / 0).
344     DivisionByZero,
345     /// Something was "remainded" by 0 (x % 0).
346     RemainderByZero,
347     /// Overflowing inbounds pointer arithmetic.
348     PointerArithOverflow,
349 }
350
351 impl fmt::Debug for UndefinedBehaviorInfo {
352     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353         use UndefinedBehaviorInfo::*;
354         match self {
355             Ub(msg) | UbExperimental(msg) => write!(f, "{}", msg),
356             Unreachable => write!(f, "entering unreachable code"),
357             InvalidDiscriminant(val) => write!(f, "encountering invalid enum discriminant {}", val),
358             BoundsCheckFailed { ref len, ref index } => write!(
359                 f,
360                 "indexing out of bounds: the len is {:?} but the index is {:?}",
361                 len, index
362             ),
363             DivisionByZero => write!(f, "dividing by zero"),
364             RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
365             PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
366         }
367     }
368 }
369
370 /// Error information for when the program did something that might (or might not) be correct
371 /// to do according to the Rust spec, but due to limitations in the interpreter, the
372 /// operation could not be carried out. These limitations can differ between CTFE and the
373 /// Miri engine, e.g., CTFE does not support casting pointers to "real" integers.
374 ///
375 /// Currently, we also use this as fall-back error kind for errors that have not been
376 /// categorized yet.
377 pub enum UnsupportedOpInfo<'tcx> {
378     /// Free-form case. Only for errors that are never caught!
379     Unsupported(String),
380
381     /// When const-prop encounters a situation it does not support, it raises this error.
382     /// This must not allocate for performance reasons.
383     ConstPropUnsupported(&'tcx str),
384
385     // -- Everything below is not categorized yet --
386     FunctionAbiMismatch(Abi, Abi),
387     FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
388     FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
389     FunctionArgCountMismatch,
390     UnterminatedCString(Pointer),
391     DanglingPointerDeref,
392     DoubleFree,
393     InvalidMemoryAccess,
394     InvalidFunctionPointer,
395     InvalidBool,
396     PointerOutOfBounds {
397         ptr: Pointer,
398         msg: CheckInAllocMsg,
399         allocation_size: Size,
400     },
401     InvalidNullPointerUsage,
402     ReadPointerAsBytes,
403     ReadBytesAsPointer,
404     ReadForeignStatic,
405     InvalidPointerMath,
406     ReadUndefBytes(Size),
407     DeadLocal,
408     InvalidBoolOp(mir::BinOp),
409     UnimplementedTraitSelection,
410     CalledClosureAsFunction,
411     NoMirFor(String),
412     DerefFunctionPointer,
413     ExecuteMemory,
414     InvalidChar(u128),
415     OutOfTls,
416     TlsOutOfBounds,
417     AlignmentCheckFailed {
418         required: Align,
419         has: Align,
420     },
421     ValidationFailure(String),
422     VtableForArgumentlessMethod,
423     ModifiedConstantMemory,
424     ModifiedStatic,
425     TypeNotPrimitive(Ty<'tcx>),
426     ReallocatedWrongMemoryKind(String, String),
427     DeallocatedWrongMemoryKind(String, String),
428     ReallocateNonBasePtr,
429     DeallocateNonBasePtr,
430     IncorrectAllocationInformation(Size, Size, Align, Align),
431     HeapAllocZeroBytes,
432     HeapAllocNonPowerOfTwoAlignment(u64),
433     ReadFromReturnPointer,
434     PathNotFound(Vec<String>),
435     TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
436 }
437
438 impl fmt::Debug for UnsupportedOpInfo<'tcx> {
439     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440         use UnsupportedOpInfo::*;
441         match self {
442             PointerOutOfBounds { ptr, msg, allocation_size } => write!(
443                 f,
444                 "{} failed: pointer must be in-bounds at offset {}, \
445                            but is outside bounds of allocation {} which has size {}",
446                 msg,
447                 ptr.offset.bytes(),
448                 ptr.alloc_id,
449                 allocation_size.bytes()
450             ),
451             ValidationFailure(ref err) => write!(f, "type validation failed: {}", err),
452             NoMirFor(ref func) => write!(f, "no MIR for `{}`", func),
453             FunctionAbiMismatch(caller_abi, callee_abi) => write!(
454                 f,
455                 "tried to call a function with ABI {:?} using caller ABI {:?}",
456                 callee_abi, caller_abi
457             ),
458             FunctionArgMismatch(caller_ty, callee_ty) => write!(
459                 f,
460                 "tried to call a function with argument of type {:?} \
461                            passing data of type {:?}",
462                 callee_ty, caller_ty
463             ),
464             TransmuteSizeDiff(from_ty, to_ty) => write!(
465                 f,
466                 "tried to transmute from {:?} to {:?}, but their sizes differed",
467                 from_ty, to_ty
468             ),
469             FunctionRetMismatch(caller_ty, callee_ty) => write!(
470                 f,
471                 "tried to call a function with return type {:?} \
472                            passing return place of type {:?}",
473                 callee_ty, caller_ty
474             ),
475             FunctionArgCountMismatch => {
476                 write!(f, "tried to call a function with incorrect number of arguments")
477             }
478             ReallocatedWrongMemoryKind(ref old, ref new) => {
479                 write!(f, "tried to reallocate memory from `{}` to `{}`", old, new)
480             }
481             DeallocatedWrongMemoryKind(ref old, ref new) => {
482                 write!(f, "tried to deallocate `{}` memory but gave `{}` as the kind", old, new)
483             }
484             InvalidChar(c) => {
485                 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c)
486             }
487             AlignmentCheckFailed { required, has } => write!(
488                 f,
489                 "tried to access memory with alignment {}, but alignment {} is required",
490                 has.bytes(),
491                 required.bytes()
492             ),
493             TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty),
494             PathNotFound(ref path) => write!(f, "cannot find path {:?}", path),
495             IncorrectAllocationInformation(size, size2, align, align2) => write!(
496                 f,
497                 "incorrect alloc info: expected size {} and align {}, \
498                            got size {} and align {}",
499                 size.bytes(),
500                 align.bytes(),
501                 size2.bytes(),
502                 align2.bytes()
503             ),
504             InvalidMemoryAccess => write!(f, "tried to access memory through an invalid pointer"),
505             DanglingPointerDeref => write!(f, "dangling pointer was dereferenced"),
506             DoubleFree => write!(f, "tried to deallocate dangling pointer"),
507             InvalidFunctionPointer => {
508                 write!(f, "tried to use a function pointer after offsetting it")
509             }
510             InvalidBool => write!(f, "invalid boolean value read"),
511             InvalidNullPointerUsage => write!(f, "invalid use of NULL pointer"),
512             ReadPointerAsBytes => write!(
513                 f,
514                 "a raw memory access tried to access part of a pointer value as raw \
515                     bytes"
516             ),
517             ReadBytesAsPointer => {
518                 write!(f, "a memory access tried to interpret some bytes as a pointer")
519             }
520             ReadForeignStatic => write!(f, "tried to read from foreign (extern) static"),
521             InvalidPointerMath => write!(
522                 f,
523                 "attempted to do invalid arithmetic on pointers that would leak base \
524                     addresses, e.g., comparing pointers into different allocations"
525             ),
526             DeadLocal => write!(f, "tried to access a dead local variable"),
527             DerefFunctionPointer => write!(f, "tried to dereference a function pointer"),
528             ExecuteMemory => write!(f, "tried to treat a memory pointer as a function pointer"),
529             OutOfTls => write!(f, "reached the maximum number of representable TLS keys"),
530             TlsOutOfBounds => write!(f, "accessed an invalid (unallocated) TLS key"),
531             CalledClosureAsFunction => {
532                 write!(f, "tried to call a closure through a function pointer")
533             }
534             VtableForArgumentlessMethod => {
535                 write!(f, "tried to call a vtable function without arguments")
536             }
537             ModifiedConstantMemory => write!(f, "tried to modify constant memory"),
538             ModifiedStatic => write!(
539                 f,
540                 "tried to modify a static's initial value from another static's \
541                     initializer"
542             ),
543             ReallocateNonBasePtr => write!(
544                 f,
545                 "tried to reallocate with a pointer not to the beginning of an \
546                     existing object"
547             ),
548             DeallocateNonBasePtr => write!(
549                 f,
550                 "tried to deallocate with a pointer not to the beginning of an \
551                     existing object"
552             ),
553             HeapAllocZeroBytes => write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
554             ReadFromReturnPointer => write!(f, "tried to read from the return pointer"),
555             UnimplementedTraitSelection => {
556                 write!(f, "there were unresolved type arguments during trait selection")
557             }
558             InvalidBoolOp(_) => write!(f, "invalid boolean operation"),
559             UnterminatedCString(_) => write!(
560                 f,
561                 "attempted to get length of a null-terminated string, but no null \
562                     found before end of allocation"
563             ),
564             ReadUndefBytes(_) => write!(f, "attempted to read undefined bytes"),
565             HeapAllocNonPowerOfTwoAlignment(_) => write!(
566                 f,
567                 "tried to re-, de-, or allocate heap memory with alignment that is \
568                     not a power of two"
569             ),
570             Unsupported(ref msg) => write!(f, "{}", msg),
571             ConstPropUnsupported(ref msg) => {
572                 write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
573             }
574         }
575     }
576 }
577
578 /// Error information for when the program exhausted the resources granted to it
579 /// by the interpreter.
580 pub enum ResourceExhaustionInfo {
581     /// The stack grew too big.
582     StackFrameLimitReached,
583     /// The program ran into an infinite loop.
584     InfiniteLoop,
585 }
586
587 impl fmt::Debug for ResourceExhaustionInfo {
588     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589         use ResourceExhaustionInfo::*;
590         match self {
591             StackFrameLimitReached => {
592                 write!(f, "reached the configured maximum number of stack frames")
593             }
594             InfiniteLoop => write!(
595                 f,
596                 "duplicate interpreter state observed here, const evaluation will never \
597                     terminate"
598             ),
599         }
600     }
601 }
602
603 pub enum InterpError<'tcx> {
604     /// The program panicked.
605     Panic(PanicInfo<u64>),
606     /// The program caused undefined behavior.
607     UndefinedBehavior(UndefinedBehaviorInfo),
608     /// The program did something the interpreter does not support (some of these *might* be UB
609     /// but the interpreter is not sure).
610     Unsupported(UnsupportedOpInfo<'tcx>),
611     /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
612     InvalidProgram(InvalidProgramInfo<'tcx>),
613     /// The program exhausted the interpreter's resources (stack/heap too big,
614     /// execution takes too long, ...).
615     ResourceExhaustion(ResourceExhaustionInfo),
616     /// Stop execution for a machine-controlled reason. This is never raised by
617     /// the core engine itself.
618     MachineStop(Box<dyn Any + Send>),
619 }
620
621 pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
622
623 impl fmt::Display for InterpError<'_> {
624     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625         // Forward `Display` to `Debug`.
626         write!(f, "{:?}", self)
627     }
628 }
629
630 impl fmt::Debug for InterpError<'_> {
631     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632         use InterpError::*;
633         match *self {
634             Unsupported(ref msg) => write!(f, "{:?}", msg),
635             InvalidProgram(ref msg) => write!(f, "{:?}", msg),
636             UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
637             ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
638             Panic(ref msg) => write!(f, "{:?}", msg),
639             MachineStop(_) => write!(f, "machine caused execution to stop"),
640         }
641     }
642 }