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