Update libiberty with latest sources from gcc mainline
authorNick Clifton <nickc@redhat.com>
Tue, 5 Jan 2021 12:36:09 +0000 (12:36 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 5 Jan 2021 12:36:09 +0000 (12:36 +0000)
13 files changed:
ChangeLog
libiberty/ChangeLog
libiberty/configure
libiberty/configure.ac
libiberty/cp-demangle.c
libiberty/cp-demangle.h
libiberty/pex-win32.c
libiberty/rust-demangle.c
libiberty/simple-object-elf.c
libiberty/strstr.c
libiberty/strverscmp.c
libiberty/testsuite/demangle-expected
libiberty/testsuite/rust-demangle-expected

index 55d04df7589a7dd6c3a0d7528243faf90fad382b..7e57a54dbb142d7da57ae526d415624085437d2f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,89 @@
+2021-01-05  Nick Clifton  <nickc@redhat.com>
+
+       * libiberty: Sync with gcc.  Bring in:
+       2021-01-04  Martin Liska  <mliska@suse.cz>
+
+       * strverscmp.c: Convert to utf8 from iso8859.
+
+       2020-12-22  Jason Merrill  <jason@redhat.com>
+
+       PR c++/67343
+       * cp-demangle.h (struct d_info): Add unresolved_name_state.
+       * cp-demangle.c (d_prefix): Add subst parm.
+       (d_nested_name): Pass it.
+       (d_unresolved_name): Split out from...
+       (d_expression_1): ...here.
+       (d_demangle_callback): Maybe retry with old sr mangling.
+       * testsuite/demangle-expected: Add test.
+
+       2020-12-21  Jason Merrill  <jason@redhat.com>
+
+       * cp-demangle.c (d_expression_1): Recognize qualified-id
+       on RHS of dt/pt.
+       * testsuite/demangle-expected: Add test.
+
+       2020-12-21  Jason Merrill  <jason@redhat.com>
+
+       * cp-demangle.c (d_unqualified_name): Clear is_expression.
+       * testsuite/demangle-expected: Add tests.
+
+       2020-11-25  Matthew Malcomson  <matthew.malcomson@arm.com>
+
+       * configure: Regenerate.
+       * configure.ac: Avoid using sanitizer.
+
+       2020-11-13  Eduard-Mihai Burtescu  <eddyb@lyken.rs>
+
+       * rust-demangle.c (struct rust_demangler): Add
+       skipping_printing and bound_lifetime_depth fields.
+       (eat): Add (v0-only).
+       (parse_integer_62): Add (v0-only).
+       (parse_opt_integer_62): Add (v0-only).
+       (parse_disambiguator): Add (v0-only).
+       (struct rust_mangled_ident): Add punycode{,_len} fields.
+       (parse_ident): Support v0 identifiers.
+       (print_str): Respect skipping_printing.
+       (print_uint64): Add (v0-only).
+       (print_uint64_hex): Add (v0-only).
+       (print_ident): Respect skipping_printing,
+       Support v0 identifiers.
+       (print_lifetime_from_index): Add (v0-only).
+       (demangle_binder): Add (v0-only).
+       (demangle_path): Add (v0-only).
+       (demangle_generic_arg): Add (v0-only).
+       (demangle_type): Add (v0-only).
+       (demangle_path_maybe_open_generics): Add (v0-only).
+       (demangle_dyn_trait): Add (v0-only).
+       (demangle_const): Add (v0-only).
+       (demangle_const_uint): Add (v0-only).
+       (basic_type): Add (v0-only).
+       (rust_demangle_callback): Support v0 symbols.
+       * testsuite/rust-demangle-expected: Add v0 testcases.
+
+       2020-11-13  Seija Kijin  <doremylover456@gmail.com>
+
+       * strstr.c (strstr): Make implementation ANSI/POSIX compliant.
+
+       2020-11-11  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/88115
+       * cp-demangle.c (d_print_comp_inner)
+       <case DEMANGLE_COMPONENT_EXTENDED_OPERATOR>: Don't print the
+       "operator " prefix for __alignof__.
+       <case DEMANGLE_COMPONENT_UNARY>: Always print parens around the
+       operand of __alignof__.
+       * testsuite/demangle-expected: Test demangling for __alignof__.
+
+       2020-11-09  Christophe Lyon  <christophe.lyon@linaro.org>
+
+       * pex-win32.c (pex_win32_exec_child): Initialize orig_err.
+
+       2020-10-06  Martin Liska  <mliska@suse.cz>
+
+       PR lto/97290
+       * simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
+       Use sh_link of a .symtab_shndx section.
+
 2021-01-05  Alan Modra  <amodra@gmail.com>
 
        * config.guess: Import from upstream.
index abf836eef13f5afd02b8236eb33b2498e1b312f4..a6f82ef6ec9daa5331b711fb63a1a3c81b56cb50 100644 (file)
@@ -1,23 +1,98 @@
-2020-09-23  Mark Wielaard  <mark@klomp.org>
+2021-01-04  Martin Liska  <mliska@suse.cz>
+
+       * strverscmp.c: Convert to utf8 from iso8859.
+
+2020-12-22  Jason Merrill  <jason@redhat.com>
+
+       PR c++/67343
+       * cp-demangle.h (struct d_info): Add unresolved_name_state.
+       * cp-demangle.c (d_prefix): Add subst parm.
+       (d_nested_name): Pass it.
+       (d_unresolved_name): Split out from...
+       (d_expression_1): ...here.
+       (d_demangle_callback): Maybe retry with old sr mangling.
+       * testsuite/demangle-expected: Add test.
+
+2020-12-21  Jason Merrill  <jason@redhat.com>
+
+       * cp-demangle.c (d_expression_1): Recognize qualified-id
+       on RHS of dt/pt.
+       * testsuite/demangle-expected: Add test.
+
+2020-12-21  Jason Merrill  <jason@redhat.com>
+
+       * cp-demangle.c (d_unqualified_name): Clear is_expression.
+       * testsuite/demangle-expected: Add tests.
+
+2020-11-25  Matthew Malcomson  <matthew.malcomson@arm.com>
+
+       * configure: Regenerate.
+       * configure.ac: Avoid using sanitizer.
+
+2020-11-13  Eduard-Mihai Burtescu  <eddyb@lyken.rs>
+
+       * rust-demangle.c (struct rust_demangler): Add
+       skipping_printing and bound_lifetime_depth fields.
+       (eat): Add (v0-only).
+       (parse_integer_62): Add (v0-only).
+       (parse_opt_integer_62): Add (v0-only).
+       (parse_disambiguator): Add (v0-only).
+       (struct rust_mangled_ident): Add punycode{,_len} fields.
+       (parse_ident): Support v0 identifiers.
+       (print_str): Respect skipping_printing.
+       (print_uint64): Add (v0-only).
+       (print_uint64_hex): Add (v0-only).
+       (print_ident): Respect skipping_printing,
+       Support v0 identifiers.
+       (print_lifetime_from_index): Add (v0-only).
+       (demangle_binder): Add (v0-only).
+       (demangle_path): Add (v0-only).
+       (demangle_generic_arg): Add (v0-only).
+       (demangle_type): Add (v0-only).
+       (demangle_path_maybe_open_generics): Add (v0-only).
+       (demangle_dyn_trait): Add (v0-only).
+       (demangle_const): Add (v0-only).
+       (demangle_const_uint): Add (v0-only).
+       (basic_type): Add (v0-only).
+       (rust_demangle_callback): Support v0 symbols.
+       * testsuite/rust-demangle-expected: Add v0 testcases.
+
+2020-11-13  Seija Kijin  <doremylover456@gmail.com>
+
+       * strstr.c (strstr): Make implementation ANSI/POSIX compliant.
+
+2020-11-11  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/88115
+       * cp-demangle.c (d_print_comp_inner)
+       <case DEMANGLE_COMPONENT_EXTENDED_OPERATOR>: Don't print the
+       "operator " prefix for __alignof__.
+       <case DEMANGLE_COMPONENT_UNARY>: Always print parens around the
+       operand of __alignof__.
+       * testsuite/demangle-expected: Test demangling for __alignof__.
+
+2020-11-09  Christophe Lyon  <christophe.lyon@linaro.org>
+
+       * pex-win32.c (pex_win32_exec_child): Initialize orig_err.
+
+2020-10-06  Martin Liska  <mliska@suse.cz>
+
+       PR lto/97290
+       * simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
+       Use sh_link of a .symtab_shndx section.
+
+2020-09-24  Mark Wielaard  <mark@klomp.org>
 
-       Sync with GCC
        * dwarfnames.c (get_DW_UT_name): Define using DW_UT_FIRST, DW_UT
        and DW_UT_END.
 
-2020-09-11  Felix Willgerodt  <felix.willgerodt@intel.com>
-
-       Sync with GCC
-       2020-09-08  Felix Willgerodt  <felix.willgerodt@intel.com>
+2020-09-08  Felix Willgerodt  <felix.willgerodt@intel.com>
 
        * floatformat.c (floatformat_bfloat16_big): New.
        (floatformat_bfloat16_little): New.
 
 2020-09-08  Alan Modra  <amodra@gmail.com>
 
-       * configure: Regenerate.
-
-       Sync from gcc
-       2020-09-08  Alan Modra  <amodra@gmail.com>
        * d-demangle.c: Include limits.h.
        (ULONG_MAX, UINT_MAX): Provide fall-back definition.
        (dlang_number): Simplify and correct overflow test.  Only
        unsigned long variables.
        * testsuite/d-demangle-expected: Add new tests.
 
-       2020-08-04  Iain Buclaw  <ibuclaw@gdcproject.org>
+2020-08-26  Iain Buclaw  <ibuclaw@gdcproject.org>
+
        * d-demangle.c (dlang_function_args): Handle 'in' and 'in ref'
        parameter storage classes.
        (dlang_type): Remove identifier type.
        * testsuite/d-demangle-expected: Update tests.
 
-       2020-08-03  Richard Biener  <rguenther@suse.de>
+2020-08-03  Richard Biener  <rguenther@suse.de>
+
        PR lto/96385
        * simple-object-elf.c
        (simple_object_elf_copy_lto_debug_sections): Localize global
        UNDEFs and reuse the prevailing name.
 
-       2020-07-10  Ian Lance Taylor  <iant@golang.org>
+2020-07-30  H.J. Lu  <hjl.tools@gmail.com>
+
+       PR bootstrap/96202
+       * configure: Regenerated.
+
+2020-07-14  Ian Lance Taylor  <iant@golang.org>
+
        PR demangler/96143
        * cp-demangle.c (d_lambda): Don't add substitution candidate.
        * testsuite/demangle-expected: Update a few existing test cases
        accordingly, and add a new test case.
 
-       2020-07-04  Jason Merrill  <jason@redhat.com>
+2020-07-10  Jason Merrill  <jason@redhat.com>
+
        * cp-demangle.c (cplus_demangle_operators): Add di, dx, dX.
        (d_expression_1): Handle di and dX.
        (is_designated_init, d_maybe_print_designated_init): New.
        (d_print_comp_inner): Use d_maybe_print_designated_init.
        * testsuite/demangle-expected: Add designator tests.
 
-       2020-06-25  Nick Clifton  <nickc@redhat.com>
+2020-06-26  Nick Clifton  <nickc@redhat.com>
+
        * bsearch.c (bsearch): Remove use of register keyword.
        * bsearch_r.c (bsearch_r): Likewise.
 
        (find_executable): Likewise.
        (win32_spawn): Cast alloca return to (char**).
        Replace malloc with XNEWVEC.
-       bcopy.c (bcopy): Add explicit casts in assignments.
+       bcopy.c (bcopy): Add explict casts in assignments.
 
 2006-10-25  Ben Elliston  <bje@au.ibm.com>
 
index ff93c9ee9a6fa9c6bb1938bcdfffb2d0ae8c9698..b6af9baf21204a323cad0e7b40a426c72988ba3b 100755 (executable)
@@ -5264,6 +5264,7 @@ fi
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 
 
index 4e2599c14a89bafcb8c7e523b9ce5b3d60b8c0f6..ad952963971a31968b5d109661b9cab0aa4b95fc 100644 (file)
@@ -240,6 +240,7 @@ AC_SUBST(PICFLAG)
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 AC_SUBST(NOASANFLAG)
 
index 4f709f4ca740279f2e8ad05a0c3ef971abda8bcd..d3e798455cc6a3a21f19314a76af26b189c44a3e 100644 (file)
@@ -429,7 +429,7 @@ static struct demangle_component *d_name (struct d_info *);
 
 static struct demangle_component *d_nested_name (struct d_info *);
 
-static struct demangle_component *d_prefix (struct d_info *);
+static struct demangle_component *d_prefix (struct d_info *, int);
 
 static struct demangle_component *d_unqualified_name (struct d_info *);
 
@@ -1510,7 +1510,7 @@ d_nested_name (struct d_info *di)
      once we have something to attach it to.  */
   rqual = d_ref_qualifier (di, NULL);
 
-  *pret = d_prefix (di);
+  *pret = d_prefix (di, 1);
   if (*pret == NULL)
     return NULL;
 
@@ -1536,10 +1536,12 @@ d_nested_name (struct d_info *di)
    <template-prefix> ::= <prefix> <(template) unqualified-name>
                      ::= <template-param>
                      ::= <substitution>
-*/
+
+   SUBST is true if we should add substitutions (as normal), false
+   if not (in an unresolved-name).  */
 
 static struct demangle_component *
-d_prefix (struct d_info *di)
+d_prefix (struct d_info *di, int subst)
 {
   struct demangle_component *ret = NULL;
 
@@ -1605,7 +1607,7 @@ d_prefix (struct d_info *di)
       else
        ret = d_make_comp (di, comb_type, ret, dc);
 
-      if (peek != 'S' && d_peek_char (di) != 'E')
+      if (peek != 'S' && d_peek_char (di) != 'E' && subst)
        {
          if (! d_add_substitution (di, ret))
            return NULL;
@@ -1632,9 +1634,15 @@ d_unqualified_name (struct d_info *di)
     ret = d_source_name (di);
   else if (IS_LOWER (peek))
     {
+      int was_expr = di->is_expression;
       if (peek == 'o' && d_peek_next_char (di) == 'n')
-       d_advance (di, 2);
+       {
+         d_advance (di, 2);
+         /* Treat cv as naming a conversion operator.  */
+         di->is_expression = 0;
+       }
       ret = d_operator_name (di);
+      di->is_expression = was_expr;
       if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
        {
          di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
@@ -3285,14 +3293,58 @@ op_is_new_cast (struct demangle_component *op)
              || code[0] == 'c' || code[0] == 'r'));
 }
 
+/*   <unresolved-name> ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+       ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+       # T::N::x /decltype(p)::N::x
+       ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+       # A::x, N::y, A<T>::z; "gs" means leading "::"
+       ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+     "gs" is handled elsewhere, as a unary operator.  */
+
+static struct demangle_component *
+d_unresolved_name (struct d_info *di)
+{
+  struct demangle_component *type;
+  struct demangle_component *name;
+  char peek;
+
+  /* Consume the "sr".  */
+  d_advance (di, 2);
+
+  peek = d_peek_char (di);
+  if (di->unresolved_name_state
+      && (IS_DIGIT (peek)
+         || IS_LOWER (peek)
+         || peek == 'C'
+         || peek == 'U'
+         || peek == 'L'))
+    {
+      /* The third production is ambiguous with the old unresolved-name syntax
+        of <type> <base-unresolved-name>; in the old mangling, A::x was mangled
+        as sr1A1x, now sr1AE1x.  So we first try to demangle using the new
+        mangling, then with the old if that fails.  */
+      di->unresolved_name_state = -1;
+      type = d_prefix (di, 0);
+      if (d_peek_char (di) == 'E')
+       d_advance (di, 1);
+    }
+  else
+    type = cplus_demangle_type (di);
+  name = d_unqualified_name (di);
+  if (d_peek_char (di) == 'I')
+    name = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+                       d_template_args (di));
+  return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
+}
+
 /* <expression> ::= <(unary) operator-name> <expression>
                 ::= <(binary) operator-name> <expression> <expression>
                 ::= <(trinary) operator-name> <expression> <expression> <expression>
                ::= cl <expression>+ E
                 ::= st <type>
                 ::= <template-param>
-                ::= sr <type> <unqualified-name>
-                ::= sr <type> <unqualified-name> <template-args>
+               ::= <unresolved-name>
                 ::= <expr-primary>
 
   <braced-expression> ::= <expression>
@@ -3302,7 +3354,7 @@ op_is_new_cast (struct demangle_component *op)
                                                                        # [expr ... expr] = expr
 */
 
-static inline struct demangle_component *
+static struct demangle_component *
 d_expression_1 (struct d_info *di)
 {
   char peek;
@@ -3313,20 +3365,7 @@ d_expression_1 (struct d_info *di)
   else if (peek == 'T')
     return d_template_param (di);
   else if (peek == 's' && d_peek_next_char (di) == 'r')
-    {
-      struct demangle_component *type;
-      struct demangle_component *name;
-
-      d_advance (di, 2);
-      type = cplus_demangle_type (di);
-      name = d_unqualified_name (di);
-      if (d_peek_char (di) != 'I')
-       return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
-      else
-       return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
-                           d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
-                                        d_template_args (di)));
-    }
+    return d_unresolved_name (di);
   else if (peek == 's' && d_peek_next_char (di) == 'p')
     {
       d_advance (di, 2);
@@ -3470,10 +3509,22 @@ d_expression_1 (struct d_info *di)
              right = d_exprlist (di, 'E');
            else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
              {
-               right = d_unqualified_name (di);
-               if (d_peek_char (di) == 'I')
-                 right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
-                                      right, d_template_args (di));
+               peek = d_peek_char (di);
+               /* These codes start a qualified name.  */
+               if ((peek == 'g' && d_peek_next_char (di) == 's')
+                   || (peek == 's' && d_peek_next_char (di) == 'r'))
+                 right = d_expression_1 (di);
+               else
+                 {
+                   /* Otherwise it's an unqualified name.  We use
+                      d_unqualified_name rather than d_expression_1 here for
+                      old mangled names that didn't add 'on' before operator
+                      names.  */
+                   right = d_unqualified_name (di);
+                   if (d_peek_char (di) == 'I')
+                     right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
+                                          right, d_template_args (di));
+                 }
              }
            else
              right = d_expression_1 (di);
