diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9..d8b207fa25a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -387,10 +387,10 @@ impl_stable_hash_for!(enum mir::interpret::ErrorHandled { TooGeneric }); -impl_stable_hash_for!(struct mir::interpret::FrameInfo { +impl_stable_hash_for!(struct mir::interpret::FrameInfo<'tcx> { span, lint_root, - location + instance }); impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed42..c30d41f3403 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -10,8 +10,9 @@ use std::{fmt, env}; +use hir::map::definitions::DefPathData; use mir; -use ty::{Ty, layout}; +use ty::{self, Ty, layout}; use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; @@ -19,7 +20,6 @@ use super::{Pointer, Scalar}; use backtrace::Backtrace; -use ty; use ty::query::TyCtxtAt; use errors::DiagnosticBuilder; @@ -52,16 +52,30 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; pub struct ConstEvalErr<'tcx> { pub span: Span, pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>, - pub stacktrace: Vec, + pub stacktrace: Vec>, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct FrameInfo { +pub struct FrameInfo<'tcx> { pub span: Span, - pub location: String, + pub instance: ty::Instance<'tcx>, pub lint_root: Option, } +impl<'tcx> fmt::Display for FrameInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(|tcx| { + if tcx.def_key(self.instance.def_id()).disambiguated_data.data + == DefPathData::ClosureExpr + { + write!(f, "inside call to closure") + } else { + write!(f, "inside call to `{}`", self.instance) + } + }) + } +} + impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { pub fn struct_error(&self, tcx: TyCtxtAt<'a, 'gcx, 'tcx>, @@ -135,8 +149,13 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { struct_error(tcx, message) }; err.span_label(self.span, self.error.to_string()); - for FrameInfo { span, location, .. } in &self.stacktrace { - err.span_label(*span, format!("inside call to `{}`", location)); + // Skip the last, which is just the environment of the constant. The stacktrace + // is sometimes empty because we create "fake" eval contexts in CTFE to do work + // on constant values. + if self.stacktrace.len() > 0 { + for frame_info in &self.stacktrace[..self.stacktrace.len()-1] { + err.span_label(frame_info.span, frame_info.to_string()); + } } Ok(err) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6267012dc2..279955fba17 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,7 +14,6 @@ use std::mem; use syntax::source_map::{self, Span, DUMMY_SP}; use rustc::hir::def_id::DefId; use rustc::hir::def::Def; -use rustc::hir::map::definitions::DefPathData; use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout @@ -654,11 +653,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec { + pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec> { let mut last_span = None; let mut frames = Vec::new(); - // skip 1 because the last frame is just the environment of the constant - for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() { + for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous if explicit_span == Some(span) { last_span = Some(span); @@ -671,13 +669,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } else { last_span = Some(span); } - let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data - == DefPathData::ClosureExpr - { - "closure".to_owned() - } else { - instance.to_string() - }; let block = &mir.basic_blocks()[block]; let source_info = if stmt < block.statements.len() { block.statements[stmt].source_info @@ -688,7 +679,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root), mir::ClearCrossCrate::Clear => None, }; - frames.push(FrameInfo { span, location, lint_root }); + frames.push(FrameInfo { span, instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames