@@ -36,6 +36,7 @@ use core::fmt;
3636pub struct Demangle < ' a > {
3737 original : & ' a str ,
3838 inner : & ' a str ,
39+ suffix : & ' a str ,
3940 valid : bool ,
4041 /// The number of ::-separated elements in the original name.
4142 elements : usize ,
@@ -98,6 +99,18 @@ pub fn demangle(mut s: &str) -> Demangle {
9899 }
99100 }
100101
102+ // Output like LLVM IR adds extra period-delimited words. See if
103+ // we are in that case and save the trailing words if so.
104+ let mut suffix = "" ;
105+ if let Some ( i) = s. rfind ( "E." ) {
106+ let ( head, tail) = s. split_at ( i + 1 ) ; // After the E, before the period
107+
108+ if is_symbol_like ( tail) {
109+ s = head;
110+ suffix = tail;
111+ }
112+ }
113+
101114 // First validate the symbol. If it doesn't look like anything we're
102115 // expecting, we just print it literally. Note that we must handle non-Rust
103116 // symbols because we could have any function in the backtrace.
@@ -155,6 +168,7 @@ pub fn demangle(mut s: &str) -> Demangle {
155168
156169 Demangle {
157170 inner : inner,
171+ suffix : suffix,
158172 valid : valid,
159173 elements : elements,
160174 original : s,
@@ -202,6 +216,35 @@ fn is_rust_hash(s: &str) -> bool {
202216 s. starts_with ( 'h' ) && s[ 1 ..] . chars ( ) . all ( |c| c. is_digit ( 16 ) )
203217}
204218
219+ fn is_symbol_like ( s : & str ) -> bool {
220+ s. chars ( ) . all ( |c| {
221+ // Once `char::is_ascii_punctuation` and `char::is_ascii_alphanumeric`
222+ // have been stable for long enough, use those instead for clarity
223+ is_ascii_alphanumeric ( c) || is_ascii_punctuation ( c)
224+ } )
225+ }
226+
227+ // Copied from the documentation of `char::is_ascii_alphanumeric`
228+ fn is_ascii_alphanumeric ( c : char ) -> bool {
229+ match c {
230+ '\u{0041}' ... '\u{005A}' |
231+ '\u{0061}' ... '\u{007A}' |
232+ '\u{0030}' ... '\u{0039}' => true ,
233+ _ => false ,
234+ }
235+ }
236+
237+ // Copied from the documentation of `char::is_ascii_punctuation`
238+ fn is_ascii_punctuation ( c : char ) -> bool {
239+ match c {
240+ '\u{0021}' ... '\u{002F}' |
241+ '\u{003A}' ... '\u{0040}' |
242+ '\u{005B}' ... '\u{0060}' |
243+ '\u{007B}' ... '\u{007E}' => true ,
244+ _ => false ,
245+ }
246+ }
247+
205248impl < ' a > fmt:: Display for Demangle < ' a > {
206249 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
207250 // Alright, let's do this.
@@ -288,6 +331,8 @@ impl<'a> fmt::Display for Demangle<'a> {
288331 }
289332 }
290333
334+ try!( f. write_str ( self . suffix ) ) ;
335+
291336 Ok ( ( ) )
292337 }
293338}
@@ -398,6 +443,17 @@ mod tests {
398443 t_nohash ! ( "_ZN9backtrace3foo17hbb467fcdaea5d79bE.llvm.A5310EB9" , "backtrace::foo" ) ;
399444 }
400445
446+ #[ test]
447+ fn demangle_llvm_ir_branch_labels ( ) {
448+ t ! ( "_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i" , "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut::haf9727c2edfbc47b.exit.i.i" ) ;
449+ t_nohash ! ( "_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i" , "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut.exit.i.i" ) ;
450+ }
451+
452+ #[ test]
453+ fn demangle_ignores_suffix_that_doesnt_look_like_a_symbol ( ) {
454+ t ! ( "_ZN3fooE.llvm moocow" , "_ZN3fooE.llvm moocow" ) ;
455+ }
456+
401457 #[ test]
402458 fn dont_panic ( ) {
403459 super :: demangle ( "_ZN2222222222222222222222EE" ) . to_string ( ) ;
0 commit comments