@@ -5458,9 +5509,18 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
       }
 
     case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
-      d_append_string (dpi, "operator ");
-      d_print_comp (dpi, options, dc->u.s_extended_operator.name);
-      return;
+      {
+       struct demangle_component *name = dc->u.s_extended_operator.name;
+       if (name->type == DEMANGLE_COMPONENT_NAME
+           && !strncmp (name->u.s_name.s, "__alignof__", name->u.s_name.len))
+         d_print_comp (dpi, options, dc->u.s_extended_operator.name);
+       else
+         {
+           d_append_string (dpi, "operator ");
+           d_print_comp (dpi, options, dc->u.s_extended_operator.name);
+         }
+       return;
+      }
 
     case DEMANGLE_COMPONENT_CONVERSION:
       d_append_string (dpi, "operator ");
@@ -5525,8 +5585,14 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
        if (code && !strcmp (code, "gs"))
          /* Avoid parens after '::'.  */
          d_print_comp (dpi, options, operand);
-       else if (code && !strcmp (code, "st"))
-         /* Always print parens for sizeof (type).  */
+       else if ((code && !strcmp (code, "st"))
+                || (op->type == DEMANGLE_COMPONENT_EXTENDED_OPERATOR
+                    && (op->u.s_extended_operator.name->type
+                        == DEMANGLE_COMPONENT_NAME)
+                    && !strncmp (op->u.s_extended_operator.name->u.s_name.s,
+                                 "__alignof__",
+                                 op->u.s_extended_operator.name->u.s_name.len)))
+         /* Always print parens for sizeof (type) and __alignof__.  */
          {
            d_append_char (dpi, '(');
            d_print_comp (dpi, options, operand);
@@ -6364,6 +6430,9 @@ d_demangle_callback (const char *mangled, int options,
       type = DCT_TYPE;
     }
 
+  di.unresolved_name_state = 1;
+
+ again:
   cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
 
   /* PR 87675 - Check for a mangled string that is so long
@@ -6422,6 +6491,13 @@ d_demangle_callback (const char *mangled, int options,
     if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
       dc = NULL;
 
+    /* See discussion in d_unresolved_name.  */
+    if (dc == NULL && di.unresolved_name_state == -1)
+      {
+       di.unresolved_name_state = 0;
+       goto again;
+      }
+
 #ifdef CP_DEMANGLE_DEBUG
     d_dump (dc, 0);
 #endif
index 84eb5db1e6b252be30a999132099b5348bfff66f..cb47bdf0d2e4554832f038d0571238b846562c88 100644 (file)
@@ -122,6 +122,10 @@ struct d_info
   /* Non-zero if we are parsing the type operand of a conversion
      operator, but not when in an expression.  */
   int is_conversion;
+  /*  1: using new unresolved-name grammar.
+     -1: using new unresolved-name grammar and saw an unresolved-name.
+      0: using old unresolved-name grammar.  */
+  int unresolved_name_state;
   /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
      the current recursion level.  */
   unsigned int recursion_level;
index 4be00f13f30631937c82871c0502350ced9589e6..ecfe7f160e5c8cd741f0ce79986f15a55709fe38 100644 (file)
@@ -771,7 +771,7 @@ pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
   OSVERSIONINFO version_info;
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
-  int orig_out, orig_in, orig_err;
+  int orig_out, orig_in, orig_err = 0;
   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
 
   /* Ensure we have inheritable descriptors to pass to the child.  */
index 511897671982b0013b1f3704c29b773669666a1b..6fd8f6a4db0541615cedc72e1668c421b207bca4 100644 (file)
@@ -1,6 +1,7 @@
 /* Demangler for the Rust programming language
    Copyright (C) 2016-2021 Free Software Foundation, Inc.
    Written by David Tolnay (dtolnay@gmail.com).
+   Rewritten by Eduard-Mihai Burtescu (eddyb@lyken.rs) for v0 support.
 
 This file is part of the libiberty library.
 Libiberty is free software; you can redistribute it and/or
@@ -64,11 +65,16 @@ struct rust_demangler
   /* Non-zero if any error occurred. */
   int errored;
 
+  /* Non-zero if nothing should be printed. */
+  int skipping_printing;
+
   /* Non-zero if printing should be verbose (e.g. include hashes). */
   int verbose;
 
   /* Rust mangling version, with legacy mangling being -1. */
   int version;
+
+  uint64_t bound_lifetime_depth;
 };
 
 /* Parsing functions. */
@@ -81,6 +87,18 @@ peek (const struct rust_demangler *rdm)
   return 0;
 }
 
+static int
+eat (struct rust_demangler *rdm, char c)
+{
+  if (peek (rdm) == c)
+    {
+      rdm->next++;
+      return 1;
+    }
+  else
+    return 0;
+}
+
 static char
 next (struct rust_demangler *rdm)
 {
@@ -92,11 +110,87 @@ next (struct rust_demangler *rdm)
   return c;
 }
 
+static uint64_t
+parse_integer_62 (struct rust_demangler *rdm)
+{
+  char c;
+  uint64_t x;
+
+  if (eat (rdm, '_'))
+    return 0;
+
+  x = 0;
+  while (!eat (rdm, '_'))
+    {
+      c = next (rdm);
+      x *= 62;
+      if (ISDIGIT (c))
+        x += c - '0';
+      else if (ISLOWER (c))
+        x += 10 + (c - 'a');
+      else if (ISUPPER (c))
+        x += 10 + 26 + (c - 'A');
+      else
+        {
+          rdm->errored = 1;
+          return 0;
+        }
+    }
+  return x + 1;
+}
+
+static uint64_t
+parse_opt_integer_62 (struct rust_demangler *rdm, char tag)
+{
+  if (!eat (rdm, tag))
+    return 0;
+  return 1 + parse_integer_62 (rdm);
+}
+
+static uint64_t
+parse_disambiguator (struct rust_demangler *rdm)
+{
+  return parse_opt_integer_62 (rdm, 's');
+}
+
+static size_t
+parse_hex_nibbles (struct rust_demangler *rdm, uint64_t *value)
+{
+  char c;
+  size_t hex_len;
+
+  hex_len = 0;
+  *value = 0;
+
+  while (!eat (rdm, '_'))
+    {
+      *value <<= 4;
+
+      c = next (rdm);
+      if (ISDIGIT (c))
+        *value |= c - '0';
+      else if (c >= 'a' && c <= 'f')
+        *value |= 10 + (c - 'a');
+      else
+        {
+          rdm->errored = 1;
+          return 0;
+        }
+      hex_len++;
+    }
+
+  return hex_len;
+}
+
 struct rust_mangled_ident
 {
   /* ASCII part of the identifier. */
   const char *ascii;
   size_t ascii_len;
+
+  /* Punycode insertion codes for Unicode codepoints, if any. */
+  const char *punycode;
+  size_t punycode_len;
 };
 
 static struct rust_mangled_ident
