]>
Commit | Line | Data |
---|---|---|
064997fb | 1 | use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; |
ea8adc8c | 2 | |
74b04a01 | 3 | use crate::mir::interpret::ConstValue; |
49aad941 FG |
4 | use crate::query::TyCtxtAt; |
5 | use crate::ty::{layout, tls, Ty, ValTree}; | |
ea8adc8c | 6 | |
ba9703b0 | 7 | use rustc_data_structures::sync::Lock; |
fe692bf9 FG |
8 | use rustc_errors::{ |
9 | struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, | |
10 | IntoDiagnosticArg, | |
11 | }; | |
e1599b0c | 12 | use rustc_macros::HashStable; |
ba9703b0 | 13 | use rustc_session::CtfeBacktrace; |
3dfed10e | 14 | use rustc_span::def_id::DefId; |
add651ee FG |
15 | use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; |
16 | ||
fe692bf9 | 17 | use std::borrow::Cow; |
6a06907d | 18 | use std::{any::Any, backtrace::Backtrace, fmt}; |
e1599b0c | 19 | |
3dfed10e | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] |
a1dfa0c6 | 21 | pub enum ErrorHandled { |
ba9703b0 XL |
22 | /// Already reported an error for this evaluation, and the compilation is |
23 | /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. | |
49aad941 | 24 | Reported(ReportedErrorInfo), |
a1dfa0c6 | 25 | /// Don't emit an error, the evaluation failed because the MIR was generic |
add651ee | 26 | /// and the args didn't fully monomorphize it. |
a1dfa0c6 XL |
27 | TooGeneric, |
28 | } | |
29 | ||
5e7ed085 | 30 | impl From<ErrorGuaranteed> for ErrorHandled { |
49aad941 FG |
31 | #[inline] |
32 | fn from(error: ErrorGuaranteed) -> ErrorHandled { | |
33 | ErrorHandled::Reported(error.into()) | |
34 | } | |
35 | } | |
36 | ||
37 | #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] | |
38 | pub struct ReportedErrorInfo { | |
39 | error: ErrorGuaranteed, | |
40 | is_tainted_by_errors: bool, | |
41 | } | |
42 | ||
43 | impl ReportedErrorInfo { | |
44 | #[inline] | |
45 | pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { | |
46 | ReportedErrorInfo { is_tainted_by_errors: true, error } | |
47 | } | |
48 | ||
49 | /// Returns true if evaluation failed because MIR was tainted by errors. | |
50 | #[inline] | |
51 | pub fn is_tainted_by_errors(self) -> bool { | |
52 | self.is_tainted_by_errors | |
53 | } | |
54 | } | |
55 | ||
56 | impl From<ErrorGuaranteed> for ReportedErrorInfo { | |
57 | #[inline] | |
58 | fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { | |
59 | ReportedErrorInfo { is_tainted_by_errors: false, error } | |
60 | } | |
61 | } | |
62 | ||
63 | impl Into<ErrorGuaranteed> for ReportedErrorInfo { | |
64 | #[inline] | |
65 | fn into(self) -> ErrorGuaranteed { | |
66 | self.error | |
1b1a35ee XL |
67 | } |
68 | } | |
69 | ||
add651ee | 70 | TrivialTypeTraversalAndLiftImpls! { ErrorHandled } |
dc9dc135 | 71 | |
1b1a35ee XL |
72 | pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; |
73 | pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; | |
923072b8 | 74 | pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>; |
8faf50e0 | 75 | |
5e7ed085 FG |
76 | pub fn struct_error<'tcx>( |
77 | tcx: TyCtxtAt<'tcx>, | |
78 | msg: &str, | |
79 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { | |
8faf50e0 XL |
80 | struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) |
81 | } | |
82 | ||
6a06907d XL |
83 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
84 | static_assert_size!(InterpErrorInfo<'_>, 8); | |
85 | ||
dc9dc135 | 86 | /// Packages the kind of error we got from the const code interpreter |
60c5eb7d | 87 | /// up with a Rust-level backtrace of where the error occurred. |
cdc7bbd5 | 88 | /// These should always be constructed by calling `.into()` on |
94222f64 | 89 | /// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*` |
416331ca | 90 | /// macros for this. |
60c5eb7d | 91 | #[derive(Debug)] |
6a06907d XL |
92 | pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>); |
93 | ||
94 | #[derive(Debug)] | |
95 | struct InterpErrorInfoInner<'tcx> { | |
96 | kind: InterpError<'tcx>, | |
fe692bf9 FG |
97 | backtrace: InterpErrorBacktrace, |
98 | } | |
99 | ||
100 | #[derive(Debug)] | |
101 | pub struct InterpErrorBacktrace { | |
dc9dc135 | 102 | backtrace: Option<Box<Backtrace>>, |
a1dfa0c6 XL |
103 | } |
104 | ||
fe692bf9 FG |
105 | impl InterpErrorBacktrace { |
106 | pub fn new() -> InterpErrorBacktrace { | |
107 | let capture_backtrace = tls::with_opt(|tcx| { | |
108 | if let Some(tcx) = tcx { | |
109 | *Lock::borrow(&tcx.sess.ctfe_backtrace) | |
110 | } else { | |
111 | CtfeBacktrace::Disabled | |
112 | } | |
113 | }); | |
114 | ||
115 | let backtrace = match capture_backtrace { | |
116 | CtfeBacktrace::Disabled => None, | |
117 | CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())), | |
118 | CtfeBacktrace::Immediate => { | |
119 | // Print it now. | |
120 | let backtrace = Backtrace::force_capture(); | |
121 | print_backtrace(&backtrace); | |
122 | None | |
123 | } | |
124 | }; | |
125 | ||
126 | InterpErrorBacktrace { backtrace } | |
416331ca | 127 | } |
416331ca | 128 | |
f9f354fc | 129 | pub fn print_backtrace(&self) { |
fe692bf9 | 130 | if let Some(backtrace) = self.backtrace.as_ref() { |
f9f354fc | 131 | print_backtrace(backtrace); |
a1dfa0c6 XL |
132 | } |
133 | } | |
fe692bf9 FG |
134 | } |
135 | ||
136 | impl<'tcx> InterpErrorInfo<'tcx> { | |
fe692bf9 FG |
137 | pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) { |
138 | let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self; | |
139 | (kind, backtrace) | |
140 | } | |
6a06907d XL |
141 | |
142 | pub fn into_kind(self) -> InterpError<'tcx> { | |
143 | let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self; | |
144 | kind | |
145 | } | |
146 | ||
147 | #[inline] | |
148 | pub fn kind(&self) -> &InterpError<'tcx> { | |
149 | &self.0.kind | |
150 | } | |
a1dfa0c6 XL |
151 | } |
152 | ||
f9f354fc | 153 | fn print_backtrace(backtrace: &Backtrace) { |
add651ee | 154 | eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}"); |
ea8adc8c XL |
155 | } |
156 | ||
5e7ed085 FG |
157 | impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { |
158 | fn from(err: ErrorGuaranteed) -> Self { | |
49aad941 | 159 | InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into() |
29967ef6 XL |
160 | } |
161 | } | |
162 | ||
416331ca XL |
163 | impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> { |
164 | fn from(kind: InterpError<'tcx>) -> Self { | |
fe692bf9 FG |
165 | InterpErrorInfo(Box::new(InterpErrorInfoInner { |
166 | kind, | |
167 | backtrace: InterpErrorBacktrace::new(), | |
168 | })) | |
ea8adc8c XL |
169 | } |
170 | } | |
171 | ||
e1599b0c XL |
172 | /// Error information for when the program we executed turned out not to actually be a valid |
173 | /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp | |
174 | /// where we work on generic code or execution does not have all information available. | |
fe692bf9 | 175 | #[derive(Debug)] |
416331ca XL |
176 | pub enum InvalidProgramInfo<'tcx> { |
177 | /// Resolution can fail if we are in a too generic context. | |
178 | TooGeneric, | |
29967ef6 | 179 | /// Abort in case errors are already reported. |
49aad941 | 180 | AlreadyReported(ReportedErrorInfo), |
416331ca XL |
181 | /// An error occurred during layout computation. |
182 | Layout(layout::LayoutError<'tcx>), | |
a2a8927a XL |
183 | /// An error occurred during FnAbi computation: the passed --target lacks FFI support |
184 | /// (which unfortunately typeck does not reject). | |
185 | /// Not using `FnAbiError` as that contains a nested `LayoutError`. | |
186 | FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), | |
add651ee FG |
187 | /// We are runnning into a nonsense situation due to ConstProp violating our invariants. |
188 | ConstPropNonsense, | |
416331ca | 189 | } |
b7449926 | 190 | |
f9f354fc | 191 | /// Details of why a pointer had to be in-bounds. |
3dfed10e | 192 | #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] |
f9f354fc | 193 | pub enum CheckInAllocMsg { |
136023e0 XL |
194 | /// We are dereferencing a pointer (i.e., creating a place). |
195 | DerefTest, | |
17df50a5 | 196 | /// We are access memory. |
f9f354fc | 197 | MemoryAccessTest, |
17df50a5 | 198 | /// We are doing pointer arithmetic. |
f9f354fc | 199 | PointerArithmeticTest, |
5e7ed085 FG |
200 | /// We are doing pointer offset_from. |
201 | OffsetFromTest, | |
17df50a5 | 202 | /// None of the above -- generic/unspecific inbounds test. |
f9f354fc XL |
203 | InboundsTest, |
204 | } | |
205 | ||
fe692bf9 FG |
206 | #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] |
207 | pub enum InvalidMetaKind { | |
208 | /// Size of a `[T]` is too big | |
209 | SliceTooBig, | |
210 | /// Size of a DST is too big | |
211 | TooBig, | |
212 | } | |
213 | ||
214 | impl IntoDiagnosticArg for InvalidMetaKind { | |
215 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
216 | DiagnosticArgValue::Str(Cow::Borrowed(match self { | |
217 | InvalidMetaKind::SliceTooBig => "slice_too_big", | |
218 | InvalidMetaKind::TooBig => "too_big", | |
219 | })) | |
f9f354fc XL |
220 | } |
221 | } | |
222 | ||
add651ee | 223 | /// Details of an access to uninitialized bytes / bad pointer bytes where it is not allowed. |
fe692bf9 | 224 | #[derive(Debug, Clone, Copy)] |
add651ee | 225 | pub struct BadBytesAccess { |
064997fb FG |
226 | /// Range of the original memory access. |
227 | pub access: AllocRange, | |
add651ee FG |
228 | /// Range of the bad memory that was encountered. (Might not be maximal.) |
229 | pub bad: AllocRange, | |
f9f354fc XL |
230 | } |
231 | ||
04454e1e FG |
232 | /// Information about a size mismatch. |
233 | #[derive(Debug)] | |
234 | pub struct ScalarSizeMismatch { | |
235 | pub target_size: u64, | |
236 | pub data_size: u64, | |
237 | } | |
238 | ||
fe692bf9 FG |
239 | macro_rules! impl_into_diagnostic_arg_through_debug { |
240 | ($($ty:ty),*$(,)?) => {$( | |
241 | impl IntoDiagnosticArg for $ty { | |
242 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
243 | DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}"))) | |
244 | } | |
245 | } | |
246 | )*} | |
247 | } | |
248 | ||
249 | // These types have nice `Debug` output so we can just use them in diagnostics. | |
250 | impl_into_diagnostic_arg_through_debug! { | |
251 | AllocId, | |
252 | Pointer, | |
253 | AllocRange, | |
254 | } | |
255 | ||
e1599b0c | 256 | /// Error information for when the program caused Undefined Behavior. |
fe692bf9 FG |
257 | #[derive(Debug)] |
258 | pub enum UndefinedBehaviorInfo<'a> { | |
259 | /// Free-form case. Only for errors that are never caught! Used by miri | |
416331ca | 260 | Ub(String), |
416331ca XL |
261 | /// Unreachable code was executed. |
262 | Unreachable, | |
60c5eb7d | 263 | /// A slice/array index projection went out-of-bounds. |
fe692bf9 | 264 | BoundsCheckFailed { len: u64, index: u64 }, |
60c5eb7d XL |
265 | /// Something was divided by 0 (x / 0). |
266 | DivisionByZero, | |
267 | /// Something was "remainded" by 0 (x % 0). | |
268 | RemainderByZero, | |
5e7ed085 FG |
269 | /// Signed division overflowed (INT_MIN / -1). |
270 | DivisionOverflow, | |
271 | /// Signed remainder overflowed (INT_MIN % -1). | |
272 | RemainderOverflow, | |
60c5eb7d XL |
273 | /// Overflowing inbounds pointer arithmetic. |
274 | PointerArithOverflow, | |
fe692bf9 FG |
275 | /// Invalid metadata in a wide pointer |
276 | InvalidMeta(InvalidMetaKind), | |
ba9703b0 XL |
277 | /// Reading a C string that does not end within its allocation. |
278 | UnterminatedCString(Pointer), | |
add651ee FG |
279 | /// Using a pointer after it got freed. |
280 | PointerUseAfterFree(AllocId, CheckInAllocMsg), | |
ba9703b0 | 281 | /// Used a pointer outside the bounds it is valid for. |
136023e0 | 282 | /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.) |
ba9703b0 | 283 | PointerOutOfBounds { |
136023e0 XL |
284 | alloc_id: AllocId, |
285 | alloc_size: Size, | |
286 | ptr_offset: i64, | |
287 | ptr_size: Size, | |
ba9703b0 | 288 | msg: CheckInAllocMsg, |
ba9703b0 | 289 | }, |
f9f354fc XL |
290 | /// Using an integer as a pointer in the wrong way. |
291 | DanglingIntPointer(u64, CheckInAllocMsg), | |
ba9703b0 | 292 | /// Used a pointer with bad alignment. |
fe692bf9 | 293 | AlignmentCheckFailed { required: Align, has: Align }, |
ba9703b0 XL |
294 | /// Writing to read-only memory. |
295 | WriteToReadOnly(AllocId), | |
fe692bf9 | 296 | /// Trying to access the data behind a function pointer. |
ba9703b0 | 297 | DerefFunctionPointer(AllocId), |
fe692bf9 | 298 | /// Trying to access the data behind a vtable pointer. |
064997fb | 299 | DerefVTablePointer(AllocId), |
ba9703b0 XL |
300 | /// Using a non-boolean `u8` as bool. |
301 | InvalidBool(u8), | |
302 | /// Using a non-character `u32` as character. | |
303 | InvalidChar(u32), | |
f035d41b XL |
304 | /// The tag of an enum does not encode an actual discriminant. |
305 | InvalidTag(Scalar), | |
f9f354fc XL |
306 | /// Using a pointer-not-to-a-function as function pointer. |
307 | InvalidFunctionPointer(Pointer), | |
064997fb FG |
308 | /// Using a pointer-not-to-a-vtable as vtable pointer. |
309 | InvalidVTablePointer(Pointer), | |
f9f354fc XL |
310 | /// Using a string that is not valid UTF-8, |
311 | InvalidStr(std::str::Utf8Error), | |
ba9703b0 | 312 | /// Using uninitialized data where it is not allowed. |
add651ee | 313 | InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>), |
ba9703b0 XL |
314 | /// Working with a local that is not currently live. |
315 | DeadLocal, | |
f9f354fc | 316 | /// Data size is not equal to target size. |
04454e1e | 317 | ScalarSizeMismatch(ScalarSizeMismatch), |
c295e0f8 | 318 | /// A discriminant of an uninhabited enum variant is written. |
add651ee FG |
319 | UninhabitedEnumVariantWritten(VariantIdx), |
320 | /// An uninhabited enum variant is projected. | |
321 | UninhabitedEnumVariantRead(VariantIdx), | |
fe692bf9 | 322 | /// Validation error. |
add651ee | 323 | ValidationError(ValidationErrorInfo<'a>), |
fe692bf9 FG |
324 | // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically |
325 | // dispatched | |
326 | /// A custom (free-form) error, created by `err_ub_custom!`. | |
327 | Custom(crate::error::CustomSubdiagnostic<'a>), | |
328 | } | |
329 | ||
330 | #[derive(Debug, Clone, Copy)] | |
331 | pub enum PointerKind { | |
332 | Ref, | |
333 | Box, | |
334 | } | |
335 | ||
336 | impl IntoDiagnosticArg for PointerKind { | |
337 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
338 | DiagnosticArgValue::Str( | |
339 | match self { | |
340 | Self::Ref => "ref", | |
341 | Self::Box => "box", | |
342 | } | |
343 | .into(), | |
344 | ) | |
345 | } | |
416331ca | 346 | } |
48663c56 | 347 | |
fe692bf9 FG |
348 | #[derive(Debug)] |
349 | pub struct ValidationErrorInfo<'tcx> { | |
350 | pub path: Option<String>, | |
351 | pub kind: ValidationErrorKind<'tcx>, | |
352 | } | |
353 | ||
354 | #[derive(Debug)] | |
355 | pub enum ExpectedKind { | |
356 | Reference, | |
357 | Box, | |
358 | RawPtr, | |
359 | InitScalar, | |
360 | Bool, | |
361 | Char, | |
362 | Float, | |
363 | Int, | |
364 | FnPtr, | |
add651ee FG |
365 | EnumTag, |
366 | Str, | |
fe692bf9 FG |
367 | } |
368 | ||
369 | impl From<PointerKind> for ExpectedKind { | |
370 | fn from(x: PointerKind) -> ExpectedKind { | |
371 | match x { | |
372 | PointerKind::Box => ExpectedKind::Box, | |
373 | PointerKind::Ref => ExpectedKind::Reference, | |
416331ca XL |
374 | } |
375 | } | |
376 | } | |
377 | ||
fe692bf9 FG |
378 | #[derive(Debug)] |
379 | pub enum ValidationErrorKind<'tcx> { | |
add651ee FG |
380 | PointerAsInt { expected: ExpectedKind }, |
381 | PartialPointer, | |
fe692bf9 FG |
382 | PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, |
383 | PtrToStatic { ptr_kind: PointerKind }, | |
384 | PtrToMut { ptr_kind: PointerKind }, | |
fe692bf9 FG |
385 | MutableRefInConst, |
386 | NullFnPtr, | |
387 | NeverVal, | |
388 | NullablePtrOutOfRange { range: WrappingRange, max_value: u128 }, | |
389 | PtrOutOfRange { range: WrappingRange, max_value: u128 }, | |
390 | OutOfRange { value: String, range: WrappingRange, max_value: u128 }, | |
391 | UnsafeCell, | |
392 | UninhabitedVal { ty: Ty<'tcx> }, | |
393 | InvalidEnumTag { value: String }, | |
add651ee | 394 | UninhabitedEnumVariant, |
fe692bf9 | 395 | Uninit { expected: ExpectedKind }, |
fe692bf9 FG |
396 | InvalidVTablePtr { value: String }, |
397 | InvalidMetaSliceTooLarge { ptr_kind: PointerKind }, | |
398 | InvalidMetaTooLarge { ptr_kind: PointerKind }, | |
399 | UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 }, | |
400 | NullPtr { ptr_kind: PointerKind }, | |
401 | DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String }, | |
402 | DanglingPtrOutOfBounds { ptr_kind: PointerKind }, | |
403 | DanglingPtrUseAfterFree { ptr_kind: PointerKind }, | |
404 | InvalidBool { value: String }, | |
405 | InvalidChar { value: String }, | |
406 | InvalidFnPtr { value: String }, | |
407 | } | |
408 | ||
e1599b0c XL |
409 | /// Error information for when the program did something that might (or might not) be correct |
410 | /// to do according to the Rust spec, but due to limitations in the interpreter, the | |
411 | /// operation could not be carried out. These limitations can differ between CTFE and the | |
f9f354fc | 412 | /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses. |
fe692bf9 | 413 | #[derive(Debug)] |
ba9703b0 | 414 | pub enum UnsupportedOpInfo { |
416331ca | 415 | /// Free-form case. Only for errors that are never caught! |
fe692bf9 | 416 | // FIXME still use translatable diagnostics |
416331ca | 417 | Unsupported(String), |
f9f354fc XL |
418 | // |
419 | // The variants below are only reachable from CTFE/const prop, miri will never emit them. | |
420 | // | |
487cf647 FG |
421 | /// Overwriting parts of a pointer; without knowing absolute addresses, the resulting state |
422 | /// cannot be represented by the CTFE interpreter. | |
add651ee FG |
423 | OverwritePartialPointer(Pointer<AllocId>), |
424 | /// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute | |
487cf647 | 425 | /// addresses, the resulting state cannot be represented by the CTFE interpreter. |
add651ee FG |
426 | ReadPartialPointer(Pointer<AllocId>), |
427 | /// Encountered a pointer where we needed an integer. | |
428 | ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>), | |
f9f354fc XL |
429 | /// Accessing thread local statics |
430 | ThreadLocalStatic(DefId), | |
3dfed10e XL |
431 | /// Accessing an unsupported extern static. |
432 | ReadExternStatic(DefId), | |
ea8adc8c XL |
433 | } |
434 | ||
e1599b0c XL |
435 | /// Error information for when the program exhausted the resources granted to it |
436 | /// by the interpreter. | |
fe692bf9 | 437 | #[derive(Debug)] |
416331ca XL |
438 | pub enum ResourceExhaustionInfo { |
439 | /// The stack grew too big. | |
440 | StackFrameLimitReached, | |
9ffffee4 | 441 | /// There is not enough memory (on the host) to perform an allocation. |
136023e0 | 442 | MemoryExhausted, |
9ffffee4 FG |
443 | /// The address space (of the target) is full. |
444 | AddressSpaceFull, | |
416331ca XL |
445 | } |
446 | ||
ba9703b0 | 447 | /// A trait for machine-specific errors (or other "machine stop" conditions). |
fe692bf9 FG |
448 | pub trait MachineStopType: Any + fmt::Debug + Send { |
449 | /// The diagnostic message for this error | |
450 | fn diagnostic_message(&self) -> DiagnosticMessage; | |
451 | /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to | |
452 | /// fluent for formatting the translated diagnostic message. | |
453 | fn add_args( | |
454 | self: Box<Self>, | |
455 | adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>), | |
456 | ); | |
457 | } | |
ba9703b0 XL |
458 | |
459 | impl dyn MachineStopType { | |
460 | #[inline(always)] | |
461 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { | |
fe692bf9 FG |
462 | let x: &dyn Any = self; |
463 | x.downcast_ref() | |
ba9703b0 XL |
464 | } |
465 | } | |
466 | ||
fe692bf9 | 467 | #[derive(Debug)] |
416331ca | 468 | pub enum InterpError<'tcx> { |
416331ca | 469 | /// The program caused undefined behavior. |
fe692bf9 | 470 | UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), |
416331ca XL |
471 | /// The program did something the interpreter does not support (some of these *might* be UB |
472 | /// but the interpreter is not sure). | |
ba9703b0 | 473 | Unsupported(UnsupportedOpInfo), |
60c5eb7d | 474 | /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...). |
416331ca XL |
475 | InvalidProgram(InvalidProgramInfo<'tcx>), |
476 | /// The program exhausted the interpreter's resources (stack/heap too big, | |
60c5eb7d | 477 | /// execution takes too long, ...). |
416331ca | 478 | ResourceExhaustion(ResourceExhaustionInfo), |
60c5eb7d XL |
479 | /// Stop execution for a machine-controlled reason. This is never raised by |
480 | /// the core engine itself. | |
ba9703b0 | 481 | MachineStop(Box<dyn MachineStopType>), |
416331ca XL |
482 | } |
483 | ||
484 | pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>; | |
485 | ||
74b04a01 | 486 | impl InterpError<'_> { |
136023e0 | 487 | /// Some errors do string formatting even if the error is never printed. |
6a06907d XL |
488 | /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, |
489 | /// so this method lets us detect them and `bug!` on unexpected errors. | |
490 | pub fn formatted_string(&self) -> bool { | |
3c0e092e XL |
491 | matches!( |
492 | self, | |
ba9703b0 | 493 | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) |
add651ee | 494 | | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. }) |
3c0e092e XL |
495 | | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) |
496 | ) | |
ea8adc8c XL |
497 | } |
498 | } |