1 | use core::convert::TryFrom; |
2 | use core::{char, fmt, iter, mem, str}; |
3 | |
4 | #[allow (unused_macros)] |
5 | macro_rules! write { |
6 | ($($ignored:tt)*) => { |
7 | compile_error!( |
8 | "use `self.print(value)` or `fmt::Trait::fmt(&value, self.out)`, \ |
9 | instead of `write!(self.out, \"{...} \", value)`" |
10 | ) |
11 | }; |
12 | } |
13 | |
14 | // Maximum recursion depth when parsing symbols before we just bail out saying |
15 | // "this symbol is invalid" |
16 | const MAX_DEPTH: u32 = 500; |
17 | |
18 | /// Representation of a demangled symbol name. |
19 | pub struct Demangle<'a> { |
20 | inner: &'a str, |
21 | } |
22 | |
23 | #[derive(PartialEq, Eq, Debug)] |
24 | pub enum ParseError { |
25 | /// Symbol doesn't match the expected `v0` grammar. |
26 | Invalid, |
27 | |
28 | /// Parsing the symbol crossed the recursion limit (see `MAX_DEPTH`). |
29 | RecursedTooDeep, |
30 | } |
31 | |
32 | /// De-mangles a Rust symbol into a more readable version |
33 | /// |
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. |
41 | let inner; |
42 | if s.len() > 2 && s.starts_with("_R" ) { |
43 | inner = &s[2..]; |
44 | } else if s.len() > 1 && s.starts_with('R' ) { |
45 | // On Windows, dbghelp strips leading underscores, so we accept "R..." |
46 | // form too. |
47 | inner = &s[1..]; |
48 | } else if s.len() > 3 && s.starts_with("__R" ) { |
49 | // On OSX, symbols are prefixed with an extra _ |
50 | inner = &s[3..]; |
51 | } else { |
52 | return Err(ParseError::Invalid); |
53 | } |
54 | |
55 | // Paths always start with uppercase characters. |
56 | match inner.as_bytes()[0] { |
57 | b'A' ..=b'Z' => {} |
58 | _ => return Err(ParseError::Invalid), |
59 | } |
60 | |
61 | // only work with ascii text |
62 | if inner.bytes().any(|c| c & 0x80 != 0) { |
63 | return Err(ParseError::Invalid); |
64 | } |
65 | |
66 | // Verify that the symbol is indeed a valid path. |
67 | let try_parse_path = |parser| { |
68 | let mut dummy_printer = Printer { |
69 | parser: Ok(parser), |
70 | out: None, |
71 | bound_lifetime_depth: 0, |
72 | }; |
73 | dummy_printer |
74 | .print_path(false) |
75 | .expect("`fmt::Error`s should be impossible without a `fmt::Formatter`" ); |
76 | dummy_printer.parser |
77 | }; |
78 | let mut parser = Parser { |
79 | sym: inner, |
80 | next: 0, |
81 | depth: 0, |
82 | }; |
83 | parser = try_parse_path(parser)?; |
84 | |
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)?; |
88 | } |
89 | |
90 | Ok((Demangle { inner }, &parser.sym[parser.next..])) |
91 | } |
92 | |
93 | impl<'s> fmt::Display for Demangle<'s> { |
94 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
95 | let mut printer: Printer<'_, '_, '_> = Printer { |
96 | parser: Ok(Parser { |
97 | sym: self.inner, |
98 | next: 0, |
99 | depth: 0, |
100 | }), |
101 | out: Some(f), |
102 | bound_lifetime_depth: 0, |
103 | }; |
104 | printer.print_path(in_value:true) |
105 | } |
106 | } |
107 | |
108 | struct Ident<'s> { |
109 | /// ASCII part of the identifier. |
110 | ascii: &'s str, |
111 | /// Punycode insertion codes for Unicode codepoints, if any. |
112 | punycode: &'s str, |
113 | } |
114 | |
115 | const SMALL_PUNYCODE_LEN: usize = 128; |
116 | |
117 | impl<'s> Ident<'s> { |
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]; |
123 | let mut out_len = 0; |
124 | let r = self.punycode_decode(|i, c| { |
125 | // Check there's space left for another character. |
126 | out.get(out_len).ok_or(())?; |
127 | |
128 | // Move the characters after the insert position. |
129 | let mut j = out_len; |
130 | out_len += 1; |
131 | |
132 | while j > i { |
133 | out[j] = out[j - 1]; |
134 | j -= 1; |
135 | } |
136 | |
137 | // Insert the new character. |
138 | out[i] = c; |
139 | |
140 | Ok(()) |
141 | }); |
142 | if r.is_ok() { |
143 | Some(f(&out[..out_len])) |
144 | } else { |
145 | None |
146 | } |
147 | } |
148 | |
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<(), ()>>( |
153 | &self, |
154 | mut insert: F, |
155 | ) -> Result<(), ()> { |
156 | let mut punycode_bytes = self.punycode.bytes().peekable(); |
157 | if punycode_bytes.peek().is_none() { |
158 | return Err(()); |
159 | } |
160 | |
161 | let mut len = 0; |
162 | |
163 | // Populate initial output from ASCII fragment. |
164 | for c in self.ascii.chars() { |
165 | insert(len, c)?; |
166 | len += 1; |
167 | } |
168 | |
169 | // Punycode parameters and initial state. |
170 | let base = 36; |
171 | let t_min = 1; |
172 | let t_max = 26; |
173 | let skew = 38; |
174 | let mut damp = 700; |
175 | let mut bias = 72; |
176 | let mut i: usize = 0; |
177 | let mut n: usize = 0x80; |
178 | |
179 | loop { |
180 | // Read one delta value. |
181 | let mut delta: usize = 0; |
182 | let mut w = 1; |
183 | let mut k: usize = 0; |
184 | loop { |
185 | use core::cmp::{max, min}; |
186 | |
187 | k += base; |
188 | let t = min(max(k.saturating_sub(bias), t_min), t_max); |
189 | |
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' ), |
193 | _ => return Err(()), |
194 | }; |
195 | let d = d as usize; |
196 | delta = delta.checked_add(d.checked_mul(w).ok_or(())?).ok_or(())?; |
197 | if d < t { |
198 | break; |
199 | } |
200 | w = w.checked_mul(base - t).ok_or(())?; |
201 | } |
202 | |
203 | // Compute the new insert position and character. |
204 | len += 1; |
205 | i = i.checked_add(delta).ok_or(())?; |
206 | n = n.checked_add(i / len).ok_or(())?; |
207 | i %= len; |
208 | |
209 | let n_u32 = n as u32; |
210 | let c = if n_u32 as usize == n { |
211 | char::from_u32(n_u32).ok_or(())? |
212 | } else { |
213 | return Err(()); |
214 | }; |
215 | |
216 | // Insert the new character and increment the insert position. |
217 | insert(i, c)?; |
218 | i += 1; |
219 | |
220 | // If there are no more deltas, decoding is complete. |
221 | if punycode_bytes.peek().is_none() { |
222 | return Ok(()); |
223 | } |
224 | |
225 | // Perform bias adaptation. |
226 | delta /= damp; |
227 | damp = 2; |
228 | |
229 | delta += delta / len; |
230 | let mut k = 0; |
231 | while delta > ((base - t_min) * t_max) / 2 { |
232 | delta /= base - t_min; |
233 | k += base; |
234 | } |
235 | bias = k + ((base - t_min + 1) * delta) / (delta + skew); |
236 | } |
237 | } |
238 | } |
239 | |
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| { |
243 | for &c in chars { |
244 | c.fmt(f)?; |
245 | } |
246 | Ok(()) |
247 | }) |
248 | .unwrap_or_else(|| { |
249 | if !self.punycode.is_empty() { |
250 | f.write_str("punycode{" )?; |
251 | |
252 | // Reconstruct a standard Punycode encoding, |
253 | // by using `-` as the separator. |
254 | if !self.ascii.is_empty() { |
255 | f.write_str(self.ascii)?; |
256 | f.write_str("-" )?; |
257 | } |
258 | f.write_str(self.punycode)?; |
259 | |
260 | f.write_str("}" ) |
261 | } else { |
262 | f.write_str(self.ascii) |
263 | } |
264 | }) |
265 | } |
266 | } |
267 | |
268 | /// Sequence of lowercase hexadecimal nibbles (`0-9a-f`), used by leaf consts. |
269 | struct HexNibbles<'s> { |
270 | nibbles: &'s str, |
271 | } |
272 | |
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" ); |
279 | |
280 | if nibbles.len() > 16 { |
281 | return None; |
282 | } |
283 | |
284 | let mut v = 0; |
285 | for nibble in nibbles.chars() { |
286 | v = (v << 4) | (nibble.to_digit(16).unwrap() as u64); |
287 | } |
288 | Some(v) |
289 | } |
290 | |
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 { |
295 | return None; |
296 | } |
297 | |
298 | // FIXME(eddyb) use `array_chunks` instead, when that becomes stable. |
299 | let mut bytes = self |
300 | .nibbles |
301 | .as_bytes() |
302 | .chunks_exact(2) |
303 | .map(|slice| match slice { |
304 | [a, b] => [a, b], |
305 | _ => unreachable!(), |
306 | }) |
307 | .map(|[&hi, &lo]| { |
308 | let half = |nibble: u8| (nibble as char).to_digit(16).unwrap() as u8; |
309 | (half(hi) << 4) | half(lo) |
310 | }); |
311 | |
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 { |
318 | ContinuationByte, |
319 | TooLong, |
320 | } |
321 | fn utf8_len_from_first_byte(byte: u8) -> Result<usize, Utf8FirstByteError> { |
322 | match byte { |
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), |
329 | } |
330 | } |
331 | |
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(())?; |
338 | } |
339 | |
340 | // Fully validate the UTF-8 sequence. |
341 | let s = str::from_utf8(utf8).map_err(|_| ())?; |
342 | |
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), |
348 | _ => unreachable!( |
349 | "str::from_utf8({:?}) = {:?} was expected to have 1 char, \ |
350 | but {} chars were found" , |
351 | utf8, |
352 | s, |
353 | s.chars().count() |
354 | ), |
355 | } |
356 | }) |
357 | }); |
358 | |
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()) { |
363 | None |
364 | } else { |
365 | Some(chars.map(Result::unwrap)) |
366 | } |
367 | } |
368 | } |
369 | |
370 | fn basic_type(tag: u8) -> Option<&'static str> { |
371 | Some(match tag { |
372 | b'b' => "bool" , |
373 | b'c' => "char" , |
374 | b'e' => "str" , |
375 | b'u' => "()" , |
376 | b'a' => "i8" , |
377 | b's' => "i16" , |
378 | b'l' => "i32" , |
379 | b'x' => "i64" , |
380 | b'n' => "i128" , |
381 | b'i' => "isize" , |
382 | b'h' => "u8" , |
383 | b't' => "u16" , |
384 | b'm' => "u32" , |
385 | b'y' => "u64" , |
386 | b'o' => "u128" , |
387 | b'j' => "usize" , |
388 | b'f' => "f32" , |
389 | b'd' => "f64" , |
390 | b'z' => "!" , |
391 | b'p' => "_" , |
392 | b'v' => "..." , |
393 | |
394 | _ => return None, |
395 | }) |
396 | } |
397 | |
398 | struct Parser<'s> { |
399 | sym: &'s str, |
400 | next: usize, |
401 | depth: u32, |
402 | } |
403 | |
404 | impl<'s> Parser<'s> { |
405 | fn push_depth(&mut self) -> Result<(), ParseError> { |
406 | self.depth += 1; |
407 | if self.depth > MAX_DEPTH { |
408 | Err(ParseError::RecursedTooDeep) |
409 | } else { |
410 | Ok(()) |
411 | } |
412 | } |
413 | |
414 | fn pop_depth(&mut self) { |
415 | self.depth -= 1; |
416 | } |
417 | |
418 | fn peek(&self) -> Option<u8> { |
419 | self.sym.as_bytes().get(self.next).cloned() |
420 | } |
421 | |
422 | fn eat(&mut self, b: u8) -> bool { |
423 | if self.peek() == Some(b) { |
424 | self.next += 1; |
425 | true |
426 | } else { |
427 | false |
428 | } |
429 | } |
430 | |
431 | fn next(&mut self) -> Result<u8, ParseError> { |
432 | let b = self.peek().ok_or(ParseError::Invalid)?; |
433 | self.next += 1; |
434 | Ok(b) |
435 | } |
436 | |
437 | fn hex_nibbles(&mut self) -> Result<HexNibbles<'s>, ParseError> { |
438 | let start = self.next; |
439 | loop { |
440 | match self.next()? { |
441 | b'0' ..=b'9' | b'a' ..=b'f' => {} |
442 | b'_' => break, |
443 | _ => return Err(ParseError::Invalid), |
444 | } |
445 | } |
446 | Ok(HexNibbles { |
447 | nibbles: &self.sym[start..self.next - 1], |
448 | }) |
449 | } |
450 | |
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), |
455 | }; |
456 | self.next += 1; |
457 | Ok(d) |
458 | } |
459 | |
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), |
466 | }; |
467 | self.next += 1; |
468 | Ok(d) |
469 | } |
470 | |
471 | fn integer_62(&mut self) -> Result<u64, ParseError> { |
472 | if self.eat(b'_' ) { |
473 | return Ok(0); |
474 | } |
475 | |
476 | let mut x: u64 = 0; |
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)?; |
481 | } |
482 | x.checked_add(1).ok_or(ParseError::Invalid) |
483 | } |
484 | |
485 | fn opt_integer_62(&mut self, tag: u8) -> Result<u64, ParseError> { |
486 | if !self.eat(tag) { |
487 | return Ok(0); |
488 | } |
489 | self.integer_62()?.checked_add(1).ok_or(ParseError::Invalid) |
490 | } |
491 | |
492 | fn disambiguator(&mut self) -> Result<u64, ParseError> { |
493 | self.opt_integer_62(b's' ) |
494 | } |
495 | |
496 | fn namespace(&mut self) -> Result<Option<char>, ParseError> { |
497 | match self.next()? { |
498 | // Special namespaces, like closures and shims. |
499 | ns @ b'A' ..=b'Z' => Ok(Some(ns as char)), |
500 | |
501 | // Implementation-specific/unspecified namespaces. |
502 | b'a' ..=b'z' => Ok(None), |
503 | |
504 | _ => Err(ParseError::Invalid), |
505 | } |
506 | } |
507 | |
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); |
513 | } |
514 | let mut new_parser = Parser { |
515 | sym: self.sym, |
516 | next: i as usize, |
517 | depth: self.depth, |
518 | }; |
519 | new_parser.push_depth()?; |
520 | Ok(new_parser) |
521 | } |
522 | |
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; |
526 | if len != 0 { |
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)?; |
530 | } |
531 | } |
532 | |
533 | // Skip past the optional `_` separator. |
534 | self.eat(b'_' ); |
535 | |
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); |
540 | } |
541 | |
542 | let ident = &self.sym[start..self.next]; |
543 | |
544 | if is_punycode { |
545 | let ident = match ident.bytes().rposition(|b| b == b'_' ) { |
546 | Some(i) => Ident { |
547 | ascii: &ident[..i], |
548 | punycode: &ident[i + 1..], |
549 | }, |
550 | None => Ident { |
551 | ascii: "" , |
552 | punycode: ident, |
553 | }, |
554 | }; |
555 | if ident.punycode.is_empty() { |
556 | return Err(ParseError::Invalid); |
557 | } |
558 | Ok(ident) |
559 | } else { |
560 | Ok(Ident { |
561 | ascii: ident, |
562 | punycode: "" , |
563 | }) |
564 | } |
565 | } |
566 | } |
567 | |
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). |
571 | /// |
572 | /// See also the documentation on the `invalid!` and `parse!` macros below. |
573 | parser: Result<Parser<'s>, ParseError>, |
574 | |
575 | /// The output formatter to demangle to, or `None` while skipping printing. |
576 | out: Option<&'a mut fmt::Formatter<'b>>, |
577 | |
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. |
581 | /// |
582 | /// See also the documentation on the `Printer::in_binder` method. |
583 | bound_lifetime_depth: u32, |
584 | } |
585 | |
586 | impl ParseError { |
587 | /// Snippet to print when the error is initially encountered. |
588 | fn message(&self) -> &str { |
589 | match self { |
590 | ParseError::Invalid => "{invalid syntax}" , |
591 | ParseError::RecursedTooDeep => "{recursion limit reached}" , |
592 | } |
593 | } |
594 | } |
595 | |
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); |
603 | return Ok(()); |
604 | }}; |
605 | } |
606 | |
607 | /// Call a parser method (if the parser hasn't errored yet), |
608 | /// and mark the parser as errored if it returns `Err`. |
609 | /// |
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, ?` |
616 | macro_rules! parse { |
617 | ($printer:ident, $method:ident $(($($arg:expr),*))*) => { |
618 | match $printer.parser { |
619 | Ok(ref mut parser) => match parser.$method($($($arg),*)*) { |
620 | Ok(x) => x, |
621 | Err(err) => { |
622 | $printer.print(err.message())?; |
623 | $printer.parser = Err(err); |
624 | return Ok(()); |
625 | } |
626 | } |
627 | Err(_) => return $printer.print("?" ), |
628 | } |
629 | }; |
630 | } |
631 | |
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) |
637 | } |
638 | |
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) |
643 | where |
644 | F: FnOnce(&mut Self) -> fmt::Result, |
645 | { |
646 | let orig_out = self.out.take(); |
647 | f(self).expect("`fmt::Error`s should be impossible without a `fmt::Formatter`" ); |
648 | self.out = orig_out; |
649 | } |
650 | |
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 |
655 | where |
656 | F: FnOnce(&mut Self) -> fmt::Result, |
657 | { |
658 | let backref_parser = parse!(self, backref); |
659 | |
660 | if self.out.is_none() { |
661 | return Ok(()); |
662 | } |
663 | |
664 | let orig_parser = mem::replace(&mut self.parser, Ok(backref_parser)); |
665 | let r = f(self); |
666 | self.parser = orig_parser; |
667 | r |
668 | } |
669 | |
670 | fn pop_depth(&mut self) { |
671 | if let Ok(ref mut parser) = self.parser { |
672 | parser.pop_depth(); |
673 | } |
674 | } |
675 | |
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)?; |
681 | } |
682 | Ok(()) |
683 | } |
684 | |
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( |
689 | &mut self, |
690 | quote: char, |
691 | chars: impl Iterator<Item = char>, |
692 | ) -> fmt::Result { |
693 | if let Some(out) = &mut self.out { |
694 | use core::fmt::Write; |
695 | |
696 | out.write_char(quote)?; |
697 | for c in chars { |
698 | // Special-case not escaping a single/double quote, when |
699 | // inside the opposite kind of quote. |
700 | if matches!((quote, c), (' \'' , '"' ) | ('"' , ' \'' )) { |
701 | out.write_char(c)?; |
702 | continue; |
703 | } |
704 | |
705 | for escaped in c.escape_debug() { |
706 | out.write_char(escaped)?; |
707 | } |
708 | } |
709 | out.write_char(quote)?; |
710 | } |
711 | Ok(()) |
712 | } |
713 | |
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() { |
720 | return Ok(()); |
721 | } |
722 | |
723 | self.print("'" )?; |
724 | if lt == 0 { |
725 | return self.print("_" ); |
726 | } |
727 | match (self.bound_lifetime_depth as u64).checked_sub(lt) { |
728 | Some(depth) => { |
729 | // Try to print lifetimes alphabetically first. |
730 | if depth < 26 { |
731 | let c = (b'a' + depth as u8) as char; |
732 | self.print(c) |
733 | } else { |
734 | // Use `'_123` after running out of letters. |
735 | self.print("_" )?; |
736 | self.print(depth) |
737 | } |
738 | } |
739 | None => invalid!(self), |
740 | } |
741 | } |
742 | |
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 |
747 | where |
748 | F: FnOnce(&mut Self) -> fmt::Result, |
749 | { |
750 | let bound_lifetimes = parse!(self, opt_integer_62(b'G' )); |
751 | |
752 | // Don't track bound lifetimes when skipping printing. |
753 | if self.out.is_none() { |
754 | return f(self); |
755 | } |
756 | |
757 | if bound_lifetimes > 0 { |
758 | self.print("for<" )?; |
759 | for i in 0..bound_lifetimes { |
760 | if i > 0 { |
761 | self.print(", " )?; |
762 | } |
763 | self.bound_lifetime_depth += 1; |
764 | self.print_lifetime_from_index(1)?; |
765 | } |
766 | self.print("> " )?; |
767 | } |
768 | |
769 | let r = f(self); |
770 | |
771 | // Restore `bound_lifetime_depth` to the previous value. |
772 | self.bound_lifetime_depth -= bound_lifetimes as u32; |
773 | |
774 | r |
775 | } |
776 | |
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> |
781 | where |
782 | F: Fn(&mut Self) -> fmt::Result, |
783 | { |
784 | let mut i = 0; |
785 | while self.parser.is_ok() && !self.eat(b'E' ) { |
786 | if i > 0 { |
787 | self.print(sep)?; |
788 | } |
789 | f(self)?; |
790 | i += 1; |
791 | } |
792 | Ok(i) |
793 | } |
794 | |
795 | fn print_path(&mut self, in_value: bool) -> fmt::Result { |
796 | parse!(self, push_depth); |
797 | |
798 | let tag = parse!(self, next); |
799 | match tag { |
800 | b'C' => { |
801 | let dis = parse!(self, disambiguator); |
802 | let name = parse!(self, ident); |
803 | |
804 | self.print(name)?; |
805 | if let Some(out) = &mut self.out { |
806 | if !out.alternate() { |
807 | out.write_str("[" )?; |
808 | fmt::LowerHex::fmt(&dis, out)?; |
809 | out.write_str("]" )?; |
810 | } |
811 | } |
812 | } |
813 | b'N' => { |
814 | let ns = parse!(self, namespace); |
815 | |
816 | self.print_path(in_value)?; |
817 | |
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() { |
824 | self.print("::" )?; |
825 | } |
826 | |
827 | let dis = parse!(self, disambiguator); |
828 | let name = parse!(self, ident); |
829 | |
830 | match ns { |
831 | // Special namespaces, like closures and shims. |
832 | Some(ns) => { |
833 | self.print("::{" )?; |
834 | match ns { |
835 | 'C' => self.print("closure" )?, |
836 | 'S' => self.print("shim" )?, |
837 | _ => self.print(ns)?, |
838 | } |
839 | if !name.ascii.is_empty() || !name.punycode.is_empty() { |
840 | self.print(":" )?; |
841 | self.print(name)?; |
842 | } |
843 | self.print("#" )?; |
844 | self.print(dis)?; |
845 | self.print("}" )?; |
846 | } |
847 | |
848 | // Implementation-specific/unspecified namespaces. |
849 | None => { |
850 | if !name.ascii.is_empty() || !name.punycode.is_empty() { |
851 | self.print("::" )?; |
852 | self.print(name)?; |
853 | } |
854 | } |
855 | } |
856 | } |
857 | b'M' | b'X' | b'Y' => { |
858 | if tag != b'Y' { |
859 | // Ignore the `impl`'s own path. |
860 | parse!(self, disambiguator); |
861 | self.skipping_printing(|this| this.print_path(false)); |
862 | } |
863 | |
864 | self.print("<" )?; |
865 | self.print_type()?; |
866 | if tag != b'M' { |
867 | self.print(" as " )?; |
868 | self.print_path(false)?; |
869 | } |
870 | self.print(">" )?; |
871 | } |
872 | b'I' => { |
873 | self.print_path(in_value)?; |
874 | if in_value { |
875 | self.print("::" )?; |
876 | } |
877 | self.print("<" )?; |
878 | self.print_sep_list(Self::print_generic_arg, ", " )?; |
879 | self.print(">" )?; |
880 | } |
881 | b'B' => { |
882 | self.print_backref(|this| this.print_path(in_value))?; |
883 | } |
884 | _ => invalid!(self), |
885 | } |
886 | |
887 | self.pop_depth(); |
888 | Ok(()) |
889 | } |
890 | |
891 | fn print_generic_arg(&mut self) -> fmt::Result { |
892 | if self.eat(b'L' ) { |
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) |
897 | } else { |
898 | self.print_type() |
899 | } |
900 | } |
901 | |
902 | fn print_type(&mut self) -> fmt::Result { |
903 | let tag = parse!(self, next); |
904 | |
905 | if let Some(ty) = basic_type(tag) { |
906 | return self.print(ty); |
907 | } |
908 | |
909 | parse!(self, push_depth); |
910 | |
911 | match tag { |
912 | b'R' | b'Q' => { |
913 | self.print("&" )?; |
914 | if self.eat(b'L' ) { |
915 | let lt = parse!(self, integer_62); |
916 | if lt != 0 { |
917 | self.print_lifetime_from_index(lt)?; |
918 | self.print(" " )?; |
919 | } |
920 | } |
921 | if tag != b'R' { |
922 | self.print("mut " )?; |
923 | } |
924 | self.print_type()?; |
925 | } |
926 | |
927 | b'P' | b'O' => { |
928 | self.print("*" )?; |
929 | if tag != b'P' { |
930 | self.print("mut " )?; |
931 | } else { |
932 | self.print("const " )?; |
933 | } |
934 | self.print_type()?; |
935 | } |
936 | |
937 | b'A' | b'S' => { |
938 | self.print("[" )?; |
939 | self.print_type()?; |
940 | if tag == b'A' { |
941 | self.print("; " )?; |
942 | self.print_const(true)?; |
943 | } |
944 | self.print("]" )?; |
945 | } |
946 | b'T' => { |
947 | self.print("(" )?; |
948 | let count = self.print_sep_list(Self::print_type, ", " )?; |
949 | if count == 1 { |
950 | self.print("," )?; |
951 | } |
952 | self.print(")" )?; |
953 | } |
954 | b'F' => self.in_binder(|this| { |
955 | let is_unsafe = this.eat(b'U' ); |
956 | let abi = if this.eat(b'K' ) { |
957 | if this.eat(b'C' ) { |
958 | Some("C" ) |
959 | } else { |
960 | let abi = parse!(this, ident); |
961 | if abi.ascii.is_empty() || !abi.punycode.is_empty() { |
962 | invalid!(this); |
963 | } |
964 | Some(abi.ascii) |
965 | } |
966 | } else { |
967 | None |
968 | }; |
969 | |
970 | if is_unsafe { |
971 | this.print("unsafe " )?; |
972 | } |
973 | |
974 | if let Some(abi) = abi { |
975 | this.print("extern \"" )?; |
976 | |
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())?; |
981 | for part in parts { |
982 | this.print("-" )?; |
983 | this.print(part)?; |
984 | } |
985 | |
986 | this.print(" \" " )?; |
987 | } |
988 | |
989 | this.print("fn(" )?; |
990 | this.print_sep_list(Self::print_type, ", " )?; |
991 | this.print(")" )?; |
992 | |
993 | if this.eat(b'u' ) { |
994 | // Skip printing the return type if it's 'u', i.e. `()`. |
995 | } else { |
996 | this.print(" -> " )?; |
997 | this.print_type()?; |
998 | } |
999 | |
1000 | Ok(()) |
1001 | })?, |
1002 | b'D' => { |
1003 | self.print("dyn " )?; |
1004 | self.in_binder(|this| { |
1005 | this.print_sep_list(Self::print_dyn_trait, " + " )?; |
1006 | Ok(()) |
1007 | })?; |
1008 | |
1009 | if !self.eat(b'L' ) { |
1010 | invalid!(self); |
1011 | } |
1012 | let lt = parse!(self, integer_62); |
1013 | if lt != 0 { |
1014 | self.print(" + " )?; |
1015 | self.print_lifetime_from_index(lt)?; |
1016 | } |
1017 | } |
1018 | b'B' => { |
1019 | self.print_backref(Self::print_type)?; |
1020 | } |
1021 | _ => { |
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)?; |
1025 | } |
1026 | } |
1027 | |
1028 | self.pop_depth(); |
1029 | Ok(()) |
1030 | } |
1031 | |
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> { |
1038 | if self.eat(b'B' ) { |
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()?; |
1044 | Ok(()) |
1045 | })?; |
1046 | Ok(open) |
1047 | } else if self.eat(b'I' ) { |
1048 | self.print_path(false)?; |
1049 | self.print("<" )?; |
1050 | self.print_sep_list(Self::print_generic_arg, ", " )?; |
1051 | Ok(true) |
1052 | } else { |
1053 | self.print_path(false)?; |
1054 | Ok(false) |
1055 | } |
1056 | } |
1057 | |
1058 | fn print_dyn_trait(&mut self) -> fmt::Result { |
1059 | let mut open = self.print_path_maybe_open_generics()?; |
1060 | |
1061 | while self.eat(b'p' ) { |
1062 | if !open { |
1063 | self.print("<" )?; |
1064 | open = true; |
1065 | } else { |
1066 | self.print(", " )?; |
1067 | } |
1068 | |
1069 | let name = parse!(self, ident); |
1070 | self.print(name)?; |
1071 | self.print(" = " )?; |
1072 | self.print_type()?; |
1073 | } |
1074 | |
1075 | if open { |
1076 | self.print(">" )?; |
1077 | } |
1078 | |
1079 | Ok(()) |
1080 | } |
1081 | |
1082 | fn print_const(&mut self, in_value: bool) -> fmt::Result { |
1083 | let tag = parse!(self, next); |
1084 | |
1085 | parse!(self, push_depth); |
1086 | |
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. |
1096 | if in_value { |
1097 | return Ok(()); |
1098 | } |
1099 | |
1100 | opened_brace = true; |
1101 | this.print("{" ) |
1102 | }; |
1103 | |
1104 | match tag { |
1105 | b'p' => self.print("_" )?, |
1106 | |
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' => { |
1110 | if self.eat(b'n' ) { |
1111 | self.print("-" )?; |
1112 | } |
1113 | |
1114 | self.print_const_uint(tag)?; |
1115 | } |
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), |
1120 | }, |
1121 | b'c' => { |
1122 | let valid_char = parse!(self, hex_nibbles) |
1123 | .try_parse_uint() |
1124 | .and_then(|v| u32::try_from(v).ok()) |
1125 | .and_then(char::from_u32); |
1126 | match valid_char { |
1127 | Some(c) => self.print_quoted_escaped_chars(' \'' , iter::once(c))?, |
1128 | None => invalid!(self), |
1129 | } |
1130 | } |
1131 | b'e' => { |
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)?; |
1136 | self.print("*" )?; |
1137 | |
1138 | self.print_const_str_literal()?; |
1139 | } |
1140 | |
1141 | b'R' | b'Q' => { |
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()?; |
1146 | } else { |
1147 | open_brace_if_outside_expr(self)?; |
1148 | self.print("&" )?; |
1149 | if tag != b'R' { |
1150 | self.print("mut " )?; |
1151 | } |
1152 | self.print_const(true)?; |
1153 | } |
1154 | } |
1155 | b'A' => { |
1156 | open_brace_if_outside_expr(self)?; |
1157 | self.print("[" )?; |
1158 | self.print_sep_list(|this| this.print_const(true), ", " )?; |
1159 | self.print("]" )?; |
1160 | } |
1161 | b'T' => { |
1162 | open_brace_if_outside_expr(self)?; |
1163 | self.print("(" )?; |
1164 | let count = self.print_sep_list(|this| this.print_const(true), ", " )?; |
1165 | if count == 1 { |
1166 | self.print("," )?; |
1167 | } |
1168 | self.print(")" )?; |
1169 | } |
1170 | b'V' => { |
1171 | open_brace_if_outside_expr(self)?; |
1172 | self.print_path(true)?; |
1173 | match parse!(self, next) { |
1174 | b'U' => {} |
1175 | b'T' => { |
1176 | self.print("(" )?; |
1177 | self.print_sep_list(|this| this.print_const(true), ", " )?; |
1178 | self.print(")" )?; |
1179 | } |
1180 | b'S' => { |
1181 | self.print(" { " )?; |
1182 | self.print_sep_list( |
1183 | |this| { |
1184 | parse!(this, disambiguator); |
1185 | let name = parse!(this, ident); |
1186 | this.print(name)?; |
1187 | this.print(": " )?; |
1188 | this.print_const(true) |
1189 | }, |
1190 | ", " , |
1191 | )?; |
1192 | self.print(" }" )?; |
1193 | } |
1194 | _ => invalid!(self), |
1195 | } |
1196 | } |
1197 | b'B' => { |
1198 | self.print_backref(|this| this.print_const(in_value))?; |
1199 | } |
1200 | _ => invalid!(self), |
1201 | } |
1202 | |
1203 | if opened_brace { |
1204 | self.print("}" )?; |
1205 | } |
1206 | |
1207 | self.pop_depth(); |
1208 | Ok(()) |
1209 | } |
1210 | |
1211 | fn print_const_uint(&mut self, ty_tag: u8) -> fmt::Result { |
1212 | let hex = parse!(self, hex_nibbles); |
1213 | |
1214 | match hex.try_parse_uint() { |
1215 | Some(v) => self.print(v)?, |
1216 | |
1217 | // Print anything that doesn't fit in `u64` verbatim. |
1218 | None => { |
1219 | self.print("0x" )?; |
1220 | self.print(hex.nibbles)?; |
1221 | } |
1222 | } |
1223 | |
1224 | if let Some(out) = &mut self.out { |
1225 | if !out.alternate() { |
1226 | let ty = basic_type(ty_tag).unwrap(); |
1227 | self.print(ty)?; |
1228 | } |
1229 | } |
1230 | |
1231 | Ok(()) |
1232 | } |
1233 | |
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), |
1238 | } |
1239 | } |
1240 | } |
1241 | |
1242 | #[cfg (test)] |
1243 | mod tests { |
1244 | use std::prelude::v1::*; |
1245 | |
1246 | macro_rules! t { |
1247 | ($a:expr, $b:expr) => {{ |
1248 | assert_eq!(format!("{}" , ::demangle($a)), $b); |
1249 | }}; |
1250 | } |
1251 | macro_rules! t_nohash { |
1252 | ($a:expr, $b:expr) => {{ |
1253 | assert_eq!(format!("{:#}" , ::demangle($a)), $b); |
1254 | }}; |
1255 | } |
1256 | macro_rules! t_nohash_type { |
1257 | ($a:expr, $b:expr) => { |
1258 | t_nohash!(concat!("_RMC0" , $a), concat!("<" , $b, ">" )) |
1259 | }; |
1260 | } |
1261 | macro_rules! t_const { |
1262 | ($mangled:expr, $value:expr) => { |
1263 | t_nohash!( |
1264 | concat!("_RIC0K" , $mangled, "E" ), |
1265 | concat!("::<" , $value, ">" ) |
1266 | ) |
1267 | }; |
1268 | } |
1269 | macro_rules! t_const_suffixed { |
1270 | ($mangled:expr, $value:expr, $value_ty_suffix:expr) => {{ |
1271 | t_const!($mangled, $value); |
1272 | t!( |
1273 | concat!("_RIC0K" , $mangled, "E" ), |
1274 | concat!("[0]::<" , $value, $value_ty_suffix, ">" ) |
1275 | ); |
1276 | }}; |
1277 | } |
1278 | |
1279 | #[test] |
1280 | fn demangle_crate_with_leading_digit() { |
1281 | t_nohash!("_RNvC6_123foo3bar" , "123foo::bar" ); |
1282 | } |
1283 | |
1284 | #[test] |
1285 | fn demangle_utf8_idents() { |
1286 | t_nohash!( |
1287 | "_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y" , |
1288 | "utf8_idents::საჭმელად_გემრიელი_სადილი" |
1289 | ); |
1290 | } |
1291 | |
1292 | #[test] |
1293 | fn demangle_closure() { |
1294 | t_nohash!( |
1295 | "_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_" , |
1296 | "cc::spawn::{closure#0}::{closure#0}" |
1297 | ); |
1298 | t_nohash!( |
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}" |
1301 | ); |
1302 | } |
1303 | |
1304 | #[test] |
1305 | fn demangle_dyn_trait() { |
1306 | t_nohash!( |
1307 | "_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std" , |
1308 | "alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>" |
1309 | ); |
1310 | } |
1311 | |
1312 | #[test] |
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). |
1316 | t_nohash_type!( |
1317 | "INtC8arrayvec8ArrayVechKj7b_E" , |
1318 | "arrayvec::ArrayVec<u8, 123>" |
1319 | ); |
1320 | t_const_suffixed!("j7b_" , "123" , "usize" ); |
1321 | } |
1322 | |
1323 | #[test] |
1324 | fn demangle_min_const_generics() { |
1325 | t_const!("p" , "_" ); |
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_" , "'∂'" ); |
1336 | } |
1337 | |
1338 | #[test] |
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_" , "{* \"∂ü \"}" ); |
1344 | t_const!( |
1345 | "ee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\ |
1346 | e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_" , |
1347 | "{* \"საჭმელად_გემრიელი_სადილი \"}" |
1348 | ); |
1349 | t_const!( |
1350 | "ef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\ |
1351 | 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_" , |
1352 | "{* \"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜 \"}" |
1353 | ); |
1354 | } |
1355 | |
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. |
1359 | #[test] |
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_" , " \"∂ü \"" ); |
1365 | t_const!( |
1366 | "Ree183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839b\ |
1367 | e183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_" , |
1368 | " \"საჭმელად_გემრიელი_სადილი \"" |
1369 | ); |
1370 | t_const!( |
1371 | "Ref09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e298\ |
1372 | 95f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_" , |
1373 | " \"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜 \"" |
1374 | ); |
1375 | } |
1376 | |
1377 | #[test] |
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 []}" ); |
1386 | } |
1387 | |
1388 | #[test] |
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]]}" ); |
1395 | } |
1396 | |
1397 | #[test] |
1398 | fn demangle_const_tuple() { |
1399 | t_const!("TE" , "{()}" ); |
1400 | t_const!("Tj0_E" , "{(0,)}" ); |
1401 | t_const!("Th1_b0_E" , "{(1, false)}" ); |
1402 | t_const!( |
1403 | "TRe616263_c78_RAh1_h2_h3_EE" , |
1404 | "{( \"abc \", 'x', &[1, 2, 3])}" |
1405 | ); |
1406 | } |
1407 | |
1408 | #[test] |
1409 | fn demangle_const_adt() { |
1410 | t_const!( |
1411 | "VNvINtNtC4core6option6OptionjE4NoneU" , |
1412 | "{core::option::Option::<usize>::None}" |
1413 | ); |
1414 | t_const!( |
1415 | "VNvINtNtC4core6option6OptionjE4SomeTj0_E" , |
1416 | "{core::option::Option::<usize>::Some(0)}" |
1417 | ); |
1418 | t_const!( |
1419 | "VNtC3foo3BarS1sRe616263_2chc78_5sliceRAh1_h2_h3_EE" , |
1420 | "{foo::Bar { s: \"abc \", ch: 'x', slice: &[1, 2, 3] }}" |
1421 | ); |
1422 | } |
1423 | |
1424 | #[test] |
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. |
1431 | t_nohash_type!( |
1432 | concat!("TTTTTT" , "p" , "B8_E" , "B7_E" , "B6_E" , "B5_E" , "B4_E" , "B3_E" ), |
1433 | "((((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \ |
1434 | ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))), \ |
1435 | (((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \ |
1436 | ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))" |
1437 | ); |
1438 | } |
1439 | |
1440 | #[test] |
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" ); |
1445 | } |
1446 | |
1447 | #[test] |
1448 | fn demangle_extra_suffix() { |
1449 | // From alexcrichton/rustc-demangle#27: |
1450 | t_nohash!( |
1451 | "_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0" , |
1452 | "rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0" |
1453 | ); |
1454 | } |
1455 | |
1456 | #[test] |
1457 | fn demangling_limits() { |
1458 | // Stress tests found via fuzzing. |
1459 | |
1460 | for sym in include_str!("v0-large-test-symbols/early-recursion-limit" ) |
1461 | .lines() |
1462 | .filter(|line| !line.is_empty() && !line.starts_with('#' )) |
1463 | { |
1464 | assert_eq!( |
1465 | super::demangle(sym).map(|_| ()), |
1466 | Err(super::ParseError::RecursedTooDeep) |
1467 | ); |
1468 | } |
1469 | |
1470 | assert_contains!( |
1471 | ::demangle( |
1472 | "RIC20tRYIMYNRYFG05_EB5_B_B6_RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\ |
1473 | RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB_E" , |
1474 | ) |
1475 | .to_string(), |
1476 | "{recursion limit reached}" |
1477 | ); |
1478 | } |
1479 | |
1480 | #[test] |
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); |
1495 | } |
1496 | sym.push('E' ); |
1497 | expected.push('>' ); |
1498 | |
1499 | t_nohash!(&sym, expected); |
1500 | } |
1501 | } |
1502 | |
1503 | #[test] |
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. |
1507 | |
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; |
1511 | |
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; |
1516 | for _ in 0..depth { |
1517 | sym.push('R' ); |
1518 | } |
1519 | |
1520 | // Write a backref to just after the length of the identifier. |
1521 | sym.push('B' ); |
1522 | sym.push(char::from_digit((backref_start - 1) as u32, 36).unwrap()); |
1523 | sym.push('_' ); |
1524 | |
1525 | // Close the `I` at the start. |
1526 | sym.push('E' ); |
1527 | |
1528 | assert_contains!(::demangle(&sym).to_string(), "{recursion limit reached}" ); |
1529 | } |
1530 | } |
1531 | |