2017-08-04 10:55:35 -07:00
|
|
|
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};
|
2018-08-27 13:34:35 +02:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2018-12-03 01:14:35 +01:00
|
|
|
use rustc_macros::HashStable;
|
2017-07-21 13:39:06 +02:00
|
|
|
|
2019-04-02 05:58:25 +03:00
|
|
|
use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef};
|
2017-07-21 13:39:06 +02:00
|
|
|
|
2017-08-03 12:37:52 +02:00
|
|
|
use backtrace::Backtrace;
|
2016-03-14 21:48:00 -06:00
|
|
|
|
2019-02-05 11:20:45 -06:00
|
|
|
use crate::ty::query::TyCtxtAt;
|
2019-02-08 00:56:05 +09:00
|
|
|
use errors::DiagnosticBuilder;
|
2018-06-25 18:46:02 +02:00
|
|
|
|
2018-11-14 23:14:57 +01:00
|
|
|
use syntax_pos::{Pos, Span};
|
2018-08-13 13:48:47 +02:00
|
|
|
use syntax::symbol::Symbol;
|
2018-06-25 18:46:02 +02:00
|
|
|
|
2019-04-05 13:11:44 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
|
2018-08-26 15:19:34 +02:00
|
|
|
pub enum ErrorHandled {
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Already reported a lint or an error for this evaluation.
|
2018-08-26 15:19:34 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2018-11-06 14:17:40 +01:00
|
|
|
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
2019-04-03 15:29:31 +02:00
|
|
|
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
|
2018-06-25 18:46:02 +02:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
|
|
|
pub struct ConstEvalErr<'tcx> {
|
|
|
|
pub span: Span,
|
2019-07-24 10:24:55 +02:00
|
|
|
pub error: crate::mir::interpret::InterpError<'tcx>,
|
2018-11-14 17:25:06 +01:00
|
|
|
pub stacktrace: Vec<FrameInfo<'tcx>>,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
|
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> {
|
2019-02-28 22:43:53 +00:00
|
|
|
/// 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-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2018-11-15 08:59:49 +01:00
|
|
|
if !self.call_site.is_dummy() {
|
2019-04-05 22:42:40 +03:00
|
|
|
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> {
|
2019-06-12 00:11:55 +03:00
|
|
|
pub fn struct_error(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2019-06-12 00:11:55 +03:00
|
|
|
message: &str,
|
|
|
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
|
2018-06-25 18:46:02 +02:00
|
|
|
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);
|
2018-08-26 15:19:34 +02:00
|
|
|
match err {
|
|
|
|
Ok(mut err) => {
|
|
|
|
err.emit();
|
|
|
|
ErrorHandled::Reported
|
|
|
|
},
|
|
|
|
Err(err) => err,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-12 00:11:55 +03:00
|
|
|
pub fn report_as_lint(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2018-06-25 18:46:02 +02:00
|
|
|
message: &str,
|
2019-02-22 15:48:14 +01:00
|
|
|
lint_root: hir::HirId,
|
2019-03-10 17:28:52 -07:00
|
|
|
span: Option<Span>,
|
2018-08-26 15:19:34 +02:00
|
|
|
) -> ErrorHandled {
|
2018-06-25 18:46:02 +02:00
|
|
|
let lint = self.struct_generic(
|
|
|
|
tcx,
|
|
|
|
message,
|
|
|
|
Some(lint_root),
|
|
|
|
);
|
2018-08-26 15:19:34 +02:00
|
|
|
match lint {
|
|
|
|
Ok(mut lint) => {
|
2019-03-10 17:28:52 -07:00
|
|
|
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 {
|
2019-03-11 09:43:05 -07:00
|
|
|
if sp != span {
|
|
|
|
lint.span_label(sp, "");
|
|
|
|
}
|
2019-03-10 17:28:52 -07:00
|
|
|
}
|
|
|
|
}
|
2018-08-26 15:19:34 +02:00
|
|
|
lint.emit();
|
|
|
|
ErrorHandled::Reported
|
|
|
|
},
|
|
|
|
Err(err) => err,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn struct_generic(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2018-06-25 18:46:02 +02:00
|
|
|
message: &str,
|
2019-02-22 15:48:14 +01:00
|
|
|
lint_root: Option<hir::HirId>,
|
2018-08-26 15:19:34 +02:00
|
|
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
|
2018-09-18 11:01:13 +02:00
|
|
|
match self.error {
|
2019-07-31 12:48:54 +05:30
|
|
|
err_inval!(Layout(LayoutError::Unknown(_))) |
|
|
|
|
err_inval!(TooGeneric) =>
|
2019-07-26 10:51:54 +05:30
|
|
|
return Err(ErrorHandled::TooGeneric),
|
2019-07-31 12:48:54 +05:30
|
|
|
err_inval!(Layout(LayoutError::SizeOverflow(_))) |
|
|
|
|
err_inval!(TypeckError) =>
|
2019-07-26 10:51:54 +05:30
|
|
|
return Err(ErrorHandled::Reported),
|
2018-06-25 18:46:02 +02:00
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
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
|
2018-06-25 18:46:02 +02:00
|
|
|
.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,
|
2018-06-25 18:46:02 +02:00
|
|
|
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] {
|
2018-11-15 08:59:49 +01:00
|
|
|
err.span_label(frame_info.call_site, frame_info.to_string());
|
2018-11-14 17:25:06 +01:00
|
|
|
}
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
2018-08-26 15:19:34 +02:00
|
|
|
Ok(err)
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 00:48:52 +03:00
|
|
|
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
|
2018-06-25 18:46:02 +02:00
|
|
|
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
|
2019-07-30 16:08:32 +05:30
|
|
|
/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
|
|
|
|
/// macros for this.
|
2018-09-18 11:01:13 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2019-06-07 18:56:27 +02:00
|
|
|
pub struct InterpErrorInfo<'tcx> {
|
2019-07-24 10:24:55 +02:00
|
|
|
pub kind: InterpError<'tcx>,
|
2019-06-07 13:48:38 +02:00
|
|
|
backtrace: Option<Box<Backtrace>>,
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
|
2019-07-24 10:24:55 +02:00
|
|
|
|
2019-07-24 11:45:39 +02:00
|
|
|
impl fmt::Display for InterpErrorInfo<'_> {
|
2019-07-24 10:24:55 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.kind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-24 11:45:39 +02:00
|
|
|
impl InterpErrorInfo<'_> {
|
2018-09-18 11:01:13 +02:00
|
|
|
pub fn print_backtrace(&mut self) {
|
|
|
|
if let Some(ref mut backtrace) = self.backtrace {
|
2018-12-11 15:53:35 +01:00
|
|
|
print_backtrace(&mut *backtrace);
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-11 15:53:35 +01:00
|
|
|
fn print_backtrace(backtrace: &mut Backtrace) {
|
2018-09-18 11:01:13 +02:00
|
|
|
backtrace.resolve();
|
2018-12-11 15:53:35 +01:00
|
|
|
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
|
2017-08-02 16:59:01 +02:00
|
|
|
}
|
|
|
|
|
2019-07-24 10:24:55 +02:00
|
|
|
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
|
|
|
fn from(kind: InterpError<'tcx>) -> Self {
|
2018-09-18 11:01:13 +02:00
|
|
|
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
|
2019-02-28 22:43:53 +00:00
|
|
|
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
|
2018-09-18 11:01:13 +02:00
|
|
|
Ok(ref val) if val != "0" => {
|
|
|
|
let mut backtrace = Backtrace::new_unresolved();
|
2018-06-03 03:01:06 +02:00
|
|
|
|
2018-09-18 11:01:13 +02:00
|
|
|
if val == "immediate" {
|
2019-02-28 22:43:53 +00:00
|
|
|
// Print it now.
|
2018-12-11 15:53:35 +01:00
|
|
|
print_backtrace(&mut backtrace);
|
2018-09-18 11:01:13 +02:00
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Box::new(backtrace))
|
2018-06-02 23:38:57 +02:00
|
|
|
}
|
2018-06-03 03:01:06 +02:00
|
|
|
},
|
2018-09-18 11:01:13 +02:00
|
|
|
_ => None,
|
|
|
|
};
|
2019-06-07 18:56:27 +02:00
|
|
|
InterpErrorInfo {
|
2018-01-31 10:39:30 +01:00
|
|
|
kind,
|
2018-09-18 11:01:13 +02:00
|
|
|
backtrace,
|
2017-08-02 16:59:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-20 11:48:16 +05:30
|
|
|
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
2019-07-29 13:28:55 +05:30
|
|
|
pub enum PanicInfo<O> {
|
2019-07-20 11:48:16 +05:30
|
|
|
Panic {
|
|
|
|
msg: Symbol,
|
|
|
|
line: u32,
|
|
|
|
col: u32,
|
|
|
|
file: Symbol,
|
|
|
|
},
|
|
|
|
BoundsCheck {
|
|
|
|
len: O,
|
|
|
|
index: O,
|
|
|
|
},
|
|
|
|
Overflow(mir::BinOp),
|
|
|
|
OverflowNeg,
|
|
|
|
DivisionByZero,
|
|
|
|
RemainderByZero,
|
2019-07-24 10:24:55 +02:00
|
|
|
GeneratorResumedAfterReturn,
|
|
|
|
GeneratorResumedAfterPanic,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Type for MIR `Assert` terminator error messages.
|
2019-07-29 13:28:55 +05:30
|
|
|
pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
|
2019-07-24 10:24:55 +02:00
|
|
|
|
2019-07-29 13:28:55 +05:30
|
|
|
impl<O> PanicInfo<O> {
|
2019-07-24 10:24:55 +02:00
|
|
|
/// 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 {
|
2019-07-29 13:28:55 +05:30
|
|
|
use PanicInfo::*;
|
2019-07-24 10:24:55 +02:00
|
|
|
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 { .. } =>
|
2019-07-29 13:28:55 +05:30
|
|
|
bug!("Unexpected PanicInfo"),
|
2019-07-24 10:24:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-29 13:28:55 +05:30
|
|
|
impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
|
2019-07-24 10:24:55 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-07-29 13:28:55 +05:30
|
|
|
use PanicInfo::*;
|
2019-07-24 10:24:55 +02:00
|
|
|
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-20 11:48:16 +05:30
|
|
|
}
|
|
|
|
|
2019-07-25 16:59:38 +05:30
|
|
|
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
2019-07-26 15:28:27 +05:30
|
|
|
pub enum InvalidProgramInfo<'tcx> {
|
2019-07-29 20:17:52 +05:30
|
|
|
/// Resolution can fail if we are in a too generic context.
|
2019-07-25 16:59:38 +05:30
|
|
|
TooGeneric,
|
|
|
|
/// Cannot compute this constant because it depends on another one
|
2019-07-29 20:17:52 +05:30
|
|
|
/// which already produced an error.
|
2019-07-25 16:59:38 +05:30
|
|
|
ReferencedConstant,
|
2019-07-29 20:17:52 +05:30
|
|
|
/// Abort in case type errors are reached.
|
2019-07-25 16:59:38 +05:30
|
|
|
TypeckError,
|
2019-07-26 19:08:12 +05:30
|
|
|
/// An error occurred during layout computation.
|
2019-07-26 15:28:27 +05:30
|
|
|
Layout(layout::LayoutError<'tcx>),
|
2019-07-25 16:59:38 +05:30
|
|
|
}
|
|
|
|
|
2019-07-27 17:49:12 +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)]
|
2019-08-02 23:24:27 +02:00
|
|
|
pub enum UndefinedBehaviorInfo {
|
2019-07-27 17:49:12 +05:30
|
|
|
/// Handle cases which for which we do not have a fixed variant.
|
2019-07-26 19:08:12 +05:30
|
|
|
Ub(String),
|
2019-07-27 17:49:12 +05:30
|
|
|
/// Unreachable code was executed.
|
2019-07-26 15:28:27 +05:30
|
|
|
Unreachable,
|
2019-07-26 10:51:54 +05:30
|
|
|
}
|
|
|
|
|
2019-08-02 23:24:27 +02:00
|
|
|
impl fmt::Debug for UndefinedBehaviorInfo {
|
2019-07-27 17:49:12 +05:30
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-08-02 23:24:27 +02:00
|
|
|
use UndefinedBehaviorInfo::*;
|
2019-07-27 17:49:12 +05:30
|
|
|
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)]
|
2019-07-29 20:17:52 +05:30
|
|
|
pub enum UnsupportedOpInfo<'tcx> {
|
2019-07-29 13:41:32 +05:30
|
|
|
/// Handle cases which for which we do not have a fixed variant.
|
2019-08-02 23:41:24 +02:00
|
|
|
Unsupported(String),
|
2019-07-27 17:49:12 +05:30
|
|
|
|
|
|
|
// -- Everything below is not classified yet --
|
2019-07-26 15:28:27 +05:30
|
|
|
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),
|
|
|
|
UnimplementedTraitSelection,
|
|
|
|
CalledClosureAsFunction,
|
|
|
|
NoMirFor(String),
|
2016-06-13 11:39:15 +02:00
|
|
|
DerefFunctionPointer,
|
|
|
|
ExecuteMemory,
|
2017-01-12 08:28:42 +01:00
|
|
|
InvalidChar(u128),
|
2017-05-25 16:40:13 -07:00
|
|
|
OutOfTls,
|
|
|
|
TlsOutOfBounds,
|
2016-07-05 14:27:27 +02:00
|
|
|
AlignmentCheckFailed {
|
2018-09-09 01:16:45 +03:00
|
|
|
required: Align,
|
|
|
|
has: Align,
|
2016-07-05 14:27:27 +02:00
|
|
|
},
|
2017-07-13 20:08:35 -07:00
|
|
|
ValidationFailure(String),
|
2016-09-09 12:51:14 +02:00
|
|
|
VtableForArgumentlessMethod,
|
2016-09-09 17:44:04 +02:00
|
|
|
ModifiedConstantMemory,
|
2018-11-19 13:49:07 +01:00
|
|
|
ModifiedStatic,
|
2016-09-13 13:08:57 +02:00
|
|
|
AssumptionNotHeld,
|
2016-11-03 12:30:41 +01:00
|
|
|
TypeNotPrimitive(Ty<'tcx>),
|
2017-07-28 16:48:43 +02:00
|
|
|
ReallocatedWrongMemoryKind(String, String),
|
|
|
|
DeallocatedWrongMemoryKind(String, String),
|
2017-07-03 16:06:06 -07:00
|
|
|
ReallocateNonBasePtr,
|
|
|
|
DeallocateNonBasePtr,
|
2018-09-09 01:16:45 +03:00
|
|
|
IncorrectAllocationInformation(Size, Size, Align, Align),
|
2017-06-23 12:55:49 +02:00
|
|
|
HeapAllocZeroBytes,
|
|
|
|
HeapAllocNonPowerOfTwoAlignment(u64),
|
2017-06-28 13:37:23 +02:00
|
|
|
ReadFromReturnPointer,
|
2017-07-12 10:36:14 +02:00
|
|
|
PathNotFound(Vec<String>),
|
2016-03-14 21:48:00 -06:00
|
|
|
}
|
|
|
|
|
2019-07-29 20:17:52 +05:30
|
|
|
impl fmt::Debug for UnsupportedOpInfo<'tcx> {
|
2018-09-18 11:01:13 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-07-29 20:17:52 +05:30
|
|
|
use UnsupportedOpInfo::*;
|
2019-07-28 20:07:33 +05:30
|
|
|
match self {
|
|
|
|
PointerOutOfBounds { ptr, msg, allocation_size } => {
|
2019-04-23 03:15:27 +03:00
|
|
|
write!(f, "{} failed: pointer must be in-bounds at offset {}, \
|
2019-04-19 02:26:57 +03:00
|
|
|
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
|
|
|
},
|
2019-07-28 20:07:33 +05:30
|
|
|
ValidationFailure(ref err) => {
|
2017-07-13 17:25:38 -07:00
|
|
|
write!(f, "type validation failed: {}", err)
|
|
|
|
}
|
2019-07-28 20:07:33 +05:30
|
|
|
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
|
|
|
|
FunctionAbiMismatch(caller_abi, callee_abi) =>
|
2018-08-27 13:34:35 +02:00
|
|
|
write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
|
|
|
|
callee_abi, caller_abi),
|
2019-07-28 20:07:33 +05:30
|
|
|
FunctionArgMismatch(caller_ty, callee_ty) =>
|
2018-08-27 13:34:35 +02:00
|
|
|
write!(f, "tried to call a function with argument of type {:?} \
|
|
|
|
passing data of type {:?}",
|
|
|
|
callee_ty, caller_ty),
|
2019-07-28 20:07:33 +05:30
|
|
|
FunctionRetMismatch(caller_ty, callee_ty) =>
|
2018-10-02 21:16:35 +02:00
|
|
|
write!(f, "tried to call a function with return type {:?} \
|
|
|
|
passing return place of type {:?}",
|
|
|
|
callee_ty, caller_ty),
|
2019-07-28 20:07:33 +05:30
|
|
|
FunctionArgCountMismatch =>
|
2018-08-27 13:34:35 +02:00
|
|
|
write!(f, "tried to call a function with incorrect number of arguments"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ReallocatedWrongMemoryKind(ref old, ref new) =>
|
2017-07-28 16:48:43 +02:00
|
|
|
write!(f, "tried to reallocate memory from {} to {}", old, new),
|
2019-07-28 20:07:33 +05:30
|
|
|
DeallocatedWrongMemoryKind(ref old, ref new) =>
|
2017-07-28 16:48:43 +02:00
|
|
|
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidChar(c) =>
|
2016-06-21 09:43:27 +02:00
|
|
|
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
|
2019-07-28 20:07:33 +05:30
|
|
|
AlignmentCheckFailed { required, has } =>
|
2016-07-05 14:27:27 +02:00
|
|
|
write!(f, "tried to access memory with alignment {}, but alignment {} is required",
|
2018-09-09 01:16:45 +03:00
|
|
|
has.bytes(), required.bytes()),
|
2019-07-28 20:07:33 +05:30
|
|
|
TypeNotPrimitive(ty) =>
|
2016-11-03 12:30:41 +01:00
|
|
|
write!(f, "expected primitive type, got {}", ty),
|
2019-07-28 20:07:33 +05:30
|
|
|
PathNotFound(ref path) =>
|
2017-07-12 10:36:14 +02:00
|
|
|
write!(f, "Cannot find path {:?}", path),
|
2019-07-28 20:07:33 +05:30
|
|
|
IncorrectAllocationInformation(size, size2, align, align2) =>
|
2018-09-09 00:22:22 +03:00
|
|
|
write!(f, "incorrect alloc info: expected size {} and align {}, \
|
|
|
|
got size {} and align {}",
|
2018-09-09 01:16:45 +03:00
|
|
|
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidDiscriminant(val) =>
|
2018-08-26 14:22:59 +02:00
|
|
|
write!(f, "encountered invalid enum discriminant {}", val),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidMemoryAccess =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to access memory through an invalid pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
DanglingPointerDeref =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "dangling pointer was dereferenced"),
|
2019-07-28 20:07:33 +05:30
|
|
|
DoubleFree =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to deallocate dangling pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidFunctionPointer =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to use a function pointer after offsetting it"),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidBool =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "invalid boolean value read"),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidNullPointerUsage =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "invalid use of NULL pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ReadBytesAsPointer =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "a memory access tried to interpret some bytes as a pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ReadForeignStatic =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to read from foreign (extern) static"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-07-28 20:07:33 +05:30
|
|
|
DeadLocal =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to access a dead local variable"),
|
2019-07-28 20:07:33 +05:30
|
|
|
DerefFunctionPointer =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to dereference a function pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ExecuteMemory =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to treat a memory pointer as a function pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
OutOfTls =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "reached the maximum number of representable TLS keys"),
|
2019-07-28 20:07:33 +05:30
|
|
|
TlsOutOfBounds =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "accessed an invalid (unallocated) TLS key"),
|
2019-07-28 20:07:33 +05:30
|
|
|
CalledClosureAsFunction =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to call a closure through a function pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
VtableForArgumentlessMethod =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to call a vtable function without arguments"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ModifiedConstantMemory =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to modify constant memory"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ModifiedStatic =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to modify a static's initial value from another static's \
|
|
|
|
initializer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
AssumptionNotHeld =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "`assume` argument was false"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-07-28 20:07:33 +05:30
|
|
|
HeapAllocZeroBytes =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ReadFromReturnPointer =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "tried to read from the return pointer"),
|
2019-07-28 20:07:33 +05:30
|
|
|
UnimplementedTraitSelection =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "there were unresolved type arguments during trait selection"),
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidBoolOp(_) =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "invalid boolean operation"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-07-28 20:07:33 +05:30
|
|
|
ReadUndefBytes(_) =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "attempted to read undefined bytes"),
|
2019-07-28 20:07:33 +05:30
|
|
|
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"),
|
2019-08-02 23:41:24 +02:00
|
|
|
Unsupported(ref msg) =>
|
2019-07-24 09:27:20 +02:00
|
|
|
write!(f, "{}", msg),
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
|
|
|
pub enum ResourceExhaustionInfo {
|
2019-07-31 12:48:54 +05:30
|
|
|
/// The stack grew too big.
|
2019-07-28 20:07:33 +05:30
|
|
|
StackFrameLimitReached,
|
2019-07-31 12:48:54 +05:30
|
|
|
/// The program ran into an infinite loop.
|
2019-07-28 20:07:33 +05:30
|
|
|
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.
|
2019-07-29 13:28:55 +05:30
|
|
|
Panic(PanicInfo<u64>),
|
2019-07-28 20:07:33 +05:30
|
|
|
/// The program caused undefined behavior.
|
2019-08-02 23:24:27 +02:00
|
|
|
UndefinedBehavior(UndefinedBehaviorInfo),
|
2019-07-28 20:07:33 +05:30
|
|
|
/// The program did something the interpreter does not support (some of these *might* be UB
|
|
|
|
/// but the interpreter is not sure).
|
2019-07-29 20:17:52 +05:30
|
|
|
Unsupported(UnsupportedOpInfo<'tcx>),
|
2019-07-28 20:07:33 +05:30
|
|
|
/// 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),
|
|
|
|
/// 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>>;
|
|
|
|
|
|
|
|
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::*;
|
|
|
|
match *self {
|
|
|
|
Unsupported(ref msg) =>
|
|
|
|
write!(f, "{:?}", msg),
|
2019-07-27 17:49:12 +05:30
|
|
|
InvalidProgram(ref msg) =>
|
|
|
|
write!(f, "{:?}", msg),
|
2019-08-02 23:24:27 +02:00
|
|
|
UndefinedBehavior(ref msg) =>
|
2019-07-27 17:49:12 +05:30
|
|
|
write!(f, "{:?}", msg),
|
|
|
|
ResourceExhaustion(ref msg) =>
|
|
|
|
write!(f, "{:?}", msg),
|
2019-07-24 10:24:55 +02:00
|
|
|
Panic(ref msg) =>
|
|
|
|
write!(f, "{:?}", msg),
|
2019-07-27 17:49:12 +05:30
|
|
|
Exit(code) =>
|
|
|
|
write!(f, "exited with status code {}", code),
|
2018-04-26 11:37:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|