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