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 kind
}); });
impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
span,
location
});
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::middle::const_val::ErrKind<'gcx> { for ::middle::const_val::ErrKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
@ -468,7 +473,10 @@ for ::middle::const_val::ErrKind<'gcx> {
LayoutError(ref layout_error) => { LayoutError(ref layout_error) => {
layout_error.hash_stable(hcx, hasher); 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>) { hasher: &mut StableHasher<W>) {
use mir::interpret::EvalErrorKind::*; 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 | DanglingPointerDeref |
DoubleFree | DoubleFree |
InvalidMemoryAccess | InvalidMemoryAccess |

View file

@ -19,6 +19,7 @@ use graphviz::IntoCow;
use syntax_pos::Span; use syntax_pos::Span;
use std::borrow::Cow; use std::borrow::Cow;
use std::rc::Rc;
pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
@ -51,7 +52,7 @@ impl<'tcx> ConstVal<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ConstEvalErr<'tcx> { pub struct ConstEvalErr<'tcx> {
pub span: Span, pub span: Span,
pub kind: ErrKind<'tcx>, pub kind: Rc<ErrKind<'tcx>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -66,13 +67,13 @@ pub enum ErrKind<'tcx> {
TypeckError, TypeckError,
CheckMatchError, CheckMatchError,
Miri(::mir::interpret::EvalError<'tcx>), Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
} }
impl<'tcx> From<::mir::interpret::EvalError<'tcx>> for ErrKind<'tcx> { #[derive(Clone, Debug)]
fn from(err: ::mir::interpret::EvalError<'tcx>) -> ErrKind<'tcx> { pub struct FrameInfo {
ErrKind::Miri(err) pub span: Span,
} pub location: String,
} }
impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> { impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
@ -85,21 +86,23 @@ impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ConstEvalErrDescription<'a> { pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
Simple(Cow<'a, str>), 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 /// Return a one-line description of the error, for lints and such
pub fn into_oneline(self) -> Cow<'a, str> { pub fn into_oneline(self) -> Cow<'a, str> {
match self { match self {
ConstEvalErrDescription::Simple(simple) => simple, ConstEvalErrDescription::Simple(simple) => simple,
ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
} }
} }
} }
impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
pub fn description(&self) -> ConstEvalErrDescription { pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
use self::ErrKind::*; use self::ErrKind::*;
use self::ConstEvalErrDescription::*; 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"), NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) => UnimplementedConstVal(what) =>
simple!("unimplemented constant expression: {}", what), simple!("unimplemented constant expression: {}", what),
@ -124,8 +127,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
TypeckError => simple!("type-checking failed"), TypeckError => simple!("type-checking failed"),
CheckMatchError => simple!("match-checking failed"), CheckMatchError => simple!("match-checking failed"),
// FIXME: report a full backtrace Miri(ref err, ref trace) => Backtrace(err, trace),
Miri(ref err) => simple!("{}", err),
} }
} }
@ -150,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
ConstEvalErrDescription::Simple(message) => { ConstEvalErrDescription::Simple(message) => {
diag.span_label(self.span, 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) { if !primary_span.contains(self.span) {
@ -163,7 +171,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
primary_span: Span, primary_span: Span,
primary_kind: &str) primary_kind: &str)
{ {
match self.kind { match *self.kind {
ErrKind::TypeckError | ErrKind::CheckMatchError => return, ErrKind::TypeckError | ErrKind::CheckMatchError => return,
_ => {} _ => {}
} }

View file

@ -1,6 +1,5 @@
use std::error::Error; use std::error::Error;
use std::{fmt, env}; use std::{fmt, env};
use std::rc::Rc;
use mir; use mir;
use ty::{FnSig, Ty, layout}; use ty::{FnSig, Ty, layout};
@ -15,7 +14,7 @@ use backtrace::Backtrace;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EvalError<'tcx> { pub struct EvalError<'tcx> {
pub kind: Rc<EvalErrorKind<'tcx>>, pub kind: EvalErrorKind<'tcx>,
pub backtrace: Option<Backtrace>, pub backtrace: Option<Backtrace>,
} }
@ -26,7 +25,7 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
_ => None _ => None
}; };
EvalError { EvalError {
kind: Rc::new(kind), kind,
backtrace, backtrace,
} }
} }
@ -132,7 +131,7 @@ pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
impl<'tcx> Error for EvalError<'tcx> { impl<'tcx> Error for EvalError<'tcx> {
fn description(&self) -> &str { fn description(&self) -> &str {
use self::EvalErrorKind::*; use self::EvalErrorKind::*;
match *self.kind { match self.kind {
MachineError(ref inner) => inner, MachineError(ref inner) => inner,
FunctionPointerTyMismatch(..) => FunctionPointerTyMismatch(..) =>
"tried to call a function through a function pointer of a different type", "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> { impl<'tcx> fmt::Display for EvalError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::EvalErrorKind::*; use self::EvalErrorKind::*;
match *self.kind { match self.kind {
PointerOutOfBounds { ptr, access, allocation_size } => { PointerOutOfBounds { ptr, access, allocation_size } => {
write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
if access { "memory access" } else { "pointer computed" }, if access { "memory access" } else { "pointer computed" },

View file

@ -775,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
ConstEvalFailure(ref err) => { ConstEvalFailure(ref err) => {
if let ::middle::const_val::ErrKind::TypeckError = err.kind { if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
return; return;
} }
err.struct_error(self.tcx, span, "constant expression") err.struct_error(self.tcx, span, "constant expression")

View file

@ -536,7 +536,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
} else { } else {
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
span: obligation.cause.span, 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> { impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
type Lifted = ConstEvalErr<'tcx>; type Lifted = ConstEvalErr<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { 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 { ConstEvalErr {
span: self.span, 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>; type Lifted = interpret::EvalError<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
use ::mir::interpret::EvalErrorKind::*; use ::mir::interpret::EvalErrorKind::*;
let kind = match *self.kind { let kind = match self.kind {
MachineError(ref err) => MachineError(err.clone()), MachineError(ref err) => MachineError(err.clone()),
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
tcx.lift(&a)?, tcx.lift(&a)?,
@ -691,7 +691,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
TypeckError => TypeckError, TypeckError => TypeckError,
}; };
Some(interpret::EvalError { Some(interpret::EvalError {
kind: Rc::new(kind), kind: kind,
backtrace: self.backtrace.clone(), backtrace: self.backtrace.clone(),
}) })
} }
@ -714,7 +714,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
TypeckError => TypeckError, TypeckError => TypeckError,
CheckMatchError => CheckMatchError, 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())),
}) })
} }
} }