Add stack traces to miri errors
This commit is contained in:
parent
8c53d54b98
commit
bd03371f71
6 changed files with 43 additions and 28 deletions
|
@ -440,6 +440,11 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {
|
|||
kind
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
|
||||
span,
|
||||
location
|
||||
});
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ::middle::const_val::ErrKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
|
@ -468,7 +473,10 @@ for ::middle::const_val::ErrKind<'gcx> {
|
|||
LayoutError(ref layout_error) => {
|
||||
layout_error.hash_stable(hcx, hasher);
|
||||
}
|
||||
Miri(ref err) => err.hash_stable(hcx, hasher),
|
||||
Miri(ref err, ref trace) => {
|
||||
err.hash_stable(hcx, hasher);
|
||||
trace.hash_stable(hcx, hasher);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -489,9 +497,9 @@ for ::mir::interpret::EvalError<'gcx> {
|
|||
hasher: &mut StableHasher<W>) {
|
||||
use mir::interpret::EvalErrorKind::*;
|
||||
|
||||
mem::discriminant(&*self.kind).hash_stable(hcx, hasher);
|
||||
mem::discriminant(&self.kind).hash_stable(hcx, hasher);
|
||||
|
||||
match *self.kind {
|
||||
match self.kind {
|
||||
DanglingPointerDeref |
|
||||
DoubleFree |
|
||||
InvalidMemoryAccess |
|
||||
|
|
|
@ -19,6 +19,7 @@ use graphviz::IntoCow;
|
|||
use syntax_pos::Span;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
|
||||
|
||||
|
@ -51,7 +52,7 @@ impl<'tcx> ConstVal<'tcx> {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct ConstEvalErr<'tcx> {
|
||||
pub span: Span,
|
||||
pub kind: ErrKind<'tcx>,
|
||||
pub kind: Rc<ErrKind<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -66,13 +67,13 @@ pub enum ErrKind<'tcx> {
|
|||
|
||||
TypeckError,
|
||||
CheckMatchError,
|
||||
Miri(::mir::interpret::EvalError<'tcx>),
|
||||
Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
|
||||
}
|
||||
|
||||
impl<'tcx> From<::mir::interpret::EvalError<'tcx>> for ErrKind<'tcx> {
|
||||
fn from(err: ::mir::interpret::EvalError<'tcx>) -> ErrKind<'tcx> {
|
||||
ErrKind::Miri(err)
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FrameInfo {
|
||||
pub span: Span,
|
||||
pub location: String,
|
||||
}
|
||||
|
||||
impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
|
||||
|
@ -85,21 +86,23 @@ impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrDescription<'a> {
|
||||
pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
|
||||
Simple(Cow<'a, str>),
|
||||
Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]),
|
||||
}
|
||||
|
||||
impl<'a> ConstEvalErrDescription<'a> {
|
||||
impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> {
|
||||
/// Return a one-line description of the error, for lints and such
|
||||
pub fn into_oneline(self) -> Cow<'a, str> {
|
||||
match self {
|
||||
ConstEvalErrDescription::Simple(simple) => simple,
|
||||
ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
||||
pub fn description(&self) -> ConstEvalErrDescription {
|
||||
pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
|
||||
use self::ErrKind::*;
|
||||
use self::ConstEvalErrDescription::*;
|
||||
|
||||
|
@ -110,7 +113,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
match self.kind {
|
||||
match *self.kind {
|
||||
NonConstPath => simple!("non-constant path in constant expression"),
|
||||
UnimplementedConstVal(what) =>
|
||||
simple!("unimplemented constant expression: {}", what),
|
||||
|
@ -124,8 +127,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
|
||||
TypeckError => simple!("type-checking failed"),
|
||||
CheckMatchError => simple!("match-checking failed"),
|
||||
// FIXME: report a full backtrace
|
||||
Miri(ref err) => simple!("{}", err),
|
||||
Miri(ref err, ref trace) => Backtrace(err, trace),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
ConstEvalErrDescription::Simple(message) => {
|
||||
diag.span_label(self.span, message);
|
||||
}
|
||||
ConstEvalErrDescription::Backtrace(miri, frames) => {
|
||||
diag.span_label(self.span, format!("{}", miri));
|
||||
for frame in frames {
|
||||
diag.span_label(frame.span, format!("inside call to {}", frame.location));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !primary_span.contains(self.span) {
|
||||
|
@ -163,7 +171,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
|||
primary_span: Span,
|
||||
primary_kind: &str)
|
||||
{
|
||||
match self.kind {
|
||||
match *self.kind {
|
||||
ErrKind::TypeckError | ErrKind::CheckMatchError => return,
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::error::Error;
|
||||
use std::{fmt, env};
|
||||
use std::rc::Rc;
|
||||
|
||||
use mir;
|
||||
use ty::{FnSig, Ty, layout};
|
||||
|
@ -15,7 +14,7 @@ use backtrace::Backtrace;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EvalError<'tcx> {
|
||||
pub kind: Rc<EvalErrorKind<'tcx>>,
|
||||
pub kind: EvalErrorKind<'tcx>,
|
||||
pub backtrace: Option<Backtrace>,
|
||||
}
|
||||
|
||||
|
@ -26,7 +25,7 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
|
|||
_ => None
|
||||
};
|
||||
EvalError {
|
||||
kind: Rc::new(kind),
|
||||
kind,
|
||||
backtrace,
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +131,7 @@ pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
|
|||
impl<'tcx> Error for EvalError<'tcx> {
|
||||
fn description(&self) -> &str {
|
||||
use self::EvalErrorKind::*;
|
||||
match *self.kind {
|
||||
match self.kind {
|
||||
MachineError(ref inner) => inner,
|
||||
FunctionPointerTyMismatch(..) =>
|
||||
"tried to call a function through a function pointer of a different type",
|
||||
|
@ -253,7 +252,7 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
impl<'tcx> fmt::Display for EvalError<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::EvalErrorKind::*;
|
||||
match *self.kind {
|
||||
match self.kind {
|
||||
PointerOutOfBounds { ptr, access, allocation_size } => {
|
||||
write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
|
||||
if access { "memory access" } else { "pointer computed" },
|
||||
|
|
|
@ -775,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
ConstEvalFailure(ref err) => {
|
||||
if let ::middle::const_val::ErrKind::TypeckError = err.kind {
|
||||
if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
|
||||
return;
|
||||
}
|
||||
err.struct_error(self.tcx, span, "constant expression")
|
||||
|
|
|
@ -536,7 +536,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
|
|||
} else {
|
||||
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
|
||||
span: obligation.cause.span,
|
||||
kind: ErrKind::UnimplementedConstVal("could not resolve"),
|
||||
kind: ErrKind::UnimplementedConstVal("could not resolve").into(),
|
||||
})))
|
||||
}
|
||||
},
|
||||
|
|
|
@ -578,10 +578,10 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
|||
impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
|
||||
type Lifted = ConstEvalErr<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.kind).map(|kind| {
|
||||
tcx.lift(&*self.kind).map(|kind| {
|
||||
ConstEvalErr {
|
||||
span: self.span,
|
||||
kind,
|
||||
kind: Rc::new(kind),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -591,7 +591,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
|||
type Lifted = interpret::EvalError<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
use ::mir::interpret::EvalErrorKind::*;
|
||||
let kind = match *self.kind {
|
||||
let kind = match self.kind {
|
||||
MachineError(ref err) => MachineError(err.clone()),
|
||||
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
|
||||
tcx.lift(&a)?,
|
||||
|
@ -691,7 +691,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
|||
TypeckError => TypeckError,
|
||||
};
|
||||
Some(interpret::EvalError {
|
||||
kind: Rc::new(kind),
|
||||
kind: kind,
|
||||
backtrace: self.backtrace.clone(),
|
||||
})
|
||||
}
|
||||
|
@ -714,7 +714,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
|
|||
|
||||
TypeckError => TypeckError,
|
||||
CheckMatchError => CheckMatchError,
|
||||
Miri(ref e) => return tcx.lift(e).map(Miri),
|
||||
Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue