1
Fork 0

Add stack traces to miri errors

This commit is contained in:
Oliver Schneider 2018-01-31 10:39:30 +01:00
parent 8c53d54b98
commit bd03371f71
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
6 changed files with 43 additions and 28 deletions

View file

@ -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 |

View file

@ -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,
_ => {}
}

View file

@ -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" },

View file

@ -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")

View file

@ -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(),
})))
}
},

View file

@ -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())),
})
}
}