@@ -104,10 +198,16 @@ parse_ident (struct rust_demangler *rdm)
 {
   char c;
   size_t start, len;
+  int is_punycode = 0;
   struct rust_mangled_ident ident;
 
   ident.ascii = NULL;
   ident.ascii_len = 0;
+  ident.punycode = NULL;
+  ident.punycode_len = 0;
+
+  if (rdm->version != -1)
+    is_punycode = eat (rdm, 'u');
 
   c = next (rdm);
   if (!ISDIGIT (c))
@@ -121,6 +221,10 @@ parse_ident (struct rust_demangler *rdm)
     while (ISDIGIT (peek (rdm)))
       len = len * 10 + (next (rdm) - '0');
 
+  /* Skip past the optional `_` separator (v0). */
+  if (rdm->version != -1)
+    eat (rdm, '_');
+
   start = rdm->next;
   rdm->next += len;
   /* Check for overflows. */
@@ -133,6 +237,27 @@ parse_ident (struct rust_demangler *rdm)
   ident.ascii = rdm->sym + start;
   ident.ascii_len = len;
 
+  if (is_punycode)
+    {
+      ident.punycode_len = 0;
+      while (ident.ascii_len > 0)
+        {
+          ident.ascii_len--;
+
+          /* The last '_' is a separator between ascii & punycode. */
+          if (ident.ascii[ident.ascii_len] == '_')
+            break;
+
+          ident.punycode_len++;
+        }
+      if (!ident.punycode_len)
+        {
+          rdm->errored = 1;
+          return ident;
+        }
+      ident.punycode = ident.ascii + (len - ident.punycode_len);
+    }
+
   if (ident.ascii_len == 0)
     ident.ascii = NULL;
 
@@ -144,12 +269,28 @@ parse_ident (struct rust_demangler *rdm)
 static void
 print_str (struct rust_demangler *rdm, const char *data, size_t len)
 {
-  if (!rdm->errored)
+  if (!rdm->errored && !rdm->skipping_printing)
     rdm->callback (data, len, rdm->callback_opaque);
 }
 
 #define PRINT(s) print_str (rdm, s, strlen (s))
 
+static void
+print_uint64 (struct rust_demangler *rdm, uint64_t x)
+{
+  char s[21];
+  snprintf (s, 21, "%" PRIu64, x);
+  PRINT (s);
+}
+
+static void
+print_uint64_hex (struct rust_demangler *rdm, uint64_t x)
+{
+  char s[17];
+  snprintf (s, 17, "%" PRIx64, x);
+  PRINT (s);
+}
+
 /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
 static int
 decode_lower_hex_nibble (char nibble)
@@ -230,9 +371,14 @@ static void
 print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
 {
   char unescaped;
-  size_t len;
-
-  if (rdm->errored)
+  uint8_t *out, *p, d;
+  size_t len, cap, punycode_pos, j;
+  /* Punycode parameters and state. */
+  uint32_t c;
+  size_t base, t_min, t_max, skew, damp, bias, i;
+  size_t delta, w, k, t;
+
+  if (rdm->errored || rdm->skipping_printing)
     return;
 
   if (rdm->version == -1)
@@ -273,8 +419,7 @@ print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
                 }
               else
                 {
-                  /* "." becomes "-" */
-                  PRINT ("-");
+                  PRINT (".");
                   len = 1;
                 }
             }
