Prune stacktraces for tag-tracking diagnostics too

This commit is contained in:
Ben Kimock 2022-02-25 19:18:05 -05:00
parent 538aedf099
commit d2bb231954

View file

@ -75,6 +75,54 @@ enum DiagLevel {
Note,
}
fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool {
stacktrace.iter().any(|frame| frame.instance.def_id().is_local())
}
fn prune_stacktrace<'mir, 'tcx>(
ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
mut stacktrace: Vec<FrameInfo<'tcx>>,
) -> Vec<FrameInfo<'tcx>> {
match ecx.machine.backtrace_style {
BacktraceStyle::Off => {
// Retain one frame so that we can print a span for the error itself
stacktrace.truncate(1);
}
BacktraceStyle::Short => {
// Only prune frames if there is at least one local frame. This check ensures that if
// we get a backtrace that never makes it to the user code because it has detected a
// bug in the Rust runtime, we don't prune away every frame.
if has_local_frame(&stacktrace) {
// This is part of the logic that `std` uses to select the relevant part of a
// backtrace. But here, we only look for __rust_begin_short_backtrace, not
// __rust_end_short_backtrace because the end symbol comes from a call to the default
// panic handler.
stacktrace = stacktrace
.into_iter()
.take_while(|frame| {
let def_id = frame.instance.def_id();
let path = ecx.tcx.tcx.def_path_str(def_id);
!path.contains("__rust_begin_short_backtrace")
})
.collect::<Vec<_>>();
// After we prune frames from the bottom, there are a few left that are part of the
// Rust runtime. So we remove frames until we get to a local symbol, which should be
// main or a test.
// This len check ensures that we don't somehow remove every frame, as doing so breaks
// the primary error message.
while stacktrace.len() > 1
&& stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
{
stacktrace.pop();
}
}
}
BacktraceStyle::Full => {}
}
stacktrace
}
/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
@ -157,46 +205,8 @@ pub fn report_error<'tcx, 'mir>(
}
};
let mut stacktrace = ecx.generate_stacktrace();
let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local());
match ecx.machine.backtrace_style {
BacktraceStyle::Off => {
// Retain one frame so that we can print a span for the error itself
stacktrace.truncate(1);
}
BacktraceStyle::Short => {
// Only prune frames if there is at least one local frame. This check ensures that if
// we get a backtrace that never makes it to the user code because it has detected a
// bug in the Rust runtime, we don't prune away every frame.
if has_local_frame {
// This is part of the logic that `std` uses to select the relevant part of a
// backtrace. But here, we only look for __rust_begin_short_backtrace, not
// __rust_end_short_backtrace because the end symbol comes from a call to the default
// panic handler.
stacktrace = stacktrace
.into_iter()
.take_while(|frame| {
let def_id = frame.instance.def_id();
let path = ecx.tcx.tcx.def_path_str(def_id);
!path.contains("__rust_begin_short_backtrace")
})
.collect::<Vec<_>>();
// After we prune frames from the bottom, there are a few left that are part of the
// Rust runtime. So we remove frames until we get to a local symbol, which should be
// main or a test.
// This len check ensures that we don't somehow remove every frame, as doing so breaks
// the primary error message.
while stacktrace.len() > 1
&& stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
{
stacktrace.pop();
}
}
}
BacktraceStyle::Full => {}
}
let stacktrace = ecx.generate_stacktrace();
let stacktrace = prune_stacktrace(ecx, stacktrace);
e.print_backtrace();
let msg = e.to_string();
report_msg(
@ -210,7 +220,7 @@ pub fn report_error<'tcx, 'mir>(
// Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
// do not include a note when backtraces are off.
if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame {
if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) {
ecx.tcx.sess.diagnostic().note_without_error(
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
);
@ -367,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
);
}
let stacktrace = prune_stacktrace(this, stacktrace);
// Show diagnostics.
for e in diagnostics.drain(..) {
use NonHaltingDiagnostic::*;