<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    No, that was a mistake, fixed in r326871. Thanks for pointing this
    out!<br>
    Erik<br>
    <br>
    <div class="moz-cite-prefix">On 2018-03-06 11:10 PM, Nico Weber
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAMGbLiEqBtZa7SoVWgnq6kuB9CMLJEkWKZ3Ky2D4d7nT25bRHQ@mail.gmail.com">
      <div dir="ltr">Hi Erik,
        <div><br>
        </div>
        <div>before this change, ___Z10blocksNRVOv_block_invoke
          demangled to 'invocation function for block in blocksNRVO()',
          now it's no longer demangled. Was that an intentional change?</div>
      </div>
      <div class="gmail_extra"><br>
        <div class="gmail_quote">On Tue, Mar 6, 2018 at 9:21 AM, Erik
          Pilkington via cfe-commits <span dir="ltr"><<a
              href="mailto:cfe-commits@lists.llvm.org" target="_blank"
              moz-do-not-send="true">cfe-commits@lists.llvm.org</a>></span>
          wrote:<br>
          <blockquote class="gmail_quote" style="margin:0 0 0
            .8ex;border-left:1px #ccc solid;padding-left:1ex">Author:
            epilk<br>
            Date: Tue Mar  6 06:21:10 2018<br>
            New Revision: 326797<br>
            <br>
            URL: <a
              href="http://llvm.org/viewvc/llvm-project?rev=326797&view=rev"
              rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-<wbr>project?rev=326797&view=rev</a><br>
            Log:<br>
            [demangler] Modernize the rest of the demangler.<br>
            <br>
            Modified:<br>
                libcxxabi/trunk/src/cxa_<wbr>demangle.cpp<br>
                libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp<br>
            <br>
            Modified: libcxxabi/trunk/src/cxa_<wbr>demangle.cpp<br>
            URL: <a
