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
|
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 |
|
||||||
|
|
|
@ -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,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" },
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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(),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue