miri: backtraces with instances

This commit is contained in:
Ralf Jung 2018-11-14 17:25:06 +01:00
parent 126a0e2aad
commit 57a7c85f93
3 changed files with 31 additions and 21 deletions

View File

@ -387,10 +387,10 @@ impl_stable_hash_for!(enum mir::interpret::ErrorHandled {
TooGeneric TooGeneric
}); });
impl_stable_hash_for!(struct mir::interpret::FrameInfo { impl_stable_hash_for!(struct mir::interpret::FrameInfo<'tcx> {
span, span,
lint_root, lint_root,
location instance
}); });
impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });

View File

@ -10,8 +10,9 @@
use std::{fmt, env}; use std::{fmt, env};
use hir::map::definitions::DefPathData;
use mir; use mir;
use ty::{Ty, layout}; use ty::{self, Ty, layout};
use ty::layout::{Size, Align, LayoutError}; use ty::layout::{Size, Align, LayoutError};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
@ -19,7 +20,6 @@ use super::{Pointer, Scalar};
use backtrace::Backtrace; use backtrace::Backtrace;
use ty;
use ty::query::TyCtxtAt; use ty::query::TyCtxtAt;
use errors::DiagnosticBuilder; use errors::DiagnosticBuilder;
@ -52,16 +52,30 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
pub struct ConstEvalErr<'tcx> { pub struct ConstEvalErr<'tcx> {
pub span: Span, pub span: Span,
pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>, pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>,
pub stacktrace: Vec<FrameInfo>, pub stacktrace: Vec<FrameInfo<'tcx>>,
} }
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct FrameInfo { pub struct FrameInfo<'tcx> {
pub span: Span, pub span: Span,
pub location: String, pub instance: ty::Instance<'tcx>,
pub lint_root: Option<ast::NodeId>, pub lint_root: Option<ast::NodeId>,
} }
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> { impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
pub fn struct_error(&self, pub fn struct_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>, tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
@ -135,8 +149,13 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
struct_error(tcx, message) struct_error(tcx, message)
}; };
err.span_label(self.span, self.error.to_string()); err.span_label(self.span, self.error.to_string());
for FrameInfo { span, location, .. } in &self.stacktrace { // Skip the last, which is just the environment of the constant. The stacktrace
err.span_label(*span, format!("inside call to `{}`", location)); // 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) Ok(err)
} }

View File

@ -14,7 +14,6 @@ use std::mem;
use syntax::source_map::{self, Span, DUMMY_SP}; use syntax::source_map::{self, Span, DUMMY_SP};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::def::Def; use rustc::hir::def::Def;
use rustc::hir::map::definitions::DefPathData;
use rustc::mir; use rustc::mir;
use rustc::ty::layout::{ use rustc::ty::layout::{
self, Size, Align, HasDataLayout, LayoutOf, TyLayout 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<Span>) -> Vec<FrameInfo> { pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo<'tcx>> {
let mut last_span = None; let mut last_span = None;
let mut frames = Vec::new(); 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().rev() {
for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() {
// make sure we don't emit frames that are duplicates of the previous // make sure we don't emit frames that are duplicates of the previous
if explicit_span == Some(span) { if explicit_span == Some(span) {
last_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 { } else {
last_span = Some(span); 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 block = &mir.basic_blocks()[block];
let source_info = if stmt < block.statements.len() { let source_info = if stmt < block.statements.len() {
block.statements[stmt].source_info 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::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
mir::ClearCrossCrate::Clear => None, mir::ClearCrossCrate::Clear => None,
}; };
frames.push(FrameInfo { span, location, lint_root }); frames.push(FrameInfo { span, instance, lint_root });
} }
trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
frames frames