@@ -75,6 +75,54 @@ 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
+
82
+ fn prune_stacktrace < ' mir , ' tcx > (
83
+ ecx : & InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ,
84
+ mut stacktrace : Vec < FrameInfo < ' tcx > > ,
85
+ ) -> Vec < FrameInfo < ' tcx > > {
86
+ match ecx. machine . backtrace_style {
87
+ BacktraceStyle :: Off => {
88
+ // Retain one frame so that we can print a span for the error itself
89
+ stacktrace. truncate ( 1 ) ;
90
+ }
91
+ BacktraceStyle :: Short => {
92
+ // Only prune frames if there is at least one local frame. This check ensures that if
93
+ // we get a backtrace that never makes it to the user code because it has detected a
94
+ // bug in the Rust runtime, we don't prune away every frame.
95
+ if has_local_frame ( & stacktrace) {
96
+ // This is part of the logic that `std` uses to select the relevant part of a
97
+ // backtrace. But here, we only look for __rust_begin_short_backtrace, not
98
+ // __rust_end_short_backtrace because the end symbol comes from a call to the default
99
+ // panic handler.
100
+ stacktrace = stacktrace
101
+ . into_iter ( )
102
+ . take_while ( |frame| {
103
+ let def_id = frame. instance . def_id ( ) ;
104
+ let path = ecx. tcx . tcx . def_path_str ( def_id) ;
105
+ !path. contains ( "__rust_begin_short_backtrace" )
106
+ } )
107
+ . collect :: < Vec < _ > > ( ) ;
108
+
109
+ // After we prune frames from the bottom, there are a few left that are part of the
110
+ // Rust runtime. So we remove frames until we get to a local symbol, which should be
111
+ // main or a test.
112
+ // This len check ensures that we don't somehow remove every frame, as doing so breaks
113
+ // the primary error message.
114
+ while stacktrace. len ( ) > 1
115
+ && stacktrace. last ( ) . map_or ( false , |e| !e. instance . def_id ( ) . is_local ( ) )
116
+ {
117
+ stacktrace. pop ( ) ;
118
+ }
119
+ }
120
+ }
121
+ BacktraceStyle :: Full => { }
122
+ }
123
+ stacktrace
124
+ }
125
+
78
126
/// Emit a custom diagnostic without going through the miri-engine machinery
79
127
pub fn report_error < ' tcx , ' mir > (
80
128
ecx : & InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ,
@@ -157,46 +205,8 @@ pub fn report_error<'tcx, 'mir>(
157
205
}
158
206
} ;
159
207
160
- let mut stacktrace = ecx. generate_stacktrace ( ) ;
161
- let has_local_frame = stacktrace. iter ( ) . any ( |frame| frame. instance . def_id ( ) . is_local ( ) ) ;
162
- match ecx. machine . backtrace_style {
163
- BacktraceStyle :: Off => {
164
- // Retain one frame so that we can print a span for the error itself
165
- stacktrace. truncate ( 1 ) ;
166
- }
167
- BacktraceStyle :: Short => {
168
- // Only prune frames if there is at least one local frame. This check ensures that if
169
- // we get a backtrace that never makes it to the user code because it has detected a
170
- // bug in the Rust runtime, we don't prune away every frame.
171
- if has_local_frame {
172
- // This is part of the logic that `std` uses to select the relevant part of a
173
- // backtrace. But here, we only look for __rust_begin_short_backtrace, not
174
- // __rust_end_short_backtrace because the end symbol comes from a call to the default
175
- // panic handler.
176
- stacktrace = stacktrace
177
- . into_iter ( )
178
- . take_while ( |frame| {
179
- let def_id = frame. instance . def_id ( ) ;
180
- let path = ecx. tcx . tcx . def_path_str ( def_id) ;
181
- !path. contains ( "__rust_begin_short_backtrace" )
182
- } )
183
- . collect :: < Vec < _ > > ( ) ;
184
-
185
- // After we prune frames from the bottom, there are a few left that are part of the
186
- // Rust runtime. So we remove frames until we get to a local symbol, which should be
187
- // main or a test.
188
- // This len check ensures that we don't somehow remove every frame, as doing so breaks
189
- // the primary error message.
190
- while stacktrace. len ( ) > 1
191
- && stacktrace. last ( ) . map_or ( false , |e| !e. instance . def_id ( ) . is_local ( ) )
192
- {
193
- stacktrace. pop ( ) ;
194
- }
195
- }
196
- }
197
- BacktraceStyle :: Full => { }
198
- }
199
-
208
+ let stacktrace = ecx. generate_stacktrace ( ) ;
209
+ let stacktrace = prune_stacktrace ( ecx, stacktrace) ;
200
210
e. print_backtrace ( ) ;
201
211
let msg = e. to_string ( ) ;
202
212
report_msg (
@@ -210,7 +220,7 @@ pub fn report_error<'tcx, 'mir>(
210
220
211
221
// Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
212
222
// do not include a note when backtraces are off.
213
- if ecx. machine . backtrace_style == BacktraceStyle :: Short && has_local_frame {
223
+ if ecx. machine . backtrace_style == BacktraceStyle :: Short && has_local_frame ( & stacktrace ) {
214
224
ecx. tcx . sess . diagnostic ( ) . note_without_error (
215
225
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace" ,
216
226
) ;
@@ -367,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
367
377
) ;
368
378
}
369
379
380
+ let stacktrace = prune_stacktrace ( this, stacktrace) ;
381
+
370
382
// Show diagnostics.
371
383
for e in diagnostics. drain ( ..) {
372
384
use NonHaltingDiagnostic :: * ;
0 commit comments