From 57a7c85f93d78b507c3779944b2978c617f91c5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 17:25:06 +0100 Subject: [PATCH 1/4] miri: backtraces with instances --- src/librustc/ich/impls_ty.rs | 4 +-- src/librustc/mir/interpret/error.rs | 33 +++++++++++++++++----- src/librustc_mir/interpret/eval_context.rs | 15 ++-------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f4..d8b207fa25aaf 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 f28aa41ed4222..c30d41f340340 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 e6267012dc275..279955fba17ad 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 From fb5135a6fc7e1517c562ea182827533354ae327d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 17:48:17 +0100 Subject: [PATCH 2/4] prettier miri backtrace printing --- src/librustc/mir/interpret/error.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index c30d41f340340..e1b22c64ed69c 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -191,16 +191,23 @@ fn print_backtrace(backtrace: &mut Backtrace) -> String { write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap(); 'frames: for (i, frame) in backtrace.frames().iter().enumerate() { if frame.symbols().is_empty() { - write!(trace_text, "{}: no symbols\n", i).unwrap(); + write!(trace_text, " {}: no symbols\n", i).unwrap(); } + let mut first = true; for symbol in frame.symbols() { - write!(trace_text, "{}: ", i).unwrap(); + if first { + write!(trace_text, " {}: ", i).unwrap(); + first = false; + } else { + let len = i.to_string().len(); + write!(trace_text, " {} ", " ".repeat(len)).unwrap(); + } if let Some(name) = symbol.name() { write!(trace_text, "{}\n", name).unwrap(); } else { write!(trace_text, "\n").unwrap(); } - write!(trace_text, "\tat ").unwrap(); + write!(trace_text, " at ").unwrap(); if let Some(file_path) = symbol.filename() { write!(trace_text, "{}", file_path.display()).unwrap(); } else { From b396505425ab0b0efbc5f399767c6983fc3511e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 23:14:57 +0100 Subject: [PATCH 3/4] put file and line into miri backtrace --- src/librustc/mir/interpret/error.rs | 11 +- .../infinite-recursion-const-fn.stderr | 102 +++++++++--------- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index e1b22c64ed69c..d375e62b27c58 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -23,7 +23,7 @@ use backtrace::Backtrace; use ty::query::TyCtxtAt; use errors::DiagnosticBuilder; -use syntax_pos::Span; +use syntax_pos::{Pos, Span}; use syntax::ast; use syntax::symbol::Symbol; @@ -68,10 +68,15 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr { - write!(f, "inside call to closure") + write!(f, "inside call to closure")?; } else { - write!(f, "inside call to `{}`", self.instance) + write!(f, "inside call to `{}`", self.instance)?; } + if !self.span.is_dummy() { + let lo = tcx.sess.source_map().lookup_char_pos_adj(self.span.lo()); + write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?; + } + Ok(()) }) } } diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index ef35bb6d98dae..4246ec2dad332 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -5,61 +5,61 @@ LL | const fn a() -> usize { b() } //~ ERROR evaluation of constant value failed | ^^^ | | | reached the configured maximum number of stack frames - | inside call to `b` + | inside call to `b` at $DIR/infinite-recursion-const-fn.rs:13:25 LL | const fn b() -> usize { a() } | --- | | - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 LL | const ARR: [i32; a()] = [5; 6]; - | --- inside call to `a` + | --- inside call to `a` at $DIR/infinite-recursion-const-fn.rs:15:18 error: aborting due to previous error From 62cf9abcf6611c598894e9a8abac6c54a72d862d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 08:59:49 +0100 Subject: [PATCH 4/4] rename FrameInfo span field to call_site --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/mir/interpret/error.rs | 8 ++++---- src/librustc_mir/interpret/eval_context.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d8b207fa25aaf..f3b58ee5cf19b 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -388,7 +388,7 @@ impl_stable_hash_for!(enum mir::interpret::ErrorHandled { }); impl_stable_hash_for!(struct mir::interpret::FrameInfo<'tcx> { - span, + call_site, lint_root, instance }); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index d375e62b27c58..8700f5d6e432f 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -57,7 +57,7 @@ pub struct ConstEvalErr<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct FrameInfo<'tcx> { - pub span: Span, + pub call_site: Span, // this span is in the caller! pub instance: ty::Instance<'tcx>, pub lint_root: Option, } @@ -72,8 +72,8 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { } else { write!(f, "inside call to `{}`", self.instance)?; } - if !self.span.is_dummy() { - let lo = tcx.sess.source_map().lookup_char_pos_adj(self.span.lo()); + if !self.call_site.is_dummy() { + let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo()); write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?; } Ok(()) @@ -159,7 +159,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { // 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()); + err.span_label(frame_info.call_site, 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 279955fba17ad..dbda506d115af 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -679,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, instance, lint_root }); + frames.push(FrameInfo { call_site: span, instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames