]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/error.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / error.rs
CommitLineData
1b1a35ee 1use super::{AllocId, ConstAlloc, Pointer, Scalar};
ea8adc8c 2
74b04a01 3use crate::mir::interpret::ConstValue;
923072b8 4use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
ea8adc8c 5
ba9703b0 6use rustc_data_structures::sync::Lock;
5e7ed085 7use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
e1599b0c 8use rustc_macros::HashStable;
ba9703b0 9use rustc_session::CtfeBacktrace;
3dfed10e 10use rustc_span::def_id::DefId;
a2a8927a 11use rustc_target::abi::{call, Align, Size};
6a06907d 12use std::{any::Any, backtrace::Backtrace, fmt};
e1599b0c 13
3dfed10e 14#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
a1dfa0c6 15pub enum ErrorHandled {
ba9703b0
XL
16 /// Already reported an error for this evaluation, and the compilation is
17 /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
5e7ed085 18 Reported(ErrorGuaranteed),
ba9703b0
XL
19 /// Already emitted a lint for this evaluation.
20 Linted,
a1dfa0c6
XL
21 /// Don't emit an error, the evaluation failed because the MIR was generic
22 /// and the substs didn't fully monomorphize it.
23 TooGeneric,
24}
25
5e7ed085
FG
26impl From<ErrorGuaranteed> for ErrorHandled {
27 fn from(err: ErrorGuaranteed) -> ErrorHandled {
1b1a35ee
XL
28 ErrorHandled::Reported(err)
29 }
30}
31
fc512014 32TrivialTypeFoldableAndLiftImpls! {
dc9dc135
XL
33 ErrorHandled,
34}
35
1b1a35ee
XL
36pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
37pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
923072b8 38pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
8faf50e0 39
5e7ed085
FG
40pub fn struct_error<'tcx>(
41 tcx: TyCtxtAt<'tcx>,
42 msg: &str,
43) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
8faf50e0
XL
44 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
45}
46
6a06907d
XL
47#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
48static_assert_size!(InterpErrorInfo<'_>, 8);
49
dc9dc135 50/// Packages the kind of error we got from the const code interpreter
60c5eb7d 51/// up with a Rust-level backtrace of where the error occurred.
cdc7bbd5 52/// These should always be constructed by calling `.into()` on
94222f64 53/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
416331ca 54/// macros for this.
60c5eb7d 55#[derive(Debug)]
6a06907d
XL
56pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
57
58#[derive(Debug)]
59struct InterpErrorInfoInner<'tcx> {
60 kind: InterpError<'tcx>,
dc9dc135 61 backtrace: Option<Box<Backtrace>>,
a1dfa0c6
XL
62}
63
416331ca
XL
64impl fmt::Display for InterpErrorInfo<'_> {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6a06907d 66 write!(f, "{}", self.0.kind)
416331ca
XL
67 }
68}
69
a2a8927a 70impl<'tcx> InterpErrorInfo<'tcx> {
f9f354fc 71 pub fn print_backtrace(&self) {
6a06907d 72 if let Some(backtrace) = self.0.backtrace.as_ref() {
f9f354fc 73 print_backtrace(backtrace);
a1dfa0c6
XL
74 }
75 }
6a06907d
XL
76
77 pub fn into_kind(self) -> InterpError<'tcx> {
78 let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
79 kind
80 }
81
82 #[inline]
83 pub fn kind(&self) -> &InterpError<'tcx> {
84 &self.0.kind
85 }
a1dfa0c6
XL
86}
87
f9f354fc
XL
88fn print_backtrace(backtrace: &Backtrace) {
89 eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
ea8adc8c
XL
90}
91
74b04a01 92impl From<ErrorHandled> for InterpErrorInfo<'_> {
e1599b0c
XL
93 fn from(err: ErrorHandled) -> Self {
94 match err {
5e7ed085 95 ErrorHandled::Reported(ErrorGuaranteed { .. }) | ErrorHandled::Linted => {
ba9703b0
XL
96 err_inval!(ReferencedConstant)
97 }
e1599b0c 98 ErrorHandled::TooGeneric => err_inval!(TooGeneric),
dfeec247
XL
99 }
100 .into()
e1599b0c
XL
101 }
102}
103
5e7ed085
FG
104impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
105 fn from(err: ErrorGuaranteed) -> Self {
29967ef6
XL
106 InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
107 }
108}
109
416331ca
XL
110impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
111 fn from(kind: InterpError<'tcx>) -> Self {
3dfed10e
XL
112 let capture_backtrace = tls::with_opt(|tcx| {
113 if let Some(tcx) = tcx {
114 *Lock::borrow(&tcx.sess.ctfe_backtrace)
ba9703b0
XL
115 } else {
116 CtfeBacktrace::Disabled
117 }
118 });
a1dfa0c6 119
ba9703b0
XL
120 let backtrace = match capture_backtrace {
121 CtfeBacktrace::Disabled => None,
f9f354fc 122 CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
ba9703b0
XL
123 CtfeBacktrace::Immediate => {
124 // Print it now.
f9f354fc
XL
125 let backtrace = Backtrace::force_capture();
126 print_backtrace(&backtrace);
ba9703b0 127 None
dfeec247 128 }
a1dfa0c6 129 };
ba9703b0 130
6a06907d 131 InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace }))
ea8adc8c
XL
132 }
133}
134
e1599b0c
XL
135/// Error information for when the program we executed turned out not to actually be a valid
136/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
137/// where we work on generic code or execution does not have all information available.
416331ca
XL
138pub enum InvalidProgramInfo<'tcx> {
139 /// Resolution can fail if we are in a too generic context.
140 TooGeneric,
141 /// Cannot compute this constant because it depends on another one
142 /// which already produced an error.
143 ReferencedConstant,
29967ef6 144 /// Abort in case errors are already reported.
5e7ed085 145 AlreadyReported(ErrorGuaranteed),
416331ca
XL
146 /// An error occurred during layout computation.
147 Layout(layout::LayoutError<'tcx>),
a2a8927a
XL
148 /// An error occurred during FnAbi computation: the passed --target lacks FFI support
149 /// (which unfortunately typeck does not reject).
150 /// Not using `FnAbiError` as that contains a nested `LayoutError`.
151 FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
5869c6ff
XL
152 /// SizeOf of unsized type was requested.
153 SizeOfUnsizedType(Ty<'tcx>),
416331ca 154}
b7449926 155
f9f354fc 156impl fmt::Display for InvalidProgramInfo<'_> {
416331ca
XL
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 use InvalidProgramInfo::*;
159 match self {
dfeec247
XL
160 TooGeneric => write!(f, "encountered overly generic constant"),
161 ReferencedConstant => write!(f, "referenced constant has errors"),
5e7ed085 162 AlreadyReported(ErrorGuaranteed { .. }) => {
ba9703b0
XL
163 write!(f, "encountered constants with type errors, stopping evaluation")
164 }
dfeec247 165 Layout(ref err) => write!(f, "{}", err),
a2a8927a 166 FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
5869c6ff 167 SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
416331ca
XL
168 }
169 }
170}
171
f9f354fc 172/// Details of why a pointer had to be in-bounds.
3dfed10e 173#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
f9f354fc 174pub enum CheckInAllocMsg {
136023e0
XL
175 /// We are dereferencing a pointer (i.e., creating a place).
176 DerefTest,
17df50a5 177 /// We are access memory.
f9f354fc 178 MemoryAccessTest,
17df50a5 179 /// We are doing pointer arithmetic.
f9f354fc 180 PointerArithmeticTest,
5e7ed085
FG
181 /// We are doing pointer offset_from.
182 OffsetFromTest,
17df50a5 183 /// None of the above -- generic/unspecific inbounds test.
f9f354fc
XL
184 InboundsTest,
185}
186
187impl fmt::Display for CheckInAllocMsg {
136023e0
XL
188 /// When this is printed as an error the context looks like this:
189 /// "{msg}0x01 is not a valid pointer".
f9f354fc
XL
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 write!(
192 f,
193 "{}",
194 match *self {
136023e0 195 CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
17df50a5
XL
196 CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
197 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
5e7ed085 198 CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
17df50a5 199 CheckInAllocMsg::InboundsTest => "",
f9f354fc
XL
200 }
201 )
202 }
203}
204
205/// Details of an access to uninitialized bytes where it is not allowed.
206#[derive(Debug)]
207pub struct UninitBytesAccess {
208 /// Location of the original memory access.
17df50a5 209 pub access_offset: Size,
f9f354fc
XL
210 /// Size of the original memory access.
211 pub access_size: Size,
212 /// Location of the first uninitialized byte that was accessed.
17df50a5 213 pub uninit_offset: Size,
f9f354fc
XL
214 /// Number of consecutive uninitialized bytes that were accessed.
215 pub uninit_size: Size,
216}
217
04454e1e
FG
218/// Information about a size mismatch.
219#[derive(Debug)]
220pub struct ScalarSizeMismatch {
221 pub target_size: u64,
222 pub data_size: u64,
223}
224
e1599b0c 225/// Error information for when the program caused Undefined Behavior.
f9f354fc 226pub enum UndefinedBehaviorInfo<'tcx> {
416331ca
XL
227 /// Free-form case. Only for errors that are never caught!
228 Ub(String),
416331ca
XL
229 /// Unreachable code was executed.
230 Unreachable,
60c5eb7d 231 /// A slice/array index projection went out-of-bounds.
ba9703b0
XL
232 BoundsCheckFailed {
233 len: u64,
234 index: u64,
235 },
60c5eb7d
XL
236 /// Something was divided by 0 (x / 0).
237 DivisionByZero,
238 /// Something was "remainded" by 0 (x % 0).
239 RemainderByZero,
5e7ed085
FG
240 /// Signed division overflowed (INT_MIN / -1).
241 DivisionOverflow,
242 /// Signed remainder overflowed (INT_MIN % -1).
243 RemainderOverflow,
60c5eb7d
XL
244 /// Overflowing inbounds pointer arithmetic.
245 PointerArithOverflow,
74b04a01
XL
246 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
247 InvalidMeta(&'static str),
f9f354fc 248 /// Invalid drop function in vtable.
136023e0
XL
249 InvalidVtableDropFn(FnSig<'tcx>),
250 /// Invalid size in a vtable: too large.
251 InvalidVtableSize,
252 /// Invalid alignment in a vtable: too large, or not a power of 2.
253 InvalidVtableAlignment(String),
ba9703b0
XL
254 /// Reading a C string that does not end within its allocation.
255 UnterminatedCString(Pointer),
256 /// Dereferencing a dangling pointer after it got freed.
257 PointerUseAfterFree(AllocId),
258 /// Used a pointer outside the bounds it is valid for.
136023e0 259 /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
ba9703b0 260 PointerOutOfBounds {
136023e0
XL
261 alloc_id: AllocId,
262 alloc_size: Size,
263 ptr_offset: i64,
264 ptr_size: Size,
ba9703b0 265 msg: CheckInAllocMsg,
ba9703b0 266 },
f9f354fc
XL
267 /// Using an integer as a pointer in the wrong way.
268 DanglingIntPointer(u64, CheckInAllocMsg),
ba9703b0
XL
269 /// Used a pointer with bad alignment.
270 AlignmentCheckFailed {
271 required: Align,
272 has: Align,
273 },
ba9703b0
XL
274 /// Writing to read-only memory.
275 WriteToReadOnly(AllocId),
ba9703b0
XL
276 // Trying to access the data behind a function pointer.
277 DerefFunctionPointer(AllocId),
278 /// The value validity check found a problem.
279 /// Should only be thrown by `validity.rs` and always point out which part of the value
280 /// is the problem.
136023e0
XL
281 ValidationFailure {
282 /// The "path" to the value in question, e.g. `.0[5].field` for a struct
283 /// field in the 6th element of an array that is the first element of a tuple.
284 path: Option<String>,
285 msg: String,
286 },
ba9703b0
XL
287 /// Using a non-boolean `u8` as bool.
288 InvalidBool(u8),
289 /// Using a non-character `u32` as character.
290 InvalidChar(u32),
f035d41b
XL
291 /// The tag of an enum does not encode an actual discriminant.
292 InvalidTag(Scalar),
f9f354fc
XL
293 /// Using a pointer-not-to-a-function as function pointer.
294 InvalidFunctionPointer(Pointer),
295 /// Using a string that is not valid UTF-8,
296 InvalidStr(std::str::Utf8Error),
ba9703b0 297 /// Using uninitialized data where it is not allowed.
17df50a5 298 InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>),
ba9703b0
XL
299 /// Working with a local that is not currently live.
300 DeadLocal,
f9f354fc 301 /// Data size is not equal to target size.
04454e1e 302 ScalarSizeMismatch(ScalarSizeMismatch),
c295e0f8
XL
303 /// A discriminant of an uninhabited enum variant is written.
304 UninhabitedEnumVariantWritten,
416331ca 305}
48663c56 306
f9f354fc 307impl fmt::Display for UndefinedBehaviorInfo<'_> {
416331ca
XL
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 use UndefinedBehaviorInfo::*;
310 match self {
ba9703b0 311 Ub(msg) => write!(f, "{}", msg),
dfeec247 312 Unreachable => write!(f, "entering unreachable code"),
f9f354fc
XL
313 BoundsCheckFailed { ref len, ref index } => {
314 write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
315 }
dfeec247
XL
316 DivisionByZero => write!(f, "dividing by zero"),
317 RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
5e7ed085
FG
318 DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
319 RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
dfeec247 320 PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
74b04a01 321 InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
136023e0 322 InvalidVtableDropFn(sig) => write!(
f9f354fc
XL
323 f,
324 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
325 sig
326 ),
136023e0
XL
327 InvalidVtableSize => {
328 write!(f, "invalid vtable: size is bigger than largest supported object")
329 }
330 InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
ba9703b0
XL
331 UnterminatedCString(p) => write!(
332 f,
136023e0 333 "reading a null-terminated string starting at {:?} with no null found before end of allocation",
ba9703b0
XL
334 p,
335 ),
336 PointerUseAfterFree(a) => {
f9f354fc 337 write!(f, "pointer to {} was dereferenced after this allocation got freed", a)
ba9703b0 338 }
136023e0
XL
339 PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => {
340 write!(
341 f,
342 "{}{alloc_id} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
343 msg,
344 alloc_id = alloc_id,
345 alloc_size = alloc_size.bytes(),
346 ptr_offset = ptr_offset,
347 )
348 }
349 PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!(
ba9703b0 350 f,
136023e0 351 "{}{alloc_id} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
ba9703b0 352 msg,
136023e0
XL
353 alloc_id = alloc_id,
354 alloc_size = alloc_size.bytes(),
355 ptr_size = ptr_size.bytes(),
356 ptr_size_p = pluralize!(ptr_size.bytes()),
357 ptr_offset = ptr_offset,
ba9703b0 358 ),
17df50a5
XL
359 DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
360 write!(f, "null pointer is not a valid pointer for this operation")
f9f354fc 361 }
5e7ed085
FG
362 DanglingIntPointer(0, msg) => {
363 write!(f, "{}null pointer is not a valid pointer", msg)
364 }
f9f354fc 365 DanglingIntPointer(i, msg) => {
17df50a5 366 write!(f, "{}0x{:x} is not a valid pointer", msg, i)
f9f354fc 367 }
ba9703b0
XL
368 AlignmentCheckFailed { required, has } => write!(
369 f,
370 "accessing memory with alignment {}, but alignment {} is required",
371 has.bytes(),
372 required.bytes()
373 ),
f9f354fc
XL
374 WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
375 DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
136023e0
XL
376 ValidationFailure { path: None, msg } => write!(f, "type validation failed: {}", msg),
377 ValidationFailure { path: Some(path), msg } => {
378 write!(f, "type validation failed at {}: {}", path, msg)
379 }
f9f354fc
XL
380 InvalidBool(b) => {
381 write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
382 }
383 InvalidChar(c) => {
384 write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
385 }
5e7ed085 386 InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val),
ba9703b0 387 InvalidFunctionPointer(p) => {
136023e0 388 write!(f, "using {:?} as function pointer but it does not point to a function", p)
ba9703b0 389 }
f9f354fc 390 InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
17df50a5 391 InvalidUninitBytes(Some((alloc, access))) => write!(
ba9703b0 392 f,
136023e0
XL
393 "reading {} byte{} of memory starting at {:?}, \
394 but {} byte{} {} uninitialized starting at {:?}, \
f9f354fc
XL
395 and this operation requires initialized memory",
396 access.access_size.bytes(),
397 pluralize!(access.access_size.bytes()),
17df50a5 398 Pointer::new(*alloc, access.access_offset),
f9f354fc
XL
399 access.uninit_size.bytes(),
400 pluralize!(access.uninit_size.bytes()),
5e7ed085 401 pluralize!("is", access.uninit_size.bytes()),
17df50a5 402 Pointer::new(*alloc, access.uninit_offset),
ba9703b0 403 ),
f9f354fc 404 InvalidUninitBytes(None) => write!(
ba9703b0
XL
405 f,
406 "using uninitialized data, but this operation requires initialized memory"
407 ),
408 DeadLocal => write!(f, "accessing a dead local variable"),
04454e1e 409 ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
f9f354fc
XL
410 f,
411 "scalar size mismatch: expected {} bytes but got {} bytes instead",
412 target_size, data_size
413 ),
c295e0f8
XL
414 UninhabitedEnumVariantWritten => {
415 write!(f, "writing discriminant of an uninhabited enum")
416 }
416331ca
XL
417 }
418 }
419}
420
e1599b0c
XL
421/// Error information for when the program did something that might (or might not) be correct
422/// to do according to the Rust spec, but due to limitations in the interpreter, the
423/// operation could not be carried out. These limitations can differ between CTFE and the
f9f354fc 424/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
ba9703b0 425pub enum UnsupportedOpInfo {
416331ca
XL
426 /// Free-form case. Only for errors that are never caught!
427 Unsupported(String),
ba9703b0 428 /// Encountered a pointer where we needed raw bytes.
ea8adc8c 429 ReadPointerAsBytes,
94222f64 430 /// Overwriting parts of a pointer; the resulting state cannot be represented in our
923072b8 431 /// `Allocation` data structure. See <https://github.com/rust-lang/miri/issues/2181>.
94222f64 432 PartialPointerOverwrite(Pointer<AllocId>),
f9f354fc
XL
433 //
434 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
435 //
f9f354fc
XL
436 /// Accessing thread local statics
437 ThreadLocalStatic(DefId),
3dfed10e
XL
438 /// Accessing an unsupported extern static.
439 ReadExternStatic(DefId),
ea8adc8c
XL
440}
441
f9f354fc 442impl fmt::Display for UnsupportedOpInfo {
a1dfa0c6 443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416331ca
XL
444 use UnsupportedOpInfo::*;
445 match self {
dfeec247 446 Unsupported(ref msg) => write!(f, "{}", msg),
94222f64
XL
447 ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
448 PartialPointerOverwrite(ptr) => {
449 write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
450 }
f9f354fc 451 ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
94222f64 452 ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
416331ca
XL
453 }
454 }
455}
456
e1599b0c
XL
457/// Error information for when the program exhausted the resources granted to it
458/// by the interpreter.
416331ca
XL
459pub enum ResourceExhaustionInfo {
460 /// The stack grew too big.
461 StackFrameLimitReached,
ba9703b0
XL
462 /// The program ran for too long.
463 ///
464 /// The exact limit is set by the `const_eval_limit` attribute.
465 StepLimitReached,
136023e0
XL
466 /// There is not enough memory to perform an allocation.
467 MemoryExhausted,
416331ca
XL
468}
469
f9f354fc 470impl fmt::Display for ResourceExhaustionInfo {
416331ca
XL
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 use ResourceExhaustionInfo::*;
473 match self {
dfeec247
XL
474 StackFrameLimitReached => {
475 write!(f, "reached the configured maximum number of stack frames")
476 }
ba9703b0
XL
477 StepLimitReached => {
478 write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
479 }
136023e0
XL
480 MemoryExhausted => {
481 write!(f, "tried to allocate more memory than available to compiler")
482 }
416331ca
XL
483 }
484 }
485}
486
ba9703b0
XL
487/// A trait to work around not having trait object upcasting.
488pub trait AsAny: Any {
489 fn as_any(&self) -> &dyn Any;
490}
ba9703b0
XL
491impl<T: Any> AsAny for T {
492 #[inline(always)]
493 fn as_any(&self) -> &dyn Any {
494 self
495 }
496}
497
498/// A trait for machine-specific errors (or other "machine stop" conditions).
17df50a5
XL
499pub trait MachineStopType: AsAny + fmt::Display + Send {
500 /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
501 fn is_hard_err(&self) -> bool {
502 false
503 }
504}
ba9703b0
XL
505
506impl dyn MachineStopType {
507 #[inline(always)]
508 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
509 self.as_any().downcast_ref()
510 }
511}
512
416331ca 513pub enum InterpError<'tcx> {
416331ca 514 /// The program caused undefined behavior.
f9f354fc 515 UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
416331ca
XL
516 /// The program did something the interpreter does not support (some of these *might* be UB
517 /// but the interpreter is not sure).
ba9703b0 518 Unsupported(UnsupportedOpInfo),
60c5eb7d 519 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
416331ca
XL
520 InvalidProgram(InvalidProgramInfo<'tcx>),
521 /// The program exhausted the interpreter's resources (stack/heap too big,
60c5eb7d 522 /// execution takes too long, ...).
416331ca 523 ResourceExhaustion(ResourceExhaustionInfo),
60c5eb7d
XL
524 /// Stop execution for a machine-controlled reason. This is never raised by
525 /// the core engine itself.
ba9703b0 526 MachineStop(Box<dyn MachineStopType>),
416331ca
XL
527}
528
529pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
530
531impl fmt::Display for InterpError<'_> {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc
XL
533 use InterpError::*;
534 match *self {
535 Unsupported(ref msg) => write!(f, "{}", msg),
536 InvalidProgram(ref msg) => write!(f, "{}", msg),
537 UndefinedBehavior(ref msg) => write!(f, "{}", msg),
538 ResourceExhaustion(ref msg) => write!(f, "{}", msg),
539 MachineStop(ref msg) => write!(f, "{}", msg),
540 }
416331ca
XL
541 }
542}
543
f9f354fc 544// Forward `Debug` to `Display`, so it does not look awful.
416331ca
XL
545impl fmt::Debug for InterpError<'_> {
546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc 547 fmt::Display::fmt(self, f)
74b04a01
XL
548 }
549}
550
551impl InterpError<'_> {
136023e0 552 /// Some errors do string formatting even if the error is never printed.
6a06907d
XL
553 /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
554 /// so this method lets us detect them and `bug!` on unexpected errors.
555 pub fn formatted_string(&self) -> bool {
3c0e092e
XL
556 matches!(
557 self,
ba9703b0 558 InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
3c0e092e
XL
559 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
560 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
561 )
ea8adc8c 562 }
136023e0
XL
563
564 /// Should this error be reported as a hard error, preventing compilation, or a soft error,
565 /// causing a deny-by-default lint?
566 pub fn is_hard_err(&self) -> bool {
567 use InterpError::*;
568 match *self {
569 MachineStop(ref err) => err.is_hard_err(),
570 UndefinedBehavior(_) => true,
571 ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) => true,
572 _ => false,
573 }
574 }
ea8adc8c 575}