1 use core
::convert
::TryFrom
;
2 use core
::{char, fmt, iter, mem, str}
;
4 #[allow(unused_macros)]
8 "use `self.print(value)` or `fmt::Trait::fmt(&value, self.out)`, \
9 instead of `write!(self.out, \"{...}\", value)`"
14 // Maximum recursion depth when parsing symbols before we just bail out saying
15 // "this symbol is invalid"
16 const MAX_DEPTH
: u32 = 500;
18 /// Representation of a demangled symbol name.
19 pub struct Demangle
<'a
> {
23 #[derive(PartialEq, Eq, Debug)]
25 /// Symbol doesn't match the expected `v0` grammar.
28 /// Parsing the symbol crossed the recursion limit (see `MAX_DEPTH`).
32 /// De-mangles a Rust symbol into a more readable version
34 /// This function will take a **mangled** symbol and return a value. When printed,
35 /// the de-mangled version will be written. If the symbol does not look like
36 /// a mangled symbol, the original value will be written instead.
37 pub fn demangle(s
: &str) -> Result
<(Demangle
, &str), ParseError
> {
38 // First validate the symbol. If it doesn't look like anything we're
39 // expecting, we just print it literally. Note that we must handle non-Rust
40 // symbols because we could have any function in the backtrace.
42 if s
.len() > 2 && s
.starts_with("_R") {
44 } else if s
.len() > 1 && s
.starts_with('R'
) {
45 // On Windows, dbghelp strips leading underscores, so we accept "R..."
48 } else if s
.len() > 3 && s
.starts_with("__R") {
49 // On OSX, symbols are prefixed with an extra _
52 return Err(ParseError
::Invalid
);
55 // Paths always start with uppercase characters.
56 match inner
.as_bytes()[0] {
58 _
=> return Err(ParseError
::Invalid
),
61 // only work with ascii text
62 if inner
.bytes().any(|c
| c
& 0x80 != 0) {
63 return Err(ParseError
::Invalid
);
66 // Verify that the symbol is indeed a valid path.
67 let try_parse_path
= |parser
| {
68 let mut dummy_printer
= Printer
{
71 bound_lifetime_depth
: 0,
75 .expect("`fmt::Error`s should be impossible without a `fmt::Formatter`");
78 let mut parser
= Parser
{
83 parser
= try_parse_path(parser
)?
;
85 // Instantiating crate (paths always start with uppercase characters).
86 if let Some(&(b'A'
..=b'Z'
)) = parser
.sym
.as_bytes().get(parser
.next
) {
87 parser
= try_parse_path(parser
)?
;
90 Ok((Demangle { inner }
, &parser
.sym
[parser
.next
..]))
93 impl<'s
> fmt
::Display
for Demangle
<'s
> {
94 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
95 let mut printer
= Printer
{
102 bound_lifetime_depth
: 0,
104 printer
.print_path(true)
109 /// ASCII part of the identifier.
111 /// Punycode insertion codes for Unicode codepoints, if any.
115 const SMALL_PUNYCODE_LEN
: usize = 128;
118 /// Attempt to decode punycode on the stack (allocation-free),
119 /// and pass the char slice to the closure, if successful.
120 /// This supports up to `SMALL_PUNYCODE_LEN` characters.
121 fn try_small_punycode_decode
<F
: FnOnce(&[char]) -> R
, R
>(&self, f
: F
) -> Option
<R
> {
122 let mut out
= ['
\0'
; SMALL_PUNYCODE_LEN
];
124 let r
= self.punycode_decode(|i
, c
| {
125 // Check there's space left for another character.
126 out
.get(out_len
).ok_or(())?
;
128 // Move the characters after the insert position.
137 // Insert the new character.
143 Some(f(&out
[..out_len
]))
149 /// Decode punycode as insertion positions and characters
150 /// and pass them to the closure, which can return `Err(())`
151 /// to stop the decoding process.
152 fn punycode_decode
<F
: FnMut(usize, char) -> Result
<(), ()>>(
155 ) -> Result
<(), ()> {
156 let mut punycode_bytes
= self.punycode
.bytes().peekable();
157 if punycode_bytes
.peek().is_none() {
163 // Populate initial output from ASCII fragment.
164 for c
in self.ascii
.chars() {
169 // Punycode parameters and initial state.
176 let mut i
: usize = 0;
177 let mut n
: usize = 0x80;
180 // Read one delta value.
181 let mut delta
: usize = 0;
183 let mut k
: usize = 0;
185 use core
::cmp
::{max, min}
;
188 let t
= min(max(k
.saturating_sub(bias
), t_min
), t_max
);
190 let d
= match punycode_bytes
.next() {
191 Some(d @ b'a'
..=b'z'
) => d
- b'a'
,
192 Some(d @ b'
0'
..=b'
9'
) => 26 + (d
- b'
0'
),
196 delta
= delta
.checked_add(d
.checked_mul(w
).ok_or(())?
).ok_or(())?
;
200 w
= w
.checked_mul(base
- t
).ok_or(())?
;
203 // Compute the new insert position and character.
205 i
= i
.checked_add(delta
).ok_or(())?
;
206 n
= n
.checked_add(i
/ len
).ok_or(())?
;
209 let n_u32
= n
as u32;
210 let c
= if n_u32
as usize == n
{
211 char::from_u32(n_u32
).ok_or(())?
216 // Insert the new character and increment the insert position.
220 // If there are no more deltas, decoding is complete.
221 if punycode_bytes
.peek().is_none() {
225 // Perform bias adaptation.
229 delta
+= delta
/ len
;
231 while delta
> ((base
- t_min
) * t_max
) / 2 {
232 delta
/= base
- t_min
;
235 bias
= k
+ ((base
- t_min
+ 1) * delta
) / (delta
+ skew
);
240 impl<'s
> fmt
::Display
for Ident
<'s
> {
241 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
242 self.try_small_punycode_decode(|chars
| {
249 if !self.punycode
.is_empty() {
250 f
.write_str("punycode{")?
;
252 // Reconstruct a standard Punycode encoding,
253 // by using `-` as the separator.
254 if !self.ascii
.is_empty() {
255 f
.write_str(self.ascii
)?
;
258 f
.write_str(self.punycode
)?
;
262 f
.write_str(self.ascii
)
268 /// Sequence of lowercase hexadecimal nibbles (`0-9a-f`), used by leaf consts.
269 struct HexNibbles
<'s
> {
273 impl<'s
> HexNibbles
<'s
> {
274 /// Decode an integer value (with the "most significant nibble" first),
275 /// returning `None` if it can't fit in an `u64`.
276 // FIXME(eddyb) should this "just" use `u128` instead?
277 fn try_parse_uint(&self) -> Option
<u64> {
278 let nibbles
= self.nibbles
.trim_start_matches("0");
280 if nibbles
.len() > 16 {
285 for nibble
in nibbles
.chars() {
286 v
= (v
<< 4) | (nibble
.to_digit(16).unwrap() as u64);
291 /// Decode a UTF-8 byte sequence (with each byte using a pair of nibbles)
292 /// into individual `char`s, returning `None` for invalid UTF-8.
293 fn try_parse_str_chars(&self) -> Option
<impl Iterator
<Item
= char> + 's
> {
294 if self.nibbles
.len() % 2 != 0 {
298 // FIXME(eddyb) use `array_chunks` instead, when that becomes stable.
303 .map(|slice
| match slice
{
308 let half
= |nibble
: u8| (nibble
as char).to_digit(16).unwrap() as u8;
309 (half(hi
) << 4) | half(lo
)
312 let chars
= iter
::from_fn(move || {
313 // As long as there are any bytes left, there's at least one more
314 // UTF-8-encoded `char` to decode (or the possibility of error).
315 bytes
.next().map(|first_byte
| -> Result
<char, ()> {
316 // FIXME(eddyb) this `enum` and `fn` should be somewhere in `core`.
317 enum Utf8FirstByteError
{
321 fn utf8_len_from_first_byte(byte
: u8) -> Result
<usize, Utf8FirstByteError
> {
323 0x00..=0x7f => Ok(1),
324 0x80..=0xbf => Err(Utf8FirstByteError
::ContinuationByte
),
325 0xc0..=0xdf => Ok(2),
326 0xe0..=0xef => Ok(3),
327 0xf0..=0xf7 => Ok(4),
328 0xf8..=0xff => Err(Utf8FirstByteError
::TooLong
),
332 // Collect the appropriate amount of bytes (up to 4), according
333 // to the UTF-8 length implied by the first byte.
334 let utf8_len
= utf8_len_from_first_byte(first_byte
).map_err(|_
| ())?
;
335 let utf8
= &mut [first_byte
, 0, 0, 0][..utf8_len
];
336 for i
in 1..utf8_len
{
337 utf8
[i
] = bytes
.next().ok_or(())?
;
340 // Fully validate the UTF-8 sequence.
341 let s
= str::from_utf8(utf8
).map_err(|_
| ())?
;
343 // Since we included exactly one UTF-8 sequence, and validation
344 // succeeded, `str::chars` should return exactly one `char`.
345 let mut chars
= s
.chars();
346 match (chars
.next(), chars
.next()) {
347 (Some(c
), None
) => Ok(c
),
349 "str::from_utf8({:?}) = {:?} was expected to have 1 char, \
350 but {} chars were found",
359 // HACK(eddyb) doing a separate validation iteration like this might be
360 // wasteful, but it's easier to avoid starting to print a string literal
361 // in the first place, than to abort it mid-string.
362 if chars
.clone().any(|r
| r
.is_err()) {
365 Some(chars
.map(Result
::unwrap
))
370 fn basic_type(tag
: u8) -> Option
<&'
static str> {
404 impl<'s
> Parser
<'s
> {
405 fn push_depth(&mut self) -> Result
<(), ParseError
> {
407 if self.depth
> MAX_DEPTH
{
408 Err(ParseError
::RecursedTooDeep
)
414 fn pop_depth(&mut self) {
418 fn peek(&self) -> Option
<u8> {
419 self.sym
.as_bytes().get(self.next
).cloned()
422 fn eat(&mut self, b
: u8) -> bool
{
423 if self.peek() == Some(b
) {
431 fn next(&mut self) -> Result
<u8, ParseError
> {
432 let b
= self.peek().ok_or(ParseError
::Invalid
)?
;
437 fn hex_nibbles(&mut self) -> Result
<HexNibbles
<'s
>, ParseError
> {
438 let start
= self.next
;
441 b'
0'
..=b'
9'
| b'a'
..=b'f'
=> {}
443 _
=> return Err(ParseError
::Invalid
),
447 nibbles
: &self.sym
[start
..self.next
- 1],
451 fn digit_10(&mut self) -> Result
<u8, ParseError
> {
452 let d
= match self.peek() {
453 Some(d @ b'
0'
..=b'
9'
) => d
- b'
0'
,
454 _
=> return Err(ParseError
::Invalid
),
460 fn digit_62(&mut self) -> Result
<u8, ParseError
> {
461 let d
= match self.peek() {
462 Some(d @ b'
0'
..=b'
9'
) => d
- b'
0'
,
463 Some(d @ b'a'
..=b'z'
) => 10 + (d
- b'a'
),
464 Some(d @ b'A'
..=b'Z'
) => 10 + 26 + (d
- b'A'
),
465 _
=> return Err(ParseError
::Invalid
),
471 fn integer_62(&mut self) -> Result
<u64, ParseError
> {
477 while !self.eat(b'_'
) {
478 let d
= self.digit_62()?
as u64;
479 x
= x
.checked_mul(62).ok_or(ParseError
::Invalid
)?
;
480 x
= x
.checked_add(d
).ok_or(ParseError
::Invalid
)?
;
482 x
.checked_add(1).ok_or(ParseError
::Invalid
)
485 fn opt_integer_62(&mut self, tag
: u8) -> Result
<u64, ParseError
> {
489 self.integer_62()?
.checked_add(1).ok_or(ParseError
::Invalid
)
492 fn disambiguator(&mut self) -> Result
<u64, ParseError
> {
493 self.opt_integer_62(b's'
)
496 fn namespace(&mut self) -> Result
<Option
<char>, ParseError
> {
498 // Special namespaces, like closures and shims.
499 ns @ b'A'
..=b'Z'
=> Ok(Some(ns
as char)),
501 // Implementation-specific/unspecified namespaces.
502 b'a'
..=b'z'
=> Ok(None
),
504 _
=> Err(ParseError
::Invalid
),
508 fn backref(&mut self) -> Result
<Parser
<'s
>, ParseError
> {
509 let s_start
= self.next
- 1;
510 let i
= self.integer_62()?
;
511 if i
>= s_start
as u64 {
512 return Err(ParseError
::Invalid
);
514 let mut new_parser
= Parser
{
519 new_parser
.push_depth()?
;
523 fn ident(&mut self) -> Result
<Ident
<'s
>, ParseError
> {
524 let is_punycode
= self.eat(b'u'
);
525 let mut len
= self.digit_10()?
as usize;
527 while let Ok(d
) = self.digit_10() {
528 len
= len
.checked_mul(10).ok_or(ParseError
::Invalid
)?
;
529 len
= len
.checked_add(d
as usize).ok_or(ParseError
::Invalid
)?
;
533 // Skip past the optional `_` separator.
536 let start
= self.next
;
537 self.next
= self.next
.checked_add(len
).ok_or(ParseError
::Invalid
)?
;
538 if self.next
> self.sym
.len() {
539 return Err(ParseError
::Invalid
);
542 let ident
= &self.sym
[start
..self.next
];
545 let ident
= match ident
.bytes().rposition(|b
| b
== b'_'
) {
548 punycode
: &ident
[i
+ 1..],
555 if ident
.punycode
.is_empty() {
556 return Err(ParseError
::Invalid
);
568 struct Printer
<'a
, 'b
: 'a
, 's
> {
569 /// The input parser to demangle from, or `Err` if any (parse) error was
570 /// encountered (in order to disallow further likely-incorrect demangling).
572 /// See also the documentation on the `invalid!` and `parse!` macros below.
573 parser
: Result
<Parser
<'s
>, ParseError
>,
575 /// The output formatter to demangle to, or `None` while skipping printing.
576 out
: Option
<&'a
mut fmt
::Formatter
<'b
>>,
578 /// Cumulative number of lifetimes bound by `for<...>` binders ('G'),
579 /// anywhere "around" the current entity (e.g. type) being demangled.
580 /// This value is not tracked while skipping printing, as it'd be unused.
582 /// See also the documentation on the `Printer::in_binder` method.
583 bound_lifetime_depth
: u32,
587 /// Snippet to print when the error is initially encountered.
588 fn message(&self) -> &str {
590 ParseError
::Invalid
=> "{invalid syntax}",
591 ParseError
::RecursedTooDeep
=> "{recursion limit reached}",
596 /// Mark the parser as errored (with `ParseError::Invalid`), print the
597 /// appropriate message (see `ParseError::message`) and return early.
598 macro_rules
! invalid
{
599 ($printer
:ident
) => {{
600 let err
= ParseError
::Invalid
;
601 $printer
.print(err
.message())?
;
602 $printer
.parser
= Err(err
);
607 /// Call a parser method (if the parser hasn't errored yet),
608 /// and mark the parser as errored if it returns `Err`.
610 /// If the parser errored, before or now, this returns early,
611 /// from the current function, after printing either:
612 /// * for a new error, the appropriate message (see `ParseError::message`)
613 /// * for an earlier error, only `?` - this allows callers to keep printing
614 /// the approximate syntax of the path/type/const, despite having errors,
615 /// e.g. `Vec<[(A, ?); ?]>` instead of `Vec<[(A, ?`
617 ($printer
:ident
, $method
:ident $
(($
($arg
:expr
),*))*) => {
618 match $printer
.parser
{
619 Ok(ref mut parser
) => match parser
.$
method($
($
($arg
),*)*) {
622 $printer
.print(err
.message())?
;
623 $printer
.parser
= Err(err
);
627 Err(_
) => return $printer
.print("?"),
632 impl<'a
, 'b
, 's
> Printer
<'a
, 'b
, 's
> {
633 /// Eat the given character from the parser,
634 /// returning `false` if the parser errored.
635 fn eat(&mut self, b
: u8) -> bool
{
636 self.parser
.as_mut().map(|p
| p
.eat(b
)) == Ok(true)
639 /// Skip printing (i.e. `self.out` will be `None`) for the duration of the
640 /// given closure. This should not change parsing behavior, only disable the
641 /// output, but there may be optimizations (such as not traversing backrefs).
642 fn skipping_printing
<F
>(&mut self, f
: F
)
644 F
: FnOnce(&mut Self) -> fmt
::Result
,
646 let orig_out
= self.out
.take();
647 f(self).expect("`fmt::Error`s should be impossible without a `fmt::Formatter`");
651 /// Print the target of a backref, using the given closure.
652 /// When printing is being skipped, the backref will only be parsed,
653 /// ignoring the backref's target completely.
654 fn print_backref
<F
>(&mut self, f
: F
) -> fmt
::Result
656 F
: FnOnce(&mut Self) -> fmt
::Result
,
658 let backref_parser
= parse
!(self, backref
);
660 if self.out
.is_none() {
664 let orig_parser
= mem
::replace(&mut self.parser
, Ok(backref_parser
));
666 self.parser
= orig_parser
;
670 fn pop_depth(&mut self) {
671 if let Ok(ref mut parser
) = self.parser
{
676 /// Output the given value to `self.out` (using `fmt::Display` formatting),
677 /// if printing isn't being skipped.
678 fn print(&mut self, x
: impl fmt
::Display
) -> fmt
::Result
{
679 if let Some(out
) = &mut self.out
{
680 fmt
::Display
::fmt(&x
, out
)?
;
685 /// Output the given `char`s (escaped using `char::escape_debug`), with the
686 /// whole sequence wrapped in quotes, for either a `char` or `&str` literal,
687 /// if printing isn't being skipped.
688 fn print_quoted_escaped_chars(
691 chars
: impl Iterator
<Item
= char>,
693 if let Some(out
) = &mut self.out
{
694 use core
::fmt
::Write
;
696 out
.write_char(quote
)?
;
698 // Special-case not escaping a single/double quote, when
699 // inside the opposite kind of quote.
700 if matches
!((quote
, c
), ('
\''
, '
"') | ('"'
, '
\''
)) {
705 for escaped
in c
.escape_debug() {
706 out
.write_char(escaped
)?
;
709 out
.write_char(quote
)?
;
714 /// Print the lifetime according to the previously decoded index.
715 /// An index of `0` always refers to `'_`, but starting with `1`,
716 /// indices refer to late-bound lifetimes introduced by a binder.
717 fn print_lifetime_from_index(&mut self, lt
: u64) -> fmt
::Result
{
718 // Bound lifetimes aren't tracked when skipping printing.
719 if self.out
.is_none() {
725 return self.print("_");
727 match (self.bound_lifetime_depth
as u64).checked_sub(lt
) {
729 // Try to print lifetimes alphabetically first.
731 let c
= (b'a'
+ depth
as u8) as char;
734 // Use `'_123` after running out of letters.
739 None
=> invalid
!(self),
743 /// Optionally enter a binder ('G') for late-bound lifetimes,
744 /// printing e.g. `for<'a, 'b> ` before calling the closure,
745 /// and make those lifetimes visible to it (via depth level).
746 fn in_binder
<F
>(&mut self, f
: F
) -> fmt
::Result
748 F
: FnOnce(&mut Self) -> fmt
::Result
,
750 let bound_lifetimes
= parse
!(self, opt_integer_62(b'G'
));
752 // Don't track bound lifetimes when skipping printing.
753 if self.out
.is_none() {
757 if bound_lifetimes
> 0 {
759 for i
in 0..bound_lifetimes
{
763 self.bound_lifetime_depth
+= 1;
764 self.print_lifetime_from_index(1)?
;
771 // Restore `bound_lifetime_depth` to the previous value.
772 self.bound_lifetime_depth
-= bound_lifetimes
as u32;
777 /// Print list elements using the given closure and separator,
778 /// until the end of the list ('E') is found, or the parser errors.
779 /// Returns the number of elements printed.
780 fn print_sep_list
<F
>(&mut self, f
: F
, sep
: &str) -> Result
<usize, fmt
::Error
>
782 F
: Fn(&mut Self) -> fmt
::Result
,
785 while self.parser
.is_ok() && !self.eat(b'E'
) {
795 fn print_path(&mut self, in_value
: bool
) -> fmt
::Result
{
796 parse
!(self, push_depth
);
798 let tag
= parse
!(self, next
);
801 let dis
= parse
!(self, disambiguator
);
802 let name
= parse
!(self, ident
);
805 if let Some(out
) = &mut self.out
{
806 if !out
.alternate() {
808 fmt
::LowerHex
::fmt(&dis
, out
)?
;
814 let ns
= parse
!(self, namespace
);
816 self.print_path(in_value
)?
;
818 // HACK(eddyb) if the parser is already marked as having errored,
819 // `parse!` below will print a `?` without its preceding `::`
820 // (because printing the `::` is skipped in certain conditions,
821 // i.e. a lowercase namespace with an empty identifier),
822 // so in order to get `::?`, the `::` has to be printed here.
823 if self.parser
.is_err() {
827 let dis
= parse
!(self, disambiguator
);
828 let name
= parse
!(self, ident
);
831 // Special namespaces, like closures and shims.
835 'C'
=> self.print("closure")?
,
836 'S'
=> self.print("shim")?
,
837 _
=> self.print(ns
)?
,
839 if !name
.ascii
.is_empty() || !name
.punycode
.is_empty() {
848 // Implementation-specific/unspecified namespaces.
850 if !name
.ascii
.is_empty() || !name
.punycode
.is_empty() {
857 b'M'
| b'X'
| b'Y'
=> {
859 // Ignore the `impl`'s own path.
860 parse
!(self, disambiguator
);
861 self.skipping_printing(|this
| this
.print_path(false));
868 self.print_path(false)?
;
873 self.print_path(in_value
)?
;
878 self.print_sep_list(Self::print_generic_arg
, ", ")?
;
882 self.print_backref(|this
| this
.print_path(in_value
))?
;
891 fn print_generic_arg(&mut self) -> fmt
::Result
{
893 let lt
= parse
!(self, integer_62
);
894 self.print_lifetime_from_index(lt
)
895 } else if self.eat(b'K'
) {
896 self.print_const(false)
902 fn print_type(&mut self) -> fmt
::Result
{
903 let tag
= parse
!(self, next
);
905 if let Some(ty
) = basic_type(tag
) {
906 return self.print(ty
);
909 parse
!(self, push_depth
);
915 let lt
= parse
!(self, integer_62
);
917 self.print_lifetime_from_index(lt
)?
;
932 self.print("const ")?
;
942 self.print_const(true)?
;
948 let count
= self.print_sep_list(Self::print_type
, ", ")?
;
954 b'F'
=> self.in_binder(|this
| {
955 let is_unsafe
= this
.eat(b'U'
);
956 let abi
= if this
.eat(b'K'
) {
960 let abi
= parse
!(this
, ident
);
961 if abi
.ascii
.is_empty() || !abi
.punycode
.is_empty() {
971 this
.print("unsafe ")?
;
974 if let Some(abi
) = abi
{
975 this
.print("extern \"")?
;
977 // If the ABI had any `-`, they were replaced with `_`,
978 // so the parts between `_` have to be re-joined with `-`.
979 let mut parts
= abi
.split('_'
);
980 this
.print(parts
.next().unwrap())?
;
990 this
.print_sep_list(Self::print_type
, ", ")?
;
994 // Skip printing the return type if it's 'u', i.e. `()`.
1003 self.print("dyn ")?
;
1004 self.in_binder(|this
| {
1005 this
.print_sep_list(Self::print_dyn_trait
, " + ")?
;
1009 if !self.eat(b'L'
) {
1012 let lt
= parse
!(self, integer_62
);
1015 self.print_lifetime_from_index(lt
)?
;
1019 self.print_backref(Self::print_type
)?
;
1022 // Go back to the tag, so `print_path` also sees it.
1023 let _
= self.parser
.as_mut().map(|p
| p
.next
-= 1);
1024 self.print_path(false)?
;
1032 /// A trait in a trait object may have some "existential projections"
1033 /// (i.e. associated type bindings) after it, which should be printed
1034 /// in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1035 /// To this end, this method will keep the `<...>` of an 'I' path
1036 /// open, by omitting the `>`, and return `Ok(true)` in that case.
1037 fn print_path_maybe_open_generics(&mut self) -> Result
<bool
, fmt
::Error
> {
1039 // NOTE(eddyb) the closure may not run if printing is being skipped,
1040 // but in that case the returned boolean doesn't matter.
1041 let mut open
= false;
1042 self.print_backref(|this
| {
1043 open
= this
.print_path_maybe_open_generics()?
;
1047 } else if self.eat(b'I'
) {
1048 self.print_path(false)?
;
1050 self.print_sep_list(Self::print_generic_arg
, ", ")?
;
1053 self.print_path(false)?
;
1058 fn print_dyn_trait(&mut self) -> fmt
::Result
{
1059 let mut open
= self.print_path_maybe_open_generics()?
;
1061 while self.eat(b'p'
) {
1069 let name
= parse
!(self, ident
);
1082 fn print_const(&mut self, in_value
: bool
) -> fmt
::Result
{
1083 let tag
= parse
!(self, next
);
1085 parse
!(self, push_depth
);
1087 // Only literals (and the names of `const` generic parameters, but they
1088 // don't get mangled at all), can appear in generic argument position
1089 // without any disambiguation, all other expressions require braces.
1090 // To avoid duplicating the mapping between `tag` and what syntax gets
1091 // used (especially any special-casing), every case that needs braces
1092 // has to call `open_brace(self)?` (and the closing brace is automatic).
1093 let mut opened_brace
= false;
1094 let mut open_brace_if_outside_expr
= |this
: &mut Self| {
1095 // If this expression is nested in another, braces aren't required.
1100 opened_brace
= true;
1105 b'p'
=> self.print("_")?
,
1107 // Primitive leaves with hex-encoded values (see `basic_type`).
1108 b'h'
| b't'
| b'm'
| b'y'
| b'o'
| b'j'
=> self.print_const_uint(tag
)?
,
1109 b'a'
| b's'
| b'l'
| b'x'
| b'n'
| b'i'
=> {
1114 self.print_const_uint(tag
)?
;
1116 b'b'
=> match parse
!(self, hex_nibbles
).try_parse_uint() {
1117 Some(0) => self.print("false")?
,
1118 Some(1) => self.print("true")?
,
1119 _
=> invalid
!(self),
1122 let valid_char
= parse
!(self, hex_nibbles
)
1124 .and_then(|v
| u32::try_from(v
).ok())
1125 .and_then(char::from_u32
);
1127 Some(c
) => self.print_quoted_escaped_chars('
\''
, iter
::once(c
))?
,
1128 None
=> invalid
!(self),
1132 // NOTE(eddyb) a string literal `"..."` has type `&str`, so
1133 // to get back the type `str`, `*"..."` syntax is needed
1134 // (even if that may not be valid in Rust itself).
1135 open_brace_if_outside_expr(self)?
;
1138 self.print_const_str_literal()?
;
1142 // NOTE(eddyb) this prints `"..."` instead of `&*"..."`, which
1143 // is what `Re..._` would imply (see comment for `str` above).
1144 if tag
== b'R'
&& self.eat(b'e'
) {
1145 self.print_const_str_literal()?
;
1147 open_brace_if_outside_expr(self)?
;
1150 self.print("mut ")?
;
1152 self.print_const(true)?
;
1156 open_brace_if_outside_expr(self)?
;
1158 self.print_sep_list(|this
| this
.print_const(true), ", ")?
;
1162 open_brace_if_outside_expr(self)?
;
1164 let count
= self.print_sep_list(|this
| this
.print_const(true), ", ")?
;
1171 open_brace_if_outside_expr(self)?
;
1172 self.print_path(true)?
;
1173 match parse
!(self, next
) {
1177 self.print_sep_list(|this
| this
.print_const(true), ", ")?
;
1182 self.print_sep_list(
1184 parse
!(this
, disambiguator
);
1185 let name
= parse
!(this
, ident
);
1188 this
.print_const(true)
1194 _
=> invalid
!(self),
1198 self.print_backref(|this
| this
.print_const(in_value
))?
;
1200 _
=> invalid
!(self),
1211 fn print_const_uint(&mut self, ty_tag
: u8) -> fmt
::Result
{
1212 let hex
= parse
!(self, hex_nibbles
);
1214 match hex
.try_parse_uint() {
1215 Some(v
) => self.print(v
)?
,
1217 // Print anything that doesn't fit in `u64` verbatim.
1220 self.print(hex
.nibbles
)?
;
1224 if let Some(out
) = &mut self.out
{
1225 if !out
.alternate() {
1226 let ty
= basic_type(ty_tag
).unwrap();
1234 fn print_const_str_literal(&mut self) -> fmt
::Result
{
1235 match parse
!(self, hex_nibbles
).try_parse_str_chars() {
1236 Some(chars
) => self.print_quoted_escaped_chars('
"', chars),
1237 None => invalid!(self),
1244 use std::prelude::v1::*;
1247 ($a:expr, $b:expr) => {{
1248 assert_eq!(format!("{}
", ::demangle($a)), $b);
1251 macro_rules! t_nohash {
1252 ($a:expr, $b:expr) => {{
1253 assert_eq!(format!("{:#}
", ::demangle($a)), $b);
1256 macro_rules! t_nohash_type {
1257 ($a:expr, $b:expr) => {
1258 t_nohash!(concat!("_RMC0
", $a), concat!("<", $b, ">"))
1261 macro_rules! t_const {
1262 ($mangled:expr, $value:expr) => {
1264 concat!("_RIC0K
", $mangled, "E
"),
1265 concat!("::<", $value, ">")
1269 macro_rules! t_const_suffixed {
1270 ($mangled:expr, $value:expr, $value_ty_suffix:expr) => {{
1271 t_const!($mangled, $value);
1273 concat!("_RIC0K
", $mangled, "E
"),
1274 concat!("[0]::<", $value, $value_ty_suffix, ">")
1280 fn demangle_crate_with_leading_digit() {
1281 t_nohash!("_RNvC6_123foo3bar
", "123foo
::bar
");
1285 fn demangle_utf8_idents() {
1287 "_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y
",
1288 "utf8_idents
::საჭმელად_გემრიელი_სადილი
"
1293 fn demangle_closure() {
1295 "_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_
",
1296 "cc
::spawn
::{closure#0}
::{closure#0}
"
1299 "_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_
",
1300 "<core
::slice
::Iter
<u8> as core
::iter
::iterator
::Iterator
>::rposition
::<core
::slice
::memchr
::memrchr
::{closure#1}
>::{closure#0}
"
1305 fn demangle_dyn_trait() {
1307 "_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std
",
1308 "alloc
::alloc
::box_free
::<dyn alloc
::boxed
::FnBox
<(), Output
= ()>>"
1313 fn demangle_const_generics_preview() {
1314 // NOTE(eddyb) this was hand-written, before rustc had working
1315 // const generics support (but the mangling format did include them).
1317 "INtC8arrayvec8ArrayVechKj7b_E
",
1318 "arrayvec
::ArrayVec
<u8, 123>"
1320 t_const_suffixed!("j7b_
", "123", "usize");
1324 fn demangle_min_const_generics() {
1326 t_const_suffixed!("hb_
", "11", "u8");
1327 t_const_suffixed!("off00ff00ff00ff00ff_
", "0xff00ff00ff00ff00ff", "u128
");
1328 t_const_suffixed!("s98_
", "152", "i16");
1329 t_const_suffixed!("anb_
", "-11", "i8");
1330 t_const!("b0_
", "false");
1331 t_const!("b1_
", "true");
1332 t_const!("c76_
", "'v'
");
1333 t_const!("c22_
", r#"'
"'"#);
1334 t_const
!("ca_", "'\\n'");
1335 t_const
!("c2202_", "'∂'");
1339 fn demangle_const_str() {
1340 t_const
!("e616263_", "{*\"abc\"}");
1341 t_const
!("e27_", r
#"{*"'"}"#);
1342 t_const
!("e090a_", "{*\"\\t\\n\"}");
1343 t_const
!("ee28882c3bc_", "{*\"∂ü\"}");
1345 "ee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\
1346 e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_",
1347 "{*\"საჭმელად_გემრიელი_სადილი\"}"
1350 "ef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\
1351 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_",
1352 "{*\"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜\"}"
1356 // NOTE(eddyb) this uses the same strings as `demangle_const_str` and should
1357 // be kept in sync with it - while a macro could be used to generate both
1358 // `str` and `&str` tests, from a single list of strings, this seems clearer.
1360 fn demangle_const_ref_str() {
1361 t_const
!("Re616263_", "\"abc\"");
1362 t_const
!("Re27_", r
#""'""#);
1363 t_const
!("Re090a_", "\"\\t\\n\"");
1364 t_const
!("Ree28882c3bc_", "\"∂ü\"");
1366 "Ree183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\
1367 e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_",
1368 "\"საჭმელად_გემრიელი_სადილი\""
1371 "Ref09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\
1372 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_",
1373 "\"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜\""
1378 fn demangle_const_ref() {
1379 t_const
!("Rp", "{&_}");
1380 t_const
!("Rh7b_", "{&123}");
1381 t_const
!("Rb0_", "{&false}");
1382 t_const
!("Rc58_", "{&'X'}");
1383 t_const
!("RRRh0_", "{&&&0}");
1384 t_const
!("RRRe_", "{&&\"\"}");
1385 t_const
!("QAE", "{&mut []}");
1389 fn demangle_const_array() {
1390 t_const
!("AE", "{[]}");
1391 t_const
!("Aj0_E", "{[0]}");
1392 t_const
!("Ah1_h2_h3_E", "{[1, 2, 3]}");
1393 t_const
!("ARe61_Re62_Re63_E", "{[\"a\", \"b\", \"c\"]}");
1394 t_const
!("AAh1_h2_EAh3_h4_EE", "{[[1, 2], [3, 4]]}");
1398 fn demangle_const_tuple() {
1399 t_const
!("TE", "{()}");
1400 t_const
!("Tj0_E", "{(0,)}");
1401 t_const
!("Th1_b0_E", "{(1, false)}");
1403 "TRe616263_c78_RAh1_h2_h3_EE",
1404 "{(\"abc\", 'x', &[1, 2, 3])}"
1409 fn demangle_const_adt() {
1411 "VNvINtNtC4core6option6OptionjE4NoneU",
1412 "{core::option::Option::<usize>::None}"
1415 "VNvINtNtC4core6option6OptionjE4SomeTj0_E",
1416 "{core::option::Option::<usize>::Some(0)}"
1419 "VNtC3foo3BarS1sRe616263_2chc78_5sliceRAh1_h2_h3_EE",
1420 "{foo::Bar { s: \"abc\", ch: 'x', slice: &[1, 2, 3] }}"
1425 fn demangle_exponential_explosion() {
1426 // NOTE(eddyb) because of the prefix added by `t_nohash_type!` is
1427 // 3 bytes long, `B2_` refers to the start of the type, not `B_`.
1428 // 6 backrefs (`B8_E` through `B3_E`) result in 2^6 = 64 copies of `_`.
1429 // Also, because the `p` (`_`) type is after all of the starts of the
1430 // backrefs, it can be replaced with any other type, independently.
1432 concat
!("TTTTTT", "p", "B8_E", "B7_E", "B6_E", "B5_E", "B4_E", "B3_E"),
1433 "((((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \
1434 ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))), \
1435 (((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \
1436 ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))"
1441 fn demangle_thinlto() {
1442 t_nohash
!("_RC3foo.llvm.9D1C9369", "foo");
1443 t_nohash
!("_RC3foo.llvm.9D1C9369@@16", "foo");
1444 t_nohash
!("_RNvC9backtrace3foo.llvm.A5310EB9", "backtrace::foo");
1448 fn demangle_extra_suffix() {
1449 // From alexcrichton/rustc-demangle#27:
1451 "_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0",
1452 "rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0"
1457 fn demangling_limits() {
1458 // Stress tests found via fuzzing.
1460 for sym
in include_str
!("v0-large-test-symbols/early-recursion-limit")
1462 .filter(|line
| !line
.is_empty() && !line
.starts_with('
#'))
1465 super::demangle(sym
).map(|_
| ()),
1466 Err(super::ParseError
::RecursedTooDeep
)
1472 "RIC20tRYIMYNRYFG05_EB5_B_B6_RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
1473 RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB_E",
1476 "{recursion limit reached}"
1481 fn recursion_limit_leaks() {
1482 // NOTE(eddyb) this test checks that both paths and types support the
1483 // recursion limit correctly, i.e. matching `push_depth` and `pop_depth`,
1484 // and don't leak "recursion levels" and trip the limit.
1485 // The test inputs are generated on the fly, using a repeated pattern,
1486 // as hardcoding the actual strings would be too verbose.
1487 // Also, `MAX_DEPTH` can be directly used, instead of assuming its value.
1488 for &(sym_leaf
, expected_leaf
) in &[("p", "_"), ("Rp", "&_"), ("C1x", "x")] {
1489 let mut sym
= format
!("_RIC0p");
1490 let mut expected
= format
!("::<_");
1491 for _
in 0..(super::MAX_DEPTH
* 2) {
1492 sym
.push_str(sym_leaf
);
1493 expected
.push_str(", ");
1494 expected
.push_str(expected_leaf
);
1499 t_nohash
!(&sym
, expected
);
1504 fn recursion_limit_backref_free_bypass() {
1505 // NOTE(eddyb) this test checks that long symbols cannot bypass the
1506 // recursion limit by not using backrefs, and cause a stack overflow.
1508 // This value was chosen to be high enough that stack overflows were
1509 // observed even with `cargo test --release`.
1510 let depth
= 100_000;
1512 // In order to hide the long mangling from the initial "shallow" parse,
1513 // it's nested in an identifier (crate name), preceding its use.
1514 let mut sym
= format
!("_RIC{}", depth
);
1515 let backref_start
= sym
.len() - 2;
1520 // Write a backref to just after the length of the identifier.
1522 sym
.push(char::from_digit((backref_start
- 1) as u32, 36).unwrap());
1525 // Close the `I` at the start.
1528 assert_contains
!(::demangle(&sym
).to_string(), "{recursion limit reached}");