44use crate :: backtrace_rs:: { self , BacktraceFmt , BytesOrWideString , PrintFmt } ;
55use crate :: borrow:: Cow ;
66use crate :: io:: prelude:: * ;
7+ use crate :: mem:: { ManuallyDrop , MaybeUninit } ;
78use crate :: path:: { self , Path , PathBuf } ;
89use crate :: sync:: { Mutex , MutexGuard , PoisonError } ;
910use crate :: { env, fmt, io} ;
@@ -68,6 +69,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
6869 let mut first_omit = true ;
6970 // If we're using a short backtrace, ignore all frames until we're told to start printing.
7071 let mut print = print_fmt != PrintFmt :: Short ;
72+ let mut skip = false ;
7173 set_image_base ( ) ;
7274 // SAFETY: we roll our own locking in this town
7375 unsafe {
@@ -81,12 +83,30 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
8183 let frame_ip = frame. ip ( ) ;
8284 res = writeln ! ( bt_fmt. formatter( ) , "{idx:4}: {frame_ip:HEX_WIDTH$?}" ) ;
8385 } else {
86+ // `call_with_short_backtrace_marker::<End>` means we are done hiding symbols
87+ // for now. Print until we see `call_with_short_backtrace_marker::<Begin>`.
88+ if print_fmt == PrintFmt :: Short {
89+ let sym = frame. symbol_address ( ) ;
90+ if sym == call_with_short_backtrace_marker :: < End > as _ {
91+ skip = true ;
92+ print = true ;
93+ } else if print && sym == call_with_short_backtrace_marker :: < Begin > as _ {
94+ skip = true ;
95+ print = false ;
96+ }
97+ }
98+
8499 let mut hit = false ;
85100 backtrace_rs:: resolve_frame_unsynchronized ( frame, |symbol| {
86101 hit = true ;
102+ if skip {
103+ skip = false ;
104+ return ;
105+ }
87106
88- // `__rust_end_short_backtrace` means we are done hiding symbols
89- // for now. Print until we see `__rust_begin_short_backtrace`.
107+ // Hide `__rust_[begin|end]_short_backtrace` frames from short backtraces.
108+ // Unfortunately these generic functions have to be matched by name, as we do
109+ // not know their generic parameters.
90110 if print_fmt == PrintFmt :: Short {
91111 if let Some ( sym) = symbol. name ( ) . and_then ( |s| s. as_str ( ) ) {
92112 if sym. contains ( "__rust_end_short_backtrace" ) {
@@ -159,32 +179,43 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
159179/// this is only inline(never) when backtraces in std are enabled, otherwise
160180/// it's fine to optimize away.
161181#[ cfg_attr( feature = "backtrace" , inline( never) ) ]
162- pub fn __rust_begin_short_backtrace < F , T > ( f : F ) -> T
163- where
164- F : FnOnce ( ) -> T ,
165- {
166- let result = f ( ) ;
182+ fn call_with_short_backtrace_marker < T : Terminus > ( f : & mut dyn FnMut ( ) ) {
183+ f ( ) ;
167184
168- // prevent this frame from being tail-call optimised away
169- crate :: hint:: black_box ( ( ) ) ;
185+ // (Try to) prevent both ICF and TCO
186+ crate :: hint:: black_box ( T :: ID ) ;
187+ }
170188
171- result
189+ trait Terminus {
190+ const ID : u32 ;
172191}
173192
174- /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
175- /// this is only inline(never) when backtraces in std are enabled, otherwise
176- /// it's fine to optimize away.
177- #[ cfg_attr( feature = "backtrace" , inline( never) ) ]
178- pub fn __rust_end_short_backtrace < F , T > ( f : F ) -> T
179- where
180- F : FnOnce ( ) -> T ,
181- {
182- let result = f ( ) ;
193+ macro_rules! short_backtrace_termini {
194+ ( $( $f: ident => $t: ident( $id: literal) ) ,* $( , ) ?) => { $(
195+ struct $t;
196+ impl Terminus for $t {
197+ const ID : u32 = $id;
198+ }
183199
184- // prevent this frame from being tail-call optimised away
185- crate :: hint:: black_box ( ( ) ) ;
200+ #[ doc( hidden) ]
201+ #[ unstable( feature = "short_backtrace_termini" , reason = "for rustc to have ICE backtraces abbreviated" , issue = "none" ) ]
202+ #[ inline( always) ]
203+ pub fn $f<F , T >( f: F ) -> T
204+ where
205+ F : FnOnce ( ) -> T ,
206+ {
207+ let mut result = MaybeUninit :: <T >:: uninit( ) ;
208+ let mut f = ManuallyDrop :: new( f) ;
209+ let mut f = || { result. write( unsafe { ManuallyDrop :: take( & mut f) } ( ) ) ; } ;
210+ call_with_short_backtrace_marker:: <$t>( & mut f) ;
211+ unsafe { result. assume_init( ) }
212+ }
213+ ) * } ;
214+ }
186215
187- result
216+ short_backtrace_termini ! {
217+ __rust_begin_short_backtrace => Begin ( 0 ) ,
218+ __rust_end_short_backtrace => End ( 1 ) ,
188219}
189220
190221/// Prints the filename of the backtrace frame.
0 commit comments