@@ -294,6 +439,830 @@ print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
 
       return;
     }
+
+  if (!ident.punycode)
+    {
+      print_str (rdm, ident.ascii, ident.ascii_len);
+      return;
+    }
+
+  len = 0;
+  cap = 4;
+  while (cap < ident.ascii_len)
+    {
+      cap *= 2;
+      /* Check for overflows. */
+      if ((cap * 4) / 4 != cap)
+        {
+          rdm->errored = 1;
+          return;
+        }
+    }
+
+  /* Store the output codepoints as groups of 4 UTF-8 bytes. */
+  out = (uint8_t *)malloc (cap * 4);
+  if (!out)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  /* Populate initial output from ASCII fragment. */
+  for (len = 0; len < ident.ascii_len; len++)
+    {
+      p = out + 4 * len;
+      p[0] = 0;
+      p[1] = 0;
+      p[2] = 0;
+      p[3] = ident.ascii[len];
+    }
+
+  /* Punycode parameters and initial state. */
+  base = 36;
+  t_min = 1;
+  t_max = 26;
+  skew = 38;
+  damp = 700;
+  bias = 72;
+  i = 0;
+  c = 0x80;
+
+  punycode_pos = 0;
+  while (punycode_pos < ident.punycode_len)
+    {
+      /* Read one delta value. */
+      delta = 0;
+      w = 1;
+      k = 0;
+      do
+        {
+          k += base;
+          t = k < bias ? 0 : (k - bias);
+          if (t < t_min)
+            t = t_min;
+          if (t > t_max)
+            t = t_max;
+
+          if (punycode_pos >= ident.punycode_len)
+            goto cleanup;
+          d = ident.punycode[punycode_pos++];
+
+          if (ISLOWER (d))
+            d = d - 'a';
+          else if (ISDIGIT (d))
+            d = 26 + (d - '0');
+          else
+            {
+              rdm->errored = 1;
+              goto cleanup;
+            }
+
+          delta += d * w;
+          w *= base - t;
+        }
+      while (d >= t);
+
+      /* Compute the new insert position and character. */
+      len++;
+      i += delta;
+      c += i / len;
+      i %= len;
+
+      /* Ensure enough space is available. */
+      if (cap < len)
+        {
+          cap *= 2;
+          /* Check for overflows. */
+          if ((cap * 4) / 4 != cap || cap < len)
+            {
+              rdm->errored = 1;
+              goto cleanup;
+            }
+        }
+      p = (uint8_t *)realloc (out, cap * 4);
+      if (!p)
+        {
+          rdm->errored = 1;
+          goto cleanup;
+        }
+      out = p;
+
+      /* Move the characters after the insert position. */
+      p = out + i * 4;
+      memmove (p + 4, p, (len - i - 1) * 4);
+
+      /* Insert the new character, as UTF-8 bytes. */
+      p[0] = c >= 0x10000 ? 0xf0 | (c >> 18) : 0;
+      p[1] = c >= 0x800 ? (c < 0x10000 ? 0xe0 : 0x80) | ((c >> 12) & 0x3f) : 0;
+      p[2] = (c < 0x800 ? 0xc0 : 0x80) | ((c >> 6) & 0x3f);
+      p[3] = 0x80 | (c & 0x3f);
+
+      /* If there are no more deltas, decoding is complete. */
+      if (punycode_pos == ident.punycode_len)
+        break;
+
+      i++;
+
+      /* Perform bias adaptation. */
+      delta /= damp;
+      damp = 2;
+
+      delta += delta / len;
+      k = 0;
+      while (delta > ((base - t_min) * t_max) / 2)
+        {
+          delta /= base - t_min;
+          k += base;
+        }
+      bias = k + ((base - t_min + 1) * delta) / (delta + skew);
+    }
+
+  /* Remove all the 0 bytes to leave behind an UTF-8 string. */
+  for (i = 0, j = 0; i < len * 4; i++)
+    if (out[i] != 0)
+      out[j++] = out[i];
+
+  print_str (rdm, (const char *)out, j);
+
+cleanup:
+  free (out);
+}
+
+/* Print the lifetime according to the previously decoded index.
+   An index of `0` always refers to `'_`, but starting with `1`,
+   indices refer to late-bound lifetimes introduced by a binder. */
+static void
+print_lifetime_from_index (struct rust_demangler *rdm, uint64_t lt)
+{
+  char c;
+  uint64_t depth;
+
+  PRINT ("'");
+  if (lt == 0)
+    {
+      PRINT ("_");
+      return;
+    }
+
+  depth = rdm->bound_lifetime_depth - lt;
+  /* Try to print lifetimes alphabetically first. */
+  if (depth < 26)
+    {
+      c = 'a' + depth;
+      print_str (rdm, &c, 1);
+    }
+  else
+    {
+      /* Use `'_123` after running out of letters. */
+      PRINT ("_");
+      print_uint64 (rdm, depth);
+    }
+}
+
+/* Demangling functions. */
+
+static void demangle_binder (struct rust_demangler *rdm);
+static void demangle_path (struct rust_demangler *rdm, int in_value);
+static void demangle_generic_arg (struct rust_demangler *rdm);
+static void demangle_type (struct rust_demangler *rdm);
+static int 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_int (struct rust_demangler *rdm);
+static void demangle_const_bool (struct rust_demangler *rdm);
+static void demangle_const_char (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)
+{
+  uint64_t i, bound_lifetimes;
+
+  if (rdm->errored)
+    return;
+
+  bound_lifetimes = parse_opt_integer_62 (rdm, 'G');
+  if (bound_lifetimes > 0)
+    {
+      PRINT ("for<");
+      for (i = 0; i < bound_lifetimes; i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          rdm->bound_lifetime_depth++;
+          print_lifetime_from_index (rdm, 1);
+        }
+      PRINT ("> ");
+    }
+}
+
+static void
+demangle_path (struct rust_demangler *rdm, int in_value)
+{
+  char tag, ns;
+  int was_skipping_printing;
+  size_t i, backref, old_next;
+  uint64_t dis;
+  struct rust_mangled_ident name;
+
+  if (rdm->errored)
+    return;
+
+  switch (tag = next (rdm))
+    {
+    case 'C':
+      dis = parse_disambiguator (rdm);
+      name = parse_ident (rdm);
+
+      print_ident (rdm, name);
+      if (rdm->verbose)
+        {
+          PRINT ("[");
+          print_uint64_hex (rdm, dis);
+          PRINT ("]");
+        }
+      break;
+    case 'N':
+      ns = next (rdm);
+      if (!ISLOWER (ns) && !ISUPPER (ns))
+        {
+          rdm->errored = 1;
+          return;
+        }
+
+      demangle_path (rdm, in_value);
+
+      dis = parse_disambiguator (rdm);
+      name = parse_ident (rdm);
+
+      if (ISUPPER (ns))
+        {
+          /* Special namespaces, like closures and shims. */
+          PRINT ("::{");
+          switch (ns)
+            {
+            case 'C':
+              PRINT ("closure");
+              break;
+            case 'S':
+              PRINT ("shim");
+              break;
+            default:
+              print_str (rdm, &ns, 1);
+            }
+          if (name.ascii || name.punycode)
+            {
+              PRINT (":");
+              print_ident (rdm, name);
+            }
+          PRINT ("#");
+          print_uint64 (rdm, dis);
+          PRINT ("}");
+        }
+      else
+        {
+          /* Implementation-specific/unspecified namespaces. */
+
+          if (name.ascii || name.punycode)
+            {
+              PRINT ("::");
+              print_ident (rdm, name);
+            }
+        }
+      break;
+    case 'M':
+    case 'X':
+      /* Ignore the `impl`'s own path.*/
+      parse_disambiguator (rdm);
+      was_skipping_printing = rdm->skipping_printing;
+      rdm->skipping_printing = 1;
+      demangle_path (rdm, in_value);
+      rdm->skipping_printing = was_skipping_printing;
+      /* fallthrough */
+    case 'Y':
+      PRINT ("<");
+      demangle_type (rdm);
+      if (tag != 'M')
+        {
+          PRINT (" as ");
+          demangle_path (rdm, 0);
+        }
+      PRINT (">");
+      break;
+    case 'I':
+      demangle_path (rdm, in_value);
+      if (in_value)
+        PRINT ("::");
+      PRINT ("<");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_generic_arg (rdm);
+        }
+      PRINT (">");
+      break;
+    case 'B':
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_path (rdm, in_value);
+          rdm->next = old_next;
+        }
+      break;
+    default:
+      rdm->errored = 1;
+      return;
+    }
+}
+
+static void
+demangle_generic_arg (struct rust_demangler *rdm)
+{
+  uint64_t lt;
+  if (eat (rdm, 'L'))
+    {
+      lt = parse_integer_62 (rdm);
+      print_lifetime_from_index (rdm, lt);
+    }
+  else if (eat (rdm, 'K'))
+    demangle_const (rdm);
+  else
+    demangle_type (rdm);
+}
+
+static const char *
+basic_type (char tag)
+{
+  switch (tag)
+    {
+    case 'b':
+      return "bool";
+    case 'c':
+      return "char";
+    case 'e':
+      return "str";
+    case 'u':
+      return "()";
+    case 'a':
+      return "i8";
+    case 's':
+      return "i16";
+    case 'l':
+      return "i32";
+    case 'x':
+      return "i64";
+    case 'n':
+      return "i128";
+    case 'i':
+      return "isize";
+    case 'h':
+      return "u8";
+    case 't':
+      return "u16";
+    case 'm':
+      return "u32";
+    case 'y':
+      return "u64";
+    case 'o':
+      return "u128";
+    case 'j':
+      return "usize";
+    case 'f':
+      return "f32";
+    case 'd':
+      return "f64";
+    case 'z':
+      return "!";
+    case 'p':
+      return "_";
+    case 'v':
+      return "...";
+
+    default:
+      return NULL;
+    }
+}
+
+static void
+demangle_type (struct rust_demangler *rdm)
+{
+  char tag;
+  size_t i, old_next, backref;
+  uint64_t lt, old_bound_lifetime_depth;
+  const char *basic;
+  struct rust_mangled_ident abi;
+
+  if (rdm->errored)
+    return;
+
+  tag = next (rdm);
+
+  basic = basic_type (tag);
+  if (basic)
+    {
+      PRINT (basic);
+      return;
+    }
+
+  switch (tag)
+    {
+    case 'R':
+    case 'Q':
+      PRINT ("&");
+      if (eat (rdm, 'L'))
+        {
+          lt = parse_integer_62 (rdm);
+          if (lt)
+            {
+              print_lifetime_from_index (rdm, lt);
+              PRINT (" ");
+            }
+        }
+      if (tag != 'R')
+        PRINT ("mut ");
+      demangle_type (rdm);
+      break;
+    case 'P':
+    case 'O':
+      PRINT ("*");
+      if (tag != 'P')
+        PRINT ("mut ");
+      else
+        PRINT ("const ");
+      demangle_type (rdm);
+      break;
+    case 'A':
+    case 'S':
+      PRINT ("[");
+      demangle_type (rdm);
+      if (tag == 'A')
+        {
+          PRINT ("; ");
+          demangle_const (rdm);
+        }
+      PRINT ("]");
+      break;
+    case 'T':
+      PRINT ("(");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_type (rdm);
+        }
+      if (i == 1)
+        PRINT (",");
+      PRINT (")");
+      break;
+    case 'F':
+      old_bound_lifetime_depth = rdm->bound_lifetime_depth;
+      demangle_binder (rdm);
+
+      if (eat (rdm, 'U'))
+        PRINT ("unsafe ");
+
+      if (eat (rdm, 'K'))
+        {
+          if (eat (rdm, 'C'))
+            {
+              abi.ascii = "C";
+              abi.ascii_len = 1;
+            }
+          else
+            {
+              abi = parse_ident (rdm);
+              if (!abi.ascii || abi.punycode)
+                {
+                  rdm->errored = 1;
+                  goto restore;
+                }
+            }
+
+          PRINT ("extern \"");
+
+          /* If the ABI had any `-`, they were replaced with `_`,
+             so the parts between `_` have to be re-joined with `-`. */
+          for (i = 0; i < abi.ascii_len; i++)
+            {
+              if (abi.ascii[i] == '_')
+                {
+                  print_str (rdm, abi.ascii, i);
+                  PRINT ("-");
+                  abi.ascii += i + 1;
+                  abi.ascii_len -= i + 1;
+                  i = 0;
+                }
+            }
+          print_str (rdm, abi.ascii, abi.ascii_len);
+
+          PRINT ("\" ");
+        }
+
+      PRINT ("fn(");
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_type (rdm);
+        }
+      PRINT (")");
+
+      if (eat (rdm, 'u'))
+        {
+          /* Skip printing the return type if it's 'u', i.e. `()`. */
+        }
+      else
+        {
+          PRINT (" -> ");
+          demangle_type (rdm);
+        }
+
+    /* Restore `bound_lifetime_depth` to outside the binder. */
+    restore:
+      rdm->bound_lifetime_depth = old_bound_lifetime_depth;
+      break;
+    case 'D':
+      PRINT ("dyn ");
+
+      old_bound_lifetime_depth = rdm->bound_lifetime_depth;
+      demangle_binder (rdm);
+
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (" + ");
+          demangle_dyn_trait (rdm);
+        }
+
+      /* Restore `bound_lifetime_depth` to outside the binder. */
+      rdm->bound_lifetime_depth = old_bound_lifetime_depth;
+
+      if (!eat (rdm, 'L'))
+        {
+          rdm->errored = 1;
+          return;
+        }
+      lt = parse_integer_62 (rdm);
+      if (lt)
+        {
+          PRINT (" + ");
+          print_lifetime_from_index (rdm, lt);
+        }
+      break;
+    case 'B':
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_type (rdm);
+          rdm->next = old_next;
+        }
+      break;
+    default:
+      /* Go back to the tag, so `demangle_path` also sees it. */
+      rdm->next--;
+      demangle_path (rdm, 0);
+    }
+}
+
+/* A trait in a trait object may have some "existential projections"
+   (i.e. associated type bindings) after it, which should be printed
+   in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
+   To this end, this method will keep the `<...>` of an 'I' path
+   open, by omitting the `>`, and return `Ok(true)` in that case. */
+static int
+demangle_path_maybe_open_generics (struct rust_demangler *rdm)
+{
+  int open;
+  size_t i, old_next, backref;
+
+  open = 0;
+
+  if (rdm->errored)
+    return open;
+
+  if (eat (rdm, 'B'))
+    {
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          open = demangle_path_maybe_open_generics (rdm);
+          rdm->next = old_next;
+        }
+    }
+  else if (eat (rdm, 'I'))
+    {
+      demangle_path (rdm, 0);
+      PRINT ("<");
+      open = 1;
+      for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
+        {
+          if (i > 0)
+            PRINT (", ");
+          demangle_generic_arg (rdm);
+        }
+    }
+  else
+    demangle_path (rdm, 0);
+  return open;
+}
+
+static void
+demangle_dyn_trait (struct rust_demangler *rdm)
+{
+  int open;
+  struct rust_mangled_ident name;
+
+  if (rdm->errored)
+    return;
+
+  open = demangle_path_maybe_open_generics (rdm);
+
+  while (eat (rdm, 'p'))
+    {
+      if (!open)
+        PRINT ("<");
+      else
+        PRINT (", ");
+      open = 1;
+
+      name = parse_ident (rdm);
+      print_ident (rdm, name);
+      PRINT (" = ");
+      demangle_type (rdm);
+    }
+
+  if (open)
+    PRINT (">");
+}
+
+static void
+demangle_const (struct rust_demangler *rdm)
+{
+  char ty_tag;
+  size_t old_next, backref;
+
+  if (rdm->errored)
+    return;
+
+  if (eat (rdm, 'B'))
+    {
+      backref = parse_integer_62 (rdm);
+      if (!rdm->skipping_printing)
+        {
+          old_next = rdm->next;
+          rdm->next = backref;
+          demangle_const (rdm);
+          rdm->next = old_next;
+        }
+      return;
+    }
+
+  ty_tag = next (rdm);
+  switch (ty_tag)
+    {
+    /* Placeholder. */
+    case 'p':
+      PRINT ("_");
+      return;
+
+    /* Unsigned integer types. */
+    case 'h':
+    case 't':
+    case 'm':
+    case 'y':
+    case 'o':
+    case 'j':
+      demangle_const_uint (rdm);
+      break;
+
+    /* Signed integer types. */
+    case 'a':
+    case 's':
+    case 'l':
+    case 'x':
+    case 'n':
+    case 'i':
+      demangle_const_int (rdm);
+      break;
+
+    /* Boolean. */
+    case 'b':
+      demangle_const_bool (rdm);
+      break;
+
+    /* Character. */
+    case 'c':
+      demangle_const_char (rdm);
+      break;
+
+    default:
+      rdm->errored = 1;
+      return;
+    }
+
+  if (rdm->errored)
+    return;
+
+  if (rdm->verbose)
+    {
+      PRINT (": ");
+      PRINT (basic_type (ty_tag));
+    }
+}
+
+static void
+demangle_const_uint (struct rust_demangler *rdm)
+{
+  size_t hex_len;
+  uint64_t value;
+
+  if (rdm->errored)
+    return;
+
+  hex_len = parse_hex_nibbles (rdm, &value);
+
+  if (hex_len > 16)
+    {
+      /* Print anything that doesn't fit in `uint64_t` verbatim. */
+      PRINT ("0x");
+      print_str (rdm, rdm->sym + (rdm->next - hex_len), hex_len);
+    }
+  else if (hex_len > 0)
+    print_uint64 (rdm, value);
+  else
+    rdm->errored = 1;
+}
+
+static void
+demangle_const_int (struct rust_demangler *rdm)
+{
+  if (eat (rdm, 'n'))
+    PRINT ("-");
+  demangle_const_uint (rdm);
+}
+
+static void
+demangle_const_bool (struct rust_demangler *rdm)
+{
+  uint64_t value;
+
+  if (parse_hex_nibbles (rdm, &value) != 1)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  if (value == 0)
+    PRINT ("false");
+  else if (value == 1)
+    PRINT ("true");
+  else
+    rdm->errored = 1;
+}
+
+static void
+demangle_const_char (struct rust_demangler *rdm)
+{
+  size_t hex_len;
+  uint64_t value;
+
+  hex_len = parse_hex_nibbles (rdm, &value);
+
+  if (hex_len == 0 || hex_len > 8)
+    {
+      rdm->errored = 1;
+      return;
+    }
+
+  /* Match Rust's character "debug" output as best as we can. */
+  PRINT ("'");
+  if (value == '\t')
+    PRINT ("\\t");
+  else if (value == '\r')
+    PRINT ("\\r");
+  else if (value == '\n')
+    PRINT ("\\n");
+  else if (value > ' ' && value < '~')
+    /* Rust also considers many non-ASCII codepoints to be printable, but
+       that logic is not easily ported to C. */
+    print_str (rdm, (char *) &value, 1);
+  else
+    {
+      PRINT ("\\u{");
+      print_uint64_hex (rdm, value);
+      PRINT ("}");
+    }
+  PRINT ("'");
 }
 
 /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
@@ -345,11 +1314,15 @@ rust_demangle_callback (const char *mangled, int options,
 
   rdm.next = 0;
   rdm.errored = 0;
+  rdm.skipping_printing = 0;
   rdm.verbose = (options & DMGL_VERBOSE) != 0;
   rdm.version = 0;
+  rdm.bound_lifetime_depth = 0;
 
-  /* Rust symbols always start with _ZN (legacy). */
-  if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N')
+  /* Rust symbols always start with _R (v0) or _ZN (legacy). */
+  if (rdm.sym[0] == '_' && rdm.sym[1] == 'R')
+    rdm.sym += 2;
+  else if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N')
     {
       rdm.sym += 3;
       rdm.version = -1;
@@ -357,7 +1330,11 @@ rust_demangle_callback (const char *mangled, int options,
   else
     return 0;
 
-  /* Legacy Rust symbols use only [_0-9a-zA-Z.:$] characters. */
+  /* Paths (v0) always start with uppercase characters. */
+  if (rdm.version != -1 && !ISUPPER (rdm.sym[0]))
+    return 0;
+
+  /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
   for (p = rdm.sym; *p; p++)
     {
       rdm.sym_len++;
@@ -365,6 +1342,7 @@ rust_demangle_callback (const char *mangled, int options,
       if (*p == '_' || ISALNUM (*p))
         continue;
 
+      /* Legacy Rust symbols can also contain [.:$] characters. */
       if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':'))
         continue;
 
@@ -418,7 +1396,19 @@ rust_demangle_callback (const char *mangled, int options,
       while (rdm.next < rdm.sym_len);
     }
   else
-    return 0;
+    {
+      demangle_path (&rdm, 1);
+
+      /* Skip instantiating crate. */
+      if (!rdm.errored && rdm.next < rdm.sym_len)
+        {
+          rdm.skipping_printing = 1;
+          demangle_path (&rdm, 0);
+        }
+
+      /* It's an error to not reach the end. */
+      rdm.errored |= rdm.next != rdm.sym_len;
+    }
 
   return !rdm.errored;
 }
index e37e33456eea0e4bb1f66bfce7fa84246988ee51..a421177f0c2077b809680c7d8168a9a208b59f30 100644 (file)
@@ -1191,7 +1191,7 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
          unsigned int sh_link;
          sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
                                     shdr, sh_link, Elf_Word);
-         symtab_indices_shndx[sh_link - 1] = i;
+         symtab_indices_shndx[sh_link - 1] = i - 1;
          /* Always discard the extended index sections, after
             copying it will not be needed.  This way we don't need to
             update it and deal with the ordering constraints of
@@ -1372,19 +1372,22 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
        {
          unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
                                              shdr, sh_entsize, Elf_Addr);
-         unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
-                                            shdr, sh_link, Elf_Word);
          size_t prevailing_name_idx = 0;
          unsigned char *ent;
          unsigned *shndx_table = NULL;
          /* Read the section index table if present.  */
          if (symtab_indices_shndx[i - 1] != 0)
            {
-             unsigned char *sidxhdr = shdrs + (strtab - 1) * shdr_size;
+             unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size;
              off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
                                               sidxhdr, sh_offset, Elf_Addr);
              size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
                                               sidxhdr, sh_size, Elf_Addr);
