@@ -75,24 +75,26 @@ enum DiagLevel {
75
75
Note ,
76
76
}
77
77
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.
82
81
fn prune_stacktrace < ' mir , ' tcx > (
83
82
ecx : & InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ,
84
83
mut stacktrace : Vec < FrameInfo < ' tcx > > ,
85
- ) -> Vec < FrameInfo < ' tcx > > {
84
+ ) -> ( Vec < FrameInfo < ' tcx > > , bool ) {
86
85
match ecx. machine . backtrace_style {
87
86
BacktraceStyle :: Off => {
88
87
// Retain one frame so that we can print a span for the error itself
89
88
stacktrace. truncate ( 1 ) ;
89
+ ( stacktrace, false )
90
90
}
91
91
BacktraceStyle :: Short => {
92
+ let original_len = stacktrace. len ( ) ;
92
93
// Only prune frames if there is at least one local frame. This check ensures that if
93
94
// we get a backtrace that never makes it to the user code because it has detected a
94
95
// 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 {
96
98
// This is part of the logic that `std` uses to select the relevant part of a
97
99
// backtrace. But here, we only look for __rust_begin_short_backtrace, not
98
100
// __rust_end_short_backtrace because the end symbol comes from a call to the default
@@ -117,10 +119,11 @@ fn prune_stacktrace<'mir, 'tcx>(
117
119
stacktrace. pop ( ) ;
118
120
}
119
121
}
122
+ let was_pruned = stacktrace. len ( ) != original_len;
123
+ ( stacktrace, was_pruned)
120
124
}
121
- BacktraceStyle :: Full => { }
125
+ BacktraceStyle :: Full => ( stacktrace , false ) ,
122
126
}
123
- stacktrace
124
127
}
125
128
126
129
/// Emit a custom diagnostic without going through the miri-engine machinery
@@ -206,7 +209,7 @@ pub fn report_error<'tcx, 'mir>(
206
209
} ;
207
210
208
211
let stacktrace = ecx. generate_stacktrace ( ) ;
209
- let stacktrace = prune_stacktrace ( ecx, stacktrace) ;
212
+ let ( stacktrace, was_pruned ) = prune_stacktrace ( ecx, stacktrace) ;
210
213
e. print_backtrace ( ) ;
211
214
let msg = e. to_string ( ) ;
212
215
report_msg (
@@ -218,9 +221,8 @@ pub fn report_error<'tcx, 'mir>(
218
221
& stacktrace,
219
222
) ;
220
223
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 {
224
226
ecx. tcx . sess . diagnostic ( ) . note_without_error (
225
227
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace" ,
226
228
) ;
@@ -377,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
377
379
) ;
378
380
}
379
381
380
- let stacktrace = prune_stacktrace ( this, stacktrace) ;
382
+ let ( stacktrace, _was_pruned ) = prune_stacktrace ( this, stacktrace) ;
381
383
382
384
// Show diagnostics.
383
385
for e in diagnostics. drain ( ..) {
0 commit comments