@@ -75,6 +75,54 @@ 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+
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+
78126/// Emit a custom diagnostic without going through the miri-engine machinery
79127pub fn report_error < ' tcx , ' mir > (
80128 ecx : & InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ,
@@ -157,46 +205,8 @@ pub fn report_error<'tcx, 'mir>(
157205 }
158206 } ;
159207
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) ;
200210 e. print_backtrace ( ) ;
201211 let msg = e. to_string ( ) ;
202212 report_msg (
@@ -210,7 +220,7 @@ pub fn report_error<'tcx, 'mir>(
210220
211221 // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
212222 // 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 ) {
214224 ecx. tcx . sess . diagnostic ( ) . note_without_error (
215225 "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace" ,
216226 ) ;
@@ -367,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
367377 ) ;
368378 }
369379
380+ let stacktrace = prune_stacktrace ( this, stacktrace) ;
381+
370382 // Show diagnostics.
371383 for e in diagnostics. drain ( ..) {
372384 use NonHaltingDiagnostic :: * ;
0 commit comments