+             unsigned int shndx_type
+               = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                  sidxhdr, sh_type, Elf_Word);
+             if (shndx_type != SHT_SYMTAB_SHNDX)
+               return "Wrong section type of a SYMTAB SECTION INDICES section";
              shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
              simple_object_internal_read (sobj->descriptor,
                                           sobj->offset + sidxoff,
index 60902ea40ee80b513a525f9403728398ea876d7e..c6f68495a33d124cec901251812150c52e2d0ea3 100644 (file)
@@ -16,26 +16,20 @@ length, the function returns @var{string}.
 
 */
 
-
-/* FIXME:  The above description is ANSI compiliant.  This routine has not
-   been validated to comply with it.  -fnf */
-
 #include <stddef.h>
 
-extern char *strchr (const char *, int);
-extern int strncmp (const void *, const void *, size_t);
+extern int memcmp (const void *, const void *, size_t);
 extern size_t strlen (const char *);
 
 char *
 strstr (const char *s1, const char *s2)
 {
-  const char *p = s1;
   const size_t len = strlen (s2);
-
-  for (; (p = strchr (p, *s2)) != 0; p++)
+  while (*s1)
     {
-      if (strncmp (p, s2, len) == 0)
-       return (char *)p;
+      if (!memcmp (s1, s2, len))
+       return (char *)s1;
+      ++s1;
     }
   return (0);
 }
index 6f3e8b48dd660995a77ab687a111f444ec806066..57a71da06feb370923b62da26d163599d3d9e86a 100644 (file)
@@ -1,7 +1,7 @@
 /* Compare strings while treating digits characters numerically.
    Copyright (C) 1997-2021 Free Software Foundation, Inc.
    This file is part of the libiberty library.
-   Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
+   Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
 
    Libiberty is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
index 0850db3d6dd448e254a85e7e941eb9604dcf5dc6..e6b5b64b9a9bc31a1cbf75b80e4b25407116dd82 100644 (file)
@@ -1469,3 +1469,22 @@ f(A<X{.a.b[3 ... 4]=(1)}>)
 # PR 96143
 _Z2F2IZ1FvEUlvE_EN1AIT_E1XES2_
 A<F()::{lambda()#1}>::X F2<F()::{lambda()#1}>(F()::{lambda()#1})
+
+# PR 88115
+_Z1fIiEvDTv111__alignof__T_E
+void f<int>(decltype (__alignof__(int)))
+
+_Z1fIiEvDTv111__alignof__tlT_EE
+void f<int>(decltype (__alignof__(int{})))
+
+_Z1gI1AEv1SIXadsrT_oncviEE
+void g<A>(S<&A::operator int>)
+
+_Z1jI1AEDTcldtfp_oncvPT_EES1_
+decltype (({parm#1}.(operator A*))()) j<A>(A)
+
+_Z1fI1AEDtdtfp_srT_1xES1_
+decltype ({parm#1}.A::x) f<A>(A)
+
+_Z2f6IP1AEDtptfp_gssr1A1BE1xET_
+decltype ({parm#1}->(::A::B::x)) f6<A*>(A*)
index 74774794736a8ae1dde4e2ff59fed5a4da46b8d2..7dca315d0054801636f1563c19f42da517ad67e0 100644 (file)
@@ -11,7 +11,7 @@
 #
 ############
 #
-# Coverage Tests
+# Coverage Tests (legacy)
 #
 #
 # Demangles as rust symbol.
@@ -163,3 +163,135 @@ _ZN63_$LT$core..ptr..Unique$LT$T$GT$$u20$as$u20$core..ops..Deref$GT$5deref17h19f
 --format=rust
 _ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h059a991a004536adE
 issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
+--format=rust
+_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h000b1ad6c4f30bd6E
+core::ops::function::FnOnce::call_once{{vtable.shim}}
+#
+############
+#
+# Coverage Tests (v0)
+#
+#
+# Crate with a leading digit.
+--format=rust
+_RNvC6_123foo3bar
+123foo::bar
+# UTF-8 identifiers.
+--format=rust
+_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y
+utf8_idents::საჭმელად_გემრიელი_სადილი
+# Closure path elements.
+--format=rust
+_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_
+cc::spawn::{closure#0}::{closure#0}
+#
+--format=rust
+_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_
+<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}
+# dyn Trait ("trait object") types.
+--format=rust
+_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std
+alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>
+# Types with const generics parameters.
+--format=rust
+_RNvMC0INtC8arrayvec8ArrayVechKj7b_E3new
+<arrayvec::ArrayVec<u8, 123>>::new
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E
+<const_generic::Unsigned<11>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E
+<const_generic::Signed<152>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E
+<const_generic::Signed<-11>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E
+<const_generic::Bool<false>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E
+<const_generic::Bool<true>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E
+<const_generic::Char<'v'>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E
+<const_generic::Char<'\n'>>
+#
+--format=rust
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E
+<const_generic::Char<'\u{2202}'>>
+#
+--format=rust
+_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO
+<const_generic::Foo<_>>::foo::FOO
+#
+# All of the tests above but in auto mode instead:
+#
+# Crate with a leading digit.
+--format=auto
+_RNvC6_123foo3bar
+123foo::bar
+# UTF-8 identifiers.
+--format=auto
+_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y
+utf8_idents::საჭმელად_გემრიელი_სადილი
+# Closure path elements.
+--format=auto
+_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_
+cc::spawn::{closure#0}::{closure#0}
+#
+--format=auto
+_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_
+<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}
+# dyn Trait ("trait object") types.
+--format=auto
+_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std
+alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>
+# Types with const generics parameters.
+--format=auto
+_RNvMC0INtC8arrayvec8ArrayVechKj7b_E3new
+<arrayvec::ArrayVec<u8, 123>>::new
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E
+<const_generic::Unsigned<11>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E
+<const_generic::Signed<152>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E
+<const_generic::Signed<-11>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E
+<const_generic::Bool<false>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E
+<const_generic::Bool<true>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E
+<const_generic::Char<'v'>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E
+<const_generic::Char<'\n'>>
+#
+--format=auto
+_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E
+<const_generic::Char<'\u{2202}'>>
+#
+--format=auto
+_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO
+<const_generic::Foo<_>>::foo::FOO