diff --git a/README.md b/README.md index a100ae7..0b1d54b 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,15 @@ The current port status by category is: * [[#26] v0: allow identifiers to start with a digit.](https://github.com/rust-lang/rustc-demangle/pull/26) * [[#53] v0: replace `skip_*` methods with `print_*` methods in a "skip printing" mode.](https://github.com/rust-lang/rustc-demangle/pull/53) * arguably backported to Rust, as the C port always took this approach - * **(UNPORTED)** symbol prefix flexibility (`__R` and `R`, instead of `_R`) - * **(UNPORTED)** `min_const_generics` constants (`bool`, `char`, negative signed integers) - * this arguably also includes `p` as an *untyped* placeholder constant - * **(UNPORTED)** [`str` and structural constants](https://github.com/rust-lang/rfcs/pull/3161) - (only usable in `const` generics on unstable Rust) + * symbol prefix flexibility (`__R` and `R`, instead of `_R`) + * [[#39] Add support for `min_const_generics` constants](https://github.com/rust-lang/rustc-demangle/pull/39) + * [[#40] Elide the type when the const value is a placeholder `p`](https://github.com/rust-lang/rustc-demangle/pull/40) + * [[#55] v0: demangle structural constants and &str.](https://github.com/rust-lang/rustc-demangle/pull/55) + (only usable in `const` generics on unstable Rust) * **(UNPORTED)** recursion limits * miscellaneous - * **(UNPORTED)** extraneous symbol suffix (e.g. `.llvm.*`) removal + * **ported** PRs: + * [[#30] v0: also support preserving extra suffixes found after mangled symbol.](https://github.com/rust-lang/rustc-demangle/pull/30) * **(UNPORTED)** output size limits Notable differences (intentionally) introduced by porting: diff --git a/rust-demangle.c b/rust-demangle.c index 6f150ed..5b1dbc1 100644 --- a/rust-demangle.c +++ b/rust-demangle.c @@ -70,6 +70,54 @@ static char next(struct rust_demangler *rdm) { return c; } +struct hex_nibbles { + const char *nibbles; + size_t nibbles_len; +}; + +static struct hex_nibbles parse_hex_nibbles(struct rust_demangler *rdm) { + struct hex_nibbles hex; + + hex.nibbles = NULL; + hex.nibbles_len = 0; + + size_t start = rdm->next, hex_len = 0; + while (!eat(rdm, '_')) { + char c = next(rdm); + CHECK_OR(IS_DIGIT(c) || (c >= 'a' && c <= 'f'), return hex); + hex_len++; + } + + hex.nibbles = rdm->sym + start; + hex.nibbles_len = hex_len; + return hex; +} + +static struct hex_nibbles +parse_hex_nibbles_for_const_uint(struct rust_demangler *rdm) { + struct hex_nibbles hex = parse_hex_nibbles(rdm); + CHECK_OR(!rdm->errored, return hex); + + // Trim leading `0`s. + while (hex.nibbles_len > 0 && *hex.nibbles == '0') { + hex.nibbles++; + hex.nibbles_len--; + } + + return hex; +} + +static struct hex_nibbles +parse_hex_nibbles_for_const_bytes(struct rust_demangler *rdm) { + struct hex_nibbles hex = parse_hex_nibbles(rdm); + CHECK_OR(!rdm->errored && (hex.nibbles_len % 2 == 0), return hex); + return hex; +} + +static uint8_t decode_hex_nibble(char nibble) { + return nibble >= 'a' ? 10 + (nibble - 'a') : nibble - '0'; +} + static uint64_t parse_integer_62(struct rust_demangler *rdm) { if (eat(rdm, '_')) return 0; @@ -182,6 +230,63 @@ static void print_uint64_hex(struct rust_demangler *rdm, uint64_t x) { PRINT(s); } +static void +print_quoted_escaped_char(struct rust_demangler *rdm, char quote, uint32_t c) { + CHECK_OR(c < 0xd800 || (c > 0xdfff && c < 0x10ffff), return); + + switch (c) { + case '\0': + PRINT("\\0"); + break; + + case '\t': + PRINT("\\t"); + break; + + case '\r': + PRINT("\\r"); + break; + + case '\n': + PRINT("\\n"); + break; + + case '\\': + PRINT("\\\\"); + break; + + case '"': + if (quote == '"') { + PRINT("\\\""); + } else { + PRINT("\""); + } + break; + + case '\'': + if (quote == '\'') { + PRINT("\\'"); + } else { + PRINT("'"); + } + break; + + default: + if (c >= 0x20 && c <= 0x7e) { + // Printable ASCII + char v = (char)c; + print_str(rdm, &v, 1); + } else { + // FIXME show printable unicode characters without hex encoding + PRINT("\\u{"); + char s[9] = {0}; + sprintf(s, "%" PRIx32, c); + PRINT(s); + PRINT("}"); + } + } +} + static void print_ident(struct rust_demangler *rdm, struct rust_mangled_ident ident) { if (rdm->errored || rdm->skipping_printing) @@ -197,12 +302,12 @@ print_ident(struct rust_demangler *rdm, struct rust_mangled_ident ident) { while (cap < ident.ascii_len) { cap *= 2; // Check for overflows. - CHECK_OR((cap * 4) / 4 == cap, return ); + CHECK_OR((cap * 4) / 4 == cap, return); } // Store the output codepoints as groups of 4 UTF-8 bytes. uint8_t *out = (uint8_t *)malloc(cap * 4); - CHECK_OR(out, return ); + CHECK_OR(out, return); // Populate initial output from ASCII fragment. for (len = 0; len < ident.ascii_len; len++) { @@ -342,14 +447,15 @@ static void demangle_generic_arg(struct rust_demangler *rdm); static void demangle_type(struct rust_demangler *rdm); static bool demangle_path_maybe_open_generics(struct rust_demangler *rdm); static void demangle_dyn_trait(struct rust_demangler *rdm); -static void demangle_const(struct rust_demangler *rdm); -static void demangle_const_uint(struct rust_demangler *rdm); +static void demangle_const(struct rust_demangler *rdm, bool in_value); +static void demangle_const_uint(struct rust_demangler *rdm, char ty_tag); +static void demangle_const_str_literal(struct rust_demangler *rdm); /// Optionally enter a binder ('G') for late-bound lifetimes, /// printing e.g. `for<'a, 'b> `, and make those lifetimes visible /// to the caller (via depth level, which the caller should reset). static void demangle_binder(struct rust_demangler *rdm) { - CHECK_OR(!rdm->errored, return ); + CHECK_OR(!rdm->errored, return); uint64_t bound_lifetimes = parse_opt_integer_62(rdm, 'G'); if (bound_lifetimes > 0) { @@ -365,7 +471,7 @@ static void demangle_binder(struct rust_demangler *rdm) { } static void demangle_path(struct rust_demangler *rdm, bool in_value) { - CHECK_OR(!rdm->errored, return ); + CHECK_OR(!rdm->errored, return); char tag = next(rdm); switch (tag) { @@ -383,7 +489,7 @@ static void demangle_path(struct rust_demangler *rdm, bool in_value) { } case 'N': { char ns = next(rdm); - CHECK_OR(IS_LOWER(ns) || IS_UPPER(ns), return ); + CHECK_OR(IS_LOWER(ns) || IS_UPPER(ns), return); demangle_path(rdm, in_value); @@ -428,6 +534,7 @@ static void demangle_path(struct rust_demangler *rdm, bool in_value) { rdm->skipping_printing = true; demangle_path(rdm, in_value); rdm->skipping_printing = was_skipping_printing; + __attribute__((fallthrough)); case 'Y': PRINT("<"); demangle_type(rdm); @@ -460,7 +567,7 @@ static void demangle_path(struct rust_demangler *rdm, bool in_value) { break; } default: - ERROR_AND(return ); + ERROR_AND(return); } } @@ -469,7 +576,7 @@ static void demangle_generic_arg(struct rust_demangler *rdm) { uint64_t lt = parse_integer_62(rdm); print_lifetime_from_index(rdm, lt); } else if (eat(rdm, 'K')) - demangle_const(rdm); + demangle_const(rdm, false); else demangle_type(rdm); } @@ -525,7 +632,7 @@ static const char *basic_type(char tag) { } static void demangle_type(struct rust_demangler *rdm) { - CHECK_OR(!rdm->errored, return ); + CHECK_OR(!rdm->errored, return); char tag = next(rdm); @@ -565,11 +672,11 @@ static void demangle_type(struct rust_demangler *rdm) { demangle_type(rdm); if (tag == 'A') { PRINT("; "); - demangle_const(rdm); + demangle_const(rdm, true); } PRINT("]"); break; - case 'T': + case 'T': { PRINT("("); size_t i; for (i = 0; !rdm->errored && !eat(rdm, 'E'); i++) { @@ -581,6 +688,7 @@ static void demangle_type(struct rust_demangler *rdm) { PRINT(","); PRINT(")"); break; + } case 'F': { uint64_t old_bound_lifetime_depth = rdm->bound_lifetime_depth; demangle_binder(rdm); @@ -652,7 +760,7 @@ static void demangle_type(struct rust_demangler *rdm) { // Restore `bound_lifetime_depth` to outside the binder. rdm->bound_lifetime_depth = old_bound_lifetime_depth; - CHECK_OR(eat(rdm, 'L'), return ); + CHECK_OR(eat(rdm, 'L'), return); uint64_t lt = parse_integer_62(rdm); if (lt) { PRINT(" + "); @@ -709,7 +817,7 @@ static bool demangle_path_maybe_open_generics(struct rust_demangler *rdm) { } static void demangle_dyn_trait(struct rust_demangler *rdm) { - CHECK_OR(!rdm->errored, return ); + CHECK_OR(!rdm->errored, return); bool open = demangle_path_maybe_open_generics(rdm); @@ -730,22 +838,17 @@ static void demangle_dyn_trait(struct rust_demangler *rdm) { PRINT(">"); } -static void demangle_const(struct rust_demangler *rdm) { - CHECK_OR(!rdm->errored, return ); +static void demangle_const(struct rust_demangler *rdm, bool in_value) { + CHECK_OR(!rdm->errored, return); - if (eat(rdm, 'B')) { - size_t backref = parse_integer_62(rdm); - if (!rdm->skipping_printing) { - size_t old_next = rdm->next; - rdm->next = backref; - demangle_const(rdm); - rdm->next = old_next; - } - return; - } + bool opened_brace = false; char ty_tag = next(rdm); switch (ty_tag) { + case 'p': + PRINT("_"); + break; + // Unsigned integer types. case 'h': case 't': @@ -753,56 +856,311 @@ static void demangle_const(struct rust_demangler *rdm) { case 'y': case 'o': case 'j': + demangle_const_uint(rdm, ty_tag); break; - default: - ERROR_AND(return ); + case 'a': + case 's': + case 'l': + case 'x': + case 'n': + case 'i': + if (eat(rdm, 'n')) { + PRINT("-"); + } + demangle_const_uint(rdm, ty_tag); + break; + + case 'b': { + struct hex_nibbles hex = parse_hex_nibbles_for_const_uint(rdm); + CHECK_OR(!rdm->errored && hex.nibbles_len <= 1, return); + uint8_t v = hex.nibbles_len > 0 ? decode_hex_nibble(hex.nibbles[0]) : 0; + CHECK_OR(v <= 1, return); + PRINT(v == 1 ? "true" : "false"); + break; } - if (eat(rdm, 'p')) - PRINT("_"); - else { - demangle_const_uint(rdm); - if (rdm->verbose) - PRINT(basic_type(ty_tag)); + case 'c': { + struct hex_nibbles hex = parse_hex_nibbles_for_const_uint(rdm); + CHECK_OR(!rdm->errored && hex.nibbles_len <= 6, return); + + uint32_t c = 0; + for (size_t i = 0; i < hex.nibbles_len; i++) + c = (c << 4) | decode_hex_nibble(hex.nibbles[i]); + + PRINT("'"); + print_quoted_escaped_char(rdm, '\'', c); + PRINT("'"); + + break; } -} -static void demangle_const_uint(struct rust_demangler *rdm) { - CHECK_OR(!rdm->errored, return ); + case 'e': + // NOTE(eddyb) a string literal `"..."` has type `&str`, so + // to get back the type `str`, `*"..."` syntax is needed + // (even if that may not be valid in Rust itself). + if (!in_value) { + opened_brace = true; + PRINT("{"); + } + PRINT("*"); - uint64_t value = 0; - size_t hex_len = 0; - while (!eat(rdm, '_')) { - value <<= 4; + demangle_const_str_literal(rdm); + break; - char c = next(rdm); - if (IS_DIGIT(c)) - value |= c - '0'; - else if (c >= 'a' && c <= 'f') - value |= 10 + (c - 'a'); - else - ERROR_AND(return ); - hex_len++; + case 'R': + case 'Q': + if (ty_tag == 'R' && eat(rdm, 'e')) { + // NOTE(eddyb) this prints `"..."` instead of `&*"..."`, which + // is what `Re..._` would imply (see comment for `str` above). + demangle_const_str_literal(rdm); + break; + } + + if (!in_value) { + opened_brace = true; + PRINT("{"); + } + + PRINT("&"); + if (ty_tag != 'R') { + PRINT("mut "); + } + + demangle_const(rdm, true); + break; + + case 'A': { + if (!in_value) { + opened_brace = true; + PRINT("{"); + } + + PRINT("["); + + size_t i = 0; + while (!eat(rdm, 'E')) { + CHECK_OR(!rdm->errored, return); + + if (i > 0) + PRINT(", "); + + demangle_const(rdm, true); + + i += 1; + } + + PRINT("]"); + break; + } + + case 'T': { + if (!in_value) { + opened_brace = true; + PRINT("{"); + } + + PRINT("("); + + size_t i = 0; + while (!eat(rdm, 'E')) { + CHECK_OR(!rdm->errored, return); + + if (i > 0) + PRINT(", "); + + demangle_const(rdm, true); + + i += 1; + } + + if (i == 1) + PRINT(","); + + PRINT(")"); + break; + } + + case 'V': + if (!in_value) { + opened_brace = true; + PRINT("{"); + } + + demangle_path(rdm, true); + + switch (next(rdm)) { + case 'U': + break; + + case 'T': { + PRINT("("); + + size_t i = 0; + while (!eat(rdm, 'E')) { + CHECK_OR(!rdm->errored, return); + + if (i > 0) + PRINT(", "); + + demangle_const(rdm, true); + + i += 1; + } + + PRINT(")"); + break; + } + + case 'S': { + PRINT(" { "); + + size_t i = 0; + while (!eat(rdm, 'E')) { + CHECK_OR(!rdm->errored, return); + + if (i > 0) + PRINT(", "); + + parse_disambiguator(rdm); + + struct rust_mangled_ident name = parse_ident(rdm); + print_ident(rdm, name); + + PRINT(": "); + + demangle_const(rdm, true); + + i += 1; + } + + PRINT(" }"); + break; + } + + default: + ERROR_AND(return); + } + + break; + + case 'B': { + size_t backref = parse_integer_62(rdm); + if (!rdm->skipping_printing) { + size_t old_next = rdm->next; + rdm->next = backref; + demangle_const(rdm, in_value); + rdm->next = old_next; + } + break; } + default: + ERROR_AND(return); + } + + if (opened_brace) { + PRINT("}"); + } +} + +static void demangle_const_uint(struct rust_demangler *rdm, char ty_tag) { + CHECK_OR(!rdm->errored, return); + + struct hex_nibbles hex = parse_hex_nibbles_for_const_uint(rdm); + CHECK_OR(!rdm->errored, return); + // Print anything that doesn't fit in `uint64_t` verbatim. - if (hex_len > 16) { + if (hex.nibbles_len > 16) { PRINT("0x"); - print_str(rdm, rdm->sym + (rdm->next - hex_len), hex_len); - return; + print_str(rdm, hex.nibbles, hex.nibbles_len); + } else { + uint64_t v = 0; + for (size_t i = 0; i < hex.nibbles_len; i++) + v = (v << 4) | decode_hex_nibble(hex.nibbles[i]); + print_uint64(rdm, v); + } + + if (rdm->verbose) + PRINT(basic_type(ty_tag)); +} + +// UTF-8 uses an unary encoding for its "length" field (`1`s followed by a `0`). +struct utf8_byte { + // Decoded "length" field of an UTF-8 byte, including the special cases: + // - `0` indicates this is a lone ASCII byte + // - `1` indicates a continuation byte (cannot start an UTF-8 sequence) + size_t seq_len; + + // Remaining (`payload_width`) bits in the UTF-8 byte, contributing to + // the Unicode scalar value being encoded in the UTF-8 sequence. + uint8_t payload; + size_t payload_width; +}; +static struct utf8_byte utf8_decode(uint8_t byte) { + struct utf8_byte utf8; + + utf8.seq_len = 0; + utf8.payload = byte; + utf8.payload_width = 8; + + // FIXME(eddyb) figure out if using "count leading ones/zeros" is an option. + while (utf8.seq_len <= 6) { + uint8_t msb = 0x80 >> utf8.seq_len; + utf8.payload &= ~msb; + utf8.payload_width--; + if ((byte & msb) == 0) + break; + utf8.seq_len++; } - print_uint64(rdm, value); + return utf8; +} + +static void demangle_const_str_literal(struct rust_demangler *rdm) { + CHECK_OR(!rdm->errored, return); + + struct hex_nibbles hex = parse_hex_nibbles_for_const_bytes(rdm); + CHECK_OR(!rdm->errored, return); + + PRINT("\""); + for (size_t i = 0; i < hex.nibbles_len; i += 2) { + struct utf8_byte utf8 = utf8_decode( + (decode_hex_nibble(hex.nibbles[i]) << 4) | + decode_hex_nibble(hex.nibbles[i + 1]) + ); + uint32_t c = utf8.payload; + if (utf8.seq_len > 0) { + CHECK_OR(utf8.seq_len >= 2 && utf8.seq_len <= 4, return); + for (size_t extra = utf8.seq_len - 1; extra > 0; extra--) { + i += 2; + utf8 = utf8_decode( + (decode_hex_nibble(hex.nibbles[i]) << 4) | + decode_hex_nibble(hex.nibbles[i + 1]) + ); + CHECK_OR(utf8.seq_len == 1, return); + c = (c << utf8.payload_width) | utf8.payload; + } + } + print_quoted_escaped_char(rdm, '"', c); + } + PRINT("\""); } bool rust_demangle_with_callback( const char *mangled, int flags, void (*callback)(const char *data, size_t len, void *opaque), void *opaque ) { - // Rust symbols always start with _R. + // Rust symbols always start with R, _R or __R. if (mangled[0] == '_' && mangled[1] == 'R') mangled += 2; + else if (mangled[0] == 'R') + // On Windows, dbghelp strips leading underscores, so we accept "R..." + // form too. + mangled += 1; + else if (mangled[0] == '_' && mangled[1] == '_' && mangled[2] == 'R') + // On OSX, symbols are prefixed with an extra _ + mangled += 3; else return false; @@ -825,23 +1183,30 @@ bool rust_demangle_with_callback( rdm.version = 0; rdm.bound_lifetime_depth = 0; - // Rust symbols use only [_0-9a-zA-Z] characters. + // Rust symbols only use ASCII characters. for (const char *p = mangled; *p; p++) { - if (!(*p == '_' || IS_DIGIT(*p) || IS_LOWER(*p) || IS_UPPER(*p))) + if ((*p & 0x80) != 0) return false; + + if (*p == '.' && strncmp(p, ".llvm.", 6) == 0) { + // Ignore .llvm. suffixes + break; + } + rdm.sym_len++; } demangle_path(&rdm, true); // Skip instantiating crate. - if (!rdm.errored && rdm.next < rdm.sym_len) { + if (!rdm.errored && rdm.next < rdm.sym_len && peek(&rdm) >= 'A' && + peek(&rdm) <= 'Z') { rdm.skipping_printing = true; demangle_path(&rdm, false); } - // It's an error to not reach the end. - rdm.errored |= rdm.next != rdm.sym_len; + // Print trailing garbage + print_str(&rdm, rdm.sym + rdm.next, rdm.sym_len - rdm.next); return !rdm.errored; } diff --git a/test-harness/src/lib.rs b/test-harness/src/lib.rs index 34725eb..4293628 100644 --- a/test-harness/src/lib.rs +++ b/test-harness/src/lib.rs @@ -68,6 +68,36 @@ impl fmt::Display for Demangle<'_> { } } +// HACK(eddyb) the C port doesn't have the "is printable Unicode" heuristic, +// to avoid having to include the non-trivial amount of data that requires, +// so instead we allow mismatches when `b` has more `\u{...}` escapes than `a`. +fn equal_modulo_unicode_escapes(a: &str, b: &str) -> bool { + let mut a_chars = a.chars(); + let mut a_active_escape: Option = None; + let mut b_chars = b.chars(); + loop { + let a_ch = a_active_escape + .as_mut() + .and_then(|escape| escape.next()) + .or_else(|| { + a_active_escape = None; + a_chars.next() + }); + let b_ch = b_chars.next(); + match (a_ch, b_ch) { + (Some(a_ch), Some(b_ch)) if a_ch == b_ch => {} + // Compare with the `\u{...}` escape instead, if possible. + (Some(a_ch), Some('\\')) if a_active_escape.is_none() => { + let mut escape = a_ch.escape_unicode(); + assert_eq!(escape.next(), Some('\\')); + a_active_escape = Some(escape); + } + (None, None) => return true, + _ => return false, + } + } +} + impl Demangle<'_> { pub fn to_string_maybe_verbose(&self, verbose: bool) -> String { let rust = if verbose { @@ -76,7 +106,7 @@ impl Demangle<'_> { format!("{:#}", self.rustc_demangle) }; let c = demangle_via_c(self.original, verbose); - if rust != c { + if rust != c && !equal_modulo_unicode_escapes(&rust, &c) { panic!( "Rust vs C demangling difference:\ \n mangled: {mangled:?}\ diff --git a/test-harness/tests/top_level.rs b/test-harness/tests/top_level.rs index d00fc75..d17fc4f 100644 --- a/test-harness/tests/top_level.rs +++ b/test-harness/tests/top_level.rs @@ -238,14 +238,20 @@ fn limit_recursion() { } // FIXME(eddyb) port the relevant functionality to C. -#[should_panic] +#[ignore = "would slowly use up all RAM before being OOM-killed"] #[test] -fn limit_output() { +fn limit_output_oom_hazard() { assert_ends_with!( rust_demangle_c_test_harness::demangle("RYFG_FGyyEvRYFF_EvRYFFEvERLB_B_B_ERLRjB_B_B_") .to_string(), "{size limit reached}" ); +} + +// FIXME(eddyb) port the relevant functionality to C. +#[should_panic] +#[test] +fn limit_output() { // NOTE(eddyb) somewhat reduced version of the above, effectively // ` fn()>` with a larger number of lifetimes in `...`. assert_ends_with!( diff --git a/test-harness/tests/v0.rs b/test-harness/tests/v0.rs index 95549e9..d6fd3fc 100644 --- a/test-harness/tests/v0.rs +++ b/test-harness/tests/v0.rs @@ -92,8 +92,6 @@ fn demangle_const_generics_preview() { t_const_suffixed!("j7b_", "123", "usize"); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_min_const_generics() { t_const!("p", "_"); @@ -109,8 +107,6 @@ fn demangle_min_const_generics() { t_const!("c2202_", "'∂'"); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_const_str() { t_const!("e616263_", "{*\"abc\"}"); @@ -129,8 +125,6 @@ fn demangle_const_str() { ); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] // NOTE(eddyb) this uses the same strings as `demangle_const_str` and should // be kept in sync with it - while a macro could be used to generate both // `str` and `&str` tests, from a single list of strings, this seems clearer. @@ -152,8 +146,6 @@ fn demangle_const_ref_str() { ); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_const_ref() { t_const!("Rp", "{&_}"); @@ -165,8 +157,6 @@ fn demangle_const_ref() { t_const!("QAE", "{&mut []}"); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_const_array() { t_const!("AE", "{[]}"); @@ -176,8 +166,6 @@ fn demangle_const_array() { t_const!("AAh1_h2_EAh3_h4_EE", "{[[1, 2], [3, 4]]}"); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_const_tuple() { t_const!("TE", "{()}"); @@ -189,8 +177,6 @@ fn demangle_const_tuple() { ); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_const_adt() { t_const!( @@ -223,8 +209,6 @@ fn demangle_exponential_explosion() { ); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_thinlto() { t_nohash!("_RC3foo.llvm.9D1C9369", "foo"); @@ -232,8 +216,6 @@ fn demangle_thinlto() { t_nohash!("_RNvC9backtrace3foo.llvm.A5310EB9", "backtrace::foo"); } -// FIXME(eddyb) port the relevant functionality to C. -#[should_panic] #[test] fn demangle_extra_suffix() { // From alexcrichton/rustc-demangle#27: