<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">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">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">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">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">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>