href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=326797&r1=326796&r2=326797&view=diff"
              rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-<wbr>project/libcxxabi/trunk/src/<wbr>cxa_demangle.cpp?rev=326797&<wbr>r1=326796&r2=326797&view=diff</a><br>
            ==============================<wbr>==============================<wbr>==================<br>
            --- libcxxabi/trunk/src/cxa_<wbr>demangle.cpp (original)<br>
            +++ libcxxabi/trunk/src/cxa_<wbr>demangle.cpp Tue Mar  6
            06:21:10 2018<br>
            @@ -2002,6 +2002,8 @@ struct Db {<br>
            <br>
               BumpPointerAllocator ASTAllocator;<br>
            <br>
            +  Db(const char *First_, const char *Last_) :
            First(First_), Last(Last_) {}<br>
            +<br>
               template <class T, class... Args> T *make(Args
            &&... args) {<br>
                 return new (ASTAllocator.allocate(sizeof(<wbr>T)))<br>
                     T(std::forward<Args>(args)...)<wbr>;<br>
            @@ -2054,6 +2056,12 @@ struct Db {<br>
               bool parsePositiveInteger(size_t *Out);<br>
               StringView parseBareSourceName();<br>
            <br>
            +  bool parseSeqId(size_t *Out);<br>
            +  Node *parseSubstitution();<br>
            +  Node *parseTemplateParam();<br>
            +  Node *parseTemplateArgs();<br>
            +  Node *parseTemplateArg();<br>
            +<br>
               /// Parse the <expr> production.<br>
               Node *parseExpr();<br>
               Node *parsePrefixExpr(StringView Kind);<br>
            @@ -2109,66 +2117,11 @@ struct Db {<br>
               Node *parseUnresolvedType();<br>
               Node *parseDestructorName();<br>
            <br>
            -  // FIXME: remove this when all the parse_* functions have
            been rewritten.<br>
            -  template <const char *(*parse_fn)(const char *, const
            char *, Db &)><br>
            -  Node *legacyParse() {<br>
            -    size_t BeforeType = Names.size();<br>
            -    const char *OrigFirst = First;<br>
            -    const char *T = parse_fn(First, Last, *this);<br>
            -    if (T == OrigFirst || BeforeType + 1 != Names.size())<br>
            -      return nullptr;<br>
            -    First = T;<br>
            -    Node *R = Names.back();<br>
            -    Names.pop_back();<br>
            -    return R;<br>
            -  }<br>
            +  /// Top-level entry point into the parser.<br>
            +  Node *parse();<br>
             };<br>
            <br>
            -const char *parse_expression(const char *first, const char
            *last, Db &db) {<br>
            -  db.First = first;<br>
            -  db.Last = last;<br>
            -  Node *R = db.parseExpr();<br>
            -  if (R == nullptr)<br>
            -    return first;<br>
            -  db.Names.push_back(R);<br>
            -  return db.First;<br>
            -}<br>
            -<br>
            -const char *parse_expr_primary(const char *first, const
            char *last, Db &db) {<br>
            -  db.First = first;<br>
            -  db.Last = last;<br>
            -  Node *R = db.parseExprPrimary();<br>
            -  if (R == nullptr)<br>
            -    return first;<br>
            -  db.Names.push_back(R);<br>
            -  return db.First;<br>
            -}<br>
            -<br>
            -const char *parse_type(const char *first, const char *last,
            Db &db) {<br>
            -  db.First = first;<br>
            -  db.Last = last;<br>
            -  Node *R = db.parseType();<br>
            -  if (R == nullptr)<br>
            -    return first;<br>
            -  db.Names.push_back(R);<br>
            -  return db.First;<br>
            -}<br>
            -<br>
            -const char *parse_encoding(const char *first, const char
            *last, Db &db) {<br>
            -  db.First = first;<br>
            -  db.Last = last;<br>
            -  Node *R = db.parseEncoding();<br>
            -  if (R == nullptr)<br>
            -    return first;<br>
            -  db.Names.push_back(R);<br>
            -  return db.First;<br>
            -}<br>
            -<br>
             const char* parse_discriminator(const char* first, const
            char* last);<br>
            -const char *parse_template_args(const char *first, const
            char *last, Db &db);<br>
            -const char *parse_template_param(const char *, const char
            *, Db &);<br>
            -const char *parse_substitution(const char *, const char *,
            Db &);<br>
            -<br>
            <br>
             // <name> ::= <nested-name> // N<br>
             //        ::= <local-name> # See Scope Encoding
            below  // Z<br>
            @@ -2187,10 +2140,12 @@ Node *Db::parseName(NameState
            *State) {<br>
            <br>
               //        ::= <unscoped-template-name>
            <template-args><br>
               if (look() == 'S' && look(1) != 't') {<br>
            -    Node *S = legacyParse<parse_<wbr>substitution>();<br>
            +    Node *S = parseSubstitution();<br>
            +    if (S == nullptr)<br>
            +      return nullptr;<br>
                 if (look() != 'I')<br>
                   return nullptr;<br>
            -    Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +    Node *TA = parseTemplateArgs();<br>
                 if (TA == nullptr)<br>
                   return nullptr;<br>
                 if (State) State->EndsWithTemplateArgs = true;<br>
            @@ -2203,7 +2158,7 @@ Node *Db::parseName(NameState *State)
            {<br>
               //        ::= <unscoped-template-name>
            <template-args><br>
               if (look() == 'I') {<br>
                 Subs.push_back(N);<br>
            -    Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +    Node *TA = parseTemplateArgs();<br>
                 if (TA == nullptr)<br>
                   return nullptr;<br>
                 if (State) State->EndsWithTemplateArgs = true;<br>
            @@ -2693,7 +2648,7 @@ Node *Db::parseNestedName(NameState
            *Sta<br>
            <br>
                 //          ::= <template-param><br>
                 if (look() == 'T') {<br>
            -      Node *TP = legacyParse<parse_template_<wbr>param>();<br>
            +      Node *TP = parseTemplateParam();<br>
                   if (TP == nullptr)<br>
                     return nullptr;<br>
                   PushComponent(TP);<br>
            @@ -2703,7 +2658,7 @@ Node *Db::parseNestedName(NameState
            *Sta<br>
            <br>
                 //          ::= <template-prefix>
            <template-args><br>
                 if (look() == 'I') {<br>
            -      Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +      Node *TA = parseTemplateArgs();<br>
                   if (TA == nullptr || SoFar == nullptr)<br>
                     return nullptr;<br>
                   SoFar = make<NameWithTemplateArgs>(<wbr>SoFar,
            TA);<br>
            @@ -2724,7 +2679,7 @@ Node *Db::parseNestedName(NameState
            *Sta<br>
            <br>
                 //          ::= <substitution><br>
                 if (look() == 'S' && look(1) != 't') {<br>
            -      Node *S = legacyParse<parse_<wbr>substitution>();<br>
            +      Node *S = parseSubstitution();<br>
                   if (S == nullptr)<br>
                     return nullptr;<br>
                   PushComponent(S);<br>
            @@ -2769,7 +2724,7 @@ Node *Db::parseSimpleId() {<br>
               if (SN == nullptr)<br>
                 return nullptr;<br>
               if (look() == 'I') {<br>
            -    Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +    Node *TA = parseTemplateArgs();<br>
                 if (TA == nullptr)<br>
                   return nullptr;<br>
                 return make<NameWithTemplateArgs>(SN, TA);<br>
            @@ -2795,7 +2750,7 @@ Node *Db::parseDestructorName() {<br>
             //                   ::= <substitution><br>
             Node *Db::parseUnresolvedType() {<br>
               if (look() == 'T') {<br>
            -    Node *TP = legacyParse<parse_template_<wbr>param>();<br>
            +    Node *TP = parseTemplateParam();<br>
                 if (TP == nullptr)<br>
                   return nullptr;<br>
                 Subs.push_back(TP);<br>
            @@ -2808,7 +2763,7 @@ Node *Db::parseUnresolvedType() {<br>
                 Subs.push_back(DT);<br>
                 return DT;<br>
               }<br>
            -  return legacyParse<parse_<wbr>substitution>();<br>
            +  return parseSubstitution();<br>
             }<br>
            <br>
             // <base-unresolved-name> ::= <simple-id>     
                                      # unresolved name<br>
            @@ -2831,7 +2786,7 @@ Node *Db::parseBaseUnresolvedName() {<br>
               if (Oper == nullptr)<br>
                 return nullptr;<br>
               if (look() == 'I') {<br>
            -    Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +    Node *TA = parseTemplateArgs();<br>
                 if (TA == nullptr)<br>
                   return nullptr;<br>
                 return make<NameWithTemplateArgs>(<wbr>Oper, TA);<br>
            @@ -2861,7 +2816,7 @@ Node *Db::parseUnresolvedName() {<br>
                   return nullptr;<br>
            <br>
                 if (look() == 'I') {<br>
            -      Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +      Node *TA = parseTemplateArgs();<br>
                   if (TA == nullptr)<br>
                     return nullptr;<br>
                   SoFar = make<NameWithTemplateArgs>(<wbr>SoFar,
            TA);<br>
            @@ -2914,7 +2869,7 @@ Node *Db::parseUnresolvedName() {<br>
                   return nullptr;<br>
            <br>
                 if (look() == 'I') {<br>
            -      Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +      Node *TA = parseTemplateArgs();<br>
                   if (TA == nullptr)<br>
                     return nullptr;<br>
                   SoFar = make<NameWithTemplateArgs>(<wbr>SoFar,
            TA);<br>
            @@ -3436,7 +3391,7 @@ Node *Db::parseType() {<br>
                   break;<br>
                 }<br>
            <br>
            -    Result = legacyParse<parse_template_<wbr>param>();<br>
            +    Result = parseTemplateParam();<br>
                 if (Result == nullptr)<br>
                   return nullptr;<br>
            <br>
            @@ -3451,7 +3406,7 @@ Node *Db::parseType() {<br>
                 // parse them, take the second production.<br>
            <br>
                 if (TryToParseTemplateArgs && look() == 'I') {<br>
            -      Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +      Node *TA = parseTemplateArgs();<br>
                   if (TA == nullptr)<br>
                     return nullptr;<br>
                   Result = make<NameWithTemplateArgs>(<wbr>Result,
            TA);<br>
            @@ -3506,7 +3461,7 @@ Node *Db::parseType() {<br>
               //             ::= <substitution>  # See
            Compression below<br>
               case 'S': {<br>
                 if (look(1) && look(1) != 't') {<br>
            -      Node *Sub = legacyParse<parse_<wbr>substitution>();<br>
            +      Node *Sub = parseSubstitution();<br>
                   if (Sub == nullptr)<br>
                     return nullptr;<br>
            <br>
            @@ -3521,7 +3476,7 @@ Node *Db::parseType() {<br>
                   // parse them, take the second production.<br>
            <br>
                   if (TryToParseTemplateArgs && look() == 'I')
            {<br>
            -        Node *TA = legacyParse<parse_template_<wbr>args>();<br>
            +        Node *TA = parseTemplateArgs();<br>
                     if (TA == nullptr)<br>
                       return nullptr;<br>
                     Result = make<NameWithTemplateArgs>(<wbr>Sub,
            TA);<br>
            @@ -3872,7 +3827,7 @@ Node *Db::parseExpr() {<br>
               case 'L':<br>
                 return parseExprPrimary();<br>
               case 'T':<br>
            -    return legacyParse<parse_template_<wbr>param>();<br>
            +    return parseTemplateParam();<br>
               case 'f':<br>
                 return parseFunctionParam();<br>
               case 'a':<br>
            @@ -4244,7 +4199,7 @@ Node *Db::parseExpr() {<br>
                 case 'Z':<br>
                   First += 2;<br>
                   if (look() == 'T') {<br>
            -        Node *R = legacyParse<parse_template_<wbr>param>();<br>
            +        Node *R = parseTemplateParam();<br>
                     if (R == nullptr)<br>
                       return nullptr;<br>
                     return make<SizeofParamPackExpr>(R);<br>
            @@ -4572,6 +4527,28 @@ template <class Float> Node
            *Db::parseFl<br>
               return make<FloatExpr<Float>>(Data);<br>
             }<br>
            <br>
            +// <seq-id> ::= <0-9A-Z>+<br>
            +bool Db::parseSeqId(size_t *Out) {<br>
            +  if (!(look() >= '0' && look() <= '9')
            &&<br>
            +      !(look() >= 'A' && look() <= 'Z'))<br>
            +    return true;<br>
            +<br>
            +  size_t Id = 0;<br>
            +  while (true) {<br>
            +    if (look() >= '0' && look() <= '9') {<br>
            +      Id *= 36;<br>
            +      Id += static_cast<size_t>(look() - '0');<br>
            +    } else if (look() >= 'A' && look() <=
            'Z') {<br>
            +      Id *= 36;<br>
            +      Id += static_cast<size_t>(look() - 'A') + 10;<br>
            +    } else {<br>
            +      *Out = Id;<br>
            +      return false;<br>
            +    }<br>
            +    ++First;<br>
            +  }<br>
            +}<br>
            +<br>
             // <substitution> ::= S <seq-id> _<br>
             //                ::= S_<br>
             // <substitution> ::= Sa # ::std::allocator<br>
            @@ -4582,243 +4559,172 @@ template <class Float> Node
            *Db::parseFl<br>
             // <substitution> ::= Si #
            ::std::basic_istream<char,  std::char_traits<char>
            ><br>
             // <substitution> ::= So #
            ::std::basic_ostream<char,  std::char_traits<char>
            ><br>
             // <substitution> ::= Sd #
            ::std::basic_iostream<char, std::char_traits<char>
            ><br>
            +Node *Db::parseSubstitution() {<br>
            +  if (!consumeIf('S'))<br>
            +    return nullptr;<br>
            <br>
            -const char*<br>
            -parse_substitution(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (last - first >= 2)<br>
            -    {<br>
            -        if (*first == 'S')<br>
            -        {<br>
            -            switch (first[1])<br>
            -            {<br>
            -            case 'a':<br>
            -                db.Names.push_back(<br>
            -                    db.make<SpecialSubstitution>(<br>
            -                        SpecialSubKind::allocator));<br>
            -                first += 2;<br>
            -                break;<br>
            -            case 'b':<br>
            -                db.Names.push_back(<br>
            -                    db.make<SpecialSubstitution>(<wbr>SpecialSubKind::basic_string))<wbr>;<br>
            -                first += 2;<br>
            -                break;<br>
            -            case 's':<br>
            -                db.Names.push_back(<br>
            -                    db.make<SpecialSubstitution>(<br>
            -                        SpecialSubKind::string));<br>
            -                first += 2;<br>
            -                break;<br>
            -            case 'i':<br>
            -                db.Names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::istream));<br>
            -                first += 2;<br>
            -                break;<br>
            -            case 'o':<br>
            -                db.Names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::ostream));<br>
            -                first += 2;<br>
            -                break;<br>
            -            case 'd':<br>
            -                db.Names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::iostream));<br>
            -                first += 2;<br>
            -                break;<br>
            -            case '_':<br>
            -                if (!db.Subs.empty())<br>
            -                {<br>
            -                    db.Names.push_back(db.Subs[0])<wbr>;<br>
            -                    first += 2;<br>
            -                }<br>
            -                break;<br>
            -            default:<br>
            -                if (std::isdigit(first[1]) ||
            std::isupper(first[1]))<br>
            -                {<br>
            -                    size_t sub = 0;<br>
            -                    const char* t = first+1;<br>
            -                    if (std::isdigit(*t))<br>
            -                        sub = static_cast<size_t>(*t
            - '0');<br>
            -                    else<br>
            -                        sub = static_cast<size_t>(*t
            - 'A') + 10;<br>
            -                    for (++t; t != last &&
            (std::isdigit(*t) || std::isupper(*t)); ++t)<br>
            -                    {<br>
            -                        sub *= 36;<br>
            -                        if (std::isdigit(*t))<br>
            -                            sub +=
            static_cast<size_t>(*t - '0');<br>
            -                        else<br>
            -                            sub +=
            static_cast<size_t>(*t - 'A') + 10;<br>
            -                    }<br>
            -                    if (t == last || *t != '_')<br>
            -                        return first;<br>
            -                    ++sub;<br>
            -                    if (sub < db.Subs.size())<br>
            -                    {<br>
            -                        db.Names.push_back(db.Subs[<wbr>sub]);<br>
            -                        first = t+1;<br>
            -                    }<br>
            -                }<br>
            -                break;<br>
            -            }<br>
            -        }<br>
            +  if (std::islower(look())) {<br>
            +    Node *SpecialSub;<br>
            +    switch (look()) {<br>
            +    case 'a':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::allocator);<br>
            +      break;<br>
            +    case 'b':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::basic_string);<br>
            +      break;<br>
            +    case 's':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::string);<br>
            +      break;<br>
            +    case 'i':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::istream);<br>
            +      break;<br>
            +    case 'o':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::ostream);<br>
            +      break;<br>
            +    case 'd':<br>
            +      ++First;<br>
            +      SpecialSub = make<SpecialSubstitution>(<wbr>SpecialSubKind::iostream);<br>
            +      break;<br>
            +    default:<br>
            +      return nullptr;<br>
                 }<br>
            -    return first;<br>
            +    // Itanium C++ ABI 5.1.2: If a name that would use a
            built-in <substitution><br>
            +    // has ABI tags, the tags are appended to the
            substitution; the result is a<br>
            +    // substitutable component.<br>
            +    Node *WithTags = parseAbiTags(SpecialSub);<br>
            +    if (WithTags != SpecialSub) {<br>
            +      Subs.push_back(WithTags);<br>
            +      SpecialSub = WithTags;<br>
            +    }<br>
            +    return SpecialSub;<br>
            +  }<br>
            +<br>
            +  //                ::= S_<br>
            +  if (consumeIf('_')) {<br>
            +    if (Subs.empty())<br>
            +      return nullptr;<br>
            +    return Subs[0];<br>
            +  }<br>
            +<br>
            +  //                ::= S <seq-id> _<br>
            +  size_t Index = 0;<br>
            +  if (parseSeqId(&Index))<br>
            +    return nullptr;<br>
            +  ++Index;<br>
            +  if (!consumeIf('_') || Index >= Subs.size())<br>
            +    return nullptr;<br>
            +  return Subs[Index];<br>
             }<br>
            <br>
             // <template-param> ::= T_    # first template
            parameter<br>
             //                  ::= T <parameter-2 non-negative
            number> _<br>
            +Node *Db::parseTemplateParam() {<br>
            +  if (!consumeIf('T'))<br>
            +    return nullptr;<br>
            <br>
            -const char*<br>
            -parse_template_param(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (last - first >= 2)<br>
            -    {<br>
            -        if (*first == 'T')<br>
            -        {<br>
            -            if (first[1] == '_')<br>
            -            {<br>
            -                if (!db.TemplateParams.empty())<br>
            -                {<br>
            -                    db.Names.push_back(db.<wbr>TemplateParams[0]);<br>
            -                    first += 2;<br>
            -                }<br>
            -                else<br>
            -                {<br>
            -                    db.Names.push_back(db.make<<wbr>NameType>("T_"));<br>
            -                    first += 2;<br>
            -                    db.FixForwardReferences = true;<br>
            -                }<br>
            -            }<br>
            -            else if (isdigit(first[1]))<br>
            -            {<br>
            -                const char* t = first+1;<br>
            -                size_t sub = static_cast<size_t>(*t -
            '0');<br>
            -                for (++t; t != last && isdigit(*t);
            ++t)<br>
            -                {<br>
            -                    sub *= 10;<br>
            -                    sub += static_cast<size_t>(*t -
            '0');<br>
            -                }<br>
            -                if (t == last || *t != '_')<br>
            -                    return first;<br>
            -                ++sub;<br>
            -                if (sub < db.TemplateParams.size())<br>
            -                {<br>
            -                    db.Names.push_back(db.<wbr>TemplateParams[sub]);<br>
            -                    first = t+1;<br>
            -                }<br>
            -                else<br>
            -                {<br>
            -                    db.Names.push_back(<br>
            -                        db.make<NameType>(StringView(<wbr>first,
            t + 1)));<br>
            -                    first = t+1;<br>
            -                    db.FixForwardReferences = true;<br>
            -                }<br>
            -            }<br>
            -        }<br>
            +  if (consumeIf('_')) {<br>
            +    if (TemplateParams.empty()) {<br>
            +      FixForwardReferences = true;<br>
            +      return make<NameType>("FORWARD_<wbr>REFERENCE");<br>
                 }<br>
            -    return first;<br>
            +    return TemplateParams[0];<br>
            +  }<br>
            +<br>
            +  size_t Index;<br>
            +  if (parsePositiveInteger(&Index))<br>
            +    return nullptr;<br>
            +  ++Index;<br>
            +  if (!consumeIf('_'))<br>
            +    return nullptr;<br>
            +  if (Index >= TemplateParams.size()) {<br>
            +    FixForwardReferences = true;<br>
            +    return make<NameType>("FORWARD_<wbr>REFERENCE");<br>
            +  }<br>
            +  return TemplateParams[Index];<br>
             }<br>
            <br>
            -// <template-arg> ::= <type>                   
                                     # type or template<br>
            -//                ::= X <expression> E               
                               # expression<br>
            -//                ::= <expr-primary>                 
                               # simple expressions<br>
            -//                ::= J <template-arg>* E           
                                # argument pack<br>
            -//                ::= LZ <encoding> E               
                                # extension<br>
            -const char*<br>
            -parse_template_arg(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (first != last)<br>
            -    {<br>
            -        const char* t;<br>
            -        switch (*first)<br>
            -        {<br>
            -        case 'X':<br>
            -            t = parse_expression(first+1, last, db);<br>
            -            if (t != first+1)<br>
            -            {<br>
            -                if (t != last && *t == 'E')<br>
            -                    first = t+1;<br>
            -            }<br>
            -            break;<br>
            -        case 'J': {<br>
            -            t = first+1;<br>
            -            if (t == last)<br>
            -                return first;<br>
            -            size_t ArgsBegin = db.Names.size();<br>
            -            while (*t != 'E')<br>
            -            {<br>
            -                const char* t1 = parse_template_arg(t,
            last, db);<br>
            -                if (t1 == t)<br>
            -                    return first;<br>
            -                t = t1;<br>
            -            }<br>
            -            NodeArray Args = db.popTrailingNodeArray(<wbr>ArgsBegin);<br>
            -            db.Names.push_back(db.make<<wbr>TemplateArgumentPack>(Args));<br>
            -            first = t+1;<br>
            -            break;<br>
            -        }<br>
            -        case 'L':<br>
            -            // <expr-primary> or LZ <encoding>
            E<br>
            -            if (first+1 != last && first[1] == 'Z')<br>
            -            {<br>
            -                t = parse_encoding(first+2, last, db);<br>
            -                if (t != first+2 && t != last
            && *t == 'E')<br>
            -                    first = t+1;<br>
            -            }<br>
            -            else<br>
            -                first = parse_expr_primary(first, last,
            db);<br>
            -            break;<br>
            -        default:<br>
            -            // <type><br>
            -            first = parse_type(first, last, db);<br>
            -            break;<br>
            -        }<br>
            +// <template-arg> ::= <type>                   
            # type or template<br>
            +//                ::= X <expression> E          #
            expression<br>
            +//                ::= <expr-primary>            #
            simple expressions<br>
            +//                ::= J <template-arg>* E       #
            argument pack<br>
            +//                ::= LZ <encoding> E           #
            extension<br>
            +Node *Db::parseTemplateArg() {<br>
            +  switch (look()) {<br>
            +  case 'X': {<br>
            +    ++First;<br>
            +    Node *Arg = parseExpr();<br>
            +    if (Arg == nullptr || !consumeIf('E'))<br>
            +      return nullptr;<br>
            +    return Arg;<br>
            +  }<br>
            +  case 'J': {<br>
            +    ++First;<br>
            +    size_t ArgsBegin = Names.size();<br>
            +    while (!consumeIf('E')) {<br>
            +      Node *Arg = parseTemplateArg();<br>
            +      if (Arg == nullptr)<br>
            +        return nullptr;<br>
            +      Names.push_back(Arg);<br>
                 }<br>
            -    return first;<br>
            +    NodeArray Args = popTrailingNodeArray(<wbr>ArgsBegin);<br>
            +    return make<TemplateArgumentPack>(<wbr>Args);<br>
            +  }<br>
            +  case 'L': {<br>
            +    //                ::= LZ <encoding> E           #
            extension<br>
            +    if (look(1) == 'Z') {<br>
            +      First += 2;<br>
            +      Node *Arg = parseEncoding();<br>
            +      if (Arg == nullptr || !consumeIf('E'))<br>
            +        return nullptr;<br>
            +      return Arg;<br>
            +    }<br>
            +    //                ::= <expr-primary>            #
            simple expressions<br>
            +    return parseExprPrimary();<br>
            +  }<br>
            +  default:<br>
            +    return parseType();<br>
            +  }<br>
             }<br>
            <br>
             // <template-args> ::= I <template-arg>* E<br>
             //     extension, the abi says <template-arg>+<br>
            -const char*<br>
            -parse_template_args(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (last - first >= 2 && *first == 'I')<br>
            -    {<br>
            -        if (db.TagTemplates)<br>
            -            db.TemplateParams.clear();<br>
            -        const char* t = first+1;<br>
            -        size_t begin_idx = db.Names.size();<br>
            -        while (*t != 'E')<br>
            -        {<br>
            -            if (db.TagTemplates)<br>
            -            {<br>
            -                auto TmpParams =
            std::move(db.TemplateParams);<br>
            -                size_t k0 = db.Names.size();<br>
            -                const char* t1 = parse_template_arg(t,
            last, db);<br>
            -                size_t k1 = db.Names.size();<br>
            -                db.TemplateParams = std::move(TmpParams);<br>
            -                if (t1 == t || t1 == last || k0 + 1 != k1)<br>
            -                    return first;<br>
            -                Node *TableEntry = db.Names.back();<br>
            -                if (TableEntry->getKind() ==
            Node::KTemplateArgumentPack)<br>
            -                  TableEntry =
            db.make<ParameterPack>(<br>
            -                      static_cast<<wbr>TemplateArgumentPack*>(<wbr>TableEntry)<br>
            -                          ->getElements());<br>
            -                db.TemplateParams.push_back(<wbr>TableEntry);<br>
            -                t = t1;<br>
            -                continue;<br>
            -            }<br>
            -            size_t k0 = db.Names.size();<br>
            -            const char* t1 = parse_template_arg(t, last,
            db);<br>
            -            size_t k1 = db.Names.size();<br>
            -            if (t1 == t || t1 == last || k0 > k1)<br>
            -              return first;<br>
            -            t = t1;<br>
            -        }<br>
            -        if (begin_idx > db.Names.size())<br>
            -            return first;<br>
            -        first = t + 1;<br>
            -        auto *tp = db.make<TemplateArgs>(<br>
            -            db.popTrailingNodeArray(begin_<wbr>idx));<br>
            -        db.Names.push_back(tp);<br>
            +Node *Db::parseTemplateArgs() {<br>
            +  if (!consumeIf('I'))<br>
            +    return nullptr;<br>
            +<br>
            +  // <template-params> refer to the innermost
            <template-args>. Clear out any<br>
            +  // outer args that we may have inserted into
            TemplateParams.<br>
            +  if (TagTemplates)<br>
            +    TemplateParams.clear();<br>
            +<br>
            +  size_t ArgsBegin = Names.size();<br>
            +  while (!consumeIf('E')) {<br>
            +    if (TagTemplates) {<br>
            +      auto OldParams = std::move(TemplateParams);<br>
            +      Node *Arg = parseTemplateArg();<br>
            +      TemplateParams = std::move(OldParams);<br>
            +      if (Arg == nullptr)<br>
            +        return nullptr;<br>
            +      Names.push_back(Arg);<br>
            +      Node *TableEntry = Arg;<br>
            +      if (Arg->getKind() == Node::KTemplateArgumentPack)
            {<br>
            +        TableEntry = make<ParameterPack>(<br>
            +            static_cast<<wbr>TemplateArgumentPack*>(<wbr>TableEntry)->getElements());<br>
            +      }<br>
            +      TemplateParams.push_back(<wbr>TableEntry);<br>
            +    } else {<br>
            +      Node *Arg = parseTemplateArg();<br>
            +      if (Arg == nullptr)<br>
            +        return nullptr;<br>
            +      Names.push_back(Arg);<br>
                 }<br>
            -    return first;<br>
            +  }<br>
            +  return make<TemplateArgs>(<wbr>popTrailingNodeArray(<wbr>ArgsBegin));<br>
             }<br>
            <br>
             // <discriminator> := _ <non-negative number> 
                # when number < 10<br>
            @@ -4859,183 +4765,106 @@ parse_discriminator(const char*
            first, c<br>
                 return first;<br>
             }<br>
            <br>
            -// _block_invoke<br>
            -// _block_invoke<decimal-digit>+<br>
            -// _block_invoke_<decimal-digit>+<br>
            -<br>
            -const char*<br>
            -parse_block_invoke(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (last - first >= 13)<br>
            -    {<br>
            -        // FIXME: strcmp?<br>
            -        const char test[] = "_block_invoke";<br>
            -        const char* t = first;<br>
            -        for (int i = 0; i < 13; ++i, ++t)<br>
            -        {<br>
            -            if (*t != test[i])<br>
            -                return first;<br>
            -        }<br>
            -        if (t != last)<br>
            -        {<br>
            -            if (*t == '_')<br>
            -            {<br>
            -                // must have at least 1 decimal digit<br>
            -                if (++t == last || !std::isdigit(*t))<br>
            -                    return first;<br>
            -                ++t;<br>
            -            }<br>
            -            // parse zero or more digits<br>
            -            while (t != last && isdigit(*t))<br>
            -                ++t;<br>
            -        }<br>
            -        if (db.Names.empty())<br>
            -            return first;<br>
            -        db.Names.back() =<br>
            -            db.make<SpecialName>("<wbr>invocation
            function for block in ",<br>
            -                                  db.Names.back());<br>
            -        first = t;<br>
            +// <mangled-name> ::= _Z <encoding><br>
            +//                ::= <type><br>
            +// extension      ::= ___Z <encoding> _block_invoke<br>
            +// extension      ::= ___Z <encoding>
            _block_invoke<decimal-digit>+<br>
            +// extension      ::= ___Z <encoding>
            _block_invoke_<decimal-digit>+<br>
            +Node *Db::parse() {<br>
            +  if (consumeIf("_Z")) {<br>
            +    Node *Encoding = parseEncoding();<br>
            +    if (Encoding == nullptr)<br>
            +      return nullptr;<br>
            +    if (look() == '.') {<br>
            +      Encoding = make<DotSuffix>(Encoding,
            StringView(First, Last));<br>
            +      First = Last;<br>
                 }<br>
            -    return first;<br>
            -}<br>
            +    if (numLeft() != 0)<br>
            +      return nullptr;<br>
            +    return Encoding;<br>
            +  }<br>
            <br>
            -// extension<br>
            -// <dot-suffix> := .<anything and everything><br>
            +  if (consumeIf("___Z")) {<br>
            +    Node *Encoding = parseEncoding();<br>
            +    if (Encoding == nullptr || !consumeIf("_block_invoke"))<br>
            +      return nullptr;<br>
            +    consumeIf('_');<br>
            +    if (parseNumber().empty())<br>
            +      return nullptr;<br>
            +    if (numLeft() != 0)<br>
            +      return nullptr;<br>
            +    return make<SpecialName>("invocation function for
            block in ", Encoding);<br>
            +  }<br>
            <br>
            -const char*<br>
            -parse_dot_suffix(const char* first, const char* last,
            Db& db)<br>
            -{<br>
            -    if (first != last && *first == '.')<br>
            -    {<br>
            -        if (db.Names.empty())<br>
            -            return first;<br>
            -        db.Names.back() =<br>
            -            db.make<DotSuffix>(db.Names.<wbr>back(),
            StringView(first, last));<br>
            -        first = last;<br>
            -    }<br>
            -    return first;<br>
            +  Node *Ty = parseType();<br>
            +  if (numLeft() != 0)<br>
            +    return nullptr;<br>
            +  return Ty;<br>
             }<br>
            +}  // unnamed namespace<br>
            <br>
             enum {<br>
            -    unknown_error = -4,<br>
            -    invalid_args = -3,<br>
            -    invalid_mangled_name,<br>
            -    memory_alloc_failure,<br>
            -    success<br>
            +  unknown_error = -4,<br>
            +  invalid_args = -3,<br>
            +  invalid_mangled_name = -2,<br>
            +  memory_alloc_failure = -1,<br>
            +  success = 0,<br>
             };<br>
            <br>
            -// <block-involcaton-function>
            ___Z<encoding>_block_invoke<br>
            -// <block-involcaton-function>
            ___Z<encoding>_block_invoke<<wbr>decimal-digit>+<br>
            -// <block-involcaton-function>
            ___Z<encoding>_block_invoke_<<wbr>decimal-digit>+<br>
            -// <mangled-name> ::= _Z<encoding><br>
            -//                ::= <type><br>
            -void<br>
            -demangle(const char* first, const char* last, Db& db,
            int& status)<br>
            -{<br>
            -    if (first >= last)<br>
            -    {<br>
            -        status = invalid_mangled_name;<br>
            -        return;<br>
            -    }<br>
            -    if (*first == '_')<br>
            -    {<br>
            -        if (last - first >= 4)<br>
            -        {<br>
            -            if (first[1] == 'Z')<br>
            -            {<br>
            -                const char* t = parse_encoding(first+2,
            last, db);<br>
            -                if (t != first+2 && t != last
            && *t == '.')<br>
            -                    t = parse_dot_suffix(t, last, db);<br>
            -                if (t != last)<br>
            -                    status = invalid_mangled_name;<br>
            -            }<br>
            -            else if (first[1] == '_' && first[2] ==
            '_' && first[3] == 'Z')<br>
            -            {<br>
            -                const char* t = parse_encoding(first+4,
            last, db);<br>
            -                if (t != first+4 && t != last)<br>
            -                {<br>
            -                    const char* t1 = parse_block_invoke(t,
            last, db);<br>
            -                    if (t1 != last)<br>
            -                        status = invalid_mangled_name;<br>
            -                }<br>
            -                else<br>
            -                    status = invalid_mangled_name;<br>
            -            }<br>
            -            else<br>
            -                status = invalid_mangled_name;<br>
            -        }<br>
            -        else<br>
            -            status = invalid_mangled_name;<br>
            -    }<br>
            -    else<br>
            -    {<br>
            -        const char* t = parse_type(first, last, db);<br>
            -        if (t != last)<br>
            -            status = invalid_mangled_name;<br>
            -    }<br>
            -    if (status == success && db.Names.empty())<br>
            -        status = invalid_mangled_name;<br>
            -}<br>
            -<br>
            -}  // unnamed namespace<br>
            -<br>
            -<br>
             namespace __cxxabiv1 {<br>
             extern "C" _LIBCXXABI_FUNC_VIS char *<br>
            -__cxa_demangle(const char *mangled_name, char *buf, size_t
            *n, int *status) {<br>
            -    if (mangled_name == nullptr || (buf != nullptr
            && n == nullptr))<br>
            -    {<br>
            -        if (status)<br>
            -            *status = invalid_args;<br>
            -        return nullptr;<br>
            -    }<br>
            -<br>
            -    size_t internal_size = buf != nullptr ? *n : 0;<br>
            -    Db db;<br>
            -    int internal_status = success;<br>
            -    size_t len = std::strlen(mangled_name);<br>
            -    demangle(mangled_name, mangled_name + len, db,<br>
            -             internal_status);<br>
            -<br>
            -    if (internal_status == success &&
            db.FixForwardReferences &&<br>
            -        !db.TemplateParams.empty())<br>
            -    {<br>
            -        db.FixForwardReferences = false;<br>
            -        db.TagTemplates = false;<br>
            -        db.Names.clear();<br>
            -        db.Subs.clear();<br>
            -        demangle(mangled_name, mangled_name + len, db,
            internal_status);<br>
            -        if (db.FixForwardReferences)<br>
            -            internal_status = invalid_mangled_name;<br>
            -    }<br>
            -<br>
            -    if (internal_status == success &&<br>
            -        db.Names.back()-><wbr>containsUnexpandedParameterPac<wbr>k())<br>
            -        internal_status = invalid_mangled_name;<br>
            -<br>
            -    if (internal_status == success)<br>
            -    {<br>
            -        if (!buf)<br>
            -        {<br>
            -            internal_size = 1024;<br>
            -            buf = static_cast<char*>(std::<wbr>malloc(internal_size));<br>
            -        }<br>
            +__cxa_demangle(const char *MangledName, char *Buf, size_t
            *N, int *Status) {<br>
            +  if (MangledName == nullptr || (Buf != nullptr &&
            N == nullptr)) {<br>
            +    if (Status)<br>
            +      *Status = invalid_args;<br>
            +    return nullptr;<br>
            +  }<br>
            <br>
            -        if (buf)<br>
            -        {<br>
            -            OutputStream s(buf, internal_size);<br>
            -            db.Names.back()->print(s);<br>
            -            s += '\0';<br>
            -            if (n) *n = s.getCurrentPosition();<br>
            -            buf = s.getBuffer();<br>
            -        }<br>
            -        else<br>
            -            internal_status = memory_alloc_failure;<br>
            -    }<br>
            -    else<br>
            -        buf = nullptr;<br>
            -    if (status)<br>
            -        *status = internal_status;<br>
            -    return buf;<br>
            +  size_t BufSize = Buf != nullptr ? *N : 0;<br>
            +  int InternalStatus = success;<br>
            +  size_t MangledNameLength = std::strlen(MangledName);<br>
            +<br>
            +  Db Parser(MangledName, MangledName + MangledNameLength);<br>
            +  Node *AST = Parser.parse();<br>
            +<br>
            +  if (AST == nullptr)<br>
            +    InternalStatus = invalid_mangled_name;<br>
            +<br>
            +  if (InternalStatus == success &&
            Parser.FixForwardReferences &&<br>
            +      !Parser.TemplateParams.empty()<wbr>) {<br>
            +    Parser.FixForwardReferences = false;<br>
            +    Parser.TagTemplates = false;<br>
            +    Parser.Names.clear();<br>
            +    Parser.Subs.clear();<br>
            +    Parser.First = MangledName;<br>
            +    Parser.Last = MangledName + MangledNameLength;<br>
            +    AST = Parser.parse();<br>
            +    if (AST == nullptr || Parser.FixForwardReferences)<br>
            +      InternalStatus = invalid_mangled_name;<br>
            +  }<br>
            +<br>
            +  if (InternalStatus == success && AST-><wbr>containsUnexpandedParameterPac<wbr>k())<br>
            +    InternalStatus = invalid_mangled_name;<br>
            +<br>
            +  if (InternalStatus == success) {<br>
            +    if (Buf == nullptr) {<br>
            +      BufSize = 1024;<br>
            +      Buf = static_cast<char*>(std::<wbr>malloc(BufSize));<br>
            +    }<br>
            +<br>
            +    if (Buf) {<br>
            +      OutputStream Stream(Buf, BufSize);<br>
            +      AST->print(Stream);<br>
            +      Stream += '\0';<br>
            +      if (N != nullptr)<br>
            +        *N = Stream.getCurrentPosition();<br>
            +      Buf = Stream.getBuffer();<br>
            +    } else<br>
            +      InternalStatus = memory_alloc_failure;<br>
            +  }<br>
            +<br>
            +  if (Status)<br>
            +    *Status = InternalStatus;<br>
            +  return InternalStatus == success ? Buf : nullptr;<br>
             }<br>
             }  // __cxxabiv1<br>
            <br>
            Modified: libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp<br>
            URL: <a
href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=326797&r1=326796&r2=326797&view=diff"
              rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-<wbr>project/libcxxabi/trunk/test/<wbr>test_demangle.pass.cpp?rev=<wbr>326797&r1=326796&r2=326797&<wbr>view=diff</a><br>
            ==============================<wbr>==============================<wbr>==================<br>
            --- libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp
            (original)<br>
            +++ libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp Tue
            Mar  6 06:21:10 2018<br>
            @@ -29713,6 +29713,9 @@ const char* cases[][2] =<br>
            <br>
                 {"_ZNKR4llvm8OptionalINS_<wbr>11MCFixupKindEEdeEv",
            "llvm::Optional<llvm::<wbr>MCFixupKind>::operator*()
            const &"},<br>
                 {"_<wbr>ZZL23isValidCoroutineContextRN<wbr>5clang4SemaENS_<wbr>14SourceLocationEN4llvm9String<wbr>RefEENK3$_<wbr>4clEZL23isValidCoroutineContex<wbr>tS1_S2_S4_E15InvalidFuncDiag",
            "isValidCoroutineContext(<wbr>clang::Sema&,
            clang::SourceLocation, llvm::StringRef)::$_4::<wbr>operator()(<wbr>isValidCoroutineContext(clang:<wbr>:Sema&,
            clang::SourceLocation, llvm::StringRef)::<wbr>InvalidFuncDiag)
            const"},<br>
            +<br>
            +    // ABI tags can apply to built-in substitutions.<br>
            +    {"_Z1fSsB1XS_", "f(std::string[abi:X],
            std::string[abi:X])"},<br>
             };<br>
            <br>
             const unsigned N = sizeof(cases) / sizeof(cases[0]);<br>
            <br>
            <br>
            ______________________________<wbr>_________________<br>
            cfe-commits mailing list<br>
            <a href="mailto:cfe-commits@lists.llvm.org"
              moz-do-not-send="true">cfe-commits@lists.llvm.org</a><br>
            <a
              href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits"
              rel="noreferrer" target="_blank" moz-do-not-send="true">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
          </blockquote>
        </div>
        <br>
      </div>
    </blockquote>
    <br>
  </body>
</html>