Skip to content

Commit b490e6b

Browse files
committed
Auto merge of #1989 - saethlin:short-backtraces, r=RalfJung
Only print the pruning note if the trace was definitely pruned Per #1987 (comment) The only problem with this is that it looks like we can't emit the note about `-Zmiri-backtrace=full` if we also emit a tag-tracking diagnostic. The final note about the setting simply doesn't appear on the final error if it is printed before. I feel like we're running up against some diagnostic deduplication logic?
2 parents 144d565 + f1c6498 commit b490e6b

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

src/diagnostics.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,26 @@ enum DiagLevel {
7575
Note,
7676
}
7777

78-
fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool {
79-
stacktrace.iter().any(|frame| frame.instance.def_id().is_local())
80-
}
81-
78+
/// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any
79+
/// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must
80+
/// be pointing to a problem in the Rust runtime itself, and do not prune it at all.
8281
fn prune_stacktrace<'mir, 'tcx>(
8382
ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
8483
mut stacktrace: Vec<FrameInfo<'tcx>>,
85-
) -> Vec<FrameInfo<'tcx>> {
84+
) -> (Vec<FrameInfo<'tcx>>, bool) {
8685
match ecx.machine.backtrace_style {
8786
BacktraceStyle::Off => {
8887
// Retain one frame so that we can print a span for the error itself
8988
stacktrace.truncate(1);
89+
(stacktrace, false)
9090
}
9191
BacktraceStyle::Short => {
92+
let original_len = stacktrace.len();
9293
// Only prune frames if there is at least one local frame. This check ensures that if
9394
// we get a backtrace that never makes it to the user code because it has detected a
9495
// bug in the Rust runtime, we don't prune away every frame.
95-
if has_local_frame(&stacktrace) {
96+
let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local());
97+
if has_local_frame {
9698
// This is part of the logic that `std` uses to select the relevant part of a
9799
// backtrace. But here, we only look for __rust_begin_short_backtrace, not
98100
// __rust_end_short_backtrace because the end symbol comes from a call to the default
@@ -117,10 +119,11 @@ fn prune_stacktrace<'mir, 'tcx>(
117119
stacktrace.pop();
118120
}
119121
}
122+
let was_pruned = stacktrace.len() != original_len;
123+
(stacktrace, was_pruned)
120124
}
121-
BacktraceStyle::Full => {}
125+
BacktraceStyle::Full => (stacktrace, false),
122126
}
123-
stacktrace
124127
}
125128

126129
/// Emit a custom diagnostic without going through the miri-engine machinery
@@ -206,7 +209,7 @@ pub fn report_error<'tcx, 'mir>(
206209
};
207210

208211
let stacktrace = ecx.generate_stacktrace();
209-
let stacktrace = prune_stacktrace(ecx, stacktrace);
212+
let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace);
210213
e.print_backtrace();
211214
let msg = e.to_string();
212215
report_msg(
@@ -218,9 +221,8 @@ pub fn report_error<'tcx, 'mir>(
218221
&stacktrace,
219222
);
220223

221-
// Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
222-
// do not include a note when backtraces are off.
223-
if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) {
224+
// Include a note like `std` does when we omit frames from a backtrace
225+
if was_pruned {
224226
ecx.tcx.sess.diagnostic().note_without_error(
225227
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
226228
);
@@ -377,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
377379
);
378380
}
379381

380-
let stacktrace = prune_stacktrace(this, stacktrace);
382+
let (stacktrace, _was_pruned) = prune_stacktrace(this, stacktrace);
381383

382384
// Show diagnostics.
383385
for e in diagnostics.drain(..) {

0 commit comments

Comments
 (0)