rust/src/librustc/mir/interpret/error.rs

606 lines
23 KiB
Rust
Raw Normal View History

use std::{fmt, env};
2017-08-02 16:59:01 +02:00
2019-02-22 15:48:14 +01:00
use crate::hir;
2019-02-05 11:20:45 -06:00
use crate::hir::map::definitions::DefPathData;
use crate::mir;
use crate::ty::{self, Ty, layout};
use crate::ty::layout::{Size, Align, LayoutError};
use rustc_target::spec::abi::Abi;
2018-12-03 01:14:35 +01:00
use rustc_macros::HashStable;
use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef};
use backtrace::Backtrace;
2016-03-14 21:48:00 -06:00
2019-02-05 11:20:45 -06:00
use crate::ty::query::TyCtxtAt;
use errors::DiagnosticBuilder;
2018-11-14 23:14:57 +01:00
use syntax_pos::{Pos, Span};
use syntax::symbol::Symbol;
2019-04-05 13:11:44 +02:00
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
pub enum ErrorHandled {
2019-02-08 14:53:55 +01:00
/// Already reported a lint or an error for this evaluation.
Reported,
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the substs didn't fully monomorphize it.
TooGeneric,
}
impl ErrorHandled {
pub fn assert_reported(self) {
match self {
ErrorHandled::Reported => {},
ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
even though it was fully monomorphized"),
}
}
}
2019-05-31 10:23:22 +02:00
CloneTypeFoldableImpls! {
ErrorHandled,
}
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
pub error: crate::mir::interpret::InterpError<'tcx>,
2018-11-14 17:25:06 +01:00
pub stacktrace: Vec<FrameInfo<'tcx>>,
}
2018-12-03 01:14:35 +01:00
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
2018-11-14 17:25:06 +01:00
pub struct FrameInfo<'tcx> {
/// This span is in the caller.
pub call_site: Span,
2018-11-14 17:25:06 +01:00
pub instance: ty::Instance<'tcx>,
2019-02-22 15:48:14 +01:00
pub lint_root: Option<hir::HirId>,
}
2018-11-14 17:25:06 +01:00
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
== DefPathData::ClosureExpr
{
2018-11-14 23:14:57 +01:00
write!(f, "inside call to closure")?;
2018-11-14 17:25:06 +01:00
} else {
2018-11-14 23:14:57 +01:00
write!(f, "inside call to `{}`", self.instance)?;
2018-11-14 17:25:06 +01:00
}
if !self.call_site.is_dummy() {
let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
2018-11-14 23:14:57 +01:00
}
Ok(())
2018-11-14 17:25:06 +01:00
})
}
}
2019-06-14 00:48:52 +03:00
impl<'tcx> ConstEvalErr<'tcx> {
pub fn struct_error(
&self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxtAt<'tcx>,
message: &str,
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
self.struct_generic(tcx, message, None)
}
2019-06-14 00:48:52 +03:00
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
2018-06-04 18:32:06 +02:00
let err = self.struct_error(tcx, message);
match err {
Ok(mut err) => {
err.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}
pub fn report_as_lint(
&self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxtAt<'tcx>,
message: &str,
2019-02-22 15:48:14 +01:00
lint_root: hir::HirId,
span: Option<Span>,
) -> ErrorHandled {
let lint = self.struct_generic(
tcx,
message,
Some(lint_root),
);
match lint {
Ok(mut lint) => {
if let Some(span) = span {
let primary_spans = lint.span.primary_spans().to_vec();
// point at the actual error as the primary span
lint.replace_span_with(span);
// point to the `const` statement as a secondary span
// they don't have any label
for sp in primary_spans {
if sp != span {
lint.span_label(sp, "");
}
}
}
lint.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}
fn struct_generic(
&self,
2019-06-14 00:48:52 +03:00
tcx: TyCtxtAt<'tcx>,
message: &str,
2019-02-22 15:48:14 +01:00
lint_root: Option<hir::HirId>,
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
use InvalidProgramInfo::*;
match self.error {
InterpError::InvalidProgram(Layout(LayoutError::Unknown(_))) |
InterpError::InvalidProgram(TooGeneric) =>
2019-07-26 10:51:54 +05:30
return Err(ErrorHandled::TooGeneric),
InterpError::InvalidProgram(Layout(LayoutError::SizeOverflow(_))) |
InterpError::InvalidProgram(TypeckError) =>
2019-07-26 10:51:54 +05:30
return Err(ErrorHandled::Reported),
_ => {},
}
trace!("reporting const eval failure at {:?}", self.span);
let mut err = if let Some(lint_root) = lint_root {
2019-02-22 15:48:14 +01:00
let hir_id = self.stacktrace
.iter()
.rev()
.filter_map(|frame| frame.lint_root)
.next()
.unwrap_or(lint_root);
2019-02-22 15:48:14 +01:00
tcx.struct_span_lint_hir(
2019-02-05 11:20:45 -06:00
crate::rustc::lint::builtin::CONST_ERR,
2019-02-22 15:48:14 +01:00
hir_id,
tcx.span,
message,
)
} else {
struct_error(tcx, message)
};
err.span_label(self.span, self.error.to_string());
2018-11-14 17:25:06 +01:00
// Skip the last, which is just the environment of the constant. The stacktrace
// is sometimes empty because we create "fake" eval contexts in CTFE to do work
// on constant values.
if self.stacktrace.len() > 0 {
for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
err.span_label(frame_info.call_site, frame_info.to_string());
2018-11-14 17:25:06 +01:00
}
}
Ok(err)
}
}
2019-06-14 00:48:52 +03:00
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
}
2019-06-07 15:51:29 +02:00
/// Packages the kind of error we got from the const code interpreter
/// up with a Rust-level backtrace of where the error occured.
/// Thsese should always be constructed by calling `.into()` on
/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
/// macro for this.
#[derive(Debug, Clone)]
pub struct InterpErrorInfo<'tcx> {
pub kind: InterpError<'tcx>,
backtrace: Option<Box<Backtrace>>,
}
impl fmt::Display for InterpErrorInfo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl InterpErrorInfo<'_> {
pub fn print_backtrace(&mut self) {
if let Some(ref mut backtrace) = self.backtrace {
print_backtrace(&mut *backtrace);
}
}
}
fn print_backtrace(backtrace: &mut Backtrace) {
backtrace.resolve();
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
2017-08-02 16:59:01 +02:00
}
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
Ok(ref val) if val != "0" => {
let mut backtrace = Backtrace::new_unresolved();
2018-06-03 03:01:06 +02:00
if val == "immediate" {
// Print it now.
print_backtrace(&mut backtrace);
None
} else {
Some(Box::new(backtrace))
2018-06-02 23:38:57 +02:00
}
2018-06-03 03:01:06 +02:00
},
_ => None,
};
InterpErrorInfo {
2018-01-31 10:39:30 +01:00
kind,
backtrace,
2017-08-02 16:59:01 +02:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
2019-07-23 16:42:46 +05:30
pub enum PanicMessage<O> {
Panic {
msg: Symbol,
line: u32,
col: u32,
file: Symbol,
},
BoundsCheck {
len: O,
index: O,
},
Overflow(mir::BinOp),
OverflowNeg,
DivisionByZero,
RemainderByZero,
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
}
/// Type for MIR `Assert` terminator error messages.
pub type AssertMessage<'tcx> = PanicMessage<mir::Operand<'tcx>>;
impl<O> PanicMessage<O> {
/// Getting a description does not require `O` to be printable, and does not
/// require allocation.
/// The caller is expected to handle `Panic` and `BoundsCheck` separately.
pub fn description(&self) -> &'static str {
use PanicMessage::*;
match self {
Overflow(mir::BinOp::Add) =>
"attempt to add with overflow",
Overflow(mir::BinOp::Sub) =>
"attempt to subtract with overflow",
Overflow(mir::BinOp::Mul) =>
"attempt to multiply with overflow",
Overflow(mir::BinOp::Div) =>
"attempt to divide with overflow",
Overflow(mir::BinOp::Rem) =>
"attempt to calculate the remainder with overflow",
OverflowNeg =>
"attempt to negate with overflow",
Overflow(mir::BinOp::Shr) =>
"attempt to shift right with overflow",
Overflow(mir::BinOp::Shl) =>
"attempt to shift left with overflow",
Overflow(op) =>
bug!("{:?} cannot overflow", op),
DivisionByZero =>
"attempt to divide by zero",
RemainderByZero =>
"attempt to calculate the remainder with a divisor of zero",
GeneratorResumedAfterReturn =>
"generator resumed after completion",
GeneratorResumedAfterPanic =>
"generator resumed after panicking",
Panic { .. } | BoundsCheck { .. } =>
bug!("Unexpected PanicMessage"),
}
}
}
impl<O: fmt::Debug> fmt::Debug for PanicMessage<O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PanicMessage::*;
match self {
Panic { ref msg, line, col, ref file } =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
BoundsCheck { ref len, ref index } =>
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
_ =>
write!(f, "{}", self.description()),
}
}
}
2019-07-25 16:59:38 +05:30
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum InvalidProgramInfo<'tcx> {
2019-07-25 16:59:38 +05:30
/// Resolution can fail if we are in a too generic context
TooGeneric,
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant,
/// Abort in case type errors are reached
TypeckError,
2019-07-26 19:08:12 +05:30
/// An error occurred during layout computation.
Layout(layout::LayoutError<'tcx>),
2019-07-25 16:59:38 +05:30
}
impl fmt::Debug for InvalidProgramInfo<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InvalidProgramInfo::*;
match self {
TooGeneric =>
write!(f, "encountered overly generic constant"),
ReferencedConstant =>
write!(f, "referenced constant has errors"),
TypeckError =>
write!(f, "encountered constants with type errors, stopping evaluation"),
Layout(ref err) =>
write!(f, "rustc layout computation failed: {:?}", err),
}
}
}
2019-07-26 10:51:54 +05:30
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum UndefinedBehaviourInfo {
/// Handle cases which for which we do not have a fixed variant.
2019-07-26 19:08:12 +05:30
Ub(String),
/// Unreachable code was executed.
Unreachable,
2019-07-26 10:51:54 +05:30
}
impl fmt::Debug for UndefinedBehaviourInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UndefinedBehaviourInfo::*;
match self {
Ub(ref msg) =>
write!(f, "{}", msg),
Unreachable =>
write!(f, "entered unreachable code"),
}
}
}
2019-07-26 10:51:54 +05:30
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum UnsupportedInfo<'tcx> {
2019-07-26 19:08:12 +05:30
Unimplemented(String),
// -- Everything below is not classified yet --
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionArgCountMismatch,
UnterminatedCString(Pointer),
DanglingPointerDeref,
DoubleFree,
InvalidMemoryAccess,
InvalidFunctionPointer,
InvalidBool,
InvalidDiscriminant(ScalarMaybeUndef),
PointerOutOfBounds {
ptr: Pointer,
msg: CheckInAllocMsg,
allocation_size: Size,
},
InvalidNullPointerUsage,
ReadPointerAsBytes,
ReadBytesAsPointer,
ReadForeignStatic,
InvalidPointerMath,
ReadUndefBytes(Size),
DeadLocal,
InvalidBoolOp(mir::BinOp),
InlineAsm,
UnimplementedTraitSelection,
CalledClosureAsFunction,
NoMirFor(String),
/// This variant is used by machines to signal their own errors that do not
2019-02-08 14:53:55 +01:00
/// match an existing variant.
MachineError(String),
DerefFunctionPointer,
ExecuteMemory,
2017-06-22 00:08:19 -07:00
Intrinsic(String),
2017-01-12 08:28:42 +01:00
InvalidChar(u128),
2017-05-25 16:40:13 -07:00
OutOfTls,
TlsOutOfBounds,
2017-05-25 22:38:07 -07:00
AbiViolation(String),
AlignmentCheckFailed {
required: Align,
has: Align,
},
ValidationFailure(String),
VtableForArgumentlessMethod,
ModifiedConstantMemory,
ModifiedStatic,
2016-09-13 13:08:57 +02:00
AssumptionNotHeld,
TypeNotPrimitive(Ty<'tcx>),
ReallocatedWrongMemoryKind(String, String),
DeallocatedWrongMemoryKind(String, String),
ReallocateNonBasePtr,
DeallocateNonBasePtr,
IncorrectAllocationInformation(Size, Size, Align, Align),
2017-06-23 12:55:49 +02:00
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
ReadFromReturnPointer,
PathNotFound(Vec<String>),
2016-03-14 21:48:00 -06:00
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum ResourceExhaustionInfo {
StackFrameLimitReached,
InfiniteLoop,
}
impl fmt::Debug for ResourceExhaustionInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ResourceExhaustionInfo::*;
match self {
StackFrameLimitReached =>
write!(f, "reached the configured maximum number of stack frames"),
InfiniteLoop =>
write!(f, "duplicate interpreter state observed here, const evaluation will never \
terminate"),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
pub enum InterpError<'tcx> {
/// The program panicked.
Panic(PanicMessage<u64>),
/// The program caused undefined behavior.
UndefinedBehaviour(UndefinedBehaviourInfo),
/// The program did something the interpreter does not support (some of these *might* be UB
/// but the interpreter is not sure).
Unsupported(UnsupportedInfo<'tcx>),
/// The program was invalid (ill-typed, not sufficiently monomorphized, ...).
InvalidProgram(InvalidProgramInfo<'tcx>),
/// The program exhausted the interpreter's resources (stack/heap too big,
/// execution takes too long, ..).
ResourceExhaustion(ResourceExhaustionInfo),
2019-07-26 19:08:12 +05:30
/// Not actually an interpreter error -- used to signal that execution has exited
/// with the given status code. Used by Miri, but not by CTFE.
Exit(i32),
}
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
2016-03-14 21:48:00 -06:00
impl fmt::Display for InterpError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Forward `Display` to `Debug`
write!(f, "{:?}", self)
}
}
impl fmt::Debug for InterpError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InterpError::*;
use UnsupportedInfo::*;
match *self {
Unsupported(PointerOutOfBounds { ptr, msg, allocation_size }) => {
write!(f, "{} failed: pointer must be in-bounds at offset {}, \
but is outside bounds of allocation {} which has size {}",
msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
2016-06-01 11:22:37 +02:00
},
Unsupported(ValidationFailure(ref err)) => {
2017-07-13 17:25:38 -07:00
write!(f, "type validation failed: {}", err)
}
Unsupported(NoMirFor(ref func)) => write!(f, "no mir for `{}`", func),
Unsupported(FunctionAbiMismatch(caller_abi, callee_abi)) =>
write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
callee_abi, caller_abi),
Unsupported(FunctionArgMismatch(caller_ty, callee_ty)) =>
write!(f, "tried to call a function with argument of type {:?} \
passing data of type {:?}",
callee_ty, caller_ty),
Unsupported(FunctionRetMismatch(caller_ty, callee_ty)) =>
write!(f, "tried to call a function with return type {:?} \
passing return place of type {:?}",
callee_ty, caller_ty),
Unsupported(FunctionArgCountMismatch) =>
write!(f, "tried to call a function with incorrect number of arguments"),
Unsupported(ReallocatedWrongMemoryKind(ref old, ref new)) =>
write!(f, "tried to reallocate memory from {} to {}", old, new),
Unsupported(DeallocatedWrongMemoryKind(ref old, ref new)) =>
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
Unsupported(InvalidChar(c)) =>
2016-06-21 09:43:27 +02:00
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
Unsupported(AlignmentCheckFailed { required, has }) =>
write!(f, "tried to access memory with alignment {}, but alignment {} is required",
has.bytes(), required.bytes()),
Unsupported(TypeNotPrimitive(ty)) =>
write!(f, "expected primitive type, got {}", ty),
Unsupported(PathNotFound(ref path)) =>
write!(f, "Cannot find path {:?}", path),
Unsupported(IncorrectAllocationInformation(size, size2, align, align2)) =>
write!(f, "incorrect alloc info: expected size {} and align {}, \
got size {} and align {}",
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
Unsupported(InvalidDiscriminant(val)) =>
2018-08-26 14:22:59 +02:00
write!(f, "encountered invalid enum discriminant {}", val),
Unsupported(InvalidMemoryAccess) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to access memory through an invalid pointer"),
Unsupported(DanglingPointerDeref) =>
2019-07-24 09:27:20 +02:00
write!(f, "dangling pointer was dereferenced"),
Unsupported(DoubleFree) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to deallocate dangling pointer"),
Unsupported(InvalidFunctionPointer) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to use a function pointer after offsetting it"),
Unsupported(InvalidBool) =>
2019-07-24 09:27:20 +02:00
write!(f, "invalid boolean value read"),
Unsupported(InvalidNullPointerUsage) =>
2019-07-24 09:27:20 +02:00
write!(f, "invalid use of NULL pointer"),
Unsupported(ReadPointerAsBytes) =>
2019-07-24 09:27:20 +02:00
write!(f, "a raw memory access tried to access part of a pointer value as raw \
bytes"),
Unsupported(ReadBytesAsPointer) =>
2019-07-24 09:27:20 +02:00
write!(f, "a memory access tried to interpret some bytes as a pointer"),
Unsupported(ReadForeignStatic) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to read from foreign (extern) static"),
Unsupported(InvalidPointerMath) =>
2019-07-24 09:27:20 +02:00
write!(f, "attempted to do invalid arithmetic on pointers that would leak base \
addresses, e.g., comparing pointers into different allocations"),
Unsupported(DeadLocal) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to access a dead local variable"),
Unsupported(DerefFunctionPointer) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to dereference a function pointer"),
Unsupported(ExecuteMemory) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to treat a memory pointer as a function pointer"),
Unsupported(OutOfTls) =>
2019-07-24 09:27:20 +02:00
write!(f, "reached the maximum number of representable TLS keys"),
Unsupported(TlsOutOfBounds) =>
2019-07-24 09:27:20 +02:00
write!(f, "accessed an invalid (unallocated) TLS key"),
Unsupported(CalledClosureAsFunction) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to call a closure through a function pointer"),
Unsupported(VtableForArgumentlessMethod) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to call a vtable function without arguments"),
Unsupported(ModifiedConstantMemory) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to modify constant memory"),
Unsupported(ModifiedStatic) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to modify a static's initial value from another static's \
initializer"),
Unsupported(AssumptionNotHeld) =>
2019-07-24 09:27:20 +02:00
write!(f, "`assume` argument was false"),
Unsupported(InlineAsm) =>
2019-07-24 09:27:20 +02:00
write!(f, "miri does not support inline assembly"),
Unsupported(ReallocateNonBasePtr) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to reallocate with a pointer not to the beginning of an \
existing object"),
Unsupported(DeallocateNonBasePtr) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to deallocate with a pointer not to the beginning of an \
existing object"),
Unsupported(HeapAllocZeroBytes) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
Unsupported(ReadFromReturnPointer) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to read from the return pointer"),
Unsupported(UnimplementedTraitSelection) =>
2019-07-24 09:27:20 +02:00
write!(f, "there were unresolved type arguments during trait selection"),
Unsupported(InvalidBoolOp(_)) =>
2019-07-24 09:27:20 +02:00
write!(f, "invalid boolean operation"),
Unsupported(UnterminatedCString(_)) =>
2019-07-24 09:27:20 +02:00
write!(f, "attempted to get length of a null terminated string, but no null \
found before end of allocation"),
Unsupported(ReadUndefBytes(_)) =>
2019-07-24 09:27:20 +02:00
write!(f, "attempted to read undefined bytes"),
Unsupported(HeapAllocNonPowerOfTwoAlignment(_)) =>
2019-07-24 09:27:20 +02:00
write!(f, "tried to re-, de-, or allocate heap memory with alignment that is \
not a power of two"),
Unsupported(MachineError(ref msg)) |
Unsupported(Unimplemented(ref msg)) |
Unsupported(AbiViolation(ref msg)) |
Unsupported(Intrinsic(ref msg)) =>
2019-07-24 09:27:20 +02:00
write!(f, "{}", msg),
InvalidProgram(ref msg) =>
write!(f, "{:?}", msg),
UndefinedBehaviour(ref msg) =>
write!(f, "{:?}", msg),
ResourceExhaustion(ref msg) =>
write!(f, "{:?}", msg),
Panic(ref msg) =>
write!(f, "{:?}", msg),
Exit(code) =>
write!(f, "exited with status code {}", code),
2018-04-26 11:37:03 +02:00
}
}
}