From bd03371f711adcb7724c939ea053f4090e87c16f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 10:39:30 +0100 Subject: [PATCH] Add stack traces to miri errors --- src/librustc/ich/impls_ty.rs | 14 ++++++++--- src/librustc/middle/const_val.rs | 34 ++++++++++++++++---------- src/librustc/mir/interpret/error.rs | 9 +++---- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/ty/structural_impls.rs | 10 ++++---- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 72bc5af3b7e..a398549f359 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -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> for ::middle::const_val::ErrKind<'gcx> { fn hash_stable(&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) { 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 | diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index c987ed0ea5d..d6d23c5cad8 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -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>, } #[derive(Clone, Debug)] @@ -66,13 +67,13 @@ pub enum ErrKind<'tcx> { TypeckError, CheckMatchError, - Miri(::mir::interpret::EvalError<'tcx>), + Miri(::mir::interpret::EvalError<'tcx>, Vec), } -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 for ErrKind<'tcx> { @@ -85,21 +86,23 @@ impl<'tcx> From 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, _ => {} } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 3e8aeaff57e..90d10df1515 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -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>, + pub kind: EvalErrorKind<'tcx>, pub backtrace: Option, } @@ -26,7 +25,7 @@ impl<'tcx> From> for EvalError<'tcx> { _ => None }; EvalError { - kind: Rc::new(kind), + kind, backtrace, } } @@ -132,7 +131,7 @@ pub type EvalResult<'tcx, T = ()> = Result>; 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" }, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2e554aff13e..cd2d0d7e2a0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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") diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 5c082b0610f..15925a19d75 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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(), }))) } }, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4e1f3664d7f..c1a4f5ef458 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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 { - 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 { 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())), }) } }