<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Fixed in r310226, thanks!<br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 8/4/17 12:08 PM, Kostya Serebryany
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAN=P9pjncGBt_TNwR5JRpmLrWCfHjN1fo1QcK3fA7pEn_=NT9w@mail.gmail.com">
      <div dir="ltr">and one more: 
        <div><a
            href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2837"
            moz-do-not-send="true">https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2837</a><br>
        </div>
        <div>
          <pre class="gmail-issue_text" tabindex="1" style="font-size:11.726px;white-space:pre-wrap;max-width:80em;padding:0px 0px 3px 0.7em;outline:0px;color:rgb(0,0,0)">Crash Type: Heap-buffer-overflow READ 8
Crash Address: 0x615000000078
Crash State:
  __cxxabiv1::parse_new_expr
  __cxxabiv1::parse_expression
  __cxxabiv1::parse_array_type</pre>
        </div>
      </div>
      <div class="gmail_extra"><br>
        <div class="gmail_quote">On Mon, Jul 31, 2017 at 9:56 AM, Kostya
          Serebryany <span dir="ltr"><<a
              href="mailto:kcc@google.com" target="_blank"
              moz-do-not-send="true">kcc@google.com</a>></span>
          wrote:<br>
          <blockquote class="gmail_quote" style="margin:0 0 0
            .8ex;border-left:1px #ccc solid;padding-left:1ex">
            <div dir="ltr">Yep, confirmed. Thanks! <br>
              In the meantime, two new bugs popped up (probably, got
              un-hidden after your fixes): <br>
              <a
                href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2804"
                target="_blank" moz-do-not-send="true">https://bugs.chromium.org/p/<wbr>oss-fuzz/issues/detail?id=2804</a><br>
              Crash Type: Heap-buffer-overflow READ 8<br>
              Crash Address: 0x619000000078<br>
              Crash State:<br>
                __cxxabiv1::parse_encoding<br>
                __cxxabiv1::demangle<br>
                __cxa_demangle<br>
              <br>
              <a
                href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2800"
                target="_blank" moz-do-not-send="true">https://bugs.chromium.org/p/<wbr>oss-fuzz/issues/detail?id=2800</a><br>
              Crash Type: Out-of-memory (exceeds 2048 MB)<br>
              <br>
              Two older stack overflow bugs also remain. <br>
              <br>
              --kcc<br>
            </div>
            <div class="gmail_extra"><br>
              <div class="gmail_quote">On Sun, Jul 30, 2017 at 1:12 PM,
                Erik Pilkington <span dir="ltr"><<a
                    href="mailto:erik.pilkington@gmail.com"
                    target="_blank" moz-do-not-send="true">erik.pilkington@gmail.com</a>></span>
                wrote:<br>
                <blockquote class="gmail_quote" style="margin:0 0 0
                  .8ex;border-left:1px #ccc solid;padding-left:1ex">
                  <div bgcolor="#FFFFFF" text="#000000"> r309520 should
                    fix the new failures. I'll keep an eye on oss-fuzz
                    in case anything new comes up.<br>
                    Thanks for pinging me,<br>
                    Erik<br>
                    <br>
                    <div
                      class="m_5033236531164054171m_-7358149277554787723moz-cite-prefix">On
                      7/28/17 10:06 AM, Kostya Serebryany wrote:<br>
                    </div>
                    <blockquote type="cite">
                      <div dir="ltr">
                        <div>Erik, </div>
                        A bunch of old bugs reported in this code by
                        OSS-Fuzz got auto-closed today, thanks! 
                        <div><br>
                        </div>
                        <div>Also a few new bugs got opened tonight,
                          most likely caused by this patch. You are
                          auto-CC-ed. </div>
                        <div>I would start from <a
                            href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2767"
                            target="_blank" moz-do-not-send="true">https://bugs.chromium.org<wbr>/p/oss-fuzz/issues/detail?id=<wbr>2767</a></div>
                        <div>
                          <pre class="m_5033236531164054171m_-7358149277554787723gmail-issue_text" style="max-width:80em;padding:0px 0px 3px 0.7em;outline:0px"><font color="#000000"><span style="font-size:11.726px;white-space:pre-wrap">Crash Type: Null-dereference READ
Crash Address: 0x000000000008
Crash State:
  __cxxabiv1::parse_nested_name
  __cxxabiv1::parse_name
  __cxxabiv1::parse_local_name</span></font></pre>
                          <pre class="m_5033236531164054171m_-7358149277554787723gmail-issue_text" style="max-width:80em;padding:0px 0px 3px 0.7em;outline:0px"><font color="#000000"><span style="font-size:11.726px;white-space:pre-wrap">
</span></font>Also, you have the access to all inputs generated by the demangler fuzzer in a few months of fuzzing. 
You can use that corpus for local testing, and I would also encourage you to add the corpus to the public LLVM bots. </pre>
                          <pre class="m_5033236531164054171m_-7358149277554787723gmail-issue_text" style="font-size:11.726px;white-space:pre-wrap;max-width:80em;padding:0px 0px 3px 0.7em;outline:0px;color:rgb(0,0,0)">--kcc </pre>
                        </div>
                      </div>
                      <div class="gmail_extra"><br>
                        <div class="gmail_quote">On Thu, Jul 27, 2017 at
                          5:43 PM, 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: Thu Jul 27 17:43:49 2017<br>
                            New Revision: 309340<br>
                            <br>
                            URL: <a
                              href="http://llvm.org/viewvc/llvm-project?rev=309340&view=rev"
                              rel="noreferrer" target="_blank"
                              moz-do-not-send="true">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=309340&view=rev</a><br>
                            Log:<br>
                            [demangler] Use an AST to represent
                            demangled names<br>
                            <br>
                            The demangler now demangles by producing an
                            AST, then traverses that<br>
                            AST to produce a demangled name. This is
                            done for performance reasons,<br>
                            now the demangler doesn't manuiplate
                            std::strings, which hurt<br>
                            performance and caused string operations to
                            be inlined into the<br>
                            parser, leading to large code size and stack
                            usage.<br>
                            <br>
                            Differential revision: <a
                              href="https://reviews.llvm.org/D35159"
                              rel="noreferrer" target="_blank"
                              moz-do-not-send="true">https://reviews.llvm.org/D3515<wbr>9</a><br>
                            <br>
                            Modified:<br>
                                libcxxabi/trunk/src/cxa_demang<wbr>le.cpp<br>
                                libcxxabi/trunk/test/test_dema<wbr>ngle.pass.cpp<br>
                            <br>
                            Modified: libcxxabi/trunk/src/cxa_demang<wbr>le.cpp<br>
                            URL: <a
href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=309340&r1=309339&r2=309340&view=diff"
                              rel="noreferrer" target="_blank"
                              moz-do-not-send="true">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxxabi/trunk/src/cxa_<wbr>demangle.cpp?rev=309340&r1=309<wbr>339&r2=309340&view=diff</a><br>
                            ==============================<wbr>==============================<wbr>==================<br>
                            --- libcxxabi/trunk/src/cxa_demang<wbr>le.cpp
                            (original)<br>
                            +++ libcxxabi/trunk/src/cxa_demang<wbr>le.cpp
                            Thu Jul 27 17:43:49 2017<br>
                            @@ -13,7 +13,6 @@<br>
                            <br>
                             #include <vector><br>
                             #include <algorithm><br>
                            -#include <string><br>
                             #include <numeric><br>
                             #include <cstdlib><br>
                             #include <cstring><br>
                            @@ -41,6 +40,1370 @@ enum<br>
                                 success<br>
                             };<br>
                            <br>
                            +class StringView {<br>
                            +  const char *First;<br>
                            +  const char *Last;<br>
                            +<br>
                            +public:<br>
                            +  template <size_t N><br>
                            +  StringView(const char (&Str)[N]) :
                            First(Str), Last(Str + N - 1) {}<br>
                            +  StringView(const char *First, const char
                            *Last) : First(First), Last(Last) {}<br>
                            +  StringView() : First(nullptr),
                            Last(nullptr) {}<br>
                            +<br>
                            +  StringView substr(size_t From, size_t To)
                            {<br>
                            +    if (To >= size())<br>
                            +      To = size() - 1;<br>
                            +    if (From >= size())<br>
                            +      From = size() - 1;<br>
                            +    return StringView(First + From, First +
                            To);<br>
                            +  }<br>
                            +<br>
                            +  StringView dropFront(size_t N) const {<br>
                            +    if (N >= size())<br>
                            +      N = size() - 1;<br>
                            +    return StringView(First + N, Last);<br>
                            +  }<br>
                            +<br>
                            +  bool startsWith(StringView Str) const {<br>
                            +    if (Str.size() > size())<br>
                            +      return false;<br>
                            +    return std::equal(Str.begin(),
                            Str.end(), begin());<br>
                            +  }<br>
                            +<br>
                            +  const char &operator[](size_t Idx)
                            const { return *(begin() + Idx); }<br>
                            +<br>
                            +  const char *begin() const { return First;
                            }<br>
                            +  const char *end() const { return Last; }<br>
                            +  size_t size() const { return
                            static_cast<size_t>(Last - First); }<br>
                            +};<br>
                            +<br>
                            +bool operator==(const StringView &LHS,
                            const StringView &RHS) {<br>
                            +  return LHS.size() == RHS.size()
                            &&<br>
                            +         std::equal(LHS.begin(), LHS.end(),
                            RHS.begin());<br>
                            +}<br>
                            +<br>
                            +// Stream that AST nodes write their string
                            representation into after the AST<br>
                            +// has been parsed.<br>
                            +class OutputStream {<br>
                            +  char *Buffer;<br>
                            +  size_t CurrentPosition;<br>
                            +  size_t BufferCapacity;<br>
                            +<br>
                            +  // Ensure there is at least n more
                            positions in buffer.<br>
                            +  void grow(size_t N) {<br>
                            +    if (N + CurrentPosition >=
                            BufferCapacity) {<br>
                            +      BufferCapacity *= 2;<br>
                            +      if (BufferCapacity < N +
                            CurrentPosition)<br>
                            +        BufferCapacity = N +
                            CurrentPosition;<br>
                            +      Buffer = static_cast<char
                            *>(std::realloc(Buffer, BufferCapacity));<br>
                            +    }<br>
                            +  }<br>
                            +<br>
                            +public:<br>
                            +  OutputStream(char *StartBuf, size_t Size)<br>
                            +      : Buffer(StartBuf),
                            CurrentPosition(0), BufferCapacity(Size) {}<br>
                            +<br>
                            +  OutputStream &operator+=(StringView
                            R) {<br>
                            +    size_t Size = R.size();<br>
                            +    if (Size == 0)<br>
                            +      return *this;<br>
                            +    grow(Size);<br>
                            +    memmove(Buffer + CurrentPosition,
                            R.begin(), Size);<br>
                            +    CurrentPosition += Size;<br>
                            +    return *this;<br>
                            +  }<br>
                            +<br>
                            +  OutputStream &operator+=(char C) {<br>
                            +    grow(1);<br>
                            +    Buffer[CurrentPosition++] = C;<br>
                            +    return *this;<br>
                            +  }<br>
                            +<br>
                            +  // Offset of position in buffer, used for
                            building stream_string_view.<br>
                            +  typedef unsigned StreamPosition;<br>
                            +<br>
                            +  // StringView into a stream, used for
                            caching the ast nodes.<br>
                            +  class StreamStringView {<br>
                            +    StreamPosition First, Last;<br>
                            +<br>
                            +    friend class OutputStream;<br>
                            +<br>
                            +  public:<br>
                            +    StreamStringView() : First(0), Last(0)
                            {}<br>
                            +<br>
                            +    StreamStringView(StreamPositio<wbr>n
                            First, StreamPosition Last)<br>
                            +        : First(First), Last(Last) {}<br>
                            +<br>
                            +    bool empty() const { return First ==
                            Last; }<br>
                            +  };<br>
                            +<br>
                            +  OutputStream
                            &operator+=(StreamStringView &s) {<br>
                            +    size_t Sz =
                            static_cast<size_t>(s.Last - s.First);<br>
                            +    if (Sz == 0)<br>
                            +      return *this;<br>
                            +    grow(Sz);<br>
                            +    memmove(Buffer + CurrentPosition,
                            Buffer + s.First, Sz);<br>
                            +    CurrentPosition += Sz;<br>
                            +    return *this;<br>
                            +  }<br>
                            +<br>
                            +  StreamPosition getCurrentPosition() const
                            {<br>
                            +    return
                            static_cast<StreamPosition>(Cu<wbr>rrentPosition);<br>
                            +  }<br>
                            +<br>
                            +  StreamStringView
                            makeStringViewFromPastPosition<wbr>(StreamPosition
                            Pos) {<br>
                            +    return StreamStringView(Pos,
                            getCurrentPosition());<br>
                            +  }<br>
                            +<br>
                            +  char back() const {<br>
                            +    return CurrentPosition ?
                            Buffer[CurrentPosition - 1] : '\0';<br>
                            +  }<br>
                            +<br>
                            +  bool empty() const { return
                            CurrentPosition == 0; }<br>
                            +<br>
                            +  char *getBuffer() { return Buffer; }<br>
                            +  char *getBufferEnd() { return Buffer +
                            CurrentPosition - 1; }<br>
                            +  size_t getBufferCapacity() { return
                            BufferCapacity; }<br>
                            +};<br>
                            +<br>
                            +// Base class of all AST nodes. The AST is
                            built by the parser, then is<br>
                            +// traversed by the printLeft/Right
                            functions to produce a demangled string.<br>
                            +class Node {<br>
                            +public:<br>
                            +  enum Kind : unsigned char {<br>
                            +    KDotSuffix,<br>
                            +    KVendorExtQualType,<br>
                            +    KQualType,<br>
                            +    KConversionOperatorType,<br>
                            +    KPostfixQualifiedType,<br>
                            +    KNameType,<br>
                            +    KObjCProtoName,<br>
                            +    KPointerType,<br>
                            +    KLValueReferenceType,<br>
                            +    KRValueReferenceType,<br>
                            +    KPointerToMemberType,<br>
                            +    KArrayType,<br>
                            +    KFunctionType,<br>
                            +    KTopLevelFunctionDecl,<br>
                            +    KFunctionQualType,<br>
                            +    KFunctionRefQualType,<br>
                            +    KLiteralOperator,<br>
                            +    KSpecialName,<br>
                            +    KCtorVtableSpecialName,<br>
                            +    KQualifiedName,<br>
                            +    KEmptyName,<br>
                            +    KVectorType,<br>
                            +    KTemplateParams,<br>
                            +    KNameWithTemplateArgs,<br>
                            +    KGlobalQualifiedName,<br>
                            +    KStdQualifiedName,<br>
                            +    KExpandedSpecialSubstitution,<br>
                            +    KSpecialSubstitution,<br>
                            +    KCtorDtorName,<br>
                            +    KDtorName,<br>
                            +    KUnnamedTypeName,<br>
                            +    KLambdaTypeName,<br>
                            +    KExpr,<br>
                            +  };<br>
                            +<br>
                            +  const Kind K;<br>
                            +<br>
                            +private:<br>
                            +  // If this Node has any RHS part,
                            potentally many Nodes further down.<br>
                            +  const unsigned HasRHSComponent : 1;<br>
                            +  const unsigned HasFunction : 1;<br>
                            +  const unsigned HasArray : 1;<br>
                            +<br>
                            +public:<br>
                            +  Node(Kind K, bool HasRHS = false, bool
                            HasFunction = false,<br>
                            +       bool HasArray = false)<br>
                            +      : K(K), HasRHSComponent(HasRHS),
                            HasFunction(HasFunction),<br>
                            +        HasArray(HasArray) {}<br>
                            +<br>
                            +  bool hasRHSComponent() const { return
                            HasRHSComponent; }<br>
                            +  bool hasArray() const { return HasArray;
                            }<br>
                            +  bool hasFunction() const { return
                            HasFunction; }<br>
                            +<br>
                            +  void print(OutputStream &s) const {<br>
                            +    printLeft(s);<br>
                            +    if (hasRHSComponent())<br>
                            +      printRight(s);<br>
                            +  }<br>
                            +<br>
                            +  // Print the "left" side of this Node
                            into OutputStream.<br>
                            +  virtual void printLeft(OutputStream
                            &) const = 0;<br>
                            +<br>
                            +  // Print the "right". This distinction is
                            necessary to represent C++ types<br>
                            +  // that appear on the RHS of their
                            subtype, such as arrays or functions.<br>
                            +  // Since most types don't have such a
                            component, provide a default<br>
                            +  // implemenation.<br>
                            +  virtual void printRight(OutputStream
                            &) const {}<br>
                            +<br>
                            +  virtual StringView getBaseName() const {
                            return StringView(); }<br>
                            +<br>
                            +  // Silence compiler warnings, this dtor
                            will never be called.<br>
                            +  virtual ~Node() = default;<br>
                            +};<br>
                            +<br>
                            +class NodeArray {<br>
                            +  Node **Elements;<br>
                            +  size_t NumElements;<br>
                            +<br>
                            +public:<br>
                            +  NodeArray() : NumElements(0) {}<br>
                            +  NodeArray(Node **Elements, size_t
                            NumElements)<br>
                            +      : Elements(Elements),
                            NumElements(NumElements) {}<br>
                            +<br>
                            +  bool empty() const { return NumElements
                            == 0; }<br>
                            +  size_t size() const { return NumElements;
                            }<br>
                            +<br>
                            +  void printWithSeperator(OutputStrea<wbr>m
                            &S, StringView Seperator) const {<br>
                            +    for (size_t Idx = 0; Idx !=
                            NumElements; ++Idx) {<br>
                            +      if (Idx)<br>
                            +        S += Seperator;<br>
                            +      Elements[Idx]->print(S);<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class DotSuffix final : public Node {<br>
                            +  const Node *Prefix;<br>
                            +  const StringView Suffix;<br>
                            +<br>
                            +public:<br>
                            +  DotSuffix(Node *Prefix, StringView
                            Suffix)<br>
                            +      : Node(KDotSuffix), Prefix(Prefix),
                            Suffix(Suffix) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    Prefix->print(s);<br>
                            +    s += " (";<br>
                            +    s += Suffix;<br>
                            +    s += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class VendorExtQualType final : public Node
                            {<br>
                            +  const Node *Ext;<br>
                            +  const Node *Ty;<br>
                            +<br>
                            +public:<br>
                            +  VendorExtQualType(Node *Ext, Node *Ty)<br>
                            +      : Node(KVendorExtQualType), Ext(Ext),
                            Ty(Ty) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Ext->print(S);<br>
                            +    S += " ";<br>
                            +    Ty->printLeft(S);<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override { Ty->printRight(S); }<br>
                            +};<br>
                            +<br>
                            +enum Qualifiers {<br>
                            +  QualNone = 0,<br>
                            +  QualConst = 0x1,<br>
                            +  QualVolatile = 0x2,<br>
                            +  QualRestrict = 0x4,<br>
                            +};<br>
                            +<br>
                            +void addQualifiers(Qualifiers &Q1,
                            Qualifiers Q2) {<br>
                            +  Q1 = static_cast<Qualifiers>(Q1 |
                            Q2);<br>
                            +}<br>
                            +<br>
                            +class QualType : public Node {<br>
                            +protected:<br>
                            +  const Qualifiers Quals;<br>
                            +  const Node *Child;<br>
                            +<br>
                            +  void printQuals(OutputStream &S)
                            const {<br>
                            +    if (Quals & QualConst)<br>
                            +      S += " const";<br>
                            +    if (Quals & QualVolatile)<br>
                            +      S += " volatile";<br>
                            +    if (Quals & QualRestrict)<br>
                            +      S += " restrict";<br>
                            +  }<br>
                            +<br>
                            +public:<br>
                            +  QualType(Node *Child, Qualifiers Quals)<br>
                            +      : Node(KQualType,
                            Child->hasRHSComponent(),
                            Child->hasFunction(),<br>
                            +             Child->hasArray()),<br>
                            +        Quals(Quals), Child(Child) {}<br>
                            +<br>
                            +  QualType(Node::Kind ChildKind, Node
                            *Child, Qualifiers Quals)<br>
                            +      : Node(ChildKind,
                            Child->hasRHSComponent(),
                            Child->hasFunction(),<br>
                            +             Child->hasArray()),<br>
                            +        Quals(Quals), Child(Child) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Child->printLeft(S);<br>
                            +    printQuals(S);<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override { Child->printRight(S); }<br>
                            +};<br>
                            +<br>
                            +class ConversionOperatorType final : public
                            Node {<br>
                            +  const Node *Ty;<br>
                            +<br>
                            +public:<br>
                            +  ConversionOperatorType(Node *Ty) :
                            Node(KConversionOperatorType), Ty(Ty) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "operator ";<br>
                            +    Ty->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class PostfixQualifiedType final : public
                            Node {<br>
                            +  const Node *Ty;<br>
                            +  const StringView Postfix;<br>
                            +<br>
                            +public:<br>
                            +  PostfixQualifiedType(Node *Ty, StringView
                            Postfix)<br>
                            +      : Node(KPostfixQualifiedType),
                            Ty(Ty), Postfix(Postfix) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    Ty->printLeft(s);<br>
                            +    s += Postfix;<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override { Ty->printRight(S); }<br>
                            +};<br>
                            +<br>
                            +class NameType final : public Node {<br>
                            +  const StringView Name;<br>
                            +<br>
                            +public:<br>
                            +  NameType(StringView Name) :
                            Node(KNameType), Name(Name) {}<br>
                            +<br>
                            +  StringView getName() const { return Name;
                            }<br>
                            +  StringView getBaseName() const override {
                            return Name; }<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override { s += Name; }<br>
                            +};<br>
                            +<br>
                            +class ObjCProtoName : public Node {<br>
                            +  Node *Ty;<br>
                            +  Node *Protocol;<br>
                            +<br>
                            +  friend class PointerType;<br>
                            +<br>
                            +public:<br>
                            +  ObjCProtoName(Node *Ty, Node *Protocol)<br>
                            +      : Node(KObjCProtoName), Ty(Ty),
                            Protocol(Protocol) {}<br>
                            +<br>
                            +  bool isObjCObject() const {<br>
                            +    return Ty->K == KNameType &&<br>
                            +           static_cast<NameType
                            *>(Ty)->getName() == "objc_object";<br>
                            +  }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Ty->printLeft(S);<br>
                            +    S += "<";<br>
                            +    Protocol->printLeft(S);<br>
                            +    S += ">";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class PointerType final : public Node {<br>
                            +  const Node *Pointee;<br>
                            +<br>
                            +public:<br>
                            +  PointerType(Node *Pointee)<br>
                            +      : Node(KPointerType,
                            Pointee->hasRHSComponent()),
                            Pointee(Pointee) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    // We rewrite
                            objc_object<SomeProtocol>* into
                            id<SomeProtocol>.<br>
                            +    if (Pointee->K != KObjCProtoName ||<br>
                            +        !static_cast<const ObjCProtoName
                            *>(Pointee)->isObjCObject()) {<br>
                            +      Pointee->printLeft(s);<br>
                            +      if (Pointee->hasArray())<br>
                            +        s += " ";<br>
                            +      if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +        s += "(";<br>
                            +      s += "*";<br>
                            +    } else {<br>
                            +      const auto *objcProto =
                            static_cast<const ObjCProtoName
                            *>(Pointee);<br>
                            +      s += "id<";<br>
                            +      objcProto->Protocol->print(s);<br>
                            +      s += ">";<br>
                            +    }<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &s)
                            const override {<br>
                            +    if (Pointee->K != KObjCProtoName ||<br>
                            +        !static_cast<const ObjCProtoName
                            *>(Pointee)->isObjCObject()) {<br>
                            +      if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +        s += ")";<br>
                            +      Pointee->printRight(s);<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class LValueReferenceType final : public
                            Node {<br>
                            +  const Node *Pointee;<br>
                            +<br>
                            +public:<br>
                            +  LValueReferenceType(Node *Pointee)<br>
                            +      : Node(KLValueReferenceType,
                            Pointee->hasRHSComponent()),<br>
                            +        Pointee(Pointee) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    Pointee->printLeft(s);<br>
                            +    if (Pointee->hasArray())<br>
                            +      s += " ";<br>
                            +    if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +      s += "(&";<br>
                            +    else<br>
                            +      s += "&";<br>
                            +  }<br>
                            +  void printRight(OutputStream &s)
                            const override {<br>
                            +    if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +      s += ")";<br>
                            +    Pointee->printRight(s);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class RValueReferenceType final : public
                            Node {<br>
                            +  const Node *Pointee;<br>
                            +<br>
                            +public:<br>
                            +  RValueReferenceType(Node *Pointee)<br>
                            +      : Node(KRValueReferenceType,
                            Pointee->hasRHSComponent()),<br>
                            +        Pointee(Pointee) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    Pointee->printLeft(s);<br>
                            +    if (Pointee->hasArray())<br>
                            +      s += " ";<br>
                            +    if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +      s += "(&&";<br>
                            +    else<br>
                            +      s += "&&";<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &s)
                            const override {<br>
                            +    if (Pointee->hasArray() ||
                            Pointee->hasFunction())<br>
                            +      s += ")";<br>
                            +    Pointee->printRight(s);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class PointerToMemberType final : public
                            Node {<br>
                            +  const Node *ClassType;<br>
                            +  const Node *MemberType;<br>
                            +<br>
                            +public:<br>
                            +  PointerToMemberType(Node *ClassType, Node
                            *MemberType)<br>
                            +      : Node(KPointerToMemberType,
                            MemberType->hasRHSComponent())<wbr>,<br>
                            +        ClassType(ClassType),
                            MemberType(MemberType) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    MemberType->printLeft(s);<br>
                            +    if (MemberType->hasArray() ||
                            MemberType->hasFunction())<br>
                            +      s += "(";<br>
                            +    else<br>
                            +      s += " ";<br>
                            +    ClassType->print(s);<br>
                            +    s += "::*";<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &s)
                            const override {<br>
                            +    if (MemberType->hasArray() ||
                            MemberType->hasFunction())<br>
                            +      s += ")";<br>
                            +    MemberType->printRight(s);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class NodeOrString {<br>
                            +  const void *First;<br>
                            +  const void *Second;<br>
                            +<br>
                            +public:<br>
                            +  /* implicit */ NodeOrString(StringView
                            Str) {<br>
                            +    const char *FirstChar = Str.begin();<br>
                            +    const char *SecondChar = Str.end();<br>
                            +    if (SecondChar == nullptr) {<br>
                            +      assert(FirstChar == SecondChar);<br>
                            +      ++FirstChar, ++SecondChar;<br>
                            +    }<br>
                            +    First = static_cast<const void
                            *>(FirstChar);<br>
                            +    Second = static_cast<const void
                            *>(SecondChar);<br>
                            +  }<br>
                            +<br>
                            +  /* implicit */ NodeOrString(Node *N)<br>
                            +      : First(static_cast<const void
                            *>(N)), Second(nullptr) {}<br>
                            +  NodeOrString() : First(nullptr),
                            Second(nullptr) {}<br>
                            +<br>
                            +  bool isString() const { return Second
                            && First; }<br>
                            +  bool isNode() const { return First
                            && !Second; }<br>
                            +  bool isEmpty() const { return !First
                            && !Second; }<br>
                            +<br>
                            +  StringView asString() const {<br>
                            +    assert(isString());<br>
                            +    return StringView(static_cast<const
                            char *>(First),<br>
                            +                      static_cast<const
                            char *>(Second));<br>
                            +  }<br>
                            +<br>
                            +  const Node *asNode() const {<br>
                            +    assert(isNode());<br>
                            +    return static_cast<const Node
                            *>(First);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ArrayType final : public Node {<br>
                            +  Node *Base;<br>
                            +  NodeOrString Dimension;<br>
                            +<br>
                            +public:<br>
                            +  ArrayType(Node *Base, NodeOrString
                            Dimension)<br>
                            +      : Node(KArrayType, true, false,
                            true), Base(Base), Dimension(Dimension) {}<br>
                            +<br>
                            +  // Incomplete array type.<br>
                            +  ArrayType(Node *Base) : Node(KArrayType,
                            true, false, true), Base(Base) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override { Base->printLeft(S); }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override {<br>
                            +    if (S.back() != ']')<br>
                            +      S += " ";<br>
                            +    S += "[";<br>
                            +    if (Dimension.isString())<br>
                            +      S += Dimension.asString();<br>
                            +    else if (Dimension.isNode())<br>
                            +      Dimension.asNode()->print(S);<br>
                            +    S += "]";<br>
                            +    Base->printRight(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class FunctionType final : public Node {<br>
                            +  Node *Ret;<br>
                            +  NodeArray Params;<br>
                            +<br>
                            +public:<br>
                            +  FunctionType(Node *Ret, NodeArray Params)<br>
                            +      : Node(KFunctionType, true, true),
                            Ret(Ret), Params(Params) {}<br>
                            +<br>
                            +  // Handle C++'s ... quirky decl grammer
                            by using the left & right<br>
                            +  // distinction. Consider:<br>
                            +  //   int (*f(float))(char) {}<br>
                            +  // f is a function that takes a float and
                            returns a pointer to a function<br>
                            +  // that takes a char and returns an int.
                            If we're trying to print f, start<br>
                            +  // by printing out the return types's
                            left, then print our parameters, then<br>
                            +  // finally print right of the return
                            type.<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Ret->printLeft(S);<br>
                            +    S += " ";<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override {<br>
                            +    S += "(";<br>
                            +    Params.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +    Ret->printRight(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class TopLevelFunctionDecl final : public
                            Node {<br>
                            +  const Node *Ret;<br>
                            +  const Node *Name;<br>
                            +  NodeArray Params;<br>
                            +<br>
                            +public:<br>
                            +  TopLevelFunctionDecl(Node *Ret, Node
                            *Name, NodeArray Params)<br>
                            +      : Node(KTopLevelFunctionDecl, true,
                            true), Ret(Ret), Name(Name),<br>
                            +        Params(Params) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (Ret) {<br>
                            +      Ret->printLeft(S);<br>
                            +      if (!Ret->hasRHSComponent())<br>
                            +        S += " ";<br>
                            +    }<br>
                            +    Name->print(S);<br>
                            +  }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override {<br>
                            +    S += "(";<br>
                            +    Params.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +    if (Ret)<br>
                            +      Ret->printRight(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +enum FunctionRefQual : unsigned char {<br>
                            +  FrefQualNone,<br>
                            +  FrefQualLValue,<br>
                            +  FrefQualRValue,<br>
                            +};<br>
                            +<br>
                            +class FunctionRefQualType : public Node {<br>
                            +  Node *Fn;<br>
                            +  FunctionRefQual Quals;<br>
                            +<br>
                            +  friend class FunctionQualType;<br>
                            +<br>
                            +public:<br>
                            +  FunctionRefQualType(Node *Fn,
                            FunctionRefQual Quals)<br>
                            +      : Node(KFunctionRefQualType, true,
                            true), Fn(Fn), Quals(Quals) {}<br>
                            +<br>
                            +  void printQuals(OutputStream &S)
                            const {<br>
                            +    if (Quals == FrefQualLValue)<br>
                            +      S += " &";<br>
                            +    else<br>
                            +      S += " &&";<br>
                            +  }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override { Fn->printLeft(S); }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override {<br>
                            +    Fn->printRight(S);<br>
                            +    printQuals(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class FunctionQualType final : public
                            QualType {<br>
                            +public:<br>
                            +  FunctionQualType(Node *Child, Qualifiers
                            Quals)<br>
                            +      : QualType(KFunctionQualType, Child,
                            Quals) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override { Child->printLeft(S); }<br>
                            +<br>
                            +  void printRight(OutputStream &S)
                            const override {<br>
                            +    if (Child->K ==
                            KFunctionRefQualType) {<br>
                            +      auto *RefQuals = static_cast<const
                            FunctionRefQualType *>(Child);<br>
                            +      RefQuals->Fn->printRight(S);<br>
                            +      printQuals(S);<br>
                            +      RefQuals->printQuals(S);<br>
                            +    } else {<br>
                            +      Child->printRight(S);<br>
                            +      printQuals(S);<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class LiteralOperator : public Node {<br>
                            +  const Node *OpName;<br>
                            +<br>
                            +public:<br>
                            +  LiteralOperator(Node *OpName) :
                            Node(KLiteralOperator), OpName(OpName) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "operator\"\" ";<br>
                            +    OpName->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class SpecialName final : public Node {<br>
                            +  const StringView Special;<br>
                            +  const Node *Child;<br>
                            +<br>
                            +public:<br>
                            +  SpecialName(StringView Special, Node
                            *Child)<br>
                            +      : Node(KSpecialName),
                            Special(Special), Child(Child) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += Special;<br>
                            +    Child->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class CtorVtableSpecialName final : public
                            Node {<br>
                            +  const Node *FirstType;<br>
                            +  const Node *SecondType;<br>
                            +<br>
                            +public:<br>
                            +  CtorVtableSpecialName(Node *FirstType,
                            Node *SecondType)<br>
                            +      : Node(KCtorVtableSpecialName),
                            FirstType(FirstType),<br>
                            +        SecondType(SecondType) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "construction vtable for ";<br>
                            +    FirstType->print(S);<br>
                            +    S += "-in-";<br>
                            +    SecondType->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class QualifiedName final : public Node {<br>
                            +  // qualifier::name<br>
                            +  const Node *Qualifier;<br>
                            +  const Node *Name;<br>
                            +<br>
                            +  mutable OutputStream::StreamStringView
                            Cache;<br>
                            +<br>
                            +public:<br>
                            +  QualifiedName(Node *Qualifier, Node
                            *Name)<br>
                            +      : Node(KQualifiedName),
                            Qualifier(Qualifier), Name(Name) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {
                            return Name->getBaseName(); }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (!Cache.empty()) {<br>
                            +      S += Cache;<br>
                            +      return;<br>
                            +    }<br>
                            +<br>
                            +    OutputStream::StreamPosition Start =
                            S.getCurrentPosition();<br>
                            +    if (Qualifier->K != KEmptyName) {<br>
                            +      Qualifier->print(S);<br>
                            +      S += "::";<br>
                            +    }<br>
                            +    Name->print(S);<br>
                            +    Cache = S.makeStringViewFromPastPositi<wbr>on(Start);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class EmptyName : public Node {<br>
                            +public:<br>
                            +  EmptyName() : Node(KEmptyName) {}<br>
                            +  void printLeft(OutputStream &) const
                            override {}<br>
                            +};<br>
                            +<br>
                            +class VectorType final : public Node {<br>
                            +  const Node *BaseType;<br>
                            +  const NodeOrString Dimension;<br>
                            +  const bool IsPixel;<br>
                            +<br>
                            +public:<br>
                            +  VectorType(NodeOrString Dimension)<br>
                            +      : Node(KVectorType),
                            BaseType(nullptr), Dimension(Dimension),<br>
                            +        IsPixel(true) {}<br>
                            +  VectorType(Node *BaseType, NodeOrString
                            Dimension)<br>
                            +      : Node(KVectorType),
                            BaseType(BaseType), Dimension(Dimension),<br>
                            +        IsPixel(false) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (IsPixel) {<br>
                            +      S += "pixel vector[";<br>
                            +      S += Dimension.asString();<br>
                            +      S += "]";<br>
                            +    } else {<br>
                            +      BaseType->print(S);<br>
                            +      S += " vector[";<br>
                            +      if (Dimension.isNode())<br>
                            +        Dimension.asNode()->print(S);<br>
                            +      else if (Dimension.isString())<br>
                            +        S += Dimension.asString();<br>
                            +      S += "]";<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class TemplateParams final : public Node {<br>
                            +  NodeArray Params;<br>
                            +<br>
                            +  mutable OutputStream::StreamStringView
                            Cache;<br>
                            +<br>
                            +public:<br>
                            +  TemplateParams(NodeArray Params) :
                            Node(KTemplateParams), Params(Params) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (!Cache.empty()) {<br>
                            +      S += Cache;<br>
                            +      return;<br>
                            +    }<br>
                            +<br>
                            +    OutputStream::StreamPosition Start =
                            S.getCurrentPosition();<br>
                            +<br>
                            +    S += "<";<br>
                            +    Params.printWithSeperator(S, ", ");<br>
                            +    if (S.back() == '>')<br>
                            +      S += " ";<br>
                            +    S += ">";<br>
                            +<br>
                            +    Cache = S.makeStringViewFromPastPositi<wbr>on(Start);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class NameWithTemplateArgs final : public
                            Node {<br>
                            +  // name<template_args><br>
                            +  Node *Name;<br>
                            +  Node *TemplateArgs;<br>
                            +<br>
                            +public:<br>
                            +  NameWithTemplateArgs(Node *Name, Node
                            *TemplateArgs)<br>
                            +      : Node(KNameWithTemplateArgs),
                            Name(Name), TemplateArgs(TemplateArgs) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {
                            return Name->getBaseName(); }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Name->print(S);<br>
                            +    TemplateArgs->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class GlobalQualifiedName final : public
                            Node {<br>
                            +  Node *Child;<br>
                            +<br>
                            +public:<br>
                            +  GlobalQualifiedName(Node *Child) :
                            Node(KGlobalQualifiedName), Child(Child) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {
                            return Child->getBaseName(); }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "::";<br>
                            +    Child->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class StdQualifiedName final : public Node
                            {<br>
                            +  Node *Child;<br>
                            +<br>
                            +public:<br>
                            +  StdQualifiedName(Node *Child) :
                            Node(KStdQualifiedName), Child(Child) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {
                            return Child->getBaseName(); }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "std::";<br>
                            +    Child->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +enum class SpecialSubKind {<br>
                            +  allocator,<br>
                            +  basic_string,<br>
                            +  string,<br>
                            +  istream,<br>
                            +  ostream,<br>
                            +  iostream,<br>
                            +};<br>
                            +<br>
                            +class ExpandedSpecialSubstitution final :
                            public Node {<br>
                            +  SpecialSubKind SSK;<br>
                            +<br>
                            +public:<br>
                            +  ExpandedSpecialSubstitution(Sp<wbr>ecialSubKind
                            SSK)<br>
                            +      : Node(KExpandedSpecialSubstitut<wbr>ion),
                            SSK(SSK) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {<br>
                            +    switch (SSK) {<br>
                            +    case SpecialSubKind::allocator:<br>
                            +      return StringView("allocator");<br>
                            +    case SpecialSubKind::basic_string:<br>
                            +      return StringView("basic_string");<br>
                            +    case SpecialSubKind::string:<br>
                            +      return StringView("basic_string");<br>
                            +    case SpecialSubKind::istream:<br>
                            +      return StringView("basic_istream");<br>
                            +    case SpecialSubKind::ostream:<br>
                            +      return StringView("basic_ostream");<br>
                            +    case SpecialSubKind::iostream:<br>
                            +      return StringView("basic_iostream");<br>
                            +    }<br>
                            +  }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    switch (SSK) {<br>
                            +    case SpecialSubKind::allocator:<br>
                            +      S += "std::basic_string<char,
                            std::char_traits<char>, "<br>
                            +           "std::allocator<char>
                            >";<br>
                            +      break;<br>
                            +    case SpecialSubKind::basic_string:<br>
                            +    case SpecialSubKind::string:<br>
                            +      S += "std::basic_string<char,
                            std::char_traits<char>, "<br>
                            +           "std::allocator<char>
                            >";<br>
                            +      break;<br>
                            +    case SpecialSubKind::istream:<br>
                            +      S += "std::basic_istream<char,
                            std::char_traits<char> >";<br>
                            +      break;<br>
                            +    case SpecialSubKind::ostream:<br>
                            +      S += "std::basic_ostream<char,
                            std::char_traits<char> >";<br>
                            +      break;<br>
                            +    case SpecialSubKind::iostream:<br>
                            +      S += "std::basic_iostream<char,
                            std::char_traits<char> >";<br>
                            +      break;<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class SpecialSubstitution final : public
                            Node {<br>
                            +public:<br>
                            +  SpecialSubKind SSK;<br>
                            +<br>
                            +  SpecialSubstitution(SpecialSub<wbr>Kind
                            SSK)<br>
                            +      : Node(KSpecialSubstitution),
                            SSK(SSK) {}<br>
                            +<br>
                            +  StringView getBaseName() const override {<br>
                            +    switch (SSK) {<br>
                            +    case SpecialSubKind::allocator:<br>
                            +      return StringView("allocator");<br>
                            +    case SpecialSubKind::basic_string:<br>
                            +      return StringView("basic_string");<br>
                            +    case SpecialSubKind::string:<br>
                            +      return StringView("string");<br>
                            +    case SpecialSubKind::istream:<br>
                            +      return StringView("istream");<br>
                            +    case SpecialSubKind::ostream:<br>
                            +      return StringView("ostream");<br>
                            +    case SpecialSubKind::iostream:<br>
                            +      return StringView("iostream");<br>
                            +    }<br>
                            +  }<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    switch (SSK) {<br>
                            +    case SpecialSubKind::allocator:<br>
                            +      S += "std::allocator";<br>
                            +      break;<br>
                            +    case SpecialSubKind::basic_string:<br>
                            +      S += "std::basic_string";<br>
                            +      break;<br>
                            +    case SpecialSubKind::string:<br>
                            +      S += "std::string";<br>
                            +      break;<br>
                            +    case SpecialSubKind::istream:<br>
                            +      S += "std::istream";<br>
                            +      break;<br>
                            +    case SpecialSubKind::ostream:<br>
                            +      S += "std::ostream";<br>
                            +      break;<br>
                            +    case SpecialSubKind::iostream:<br>
                            +      S += "std::iostream";<br>
                            +      break;<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class CtorDtorName final : public Node {<br>
                            +  const Node *Basename;<br>
                            +  const bool IsDtor;<br>
                            +<br>
                            +public:<br>
                            +  CtorDtorName(Node *Basename, bool IsDtor)<br>
                            +      : Node(KCtorDtorName),
                            Basename(Basename), IsDtor(IsDtor) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (IsDtor)<br>
                            +      S += "~";<br>
                            +    S += Basename->getBaseName();<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class DtorName : public Node {<br>
                            +  const Node *Base;<br>
                            +<br>
                            +public:<br>
                            +  DtorName(Node *Base) : Node(KDtorName),
                            Base(Base) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "~";<br>
                            +    Base->printLeft(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class UnnamedTypeName : public Node {<br>
                            +  const StringView Count;<br>
                            +<br>
                            +public:<br>
                            +  UnnamedTypeName(StringView Count) :
                            Node(KUnnamedTypeName), Count(Count) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "'unnamed";<br>
                            +    S += Count;<br>
                            +    S += "\'";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class LambdaTypeName : public Node {<br>
                            +  NodeArray Params;<br>
                            +  StringView Count;<br>
                            +<br>
                            +public:<br>
                            +  LambdaTypeName(NodeArray Params,
                            StringView Count)<br>
                            +      : Node(KLambdaTypeName),
                            Params(Params), Count(Count) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "\'lambda";<br>
                            +    S += Count;<br>
                            +    S += "\'(";<br>
                            +    Params.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +// -- Expression Nodes --<br>
                            +<br>
                            +struct Expr : public Node {<br>
                            +  Expr() : Node(KExpr) {}<br>
                            +};<br>
                            +<br>
                            +class BinaryExpr : public Expr {<br>
                            +  const Node *LHS;<br>
                            +  const StringView InfixOperator;<br>
                            +  const Node *RHS;<br>
                            +<br>
                            +public:<br>
                            +  BinaryExpr(Node *LHS, StringView
                            InfixOperator, Node *RHS)<br>
                            +      : LHS(LHS),
                            InfixOperator(InfixOperator), RHS(RHS) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    // might be a template argument
                            expression, then we need to disambiguate<br>
                            +    // with parens.<br>
                            +    if (InfixOperator == ">")<br>
                            +      S += "(";<br>
                            +<br>
                            +    S += "(";<br>
                            +    LHS->print(S);<br>
                            +    S += ") ";<br>
                            +    S += InfixOperator;<br>
                            +    S += " (";<br>
                            +    RHS->print(S);<br>
                            +    S += ")";<br>
                            +<br>
                            +    if (InfixOperator == ">")<br>
                            +      S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ArraySubscriptExpr : public Expr {<br>
                            +  const Node *Op1;<br>
                            +  const Node *Op2;<br>
                            +<br>
                            +public:<br>
                            +  ArraySubscriptExpr(Node *Op1, Node *Op2)
                            : Op1(Op1), Op2(Op2) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    Op1->print(S);<br>
                            +    S += ")[";<br>
                            +    Op2->print(S);<br>
                            +    S += "]";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class PostfixExpr : public Expr {<br>
                            +  const Node *Child;<br>
                            +  const StringView Operand;<br>
                            +<br>
                            +public:<br>
                            +  PostfixExpr(Node *Child, StringView
                            Operand)<br>
                            +      : Child(Child), Operand(Operand) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    Child->print(S);<br>
                            +    S += ")";<br>
                            +    S += Operand;<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ConditionalExpr : public Expr {<br>
                            +  const Node *Cond;<br>
                            +  const Node *Then;<br>
                            +  const Node *Else;<br>
                            +<br>
                            +public:<br>
                            +  ConditionalExpr(Node *Cond, Node *Then,
                            Node *Else)<br>
                            +      : Cond(Cond), Then(Then), Else(Else)
                            {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    Cond->print(S);<br>
                            +    S += ") ? (";<br>
                            +    Then->print(S);<br>
                            +    S += ") : (";<br>
                            +    Else->print(S);<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class MemberExpr : public Expr {<br>
                            +  const Node *LHS;<br>
                            +  const StringView Kind;<br>
                            +  const Node *RHS;<br>
                            +<br>
                            +public:<br>
                            +  MemberExpr(Node *LHS, StringView Kind,
                            Node *RHS)<br>
                            +      : LHS(LHS), Kind(Kind), RHS(RHS) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    LHS->print(S);<br>
                            +    S += Kind;<br>
                            +    RHS->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class EnclosingExpr : public Expr {<br>
                            +  const StringView Prefix;<br>
                            +  const Node *Infix;<br>
                            +  const StringView Postfix;<br>
                            +<br>
                            +public:<br>
                            +  EnclosingExpr(StringView Prefix, Node
                            *Infix, StringView Postfix)<br>
                            +      : Prefix(Prefix), Infix(Infix),
                            Postfix(Postfix) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += Prefix;<br>
                            +    Infix->print(S);<br>
                            +    S += Postfix;<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class CastExpr : public Expr {<br>
                            +  // cast_kind<to>(from)<br>
                            +  const StringView CastKind;<br>
                            +  const Node *To;<br>
                            +  const Node *From;<br>
                            +<br>
                            +public:<br>
                            +  CastExpr(StringView CastKind, Node *To,
                            Node *From)<br>
                            +      : CastKind(CastKind), To(To),
                            From(From) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += CastKind;<br>
                            +    S += "<";<br>
                            +    To->printLeft(S);<br>
                            +    S += ">(";<br>
                            +    From->printLeft(S);<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class SizeofParamPackExpr : public Expr {<br>
                            +  NodeArray Args;<br>
                            +<br>
                            +public:<br>
                            +  SizeofParamPackExpr(NodeArray Args) :
                            Args(Args) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "sizeof...(";<br>
                            +    Args.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class CallExpr : public Expr {<br>
                            +  const Node *Callee;<br>
                            +  NodeArray Args;<br>
                            +<br>
                            +public:<br>
                            +  CallExpr(Node *Callee, NodeArray Args) :
                            Callee(Callee), Args(Args) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    Callee->print(S);<br>
                            +    S += "(";<br>
                            +    Args.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class NewExpr : public Expr {<br>
                            +  // new (expr_list) type(init_list)<br>
                            +  NodeArray ExprList;<br>
                            +  Node *Type;<br>
                            +  NodeArray InitList;<br>
                            +  bool IsGlobal; // ::operator new ?<br>
                            +  bool IsArray;  // new[] ?<br>
                            +public:<br>
                            +  NewExpr(NodeArray ExprList, Node *Type,
                            NodeArray InitList, bool IsGlobal,<br>
                            +          bool IsArray)<br>
                            +      : ExprList(ExprList), Type(Type),
                            InitList(InitList), IsGlobal(IsGlobal),<br>
                            +        IsArray(IsArray) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (IsGlobal)<br>
                            +      S += "::operator ";<br>
                            +    S += "new";<br>
                            +    if (IsArray)<br>
                            +      S += "[]";<br>
                            +    if (!ExprList.empty()) {<br>
                            +      S += "(";<br>
                            +      ExprList.printWithSeperator(S, ", ");<br>
                            +      S += ")";<br>
                            +    }<br>
                            +    Type->print(S);<br>
                            +    if (!InitList.empty()) {<br>
                            +      S += "(";<br>
                            +      InitList.printWithSeperator(S, ", ");<br>
                            +      S += ")";<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class DeleteExpr : public Expr {<br>
                            +  Node *Op;<br>
                            +  bool IsGlobal;<br>
                            +  bool IsArray;<br>
                            +<br>
                            +public:<br>
                            +  DeleteExpr(Node *Op, bool IsGlobal, bool
                            IsArray)<br>
                            +      : Op(Op), IsGlobal(IsGlobal),
                            IsArray(IsArray) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (IsGlobal)<br>
                            +      S += "::";<br>
                            +    S += "delete";<br>
                            +    if (IsArray)<br>
                            +      S += "[] ";<br>
                            +    Op->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class PrefixExpr : public Expr {<br>
                            +  StringView Prefix;<br>
                            +  Node *Child;<br>
                            +<br>
                            +public:<br>
                            +  PrefixExpr(StringView Prefix, Node
                            *Child) : Prefix(Prefix), Child(Child) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += Prefix;<br>
                            +    S += "(";<br>
                            +    Child->print(S);<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class FunctionParam : public Expr {<br>
                            +  StringView Number;<br>
                            +<br>
                            +public:<br>
                            +  FunctionParam(StringView Number) :
                            Number(Number) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "fp";<br>
                            +    S += Number;<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ExprList : public Expr {<br>
                            +  NodeArray SubExprs;<br>
                            +<br>
                            +public:<br>
                            +  ExprList(NodeArray SubExprs) :
                            SubExprs(SubExprs) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    SubExprs.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ConversionExpr : public Expr {<br>
                            +  NodeArray Expressions;<br>
                            +  NodeArray Types;<br>
                            +<br>
                            +public:<br>
                            +  ConversionExpr(NodeArray Expressions,
                            NodeArray Types)<br>
                            +      : Expressions(Expressions),
                            Types(Types) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    Expressions.printWithSeperator<wbr>(S,
                            ", ");<br>
                            +    S += ")(";<br>
                            +    Types.printWithSeperator(S, ", ");<br>
                            +    S += ")";<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class ThrowExpr : public Expr {<br>
                            +  const Node *Op;<br>
                            +<br>
                            +public:<br>
                            +  ThrowExpr(Node *Op) : Op(Op) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "throw ";<br>
                            +    Op->print(S);<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class BoolExpr : public Expr {<br>
                            +  bool Value;<br>
                            +<br>
                            +public:<br>
                            +  BoolExpr(bool Value) : Value(Value) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += Value ? StringView("true") :
                            StringView("false");<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class IntegerCastExpr : public Expr {<br>
                            +  // ty(integer)<br>
                            +  Node *Ty;<br>
                            +  StringView Integer;<br>
                            +<br>
                            +public:<br>
                            +  IntegerCastExpr(Node *Ty, StringView
                            Integer) : Ty(Ty), Integer(Integer) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    S += "(";<br>
                            +    Ty->print(S);<br>
                            +    S += ")";<br>
                            +    S += Integer;<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +class IntegerExpr : public Expr {<br>
                            +  StringView Type;<br>
                            +  StringView Value;<br>
                            +<br>
                            +public:<br>
                            +  IntegerExpr(StringView Type, StringView
                            Value) : Type(Type), Value(Value) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &S) const
                            override {<br>
                            +    if (Type.size() > 3) {<br>
                            +      S += "(";<br>
                            +      S += Type;<br>
                            +      S += ")";<br>
                            +    }<br>
                            +<br>
                            +    if (Value[0] == 'n') {<br>
                            +      S += "-";<br>
                            +      S += Value.dropFront(1);<br>
                            +    } else<br>
                            +      S += Value;<br>
                            +<br>
                            +    if (Type.size() <= 3)<br>
                            +      S += Type;<br>
                            +  }<br>
                            +};<br>
                            +<br>
                            +template <class Float> struct
                            FloatData;<br>
                            +<br>
                            +template <class Float> class
                            FloatExpr : public Expr {<br>
                            +  const StringView Contents;<br>
                            +<br>
                            +public:<br>
                            +  FloatExpr(StringView Contents) :
                            Contents(Contents) {}<br>
                            +<br>
                            +  void printLeft(OutputStream &s) const
                            override {<br>
                            +    const char *first = Contents.begin();<br>
                            +    const char *last = Contents.end() + 1;<br>
                            +<br>
                            +    const size_t N =
                            FloatData<Float>::mangled_size<wbr>;<br>
                            +    if (static_cast<std::size_t>(last
                            - first) > N) {<br>
                            +      last = first + N;<br>
                            +      union {<br>
                            +        Float value;<br>
                            +        char buf[sizeof(Float)];<br>
                            +      };<br>
                            +      const char *t = first;<br>
                            +      char *e = buf;<br>
                            +      for (; t != last; ++t, ++e) {<br>
                            +        unsigned d1 = isdigit(*t) ?
                            static_cast<unsigned>(*t - '0')<br>
                            +                                  :
                            static_cast<unsigned>(*t - 'a' + 10);<br>
                            +        ++t;<br>
                            +        unsigned d0 = isdigit(*t) ?
                            static_cast<unsigned>(*t - '0')<br>
                            +                                  :
                            static_cast<unsigned>(*t - 'a' + 10);<br>
                            +        *e = static_cast<char>((d1
                            << 4) + d0);<br>
                            +      }<br>
                            +#if __BYTE_ORDER__ ==
                            __ORDER_LITTLE_ENDIAN__<br>
                            +      std::reverse(buf, e);<br>
                            +#endif<br>
                            +      char
                            num[FloatData<Float>::max_dema<wbr>ngled_size]
                            = {0};<br>
                            +      int n = snprintf(num, sizeof(num),
                            FloatData<Float>::spec, value);<br>
                            +      s += StringView(num, num + n);<br>
                            +    }<br>
                            +  }<br>
                            +};<br>
                            +<br>
                             template <std::size_t N><br>
                             class arena<br>
                             {<br>
                            @@ -148,168 +1511,118 @@ operator!=(const
                            short_alloc<T, N>& x, c<br>
                                 return !(x == y);<br>
                             }<br>
                            <br>
                            -template <class T><br>
                            -class malloc_alloc<br>
                            -{<br>
                            -public:<br>
                            -    typedef T value_type;<br>
                            -    typedef T& reference;<br>
                            -    typedef const T& const_reference;<br>
                            -    typedef T* pointer;<br>
                            -    typedef const T* const_pointer;<br>
                            -    typedef std::size_t size_type;<br>
                            -    typedef std::ptrdiff_t difference_type;<br>
                            -<br>
                            -    malloc_alloc() = default;<br>
                            -    template <class U>
                            malloc_alloc(const
                            malloc_alloc<U>&) noexcept {}<br>
                            -<br>
                            -    T* allocate(std::size_t n)<br>
                            -    {<br>
                            -        return
                            static_cast<T*>(std::malloc(n*<wbr>sizeof(T)));<br>
                            -    }<br>
                            -    void deallocate(T* p, std::size_t)
                            noexcept<br>
                            -    {<br>
                            -        std::free(p);<br>
                            -    }<br>
                            -<br>
                            -    template <class U> struct rebind
                            { using other = malloc_alloc<U>; };<br>
                            -    template <class U, class... Args><br>
                            -    void construct(U* p, Args&&...
                            args)<br>
                            -    {<br>
                            -        ::new ((void*)p)
                            U(std::forward<Args>(args)...)<wbr>;<br>
                            -    }<br>
                            -    void destroy(T* p)<br>
                            -    {<br>
                            -        p->~T();<br>
                            -    }<br>
                            -};<br>
                            -<br>
                            -template <class T, class U><br>
                            -inline<br>
                            -bool<br>
                            -operator==(const
                            malloc_alloc<T>&, const
                            malloc_alloc<U>&) noexcept<br>
                            -{<br>
                            -    return true;<br>
                            -}<br>
                            -<br>
                            -template <class T, class U><br>
                            -inline<br>
                            -bool<br>
                            -operator!=(const malloc_alloc<T>&
                            x, const malloc_alloc<U>& y)
                            noexcept<br>
                            -{<br>
                            -    return !(x == y);<br>
                            -}<br>
                            -<br>
                             const size_t bs = 4 * 1024;<br>
                             template <class T> using Alloc =
                            short_alloc<T, bs>;<br>
                             template <class T> using Vector =
                            std::vector<T, Alloc<T>>;<br>
                            <br>
                            -template <class StrT><br>
                            -struct string_pair<br>
                            -{<br>
                            -    StrT first;<br>
                            -    StrT second;<br>
                            +class BumpPointerAllocator {<br>
                            +  struct BlockMeta {<br>
                            +    BlockMeta* Next;<br>
                            +    size_t Current;<br>
                            +  };<br>
                            +<br>
                            +  static constexpr size_t AllocSize = 4096;<br>
                            +  static constexpr size_t UsableAllocSize =
                            AllocSize - sizeof(BlockMeta);<br>
                            +<br>
                            +  alignas(16) char
                            InitialBuffer[AllocSize];<br>
                            +  BlockMeta* BlockList = nullptr;<br>
                            +<br>
                            +  void grow() {<br>
                            +    char* NewMeta = new char[AllocSize];<br>
                            +    BlockList = new (NewMeta)
                            BlockMeta{BlockList, 0};<br>
                            +  }<br>
                            +<br>
                            +  void* allocateMassive(size_t NBytes) {<br>
                            +    NBytes += sizeof(BlockMeta);<br>
                            +    BlockMeta* NewMeta =
                            reinterpret_cast<BlockMeta*>(n<wbr>ew
                            char[NBytes]);<br>
                            +    BlockList->Next = new (NewMeta)
                            BlockMeta{BlockList->Next, 0};<br>
                            +    return static_cast<void*>(NewMeta
                            + 1);<br>
                            +  }<br>
                            <br>
                            -    string_pair() = default;<br>
                            -    string_pair(StrT f) :
                            first(std::move(f)) {}<br>
                            -    string_pair(StrT f, StrT s)<br>
                            -        : first(std::move(f)),
                            second(std::move(s)) {}<br>
                            -    template <size_t N><br>
                            -        string_pair(const char (&s)[N])
                            : first(s, N-1) {}<br>
                            +public:<br>
                            +  BumpPointerAllocator()<br>
                            +      : BlockList(new (InitialBuffer)
                            BlockMeta{nullptr, 0}) {}<br>
                            <br>
                            -    size_t size() const {return
                            first.size() + second.size();}<br>
                            -    bool empty() const { return
                            first.empty() && second.empty(); }<br>
                            -    StrT full() const {return first +
                            second;}<br>
                            -    StrT move_full() {return
                            std::move(first) + std::move(second);}<br>
                            +  void* allocate(size_t N) {<br>
                            +    N = (N + 15u) & ~15u;<br>
                            +    if (N + BlockList->Current >=
                            UsableAllocSize) {<br>
                            +      if (N > UsableAllocSize)<br>
                            +        return allocateMassive(N);<br>
                            +      grow();<br>
                            +    }<br>
                            +    BlockList->Current += N;<br>
                            +    return
                            static_cast<void*>(reinterpret<wbr>_cast<char*>(BlockList
                            + 1) +<br>
                            +                             
                            BlockList->Current - N);<br>
                            +  }<br>
                            +<br>
                            +  ~BumpPointerAllocator() {<br>
                            +    while (BlockList) {<br>
                            +      BlockMeta* Tmp = BlockList;<br>
                            +      BlockList = BlockList->Next;<br>
                            +      if
                            (reinterpret_cast<char*>(Tmp) !=
                            InitialBuffer)<br>
                            +        delete[]
                            reinterpret_cast<char*>(Tmp);<br>
                            +    }<br>
                            +  }<br>
                             };<br>
                            <br>
                             struct Db<br>
                             {<br>
                            -    typedef std::basic_string<char,
                            std::char_traits<char>,<br>
                            -                             
                            malloc_alloc<char>> String;<br>
                            -    typedef
                            Vector<string_pair<String>>
                            sub_type;<br>
                            +    typedef Vector<Node*> sub_type;<br>
                                 typedef Vector<sub_type>
                            template_param_type;<br>
                                 sub_type names;<br>
                                 template_param_type subs;<br>
                                 Vector<template_param_type>
                            template_param;<br>
                            -    unsigned cv = 0;<br>
                            -    unsigned ref = 0;<br>
                            +    Qualifiers cv = QualNone;<br>
                            +    FunctionRefQual ref = FrefQualNone;<br>
                                 unsigned encoding_depth = 0;<br>
                                 bool parsed_ctor_dtor_cv = false;<br>
                                 bool tag_templates = true;<br>
                                 bool fix_forward_references = false;<br>
                                 bool try_to_parse_template_args = true;<br>
                            <br>
                            +    BumpPointerAllocator ASTAllocator;<br>
                            +<br>
                                 template <size_t N><br>
                                 Db(arena<N>& ar) :<br>
                                     names(ar),<br>
                                     subs(0, names, ar),<br>
                                     template_param(0, subs, ar)<br>
                                 {}<br>
                            -};<br>
                            -<br>
                            <br>
                            -const char* parse_type(const char* first,
                            const char* last, Db& db);<br>
                            -const char* parse_encoding(const char*
                            first, const char* last, Db& db);<br>
                            -const char* parse_name(const char* first,
                            const char* last, Db& db,<br>
                            -                       bool*
                            ends_with_template_args = 0);<br>
                            -const char* parse_expression(const char*
                            first, const char* last, Db& db);<br>
                            -const char* parse_template_args(const char*
                            first, const char* last, Db& db);<br>
                            -const char* parse_operator_name(const char*
                            first, const char* last, Db& db);<br>
                            -const char* parse_unqualified_name(const
                            char* first, const char* last, Db& db);<br>
                            -const char* parse_decltype(const char*
                            first, const char* last, Db& db);<br>
                            +    template <class T, class... Args>
                            T* make(Args&& ...args)<br>
                            +    {<br>
                            +        return new
                            (ASTAllocator.allocate(sizeof(<wbr>T)))<br>
                            +           
                            T(std::forward<Args>(args)...)<wbr>;<br>
                            +    }<br>
                            <br>
                            -template <class C><br>
                            -void<br>
                            -print_stack(const C& db)<br>
                            -{<br>
                            -    fprintf(stderr, "---------\n");<br>
                            -    fprintf(stderr, "names:\n");<br>
                            -    for (auto& s : db.names)<br>
                            -        fprintf(stderr, "{%s#%s}\n",
                            s.first.c_str(), s.second.c_str());<br>
                            -    int i = -1;<br>
                            -    fprintf(stderr, "subs:\n");<br>
                            -    for (auto& v : db.subs)<br>
                            +    template <class It> NodeArray
                            makeNodeArray(It begin, It end)<br>
                                 {<br>
                            -        if (i >= 0)<br>
                            -            fprintf(stderr, "S%i_ = {", i);<br>
                            -        else<br>
                            -            fprintf(stderr, "S_  = {");<br>
                            -        for (auto& s : v)<br>
                            -            fprintf(stderr, "{%s#%s}",
                            s.first.c_str(), s.second.c_str());<br>
                            -        fprintf(stderr, "}\n");<br>
                            -        ++i;<br>
                            -    }<br>
                            -    fprintf(stderr, "template_param:\n");<br>
                            -    for (auto& t : db.template_param)<br>
                            -    {<br>
                            -        fprintf(stderr, "--\n");<br>
                            -        i = -1;<br>
                            -        for (auto& v : t)<br>
                            -        {<br>
                            -            if (i >= 0)<br>
                            -                fprintf(stderr, "T%i_ = {",
                            i);<br>
                            -            else<br>
                            -                fprintf(stderr, "T_  = {");<br>
                            -            for (auto& s : v)<br>
                            -                fprintf(stderr, "{%s#%s}",
                            s.first.c_str(), s.second.c_str());<br>
                            -            fprintf(stderr, "}\n");<br>
                            -            ++i;<br>
                            -        }<br>
                            +        size_t sz =
                            static_cast<size_t>(end - begin);<br>
                            +        void* mem =
                            ASTAllocator.allocate(sizeof(N<wbr>ode*) *
                            sz);<br>
                            +        Node** data = new (mem) Node*[sz];<br>
                            +        std::copy(begin, end, data);<br>
                            +        return NodeArray(data, sz);<br>
                                 }<br>
                            -    fprintf(stderr, "---------\n\n");<br>
                            -}<br>
                            <br>
                            -template <class C><br>
                            -void<br>
                            -print_state(const char* msg, const char*
                            first, const char* last, const C& db)<br>
                            -{<br>
                            -    fprintf(stderr, "%s: ", msg);<br>
                            -    for (; first != last; ++first)<br>
                            -        fprintf(stderr, "%c", *first);<br>
                            -    fprintf(stderr, "\n");<br>
                            -    print_stack(db);<br>
                            -}<br>
                            +    NodeArray popTrailingNodeArray(size_t
                            FromPosition)<br>
                            +    {<br>
                            +        assert(FromPosition <=
                            names.size());<br>
                            +        NodeArray res = makeNodeArray(<br>
                            +            names.begin() +
                            (long)FromPosition, names.end());<br>
                            +        names.erase(names.begin() +
                            (long)FromPosition, names.end());<br>
                            +        return res;<br>
                            +    }<br>
                            +};<br>
                            +<br>
                            +const char* parse_type(const char* first,
                            const char* last, Db& db);<br>
                            +const char* parse_encoding(const char*
                            first, const char* last, Db& db);<br>
                            +const char* parse_name(const char* first,
                            const char* last, Db& db,<br>
                            +                       bool*
                            ends_with_template_args = 0);<br>
                            +const char* parse_expression(const char*
                            first, const char* last, Db& db);<br>
                            +const char* parse_template_args(const char*
                            first, const char* last, Db& db);<br>
                            +const char* parse_operator_name(const char*
                            first, const char* last, Db& db);<br>
                            +const char* parse_unqualified_name(const
                            char* first, const char* last, Db& db);<br>
                            +const char* parse_decltype(const char*
                            first, const char* last, Db& db);<br>
                            <br>
                             // <number> ::= [n] <non-negative
                            decimal integer><br>
                            <br>
                            @@ -339,30 +1652,30 @@ parse_number(const
                            char* first, const ch<br>
                             }<br>
                            <br>
                             template <class Float><br>
                            -struct float_data;<br>
                            +struct FloatData;<br>
                            <br>
                             template <><br>
                            -struct float_data<float><br>
                            +struct FloatData<float><br>
                             {<br>
                                 static const size_t mangled_size = 8;<br>
                                 static const size_t max_demangled_size
                            = 24;<br>
                                 static constexpr const char* spec =
                            "%af";<br>
                             };<br>
                            <br>
                            -constexpr const char*
                            float_data<float>::spec;<br>
                            +constexpr const char*
                            FloatData<float>::spec;<br>
                            <br>
                             template <><br>
                            -struct float_data<double><br>
                            +struct FloatData<double><br>
                             {<br>
                                 static const size_t mangled_size = 16;<br>
                                 static const size_t max_demangled_size
                            = 32;<br>
                                 static constexpr const char* spec =
                            "%a";<br>
                             };<br>
                            <br>
                            -constexpr const char*
                            float_data<double>::spec;<br>
                            +constexpr const char*
                            FloatData<double>::spec;<br>
                            <br>
                             template <><br>
                            -struct float_data<long double><br>
                            +struct FloatData<long double><br>
                             {<br>
                             #if defined(__mips__) &&
                            defined(__mips_n64) || defined(__aarch64__)
                            || \<br>
                                 defined(__wasm__)<br>
                            @@ -376,46 +1689,27 @@ struct
                            float_data<long double><br>
                                 static constexpr const char* spec =
                            "%LaL";<br>
                             };<br>
                            <br>
                            -constexpr const char* float_data<long
                            double>::spec;<br>
                            +constexpr const char* FloatData<long
                            double>::spec;<br>
                            <br>
                             template <class Float><br>
                             const char*<br>
                             parse_floating_number(const char* first,
                            const char* last, Db& db)<br>
                             {<br>
                            -    const size_t N =
                            float_data<Float>::mangled_siz<wbr>e;<br>
                            -    if (static_cast<std::size_t>(last
                            - first) > N)<br>
                            +    const size_t N =
                            FloatData<Float>::mangled_size<wbr>;<br>
                            +    if (static_cast<std::size_t>(last
                            - first) <= N)<br>
                            +        return first;<br>
                            +    last = first + N;<br>
                            +    const char* t = first;<br>
                            +    for (; t != last; ++t)<br>
                                 {<br>
                            -        last = first + N;<br>
                            -        union<br>
                            -        {<br>
                            -            Float value;<br>
                            -            char buf[sizeof(Float)];<br>
                            -        };<br>
                            -        const char* t = first;<br>
                            -        char* e = buf;<br>
                            -        for (; t != last; ++t, ++e)<br>
                            -        {<br>
                            -            if (!isxdigit(*t))<br>
                            -                return first;<br>
                            -            unsigned d1 = isdigit(*t) ?
                            static_cast<unsigned>(*t - '0') :<br>
                            -                                       
                            static_cast<unsigned>(*t - 'a' + 10);<br>
                            -            ++t;<br>
                            -            unsigned d0 = isdigit(*t) ?
                            static_cast<unsigned>(*t - '0') :<br>
                            -                                       
                            static_cast<unsigned>(*t - 'a' + 10);<br>
                            -            *e =
                            static_cast<char>((d1 << 4) +
                            d0);<br>
                            -        }<br>
                            -        if (*t == 'E')<br>
                            -        {<br>
                            -#if __BYTE_ORDER__ ==
                            __ORDER_LITTLE_ENDIAN__<br>
                            -            std::reverse(buf, e);<br>
                            -#endif<br>
                            -            char
                            num[float_data<Float>::max_dem<wbr>angled_size]
                            = {0};<br>
                            -            int n = snprintf(num,
                            sizeof(num), float_data<Float>::spec,
                            value);<br>
                            -            if
                            (static_cast<std::size_t>(n) >=
                            sizeof(num))<br>
                            -                return first;<br>
                            -            db.names.push_back(Db::String(<wbr>num,
                            static_cast<std::size_t>(n)));<br>
                            -            first = t+1;<br>
                            -        }<br>
                            +        if (!isxdigit(*t))<br>
                            +            return first;<br>
                            +    }<br>
                            +    if (*t == 'E')<br>
                            +    {<br>
                            +        db.names.push_back(<br>
                            +           
                            db.make<FloatExpr<Float>>(Stri<wbr>ngView(first,
                            t)));<br>
                            +        first = t + 1;<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            @@ -440,11 +1734,11 @@
                            parse_source_name(const char* first, con<br>
                                         }<br>
                                         if
                            (static_cast<size_t>(last - t) >=
                            n)<br>
                                         {<br>
                            -                Db::String r(t, n);<br>
                            +                StringView r(t, t + n);<br>
                                             if (r.substr(0, 10) ==
                            "_GLOBAL__N")<br>
                            -                   
                            db.names.push_back("(anonymous namespace)");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("(anonymous
                            namespace)"));<br>
                                             else<br>
                            -                   
                            db.names.push_back(std::move(r<wbr>));<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>(r));<br>
                                             first = t + n;<br>
                                         }<br>
                                     }<br>
                            @@ -473,27 +1767,32 @@
                            parse_substitution(const char* first, co<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'a':<br>
                            -               
                            db.names.push_back("std::alloc<wbr>ator");<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("std::basic<wbr>_string");<br>
                            +                db.names.push_back(<br>
                            +                   
                            db.make<SpecialSubstitution>(S<wbr>pecialSubKind::basic_string));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 's':<br>
                            -               
                            db.names.push_back("std::strin<wbr>g");<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("std::istre<wbr>am");<br>
                            +               
                            db.names.push_back(db.make<Spe<wbr>cialSubstitution>(SpecialSubKi<wbr>nd::istream));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'o':<br>
                            -               
                            db.names.push_back("std::ostre<wbr>am");<br>
                            +               
                            db.names.push_back(db.make<Spe<wbr>cialSubstitution>(SpecialSubKi<wbr>nd::ostream));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'd':<br>
                            -               
                            db.names.push_back("std::iostr<wbr>eam");<br>
                            +               
                            db.names.push_back(db.make<Spe<wbr>cialSubstitution>(SpecialSubKi<wbr>nd::iostream));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case '_':<br>
                            @@ -578,87 +1877,87 @@
                            parse_builtin_type(const char* first, co<br>
                                     switch (*first)<br>
                                     {<br>
                                     case 'v':<br>
                            -            db.names.push_back("void");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("void"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'w':<br>
                            -            db.names.push_back("wchar_t");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("wchar_t"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'b':<br>
                            -            db.names.push_back("bool");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("bool"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'c':<br>
                            -            db.names.push_back("char");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("char"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'a':<br>
                            -            db.names.push_back("signed
                            char");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("signed
                            char"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'h':<br>
                            -            db.names.push_back("unsigned
                            char");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            char"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 's':<br>
                            -            db.names.push_back("short");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("short"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 't':<br>
                            -            db.names.push_back("unsigned
                            short");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            short"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'i':<br>
                            -            db.names.push_back("int");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("int"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'j':<br>
                            -            db.names.push_back("unsigned
                            int");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            int"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'l':<br>
                            -            db.names.push_back("long");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("long"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'm':<br>
                            -            db.names.push_back("unsigned
                            long");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            long"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'x':<br>
                            -            db.names.push_back("long
                            long");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("long
                            long"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'y':<br>
                            -            db.names.push_back("unsigned
                            long long");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            long long"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'n':<br>
                            -            db.names.push_back("__int128")<wbr>;<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("__int128"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'o':<br>
                            -            db.names.push_back("unsigned
                            __int128");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("unsigned
                            __int128"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'f':<br>
                            -            db.names.push_back("float");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("float"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'd':<br>
                            -            db.names.push_back("double");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("double"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'e':<br>
                            -            db.names.push_back("long
                            double");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("long
                            double"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'g':<br>
                            -            db.names.push_back("__float128<wbr>");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("__float128"));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'z':<br>
                            -            db.names.push_back("...");<br>
                            +           
                            db.names.push_back(db.make<Nam<wbr>eType>("..."));<br>
                                         ++first;<br>
                                         break;<br>
                                     case 'u':<br>
                            @@ -674,39 +1973,39 @@
                            parse_builtin_type(const char* first, co<br>
                                             switch (first[1])<br>
                                             {<br>
                                             case 'd':<br>
                            -                   
                            db.names.push_back("decimal64"<wbr>);<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("decimal64"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'e':<br>
                            -                   
                            db.names.push_back("decimal128<wbr>");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("decimal128"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'f':<br>
                            -                   
                            db.names.push_back("decimal32"<wbr>);<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("decimal32"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'h':<br>
                            -                   
                            db.names.push_back("decimal16"<wbr>);<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("decimal16"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'i':<br>
                            -                   
                            db.names.push_back("char32_t")<wbr>;<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("char32_t"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 's':<br>
                            -                   
                            db.names.push_back("char16_t")<wbr>;<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("char16_t"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'a':<br>
                            -                   
                            db.names.push_back("auto");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("auto"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'c':<br>
                            -                   
                            db.names.push_back("decltype(a<wbr>uto)");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("decltype(auto)"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             case 'n':<br>
                            -                   
                            db.names.push_back("std::nullp<wbr>tr_t");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("std::nullptr_t"));<br>
                                                 first += 2;<br>
                                                 break;<br>
                                             }<br>
                            @@ -717,27 +2016,27 @@
                            parse_builtin_type(const char* first, co<br>
                                 return first;<br>
                             }<br>
                            <br>
                            -// <CV-qualifiers> ::= [r] [V] [K]<br>
                            +// <CV-Qualifiers> ::= [r] [V] [K]<br>
                            <br>
                             const char*<br>
                            -parse_cv_qualifiers(const char* first,
                            const char* last, unsigned& cv)<br>
                            +parse_cv_qualifiers(const char* first,
                            const char* last, Qualifiers& cv)<br>
                             {<br>
                            -    cv = 0;<br>
                            +    cv = QualNone;<br>
                                 if (first != last)<br>
                                 {<br>
                                     if (*first == 'r')<br>
                                     {<br>
                            -            cv |= 4;<br>
                            +            addQualifiers(cv,
                            QualRestrict);<br>
                                         ++first;<br>
                                     }<br>
                                     if (*first == 'V')<br>
                                     {<br>
                            -            cv |= 2;<br>
                            +            addQualifiers(cv,
                            QualVolatile);<br>
                                         ++first;<br>
                                     }<br>
                                     if (*first == 'K')<br>
                                     {<br>
                            -            cv |= 1;<br>
                            +            addQualifiers(cv, QualConst);<br>
                                         ++first;<br>
                                     }<br>
                                 }<br>
                            @@ -766,7 +2065,7 @@
                            parse_template_param(const char* first,<br>
                                             }<br>
                                             else<br>
                                             {<br>
                            -                   
                            db.names.push_back("T_");<br>
                            +                   
                            db.names.push_back(db.make<Nam<wbr>eType>("T_"));<br>
                                                 first += 2;<br>
                                               
                             db.fix_forward_references = true;<br>
                                             }<br>
                            @@ -791,7 +2090,8 @@
                            parse_template_param(const char* first,<br>
                                             }<br>
                                             else<br>
                                             {<br>
                            -                   
                            db.names.push_back(Db::String(<wbr>first,
                            t+1));<br>
                            +                    db.names.push_back(<br>
                            +                       
                            db.make<NameType>(StringView(f<wbr>irst,
                            t + 1)));<br>
                                                 first = t+1;<br>
                                               
                             db.fix_forward_references = true;<br>
                                             }<br>
                            @@ -816,11 +2116,12 @@
                            parse_const_cast_expr(const char* first,<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto expr =
                            db.names.back().move_full();<br>
                            +                auto from_expr =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.back() =
                            "const_cast<" +
                            db.names.back().move_full() + ">(" + expr
                            + ")";<br>
                            +                db.names.back() =
                            db.make<CastExpr>(<br>
                            +                    "const_cast",
                            db.names.back(), from_expr);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -843,11 +2144,12 @@
                            parse_dynamic_cast_expr(const char* firs<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto expr =
                            db.names.back().move_full();<br>
                            +                auto from_expr =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.back() =
                            "dynamic_cast<" +
                            db.names.back().move_full() + ">(" + expr
                            + ")";<br>
                            +                db.names.back() =
                            db.make<CastExpr>(<br>
                            +                    "dynamic_cast",
                            db.names.back(), from_expr);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -870,11 +2172,12 @@
                            parse_reinterpret_cast_expr(co<wbr>nst char*<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto expr =
                            db.names.back().move_full();<br>
                            +                auto from_expr =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.back() =
                            "reinterpret_cast<" +
                            db.names.back().move_full() + ">(" + expr
                            + ")";<br>
                            +                db.names.back() =
                            db.make<CastExpr>(<br>
                            +                    "reinterpret_cast",
                            db.names.back(), from_expr);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -897,9 +2200,10 @@
                            parse_static_cast_expr(const char* first<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto expr =
                            db.names.back().move_full();<br>
                            +                auto from_expr =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                            -                db.names.back() =
                            "static_cast<" +
                            db.names.back().move_full() + ">(" + expr
                            + ")";<br>
                            +                db.names.back() =
                            db.make<CastExpr>(<br>
                            +                    "static_cast",
                            db.names.back(), from_expr);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -933,7 +2237,8 @@
                            parse_sizeof_type_expr(const char* first<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back() = "sizeof (" +
                            db.names.back().move_full() + ")";<br>
                            +            db.names.back() =
                            db.make<EnclosingExpr>(<br>
                            +                "sizeof (",
                            db.names.back(), ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -952,7 +2257,8 @@
                            parse_sizeof_expr_expr(const char* first<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back() = "sizeof (" +
                            db.names.back().move_full() + ")";<br>
                            +            db.names.back() =
                            db.make<EnclosingExpr>(<br>
                            +                "sizeof (",
                            db.names.back(), ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -969,30 +2275,21 @@
                            parse_sizeof_param_pack_expr(c<wbr>onst
                            char*<br>
                                     size_t k0 = db.names.size();<br>
                                     const char* t =
                            parse_template_param(first+2, last, db);<br>
                                     size_t k1 = db.names.size();<br>
                            -        if (t != first+2)<br>
                            +        if (t != first+2 && k0
                            <= k1)<br>
                                     {<br>
                            -            Db::String tmp("sizeof...(");<br>
                            -            size_t k = k0;<br>
                            -            if (k != k1)<br>
                            -            {<br>
                            -                tmp +=
                            db.names[k].move_full();<br>
                            -                for (++k; k != k1; ++k)<br>
                            -                    tmp += ", " +
                            db.names[k].move_full();<br>
                            -            }<br>
                            -            tmp += ")";<br>
                            -            for (; k1 != k0; --k1)<br>
                            -                db.names.pop_back();<br>
                            -            db.names.push_back(std::move(t<wbr>mp));<br>
                            +            Node* sizeof_expr =
                            db.make<SizeofParamPackExpr>(<br>
                            +               
                            db.popTrailingNodeArray(k0));<br>
                            +            db.names.push_back(sizeof_expr<wbr>);<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            <br>
                            -// <function-param> ::= fp
                            <top-level CV-qualifiers> _           
                                                     # L == 0, first
                            parameter<br>
                            -//                  ::= fp <top-level
                            CV-qualifiers> <parameter-2
                            non-negative number> _   # L == 0, second
                            and later parameters<br>
                            -//                  ::= fL <L-1
                            non-negative number> p <top-level
                            CV-qualifiers> _         # L > 0,
                            first parameter<br>
                            -//                  ::= fL <L-1
                            non-negative number> p <top-level
                            CV-qualifiers> <parameter-2
                            non-negative number> _   # L > 0,
                            second and later parameters<br>
                            +// <function-param> ::= fp
                            <top-level CV-Qualifiers> _           
                                                     # L == 0, first
                            parameter<br>
                            +//                  ::= fp <top-level
                            CV-Qualifiers> <parameter-2
                            non-negative number> _   # L == 0, second
                            and later parameters<br>
                            +//                  ::= fL <L-1
                            non-negative number> p <top-level
                            CV-Qualifiers> _         # L > 0,
                            first parameter<br>
                            +//                  ::= fL <L-1
                            non-negative number> p <top-level
                            CV-Qualifiers> <parameter-2
                            non-negative number> _   # L > 0,
                            second and later parameters<br>
                            <br>
                             const char*<br>
                             parse_function_param(const char* first,
                            const char* last, Db& db)<br>
                            @@ -1001,18 +2298,19 @@
                            parse_function_param(const char* first,<br>
                                 {<br>
                                     if (first[1] == 'p')<br>
                                     {<br>
                            -            unsigned cv;<br>
                            +            Qualifiers cv;<br>
                                         const char* t =
                            parse_cv_qualifiers(first+2, last, cv);<br>
                                         const char* t1 =
                            parse_number(t, last);<br>
                                         if (t1 != last && *t1
                            == '_')<br>
                                         {<br>
                            -                db.names.push_back("fp" +
                            Db::String(t, t1));<br>
                            +                db.names.push_back(<br>
                            +                   
                            db.make<FunctionParam>(StringV<wbr>iew(t,
                            t1)));<br>
                                             first = t1+1;<br>
                                         }<br>
                                     }<br>
                                     else if (first[1] == 'L')<br>
                                     {<br>
                            -            unsigned cv;<br>
                            +            Qualifiers cv;<br>
                                         const char* t0 =
                            parse_number(first+2, last);<br>
                                         if (t0 != last && *t0
                            == 'p')<br>
                                         {<br>
                            @@ -1021,7 +2319,8 @@
                            parse_function_param(const char* first,<br>
                                             const char* t1 =
                            parse_number(t, last);<br>
                                             if (t1 != last &&
                            *t1 == '_')<br>
                                             {<br>
                            -                    db.names.push_back("fp"
                            + Db::String(t, t1));<br>
                            +                    db.names.push_back(<br>
                            +                       
                            db.make<FunctionParam>(StringV<wbr>iew(t,
                            t1)));<br>
                                                 first = t1+1;<br>
                                             }<br>
                                         }<br>
                            @@ -1042,7 +2341,8 @@
                            parse_sizeof_function_param_pa<wbr>ck_expr(co<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back() = "sizeof...("
                            + db.names.back().move_full() + ")";<br>
                            +            db.names.back() =
                            db.make<EnclosingExpr>(<br>
                            +                "sizeof...(",
                            db.names.back(), ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -1066,7 +2366,8 @@
                            parse_typeid_expr(const char* first, con<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back() = "typeid(" +
                            db.names.back().move_full() + ")";<br>
                            +            db.names.back() =
                            db.make<EnclosingExpr>(<br>
                            +                "typeid(", db.names.back(),
                            ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -1085,7 +2386,7 @@ parse_throw_expr(const
                            char* first, cons<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back() = "throw " +
                            db.names.back().move_full();<br>
                            +            db.names.back() =
                            db.make<ThrowExpr>(<a
                              href="http://db.names.ba" target="_blank"
                              moz-do-not-send="true">db.names.ba</a><wbr>ck());<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -1107,9 +2408,10 @@
                            parse_dot_star_expr(const char* first, c<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto expr =
                            db.names.back().move_full();<br>
                            +                auto rhs_expr =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                            -                db.names.back().first +=
                            ".*" + expr;<br>
                            +                db.names.back() =
                            db.make<MemberExpr>(<br>
                            +                    db.names.back(), ".*",
                            rhs_expr);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -1132,9 +2434,10 @@ parse_simple_id(const
                            char* first, const<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto args =
                            db.names.back().move_full();<br>
                            +                auto args =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                            -                db.names.back().first +=
                            std::move(args);<br>
                            +                db.names.back() =<br>
                            +                   
                            db.make<NameWithTemplateArgs>(<wbr>db.names.back(),
                            args);<br>
                                         }<br>
                                         first = t1;<br>
                                     }<br>
                            @@ -1196,7 +2499,8 @@
                            parse_unresolved_type(const char* first,<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first.insert(0<wbr>,
                            "std::");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<StdQualifiedName>(db.n<wbr>ames.back());<br>
                                                   
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                     first = t;<br>
                                                 }<br>
                            @@ -1223,7 +2527,7 @@
                            parse_destructor_name(const char* first,<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back().first.insert(0<wbr>,
                            "~");<br>
                            +            db.names.back() =
                            db.make<DtorName>(db.names.bac<wbr>k());<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -1255,9 +2559,11 @@
                            parse_base_unresolved_name(con<wbr>st char*
                            f<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto args =
                            db.names.back().move_full();<br>
                            +                        auto args =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                       
                            db.names.back().first += std::move(args);<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<NameWithTemplateArgs>(<br>
                            +                               
                            db.names.back(), args);<br>
                                                 }<br>
                                             }<br>
                                         }<br>
                            @@ -1281,9 +2587,11 @@
                            parse_base_unresolved_name(con<wbr>st char*
                            f<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto args =
                            db.names.back().move_full();<br>
                            +                        auto args =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                       
                            db.names.back().first += std::move(args);<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<NameWithTemplateArgs>(<br>
                            +                               
                            db.names.back(), args);<br>
                                                 }<br>
                                             }<br>
                                         }<br>
                            @@ -1331,7 +2639,8 @@
                            parse_unresolved_name(const char* first,<br>
                                         {<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -               
                            db.names.back().first.insert(0<wbr>, "::");<br>
                            +                db.names.back() =<br>
                            +                   
                            db.make<GlobalQualifiedName>(d<wbr>b.names.back());<br>
                                         }<br>
                                         first = t2;<br>
                                     }<br>
                            @@ -1349,9 +2658,10 @@
                            parse_unresolved_name(const char* first,<br>
                                             {<br>
                                                 if (db.names.size()
                            < 2)<br>
                                                     return first;<br>
                            -                    auto args =
                            db.names.back().move_full();<br>
                            +                    auto args =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    db.names.back().first
                            += std::move(args);<br>
                            +                    db.names.back() =
                            db.make<NameWithTemplateArgs>(<br>
                            +                        db.names.back(),
                            args);<br>
                                                 t = t1;<br>
                                                 if (t == last)<br>
                                                 {<br>
                            @@ -1364,9 +2674,10 @@
                            parse_unresolved_name(const char* first,<br>
                                                 t1 =
                            parse_unresolved_qualifier_lev<wbr>el(t,
                            last, db);<br>
                                                 if (t1 == t || t1 ==
                            last || db.names.size() < 2)<br>
                                                     return first;<br>
                            -                    auto s =
                            db.names.back().move_full();<br>
                            +                    auto s =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    db.names.back().first
                            += "::" + std::move(s);<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            s);<br>
                                                 t = t1;<br>
                                             }<br>
                                             ++t;<br>
                            @@ -1379,9 +2690,10 @@
                            parse_unresolved_name(const char* first,<br>
                                             }<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto s =
                            db.names.back().move_full();<br>
                            +                auto s = db.names.back();<br>
                                             db.names.pop_back();<br>
                            -                db.names.back().first +=
                            "::" + std::move(s);<br>
                            +                db.names.back() =<br>
                            +                   
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            s);<br>
                                             first = t1;<br>
                                         }<br>
                                         else<br>
                            @@ -1396,9 +2708,11 @@
                            parse_unresolved_name(const char* first,<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto args =
                            db.names.back().move_full();<br>
                            +                        auto args =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                       
                            db.names.back().first += std::move(args);<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<NameWithTemplateArgs>(<br>
                            +                               
                            db.names.back(), args);<br>
                                                     t = t1;<br>
                                                 }<br>
                                                 t1 =
                            parse_base_unresolved_name(t, last, db);<br>
                            @@ -1410,9 +2724,10 @@
                            parse_unresolved_name(const char* first,<br>
                                                 }<br>
                                                 if (db.names.size()
                            < 2)<br>
                                                     return first;<br>
                            -                    auto s =
                            db.names.back().move_full();<br>
                            +                    auto s =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    db.names.back().first
                            += "::" + std::move(s);<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            s);<br>
                                                 first = t1;<br>
                                             }<br>
                                             else<br>
                            @@ -1425,16 +2740,19 @@
                            parse_unresolved_name(const char* first,<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first.insert(0<wbr>, "::");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<GlobalQualifiedName>(<br>
                            +                               
                            db.names.back());<br>
                                                 }<br>
                                                 while (*t != 'E')<br>
                                                 {<br>
                                                     t1 =
                            parse_unresolved_qualifier_lev<wbr>el(t,
                            last, db);<br>
                                                     if (t1 == t || t1
                            == last || db.names.size() < 2)<br>
                                                         return first;<br>
                            -                        auto s =
                            db.names.back().move_full();<br>
                            +                        auto s =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                       
                            db.names.back().first += "::" +
                            std::move(s);<br>
                            +                        db.names.back() =
                            db.make<QualifiedName>(<br>
                            +                           
                            db.names.back(), s);<br>
                                                     t = t1;<br>
                                                 }<br>
                                                 ++t;<br>
                            @@ -1447,9 +2765,10 @@
                            parse_unresolved_name(const char* first,<br>
                                                 }<br>
                                                 if (db.names.size()
                            < 2)<br>
                                                     return first;<br>
                            -                    auto s =
                            db.names.back().move_full();<br>
                            +                    auto s =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    db.names.back().first
                            += "::" + std::move(s);<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            s);<br>
                                                 first = t1;<br>
                                             }<br>
                                         }<br>
                            @@ -1473,11 +2792,11 @@ parse_dot_expr(const
                            char* first, const<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto name =
                            db.names.back().move_full();<br>
                            +                auto name =
                            db.names.back();<br>
                                             db.names.pop_back();<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.back().first +=
                            "." + name;<br>
                            +                db.names.back() =
                            db.make<MemberExpr>(db.names.b<wbr>ack(),
                            ".", name);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -1493,44 +2812,25 @@
                            parse_call_expr(const char* first, const<br>
                                 if (last - first >= 4 &&
                            first[0] == 'c' && first[1] == 'l')<br>
                                 {<br>
                                     const char* t =
                            parse_expression(first+2, last, db);<br>
                            -        if (t != first+2)<br>
                            +        if (t == last || t == first + 2 ||
                            db.names.empty())<br>
                            +            return first;<br>
                            +        Node* callee = db.names.back();<br>
                            +        db.names.pop_back();<br>
                            +        size_t args_begin =
                            db.names.size();<br>
                            +        while (*t != 'E')<br>
                                     {<br>
                            -            if (t == last)<br>
                            -                return first;<br>
                            -            if (db.names.empty())<br>
                            -                return first;<br>
                            -            db.names.back().first +=
                            db.names.back().second;<br>
                            -            db.names.back().second =
                            Db::String();<br>
                            -            db.names.back().first.append("<wbr>(");<br>
                            -            bool first_expr = true;<br>
                            -            while (*t != 'E')<br>
                            -            {<br>
                            -                const char* t1 =
                            parse_expression(t, last, db);<br>
                            -                if (t1 == t || t1 == last)<br>
                            -                    return first;<br>
                            -                if (db.names.empty())<br>
                            -                    return first;<br>
                            -                auto tmp =
                            db.names.back().move_full();<br>
                            -                db.names.pop_back();<br>
                            -                if (!tmp.empty())<br>
                            -                {<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    if (!first_expr)<br>
                            -                    {<br>
                            -                       
                            db.names.back().first.append("<wbr>, ");<br>
                            -                        first_expr = false;<br>
                            -                    }<br>
                            -                   
                            db.names.back().first.append(t<wbr>mp);<br>
                            -                }<br>
                            -                t = t1;<br>
                            -            }<br>
                            -            ++t;<br>
                            -            if (db.names.empty())<br>
                            +            const char* t1 =
                            parse_expression(t, last, db);<br>
                            +            if (t1 == last || t1 == t)<br>
                                             return first;<br>
                            -            db.names.back().first.append("<wbr>)");<br>
                            -            first = t;<br>
                            +            t = t1;<br>
                                     }<br>
                            +        if (db.names.size() <
                            args_begin)<br>
                            +            return first;<br>
                            +        ++t;<br>
                            +        CallExpr* the_call =
                            db.make<CallExpr>(<br>
                            +            callee,
                            db.popTrailingNodeArray(args_b<wbr>egin));<br>
                            +        db.names.push_back(the_call);<br>
                            +        first = t;<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            @@ -1559,31 +2859,18 @@ parse_new_expr(const
                            char* first, const<br>
                                         t += 2;<br>
                                         if (t == last)<br>
                                             return first;<br>
                            -            bool has_expr_list = false;<br>
                            -            bool first_expr = true;<br>
                            +            size_t first_expr_in_list =
                            db.names.size();<br>
                            +            NodeArray ExprList, init_list;<br>
                                         while (*t != '_')<br>
                                         {<br>
                                             const char* t1 =
                            parse_expression(t, last, db);<br>
                                             if (t1 == t || t1 == last)<br>
                                                 return first;<br>
                            -                has_expr_list = true;<br>
                            -                if (!first_expr)<br>
                            -                {<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    auto tmp =
                            db.names.back().move_full();<br>
                            -                    db.names.pop_back();<br>
                            -                    if (!tmp.empty())<br>
                            -                    {<br>
                            -                        if
                            (db.names.empty())<br>
                            -                            return first;<br>
                            -                       
                            db.names.back().first.append("<wbr>, ");<br>
                            -                       
                            db.names.back().first.append(t<wbr>mp);<br>
                            -                        first_expr = false;<br>
                            -                    }<br>
                            -                }<br>
                                             t = t1;<br>
                                         }<br>
                            +            if (first_expr_in_list <
                            db.names.size())<br>
                            +                return first;<br>
                            +            ExprList =
                            db.popTrailingNodeArray(first_<wbr>expr_in_list);<br>
                                         ++t;<br>
                                         const char* t1 = parse_type(t,
                            last, db);<br>
                                         if (t1 == t || t1 == last)<br>
                            @@ -1594,65 +2881,25 @@ parse_new_expr(const
                            char* first, const<br>
                                         {<br>
                                             t += 2;<br>
                                             has_init = true;<br>
                            -                first_expr = true;<br>
                            +                size_t init_list_begin =
                            db.names.size();<br>
                                             while (*t != 'E')<br>
                                             {<br>
                                                 t1 =
                            parse_expression(t, last, db);<br>
                                                 if (t1 == t || t1 ==
                            last)<br>
                                                     return first;<br>
                            -                    if (!first_expr)<br>
                            -                    {<br>
                            -                        if
                            (db.names.empty())<br>
                            -                            return first;<br>
                            -                        auto tmp =
                            db.names.back().move_full();<br>
                            -                       
                            db.names.pop_back();<br>
                            -                        if (!tmp.empty())<br>
                            -                        {<br>
                            -                            if
                            (db.names.empty())<br>
                            -                                return
                            first;<br>
                            -                           
                            db.names.back().first.append("<wbr>, ");<br>
                            -                           
                            db.names.back().first.append(t<wbr>mp);<br>
                            -                            first_expr =
                            false;<br>
                            -                        }<br>
                            -                    }<br>
                                                 t = t1;<br>
                                             }<br>
                            -            }<br>
                            -            if (*t != 'E')<br>
                            -                return first;<br>
                            -            Db::String init_list;<br>
                            -            if (has_init)<br>
                            -            {<br>
                            -                if (db.names.empty())<br>
                            +                if (init_list_begin <
                            db.names.size())<br>
                                                 return first;<br>
                            -                init_list =
                            db.names.back().move_full();<br>
                            -                db.names.pop_back();<br>
                            +                init_list =
                            db.popTrailingNodeArray(init_l<wbr>ist_begin);<br>
                                         }<br>
                            -            if (db.names.empty())<br>
                            +            if (*t != 'E')<br>
                                             return first;<br>
                            -            auto type =
                            db.names.back().move_full();<br>
                            +            auto type = db.names.back();<br>
                                         db.names.pop_back();<br>
                            -            Db::String expr_list;<br>
                            -            if (has_expr_list)<br>
                            -            {<br>
                            -                if (db.names.empty())<br>
                            -                    return first;<br>
                            -                expr_list =
                            db.names.back().move_full();<br>
                            -                db.names.pop_back();<br>
                            -            }<br>
                            -            Db::String r;<br>
                            -            if (parsed_gs)<br>
                            -                r = "::";<br>
                            -            if (is_array)<br>
                            -                r += "[] ";<br>
                            -            else<br>
                            -                r += " ";<br>
                            -            if (has_expr_list)<br>
                            -                r += "(" + expr_list + ")
                            ";<br>
                            -            r += type;<br>
                            -            if (has_init)<br>
                            -                r += " (" + init_list +
                            ")";<br>
                            -            db.names.push_back(std::move(r<wbr>));<br>
                            +            db.names.push_back(<br>
                            +               
                            db.make<NewExpr>(ExprList, type,
                            init_list,<br>
                            +                                 
                            parsed_gs, is_array));<br>
                                         first = t+1;<br>
                                     }<br>
                                 }<br>
                            @@ -1669,10 +2916,12 @@
                            parse_conversion_expr(const char* first,<br>
                                 {<br>
                                     bool try_to_parse_template_args =
                            db.try_to_parse_template_args;<br>
                                     db.try_to_parse_template_args =
                            false;<br>
                            +        size_t type_begin =
                            db.names.size();<br>
                                     const char* t = parse_type(first+2,
                            last, db);<br>
                                     db.try_to_parse_template_args =
                            try_to_parse_template_args;<br>
                                     if (t != first+2 && t !=
                            last)<br>
                                     {<br>
                            +            size_t ExprList_begin =
                            db.names.size();<br>
                                         if (*t != '_')<br>
                                         {<br>
                                             const char* t1 =
                            parse_expression(t, last, db);<br>
                            @@ -1685,41 +2934,30 @@
                            parse_conversion_expr(const char* first,<br>
                                             ++t;<br>
                                             if (t == last)<br>
                                                 return first;<br>
                            -                if (*t == 'E')<br>
                            -                   
                            db.names.emplace_back();<br>
                            -                else<br>
                            +                if (*t != 'E')<br>
                                             {<br>
                            -                    bool first_expr = true;<br>
                                                 while (*t != 'E')<br>
                                                 {<br>
                                                     const char* t1 =
                            parse_expression(t, last, db);<br>
                                                     if (t1 == t || t1
                            == last)<br>
                                                         return first;<br>
                            -                        if (!first_expr)<br>
                            -                        {<br>
                            -                            if
                            (db.names.empty())<br>
                            -                                return
                            first;<br>
                            -                            auto tmp =
                            db.names.back().move_full();<br>
                            -                           
                            db.names.pop_back();<br>
                            -                            if
                            (!tmp.empty())<br>
                            -                            {<br>
                            -                                if
                            (db.names.empty())<br>
                            -                                    return
                            first;<br>
                            -                               
                            db.names.back().first.append("<wbr>, ");<br>
                            -                               
                            db.names.back().first.append(t<wbr>mp);<br>
                            -                                first_expr
                            = false;<br>
                            -                            }<br>
                            -                        }<br>
                                                     t = t1;<br>
                                                 }<br>
                                             }<br>
                                             ++t;<br>
                                         }<br>
                            -            if (db.names.size() < 2)<br>
                            +            if (db.names.size() <
                            ExprList_begin)<br>
                                             return first;<br>
                            -            auto tmp =
                            db.names.back().move_full();<br>
                            -            db.names.pop_back();<br>
                            -            db.names.back() = "(" +
                            db.names.back().move_full() + ")(" + tmp +
                            ")";<br>
                            +            NodeArray expressions =
                            db.makeNodeArray(<br>
                            +                db.names.begin() +
                            (long)ExprList_begin, db.names.end());<br>
                            +            NodeArray types =
                            db.makeNodeArray(<br>
                            +                db.names.begin() +
                            (long)type_begin,<br>
                            +                db.names.begin() +
                            (long)ExprList_begin);<br>
                            +            auto* conv_expr =
                            db.make<ConversionExpr>(<br>
                            +                types, expressions);<br>
                            +            db.names.erase(<br>
                            +                db.names.begin() +
                            (long)type_begin, db.names.end());<br>
                            +            db.names.push_back(conv_expr);<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -1741,10 +2979,10 @@
                            parse_arrow_expr(const char* first, cons<br>
                                         {<br>
                                             if (db.names.size() < 2)<br>
                                                 return first;<br>
                            -                auto tmp =
                            db.names.back().move_full();<br>
                            +                auto tmp = db.names.back();<br>
                                             db.names.pop_back();<br>
                            -                db.names.back().first +=
                            "->";<br>
                            -                db.names.back().first +=
                            tmp;<br>
                            +                db.names.back() =
                            db.make<MemberExpr>(<br>
                            +                    db.names.back(),
                            "->", tmp);<br>
                                             first = t1;<br>
                                         }<br>
                                     }<br>
                            @@ -1772,11 +3010,13 @@
                            parse_function_type(const char* first, c<br>
                                                 return first;<br>
                                         }<br>
                                         const char* t1 = parse_type(t,
                            last, db);<br>
                            -            if (t1 != t)<br>
                            +            if (t1 != t &&
                            !db.names.empty())<br>
                                         {<br>
                            +                Node* ret_type =
                            db.names.back();<br>
                            +                db.names.pop_back();<br>
                            +                size_t params_begin =
                            db.names.size();<br>
                                             t = t1;<br>
                            -                Db::String sig("(");<br>
                            -                int ref_qual = 0;<br>
                            +                FunctionRefQual RefQuals =
                            FrefQualNone;<br>
                                             while (true)<br>
                                             {<br>
                                                 if (t == last)<br>
                            @@ -1797,45 +3037,30 @@
                            parse_function_type(const char* first, c<br>
                                                 }<br>
                                                 if (*t == 'R'
                            && t+1 != last && t[1] ==
                            'E')<br>
                                                 {<br>
                            -                        ref_qual = 1;<br>
                            +                        RefQuals =
                            FrefQualLValue;<br>
                                                     ++t;<br>
                                                     continue;<br>
                                                 }<br>
                                                 if (*t == 'O'
                            && t+1 != last && t[1] ==
                            'E')<br>
                                                 {<br>
                            -                        ref_qual = 2;<br>
                            +                        RefQuals =
                            FrefQualRValue;<br>
                                                     ++t;<br>
                                                     continue;<br>
                                                 }<br>
                                                 size_t k0 =
                            db.names.size();<br>
                                                 t1 = parse_type(t,
                            last, db);<br>
                                                 size_t k1 =
                            db.names.size();<br>
                            -                    if (t1 == t || t1 ==
                            last)<br>
                            +                    if (t1 == t || t1 ==
                            last || k1 < k0)<br>
                                                     return first;<br>
                            -                    for (size_t k = k0; k
                            < k1; ++k)<br>
                            -                    {<br>
                            -                        if (sig.size() >
                            1)<br>
                            -                            sig += ", ";<br>
                            -                        sig +=
                            db.names[k].move_full();<br>
                            -                    }<br>
                            -                    for (size_t k = k0; k
                            < k1; ++k)<br>
                            -                       
                            db.names.pop_back();<br>
                                                 t = t1;<br>
                                             }<br>
                            -                sig += ")";<br>
                            -                switch (ref_qual)<br>
                            -                {<br>
                            -                case 1:<br>
                            -                    sig += " &";<br>
                            -                    break;<br>
                            -                case 2:<br>
                            -                    sig += " &&";<br>
                            -                    break;<br>
                            -                }<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.back().first += "
                            ";<br>
                            -               
                            db.names.back().second.insert(<wbr>0, sig);<br>
                            +                Node* fty =
                            db.make<FunctionType>(<br>
                            +                    ret_type,
                            db.popTrailingNodeArray(params<wbr>_begin));<br>
                            +                if (RefQuals)<br>
                            +                    fty =
                            db.make<FunctionRefQualType>(f<wbr>ty,
                            RefQuals);<br>
                            +                db.names.push_back(fty);<br>
                                             first = t;<br>
                                         }<br>
                                     }<br>
                            @@ -1860,17 +3085,9 @@
                            parse_pointer_to_member_type(c<wbr>onst
                            char*<br>
                                                 return first;<br>
                                             auto func =
                            std::move(db.names.back());<br>
                                             db.names.pop_back();<br>
                            -                auto class_type =
                            std::move(db.names.back());<br>
                            -                if (!func.second.empty()
                            && func.second.front() == '(')<br>
                            -                {<br>
                            -                    db.names.back().first =
                            std::move(func.first) + "(" +
                            class_type.move_full() + "::*";<br>
                            -                    db.names.back().second
                            = ")" + std::move(func.second);<br>
                            -                }<br>
                            -                else<br>
                            -                {<br>
                            -                    db.names.back().first =
                            std::move(func.first) + " " +
                            class_type.move_full() + "::*";<br>
                            -                    db.names.back().second
                            = std::move(func.second);<br>
                            -                }<br>
                            +                auto ClassType =
                            std::move(db.names.back());<br>
                            +                db.names.back() =<br>
                            +                   
                            db.make<PointerToMemberType>(C<wbr>lassType,
                            func);<br>
                                             first = t2;<br>
                                         }<br>
                                     }<br>
                            @@ -1893,9 +3110,7 @@ parse_array_type(const
                            char* first, cons<br>
                                         {<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                if
                            (db.names.back().second.substr<wbr>(0, 2) ==
                            " [")<br>
                            -                   
                            db.names.back().second.erase(0<wbr>, 1);<br>
                            -               
                            db.names.back().second.insert(<wbr>0, "
                            []");<br>
                            +                db.names.back() =
                            db.make<ArrayType>(<a
                              href="http://db.names.ba" target="_blank"
                              moz-do-not-send="true">db.names.ba</a><wbr>ck());<br>
                                             first = t;<br>
                                         }<br>
                                     }<br>
                            @@ -1909,9 +3124,9 @@ parse_array_type(const
                            char* first, cons<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                    if
                            (db.names.back().second.substr<wbr>(0, 2) ==
                            " [")<br>
                            -                       
                            db.names.back().second.erase(0<wbr>, 1);<br>
                            -                   
                            db.names.back().second.insert(<wbr>0, " [" +
                            Db::String(first+1, t) + "]");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<ArrayType>(<a
                              href="http://db.names.ba" target="_blank"
                              moz-do-not-send="true">db.names.ba</a><wbr>ck(),<br>
                            +                                           
                            StringView(first + 1, t));<br>
                                                 first = t2;<br>
                                             }<br>
                                         }<br>
                            @@ -1926,13 +3141,11 @@
                            parse_array_type(const char* first, cons<br>
                                             {<br>
                                                 if (db.names.size()
                            < 2)<br>
                                                     return first;<br>
                            -                    auto type =
                            std::move(db.names.back());<br>
                            +                    auto base_type =
                            std::move(db.names.back());<br>
                                                 db.names.pop_back();<br>
                            -                    auto expr =
                            std::move(db.names.back());<br>
                            -                    db.names.back().first =
                            std::move(type.first);<br>
                            -                    if
                            (type.second.substr(0, 2) == " [")<br>
                            -                       
                            type.second.erase(0, 1);<br>
                            -                    db.names.back().second
                            = " [" + expr.move_full() + "]" +
                            std::move(type.second);<br>
                            +                    auto dimension_expr =
                            std::move(db.names.back());<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<ArrayType>(base_type,
                            dimension_expr);<br>
                                                 first = t2;<br>
                                             }<br>
                                         }<br>
                            @@ -1959,7 +3172,8 @@ parse_decltype(const
                            char* first, const<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                    db.names.back() =
                            "decltype(" + db.names.back().move_full() +
                            ")";<br>
                            +                    db.names.back() =
                            db.make<EnclosingExpr>(<br>
                            +                        "decltype(",
                            db.names.back(), ")");<br>
                                                 first = t+1;<br>
                                             }<br>
                                         }<br>
                            @@ -1997,21 +3211,24 @@
                            parse_vector_type(const char* first, con<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first += " vector[" +
                            Db::String(num, sz) + "]";<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<VectorType>(db.names.b<wbr>ack(),<br>
                            +                                           
                                 StringView(num, num + sz));<br>
                                                     first = t1;<br>
                                                 }<br>
                                             }<br>
                                             else<br>
                                             {<br>
                                                 ++t;<br>
                            -                   
                            db.names.push_back("pixel vector[" +
                            Db::String(num, sz) + "]");<br>
                            +                    db.names.push_back(<br>
                            +                       
                            db.make<VectorType>(StringView<wbr>(num,
                            num + sz)));<br>
                                                 first = t;<br>
                                             }<br>
                                         }<br>
                                     }<br>
                                     else<br>
                                     {<br>
                            -            Db::String num;<br>
                            +            Node* num = nullptr;<br>
                                         const char* t1 = first+2;<br>
                                         if (*t1 != '_')<br>
                                         {<br>
                            @@ -2020,7 +3237,7 @@
                            parse_vector_type(const char* first, con<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                    num =
                            db.names.back().move_full();<br>
                            +                    num = db.names.back();<br>
                                                 db.names.pop_back();<br>
                                                 t1 = t;<br>
                                             }<br>
                            @@ -2032,9 +3249,15 @@
                            parse_vector_type(const char* first, con<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                    db.names.back().first
                            += " vector[" + num + "]";<br>
                            +                    if (num)<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<VectorType>(db.names.b<wbr>ack(),
                            num);<br>
                            +                    else<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<VectorType>(db.names.b<wbr>ack(),
                            StringView());<br>
                                                 first = t;<br>
                            -                }<br>
                            +                } else if (num)<br>
                            +                   
                            db.names.push_back(num);<br>
                                         }<br>
                                     }<br>
                                 }<br>
                            @@ -2050,7 +3273,7 @@
                            parse_vector_type(const char* first, con<br>
                             //        ::=
                            <template-template-param>
                            <template-args><br>
                             //        ::= <decltype><br>
                             //        ::= <substitution><br>
                            -//        ::= <CV-qualifiers>
                            <type><br>
                            +//        ::= <CV-Qualifiers>
                            <type><br>
                             //        ::= P <type>        #
                            pointer-to<br>
                             //        ::= R <type>        #
                            reference-to<br>
                             //        ::= O <type>        #
                            rvalue reference-to (C++0x)<br>
                            @@ -2075,7 +3298,7 @@ parse_type(const char*
                            first, const char<br>
                                         case 'V':<br>
                                         case 'K':<br>
                                           {<br>
                            -                unsigned cv = 0;<br>
                            +                Qualifiers cv = QualNone;<br>
                                             const char* t =
                            parse_cv_qualifiers(first, last, cv);<br>
                                             if (t != first)<br>
                                             {<br>
                            @@ -2090,35 +3313,13 @@ parse_type(const
                            char* first, const char<br>
                                                   
                             db.subs.emplace_back(db.names<wbr>.get_allocator());<br>
                                                     for (size_t k = k0;
                            k < k1; ++k)<br>
                                                     {<br>
                            -                            if
                            (is_function)<br>
                            -                            {<br>
                            -                                size_t p =
                            db.names[k].second.size();<br>
                            -                                if
                            (db.names[k].second[p - 2] == '&'
                            &&<br>
                            -                                   
                            db.names[k].second[p - 1] == '&')<br>
                            -                                    p -= 2;<br>
                            -                                else if
                            (db.names[k].second.back() == '&')<br>
                            -                                    p -= 1;<br>
                            -                                if (cv
                            & 1)<br>
                            -                                {<br>
                            -                                   
                            db.names[k].second.insert(p, " const");<br>
                            -                                    p += 6;<br>
                            -                                }<br>
                            -                                if (cv
                            & 2)<br>
                            -                                {<br>
                            -                                   
                            db.names[k].second.insert(p, " volatile");<br>
                            -                                    p += 9;<br>
                            -                                }<br>
                            -                                if (cv
                            & 4)<br>
                            -                                   
                            db.names[k].second.insert(p, " restrict");<br>
                            -                            }<br>
                            -                            else<br>
                            -                            {<br>
                            -                                if (cv
                            & 1)<br>
                            -                                   
                            db.names[k].first.append(" const");<br>
                            -                                if (cv
                            & 2)<br>
                            -                                   
                            db.names[k].first.append(" volatile");<br>
                            -                                if (cv
                            & 4)<br>
                            -                                   
                            db.names[k].first.append(" restrict");<br>
                            +                            if (cv) {<br>
                            +                                if
                            (is_function)<br>
                            +                                   
                            db.names[k] =
                            db.make<FunctionQualType>(<br>
                            +                                       
                            db.names[k], cv);<br>
                            +                                else<br>
                            +                                   
                            db.names[k] =<br>
                            +                                       
                            db.make<QualType>(db.names[k], cv);<br>
                                                         }<br>
                                                       
                             db.subs.back().push_back(db.n<wbr>ames[k]);<br>
                                                     }<br>
                            @@ -2154,7 +3355,8 @@ parse_type(const char*
                            first, const char<br>
                                                     {<br>
                                                         if
                            (db.names.empty())<br>
                                                             return
                            first;<br>
                            -                           
                            db.names.back().first.append(" complex");<br>
                            +                            db.names.back()
                            = db.make<PostfixQualifiedType>(<br>
                            +                               
                            db.names.back(), " complex");<br>
                                                         first = t;<br>
                                                       
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                     }<br>
                            @@ -2175,7 +3377,8 @@ parse_type(const char*
                            first, const char<br>
                                                     {<br>
                                                         if
                            (db.names.empty())<br>
                                                             return
                            first;<br>
                            -                           
                            db.names.back().first.append(" imaginary");<br>
                            +                            db.names.back()
                            = db.make<PostfixQualifiedType>(<br>
                            +                               
                            db.names.back(), " imaginary");<br>
                                                         first = t;<br>
                                                       
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                     }<br>
                            @@ -2200,18 +3403,8 @@ parse_type(const
                            char* first, const char<br>
                                                       
                             db.subs.emplace_back(db.names<wbr>.get_allocator());<br>
                                                         for (size_t k =
                            k0; k < k1; ++k)<br>
                                                         {<br>
                            -                                if
                            (db.names[k].second.substr(0, 2) == " [")<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += " (";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                                else if
                            (!db.names[k].second.empty() &&<br>
                            -                                         
                            db.names[k].second.front() == '(')<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += "(";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                               
                            db.names[k].first.append("&&")<wbr>;<br>
                            +                                db.names[k]
                            =<br>
                            +                                   
                            db.make<RValueReferenceType>(d<wbr>b.names[k]);<br>
                                                           
                             db.subs.back().push_back(db.n<wbr>ames[k]);<br>
                                                         }<br>
                                                         first = t;<br>
                            @@ -2228,25 +3421,7 @@ parse_type(const
                            char* first, const char<br>
                                                       
                             db.subs.emplace_back(db.names<wbr>.get_allocator());<br>
                                                         for (size_t k =
                            k0; k < k1; ++k)<br>
                                                         {<br>
                            -                                if
                            (db.names[k].second.substr(0, 2) == " [")<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += " (";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                                else if
                            (!db.names[k].second.empty() &&<br>
                            -                                         
                            db.names[k].second.front() == '(')<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += "(";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                                if
                            (first[1] != 'U' ||
                            db.names[k].first.substr(0, 12) !=
                            "objc_object<")<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first.append("*");<br>
                            -                                }<br>
                            -                                else<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first.replace(0, 11, "id");<br>
                            -                                }<br>
                            +                                db.names[k]
                            = db.make<PointerType>(db.names[<wbr>k]);<br>
                                                           
                             db.subs.back().push_back(db.n<wbr>ames[k]);<br>
                                                         }<br>
                                                         first = t;<br>
                            @@ -2263,18 +3438,8 @@ parse_type(const
                            char* first, const char<br>
                                                       
                             db.subs.emplace_back(db.names<wbr>.get_allocator());<br>
                                                         for (size_t k =
                            k0; k < k1; ++k)<br>
                                                         {<br>
                            -                                if
                            (db.names[k].second.substr(0, 2) == " [")<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += " (";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                                else if
                            (!db.names[k].second.empty() &&<br>
                            -                                         
                            db.names[k].second.front() == '(')<br>
                            -                                {<br>
                            -                                   
                            db.names[k].first += "(";<br>
                            -                                   
                            db.names[k].second.insert(0, ")");<br>
                            -                                }<br>
                            -                               
                            db.names[k].first.append("&");<br>
                            +                                db.names[k]
                            =<br>
                            +                                   
                            db.make<LValueReferenceType>(d<wbr>b.names[k]);<br>
                                                           
                             db.subs.back().push_back(db.n<wbr>ames[k]);<br>
                                                         }<br>
                                                         first = t;<br>
                            @@ -2296,10 +3461,14 @@ parse_type(const
                            char* first, const char<br>
                                                             const char*
                            t1 = parse_template_args(t, last, db);<br>
                                                             if (t1 !=
                            t)<br>
                                                             {<br>
                            -                                    auto
                            args = db.names.back().move_full();<br>
                            +                                    auto
                            args = db.names.back();<br>
                                                               
                             db.names.pop_back();<br>
                            -                                   
                            db.names.back().first += std::move(args);<br>
                            -                                   
                            db.subs.push_back(Db::sub_type<wbr>(1,
                            db.names.back(), db.names.get_allocator()));<br>
                            +                                   
                            db.names.back() = db.make<<br>
                            +                                       
                            NameWithTemplateArgs>(<br>
                            +                                       
                            db.names.back(), args);<br>
                            +                                   
                            db.subs.push_back(Db::sub_type<wbr>(<br>
                            +                                        1,
                            db.names.back(),<br>
                            +                                       
                            db.names.get_allocator()));<br>
                                                                 t = t1;<br>
                                                             }<br>
                                                         }<br>
                            @@ -2318,24 +3487,25 @@ parse_type(const
                            char* first, const char<br>
                                                             {<br>
                                                                 if
                            (db.names.size() < 2)<br>
                                                                   
                             return first;<br>
                            -                                    auto
                            type = db.names.back().move_full();<br>
                            +                                    auto
                            type = db.names.back();<br>
                                                               
                             db.names.pop_back();<br>
                            -                                    if
                            (db.names.back().first.substr(<wbr>0, 9) !=
                            "objcproto")<br>
                            +                                    if
                            (db.names.back()->K != Node::KNameType ||<br>
                            +                                       
                            !static_cast<NameType*>(db.nam<wbr>es.back())->getName().startsWi<wbr>th("objcproto"))<br>
                                                                 {<br>
                            -                                       
                            db.names.back() = type + " " +
                            db.names.back().move_full();<br>
                            +                                       
                            db.names.back() =
                            db.make<VendorExtQualType>(typ<wbr>e,
                            db.names.back());<br>
                                                                 }<br>
                                                                 else<br>
                                                                 {<br>
                            -                                       
                            auto proto = db.names.back().move_full();<br>
                            +                                       
                            auto* proto = static_cast<NameType*>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back());<br>
                                                                   
                             db.names.pop_back();<br>
                            -                                        t =
                            parse_source_name(proto.data() + 9,
                            proto.data() + proto.size(), db);<br>
                            -                                        if
                            (t != proto.data() + 9)<br>
                            +                                        t =
                            parse_source_name(proto->getNa<wbr>me().begin()
                            + 9, proto->getName().end(), db);<br>
                            +                                        if
                            (t != proto->getName().begin() + 9)<br>
                                                                     {<br>
                            -                                           
                            db.names.back() = type + "<" +
                            db.names.back().move_full() + ">";<br>
                            +                                           
                            db.names.back() =
                            db.make<ObjCProtoName>(type,
                            db.names.back());<br>
                                                                     }<br>
                                                                   
                             else<br>
                                                                     {<br>
                            -                                           
                            db.names.push_back(type + " " + proto);<br>
                            +                                           
                            db.names.push_back(db.make<Ven<wbr>dorExtQualType>(type,
                            proto));<br>
                                                                     }<br>
                                                                 }<br>
                                                               
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                            @@ -2371,9 +3541,11 @@ parse_type(const
                            char* first, const char<br>
                                                                 {<br>
                                                                     if
                            (db.names.size() < 2)<br>
                                                                       
                             return first;<br>
                            -                                       
                            auto template_args =
                            db.names.back().move_full();<br>
                            +                                       
                            auto template_args = db.names.back();<br>
                                                                   
                             db.names.pop_back();<br>
                            -                                       
                            db.names.back().first += template_args;<br>
                            +                                       
                            db.names.back() = db.make<<br>
                            +                                         
                            NameWithTemplateArgs>(<br>
                            +                                           
                              db.names.back(), template_args);<br>
                                                                     //
                            Need to create substitution for
                            <template-template-param>
                            <template-args><br>
                                                                   
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                                   
                             first = t;<br>
                            @@ -2520,20 +3692,20 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'a':<br>
                            -               
                            db.names.push_back("operator&&<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator&&"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'd':<br>
                                         case 'n':<br>
                            -               
                            db.names.push_back("operator&"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator&"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'N':<br>
                            -               
                            db.names.push_back("operator&=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator&="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'S':<br>
                            -               
                            db.names.push_back("operator="<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2542,15 +3714,15 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'l':<br>
                            -               
                            db.names.push_back("operator()<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator()"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'm':<br>
                            -               
                            db.names.push_back("operator,"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator,"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'o':<br>
                            -               
                            db.names.push_back("operator~"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator~"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'v':<br>
                            @@ -2563,7 +3735,8 @@
                            parse_operator_name(const char* first, c<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first.insert(0<wbr>,
                            "operator ");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<ConversionOperatorType<wbr>>(db.names.back());<br>
                                                   
                             db.parsed_ctor_dtor_cv = true;<br>
                                                     first = t;<br>
                                                 }<br>
                            @@ -2575,23 +3748,23 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'a':<br>
                            -               
                            db.names.push_back("operator delete[]");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator
                            delete[]"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'e':<br>
                            -               
                            db.names.push_back("operator*"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator*"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'l':<br>
                            -               
                            db.names.push_back("operator delete");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator
                            delete"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'v':<br>
                            -               
                            db.names.push_back("operator/"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator/"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'V':<br>
                            -               
                            db.names.push_back("operator/=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator/="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2600,15 +3773,15 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'o':<br>
                            -               
                            db.names.push_back("operator^"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator^"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'O':<br>
                            -               
                            db.names.push_back("operator^=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator^="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'q':<br>
                            -               
                            db.names.push_back("operator==<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator=="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2617,11 +3790,11 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'e':<br>
                            -               
                            db.names.push_back("operator>=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator>="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 't':<br>
                            -               
                            db.names.push_back("operator>"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator>"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2629,7 +3802,7 @@
                            parse_operator_name(const char* first, c<br>
                                     case 'i':<br>
                                         if (first[1] == 'x')<br>
                                         {<br>
                            -               
                            db.names.push_back("operator[]<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator[]"));<br>
                                             first += 2;<br>
                                         }<br>
                                         break;<br>
                            @@ -2637,7 +3810,7 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'e':<br>
                            -               
                            db.names.push_back("operator<=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator<="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'i':<br>
                            @@ -2647,21 +3820,22 @@
                            parse_operator_name(const char* first, c<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first.insert(0<wbr>,
                            "operator\"\" ");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<LiteralOperator>(<a
                              href="http://db.na" target="_blank"
                              moz-do-not-send="true">db.na</a><wbr>mes.back());<br>
                                                     first = t;<br>
                                                 }<br>
                                             }<br>
                                             break;<br>
                                         case 's':<br>
                            -               
                            db.names.push_back("operator<<<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator<<"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'S':<br>
                            -               
                            db.names.push_back("operator<<<wbr>=");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator<<="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 't':<br>
                            -               
                            db.names.push_back("operator<"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator<"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2670,23 +3844,23 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'i':<br>
                            -               
                            db.names.push_back("operator-"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator-"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'I':<br>
                            -               
                            db.names.push_back("operator-=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator-="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'l':<br>
                            -               
                            db.names.push_back("operator*"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator*"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'L':<br>
                            -               
                            db.names.push_back("operator*=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator*="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'm':<br>
                            -               
                            db.names.push_back("operator--<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator--"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2695,23 +3869,23 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'a':<br>
                            -               
                            db.names.push_back("operator new[]");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator
                            new[]"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'e':<br>
                            -               
                            db.names.push_back("operator!=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator!="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'g':<br>
                            -               
                            db.names.push_back("operator-"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator-"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 't':<br>
                            -               
                            db.names.push_back("operator!"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator!"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'w':<br>
                            -               
                            db.names.push_back("operator new");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator
                            new"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2720,15 +3894,15 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'o':<br>
                            -               
                            db.names.push_back("operator||<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator||"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'r':<br>
                            -               
                            db.names.push_back("operator|"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator|"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'R':<br>
                            -               
                            db.names.push_back("operator|=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator|="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2737,27 +3911,27 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'm':<br>
                            -               
                            db.names.push_back("operator-><wbr>*");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator->*"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'l':<br>
                            -               
                            db.names.push_back("operator+"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator+"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'L':<br>
                            -               
                            db.names.push_back("operator+=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator+="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'p':<br>
                            -               
                            db.names.push_back("operator++<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator++"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 's':<br>
                            -               
                            db.names.push_back("operator+"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator+"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 't':<br>
                            -               
                            db.names.push_back("operator-><wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator->"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2765,7 +3939,7 @@
                            parse_operator_name(const char* first, c<br>
                                     case 'q':<br>
                                         if (first[1] == 'u')<br>
                                         {<br>
                            -               
                            db.names.push_back("operator?"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator?"));<br>
                                             first += 2;<br>
                                         }<br>
                                         break;<br>
                            @@ -2773,19 +3947,19 @@
                            parse_operator_name(const char* first, c<br>
                                         switch (first[1])<br>
                                         {<br>
                                         case 'm':<br>
                            -               
                            db.names.push_back("operator%"<wbr>);<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator%"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'M':<br>
                            -               
                            db.names.push_back("operator%=<wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator%="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 's':<br>
                            -               
                            db.names.push_back("operator>><wbr>");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator>>"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'S':<br>
                            -               
                            db.names.push_back("operator>><wbr>=");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("operator>>="));<br>
                                             first += 2;<br>
                                             break;<br>
                                         }<br>
                            @@ -2798,7 +3972,8 @@
                            parse_operator_name(const char* first, c<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "operator ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<ConversionOperatorType<wbr>>(db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                         }<br>
                            @@ -2809,23 +3984,13 @@
                            parse_operator_name(const char* first, c<br>
                             }<br>
                            <br>
                             const char*<br>
                            -parse_integer_literal(const char* first,
                            const char* last, const Db::String& lit,
                            Db& db)<br>
                            +parse_integer_literal(const char* first,
                            const char* last, StringView lit, Db&
                            db)<br>
                             {<br>
                                 const char* t = parse_number(first,
                            last);<br>
                                 if (t != first && t != last
                            && *t == 'E')<br>
                                 {<br>
                            -        if (lit.size() > 3)<br>
                            -            db.names.push_back("(" + lit +
                            ")");<br>
                            -        else<br>
                            -            db.names.emplace_back();<br>
                            -        if (*first == 'n')<br>
                            -        {<br>
                            -            db.names.back().first += '-';<br>
                            -            ++first;<br>
                            -        }<br>
                            -        db.names.back().first.append(f<wbr>irst,
                            t);<br>
                            -        if (lit.size() <= 3)<br>
                            -            db.names.back().first += lit;<br>
                            +        db.names.push_back(<br>
                            +            db.make<IntegerExpr>(lit,
                            StringView(first, t)));<br>
                                     first = t+1;<br>
                                 }<br>
                                 return first;<br>
                            @@ -2858,11 +4023,11 @@
                            parse_expr_primary(const char* first, co<br>
                                             switch (first[2])<br>
                                             {<br>
                                             case '0':<br>
                            -                   
                            db.names.push_back("false");<br>
                            +                   
                            db.names.push_back(db.make<Boo<wbr>lExpr>(0));<br>
                                                 first += 4;<br>
                                                 break;<br>
                                             case '1':<br>
                            -                   
                            db.names.push_back("true");<br>
                            +                   
                            db.names.push_back(db.make<Boo<wbr>lExpr>(1));<br>
                                                 first += 4;<br>
                                                 break;<br>
                                             }<br>
                            @@ -3007,7 +4172,8 @@
                            parse_expr_primary(const char* first, co<br>
                                                     {<br>
                                                         if
                            (db.names.empty())<br>
                                                             return
                            first;<br>
                            -                            db.names.back()
                            = "(" + db.names.back().move_full() + ")" +
                            Db::String(t, n);<br>
                            +                            db.names.back()
                            = db.make<IntegerCastExpr>(<br>
                            +                               
                            db.names.back(), StringView(t, n));<br>
                                                         first = n+1;<br>
                                                         break;<br>
                                                     }<br>
                            @@ -3024,69 +4190,22 @@
                            parse_expr_primary(const char* first, co<br>
                                 return first;<br>
                             }<br>
                            <br>
                            -template <class String><br>
                            -String<br>
                            -base_name(String& s)<br>
                            +Node* maybe_change_special_sub_name(<wbr>Node*
                            inp, Db& db)<br>
                             {<br>
                            -    if (s.empty())<br>
                            -        return s;<br>
                            -    if (s == "std::string")<br>
                            -    {<br>
                            -        s = "std::basic_string<char,
                            std::char_traits<char>,
                            std::allocator<char> >";<br>
                            -        return "basic_string";<br>
                            -    }<br>
                            -    if (s == "std::istream")<br>
                            -    {<br>
                            -        s = "std::basic_istream<char,
                            std::char_traits<char> >";<br>
                            -        return "basic_istream";<br>
                            -    }<br>
                            -    if (s == "std::ostream")<br>
                            -    {<br>
                            -        s = "std::basic_ostream<char,
                            std::char_traits<char> >";<br>
                            -        return "basic_ostream";<br>
                            -    }<br>
                            -    if (s == "std::iostream")<br>
                            -    {<br>
                            -        s = "std::basic_iostream<char,
                            std::char_traits<char> >";<br>
                            -        return "basic_iostream";<br>
                            -    }<br>
                            -    const char* const pf = s.data();<br>
                            -    const char* pe = pf + s.size();<br>
                            -    if (pe[-1] == '>')<br>
                            -    {<br>
                            -        unsigned c = 1;<br>
                            -        while (true)<br>
                            -        {<br>
                            -            if (--pe == pf)<br>
                            -                return String();<br>
                            -            if (pe[-1] == '<')<br>
                            -            {<br>
                            -                if (--c == 0)<br>
                            -                {<br>
                            -                    --pe;<br>
                            -                    break;<br>
                            -                }<br>
                            -            }<br>
                            -            else if (pe[-1] == '>')<br>
                            -                ++c;<br>
                            -        }<br>
                            +    if (inp->K !=
                            Node::KSpecialSubstitution)<br>
                            +        return inp;<br>
                            +    auto Kind =
                            static_cast<SpecialSubstitutio<wbr>n*>(inp)->SSK;<br>
                            +    switch (Kind)<br>
                            +    {<br>
                            +    case SpecialSubKind::string:<br>
                            +    case SpecialSubKind::istream:<br>
                            +    case SpecialSubKind::ostream:<br>
                            +    case SpecialSubKind::iostream:<br>
                            +        return
                            db.make<ExpandedSpecialSubstit<wbr>ution>(Kind);<br>
                            +    default:<br>
                            +        break;<br>
                                 }<br>
                            -    if (pe - pf <= 1)<br>
                            -      return String();<br>
                            -    const char* p0 = pe - 1;<br>
                            -    for (; p0 != pf; --p0)<br>
                            -    {<br>
                            -        if (*p0 == ':')<br>
                            -        {<br>
                            -            ++p0;<br>
                            -            break;<br>
                            -        }<br>
                            -        if (!isalpha(*p0) &&
                            !isdigit(*p0) && *p0 != '_')<br>
                            -        {<br>
                            -            return String();<br>
                            -        }<br>
                            -    }<br>
                            -    return String(p0, pe);<br>
                            +    return inp;<br>
                             }<br>
                            <br>
                             // <ctor-dtor-name> ::= C1    #
                            complete object constructor<br>
                            @@ -3114,7 +4233,10 @@
                            parse_ctor_dtor_name(const char* first,<br>
                                         case '5':<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -               
                            db.names.push_back(base_name(d<wbr>b.names.back().first));<br>
                            +                db.names.back() =<br>
                            +                   
                            maybe_change_special_sub_name(<wbr>db.names.back(),
                            db);<br>
                            +                db.names.push_back(<br>
                            +                   
                            db.make<CtorDtorName>(db.names<wbr>.back(),
                            false));<br>
                                             first += 2;<br>
                                             db.parsed_ctor_dtor_cv =
                            true;<br>
                                             break;<br>
                            @@ -3129,7 +4251,8 @@
                            parse_ctor_dtor_name(const char* first,<br>
                                         case '5':<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -                db.names.push_back("~" +
                            base_name(db.names.back().firs<wbr>t));<br>
                            +                db.names.push_back(<br>
                            +                   
                            db.make<CtorDtorName>(db.names<wbr>.back(),
                            true));<br>
                                             first += 2;<br>
                                             db.parsed_ctor_dtor_cv =
                            true;<br>
                                             break;<br>
                            @@ -3157,106 +4280,63 @@
                            parse_unnamed_type_name(const char* firs<br>
                                     {<br>
                                     case 't':<br>
                                       {<br>
                            -            db.names.push_back(Db::String(<wbr>"'unnamed"));<br>
                                         const char* t0 = first+2;<br>
                                         if (t0 == last)<br>
                            -            {<br>
                            -                db.names.pop_back();<br>
                                             return first;<br>
                            -            }<br>
                            +            StringView count;<br>
                                         if (std::isdigit(*t0))<br>
                                         {<br>
                                             const char* t1 = t0 + 1;<br>
                                             while (t1 != last
                            && std::isdigit(*t1))<br>
                                                 ++t1;<br>
                            -               
                            db.names.back().first.append(t<wbr>0, t1);<br>
                            +                count = StringView(t0, t1);<br>
                                             t0 = t1;<br>
                                         }<br>
                            -            db.names.back().first.push_bac<wbr>k('\'');<br>
                                         if (t0 == last || *t0 != '_')<br>
                            -            {<br>
                            -                db.names.pop_back();<br>
                                             return first;<br>
                            -            }<br>
                            +           
                            db.names.push_back(db.make<Unn<wbr>amedTypeName>(count));<br>
                                         first = t0 + 1;<br>
                                       }<br>
                                         break;<br>
                                     case 'l':<br>
                                       {<br>
                            -            size_t lambda_pos =
                            db.names.size();<br>
                            -            db.names.push_back(Db::String(<wbr>"'lambda'("));<br>
                            +            size_t begin_pos =
                            db.names.size();<br>
                                         const char* t0 = first+2;<br>
                            +            NodeArray lambda_params;<br>
                                         if (first[2] == 'v')<br>
                                         {<br>
                            -                db.names.back().first +=
                            ')';<br>
                                             ++t0;<br>
                                         }<br>
                                         else<br>
                                         {<br>
                            -                bool is_first_it = true;<br>
                                             while (true)<br>
                                             {<br>
                            -                    long k0 =
                            static_cast<long>(db.names.siz<wbr>e());<br>
                                                 const char* t1 =
                            parse_type(t0, last, db);<br>
                            -                    long k1 =
                            static_cast<long>(db.names.siz<wbr>e());<br>
                                                 if (t1 == t0)<br>
                                                     break;<br>
                            -                    if (k0 >= k1)<br>
                            -                        return first;<br>
                            -                    // If the call to
                            parse_type above found a pack expansion<br>
                            -                    // substitution, then
                            multiple names could have been<br>
                            -                    // inserted into the
                            name table. Walk through the names,<br>
                            -                    // appending each onto
                            the lambda's parameter list.<br>
                            -                   
                            std::for_each(db.names.begin() + k0,
                            db.names.begin() + k1,<br>
                            -                                 
                            [&](Db::sub_type::value_type &pair)
                            {<br>
                            -                                      if
                            (pair.empty())<br>
                            -                                         
                            return;<br>
                            -                                      auto
                            &lambda = db.names[lambda_pos].first;<br>
                            -                                      if
                            (!is_first_it)<br>
                            -                                         
                            lambda.append(", ");<br>
                            -                                     
                            is_first_it = false;<br>
                            -                                     
                            lambda.append(pair.move_full()<wbr>);<br>
                            -                                  });<br>
                            -                   
                            db.names.erase(db.names.begin(<wbr>) + k0,
                            db.names.end());<br>
                                                 t0 = t1;<br>
                                             }<br>
                            -                if (is_first_it)<br>
                            -                {<br>
                            -                    if (!db.names.empty())<br>
                            -                       
                            db.names.pop_back();<br>
                            +                if (db.names.size() <
                            begin_pos)<br>
                                                 return first;<br>
                            -                }<br>
                            -                if (db.names.empty() ||
                            db.names.size() - 1 != lambda_pos)<br>
                            -                  return first;<br>
                            -               
                            db.names.back().first.append("<wbr>)");<br>
                            +                lambda_params =
                            db.popTrailingNodeArray(begin_<wbr>pos);<br>
                                         }<br>
                                         if (t0 == last || *t0 != 'E')<br>
                            -            {<br>
                            -              if (!db.names.empty())<br>
                            -                db.names.pop_back();<br>
                            -              return first;<br>
                            -            }<br>
                            +                return first;<br>
                                         ++t0;<br>
                                         if (t0 == last)<br>
                            -            {<br>
                            -                if(!db.names.empty())<br>
                            -                  db.names.pop_back();<br>
                                             return first;<br>
                            -            }<br>
                            +            StringView count;<br>
                                         if (std::isdigit(*t0))<br>
                                         {<br>
                                             const char* t1 = t0 + 1;<br>
                                             while (t1 != last
                            && std::isdigit(*t1))<br>
                                                 ++t1;<br>
                            -               
                            db.names.back().first.insert(d<wbr>b.names.back().first.begin()+7<wbr>,
                            t0, t1);<br>
                            +                count = StringView(t0, t1);<br>
                                             t0 = t1;<br>
                                         }<br>
                                         if (t0 == last || *t0 != '_')<br>
                            -            {<br>
                            -                if(!db.names.empty())<br>
                            -                  db.names.pop_back();<br>
                                             return first;<br>
                            -            }<br>
                            +           
                            db.names.push_back(db.make<Lam<wbr>bdaTypeName>(lambda_params,
                            count));<br>
                                         first = t0 + 1;<br>
                                       }<br>
                                         break;<br>
                            @@ -3337,7 +4417,8 @@
                            parse_unscoped_name(const char* first, c<br>
                                         {<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -               
                            db.names.back().first.insert(0<wbr>,
                            "std::");<br>
                            +                db.names.back() =<br>
                            +                   
                            db.make<StdQualifiedName>(db.n<wbr>ames.back());<br>
                                         }<br>
                                         first = t1;<br>
                                     }<br>
                            @@ -3357,7 +4438,8 @@
                            parse_alignof_type(const char* first, co<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back().first =
                            "alignof (" + db.names.back().move_full() +
                            ")";<br>
                            +            db.names.back() =<br>
                            +               
                            db.make<EnclosingExpr>("aligno<wbr>f
                            (", db.names.back(), ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -3376,7 +4458,8 @@
                            parse_alignof_expr(const char* first, co<br>
                                     {<br>
                                         if (db.names.empty())<br>
                                             return first;<br>
                            -            db.names.back().first =
                            "alignof (" + db.names.back().move_full() +
                            ")";<br>
                            +            db.names.back() =<br>
                            +               
                            db.make<EnclosingExpr>("aligno<wbr>f
                            (", db.names.back(), ")");<br>
                                         first = t;<br>
                                     }<br>
                                 }<br>
                            @@ -3391,28 +4474,29 @@
                            parse_noexcept_expression(cons<wbr>t char*
                            fi<br>
                                 {<br>
                                     if (db.names.empty())<br>
                                         return first;<br>
                            -        db.names.back().first =  "noexcept
                            (" + db.names.back().move_full() + ")";<br>
                            +        db.names.back() =<br>
                            +           
                            db.make<EnclosingExpr>("noexce<wbr>pt
                            (", db.names.back(), ")");<br>
                                     first = t1;<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            <br>
                             const char*<br>
                            -parse_prefix_expression(const char* first,
                            const char* last, const Db::String& op,
                            Db& db)<br>
                            +parse_prefix_expression(const char* first,
                            const char* last, StringView op, Db& db)<br>
                             {<br>
                                 const char* t1 =
                            parse_expression(first, last, db);<br>
                                 if (t1 != first)<br>
                                 {<br>
                                     if (db.names.empty())<br>
                                         return first;<br>
                            -        db.names.back().first =  op + "(" +
                            db.names.back().move_full() + ")";<br>
                            +        db.names.back() =
                            db.make<PrefixExpr>(op,
                            db.names.back());<br>
                                     first = t1;<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            <br>
                             const char*<br>
                            -parse_binary_expression(const char* first,
                            const char* last, const Db::String& op,
                            Db& db)<br>
                            +parse_binary_expression(const char* first,
                            const char* last, StringView op, Db& db)<br>
                             {<br>
                                 const char* t1 =
                            parse_expression(first, last, db);<br>
                                 if (t1 != first)<br>
                            @@ -3422,20 +4506,12 @@
                            parse_binary_expression(const char* firs<br>
                                     {<br>
                                         if (db.names.size() < 2)<br>
                                             return first;<br>
                            -            auto op2 =
                            db.names.back().move_full();<br>
                            +            auto op2 = db.names.back();<br>
                                         db.names.pop_back();<br>
                            -            auto op1 =
                            db.names.back().move_full();<br>
                            -            auto& nm =
                            db.names.back().first;<br>
                            -            nm.clear();<br>
                            -            if (op == ">")<br>
                            -                nm += '(';<br>
                            -            nm += "(" + op1 + ") " + op + "
                            (" + op2 + ")";<br>
                            -            if (op == ">")<br>
                            -                nm += ')';<br>
                            +            auto op1 = db.names.back();<br>
                            +            db.names.back() =
                            db.make<BinaryExpr>(op1, op, op2);<br>
                                         first = t2;<br>
                                     }<br>
                            -        else if(!db.names.empty())<br>
                            -            db.names.pop_back();<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            @@ -3573,8 +4649,8 @@ parse_expression(const
                            char* first, cons<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first = (parsed_gs ?
                            Db::String("::") : Db::String()) +<br>
                            -                                         
                            "delete[] " + db.names.back().move_full();<br>
                            +                        db.names.back() =
                            db.make<DeleteExpr>(<br>
                            +                           
                            db.names.back(), parsed_gs,
                            /*is_array=*/true);<br>
                                                     first = t1;<br>
                                                 }<br>
                                             }<br>
                            @@ -3594,8 +4670,8 @@ parse_expression(const
                            char* first, cons<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first = (parsed_gs ?
                            Db::String("::") : Db::String()) +<br>
                            -                                         
                            "delete " + db.names.back().move_full();<br>
                            +                        db.names.back() =
                            db.make<DeleteExpr>(<br>
                            +                           
                            db.names.back(), parsed_gs,
                            /*is_array=*/false);<br>
                                                     first = t1;<br>
                                                 }<br>
                                             }<br>
                            @@ -3666,10 +4742,11 @@
                            parse_expression(const char* first, cons<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto op2 =
                            db.names.back().move_full();<br>
                            +                        auto op2 =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                        auto op1 =
                            db.names.back().move_full();<br>
                            -                        db.names.back() =
                            "(" + op1 + ")[" + op2 + "]";<br>
                            +                        auto op1 =
                            db.names.back();<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<ArraySubscriptExpr>(op<wbr>1,
                            op2);<br>
                                                     first = t2;<br>
                                                 }<br>
                                                 else if
                            (!db.names.empty())<br>
                            @@ -3739,7 +4816,8 @@ parse_expression(const
                            char* first, cons<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                        db.names.back() =
                            "(" + db.names.back().move_full() + ")--";<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<PostfixExpr>(db.names.<wbr>back(),
                            "--");<br>
                                                     first = t1;<br>
                                                 }<br>
                                             }<br>
                            @@ -3829,7 +4907,8 @@ parse_expression(const
                            char* first, cons<br>
                                                 {<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                        db.names.back() =
                            "(" + db.names.back().move_full() + ")++";<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<PostfixExpr>(db.names.<wbr>back(),
                            "++");<br>
                                                     first = t1;<br>
                                                 }<br>
                                             }<br>
                            @@ -3858,12 +4937,13 @@
                            parse_expression(const char* first, cons<br>
                                                     {<br>
                                                         if
                            (db.names.size() < 3)<br>
                                                             return
                            first;<br>
                            -                            auto op3 =
                            db.names.back().move_full();<br>
                            +                            auto op3 =
                            db.names.back();<br>
                                                       
                             db.names.pop_back();<br>
                            -                            auto op2 =
                            db.names.back().move_full();<br>
                            +                            auto op2 =
                            db.names.back();<br>
                                                       
                             db.names.pop_back();<br>
                            -                            auto op1 =
                            db.names.back().move_full();<br>
                            -                            db.names.back()
                            = "(" + op1 + ") ? (" + op2 + ") : (" + op3
                            + ")";<br>
                            +                            auto op1 =
                            db.names.back();<br>
                            +                            db.names.back()
                            =<br>
                            +                               
                            db.make<ConditionalExpr>(op1, op2,
                            op3);<br>
                                                         first = t3;<br>
                                                     }<br>
                                                     else<br>
                            @@ -3948,7 +5028,7 @@ parse_expression(const
                            char* first, cons<br>
                                             first =
                            parse_typeid_expr(first, last, db);<br>
                                             break;<br>
                                         case 'r':<br>
                            -               
                            db.names.push_back("throw");<br>
                            +               
                            db.names.push_back(db.make<Nam<wbr>eType>("throw"));<br>
                                             first += 2;<br>
                                             break;<br>
                                         case 'w':<br>
                            @@ -4037,7 +5117,7 @@
                            parse_template_args(const char* first, c<br>
                                     if (db.tag_templates)<br>
                                         db.template_param.back().clea<wbr>r();<br>
                                     const char* t = first+1;<br>
                            -        Db::String args("<");<br>
                            +        size_t begin_idx = db.names.size();<br>
                                     while (*t != 'E')<br>
                                     {<br>
                                         if (db.tag_templates)<br>
                            @@ -4047,7 +5127,7 @@
                            parse_template_args(const char* first, c<br>
                                         size_t k1 = db.names.size();<br>
                                         if (db.tag_templates)<br>
                                           
                             db.template_param.pop_back();<br>
                            -            if (t1 == t || t1 == last)<br>
                            +            if (t1 == t || t1 == last || k0
                            > k1)<br>
                                             return first;<br>
                                         if (db.tag_templates)<br>
                                         {<br>
                            @@ -4055,30 +5135,18 @@
                            parse_template_args(const char* first, c<br>
                                             for (size_t k = k0; k <
                            k1; ++k)<br>
                                               
                             db.template_param.back().back<wbr>().push_back(db.names[k]);<br>
                                         }<br>
                            -            for (size_t k = k0; k < k1;
                            ++k)<br>
                            -            {<br>
                            -                if (args.size() > 1)<br>
                            -                    args += ", ";<br>
                            -                args +=
                            db.names[k].move_full();<br>
                            -            }<br>
                            -            for (; k1 > k0; --k1)<br>
                            -                if (!db.names.empty())<br>
                            -                    db.names.pop_back();<br>
                                         t = t1;<br>
                                     }<br>
                                     first = t + 1;<br>
                            -        if (args.back() != '>')<br>
                            -            args += ">";<br>
                            -        else<br>
                            -            args += " >";<br>
                            -        db.names.push_back(std::move(a<wbr>rgs));<br>
                            -<br>
                            +        TemplateParams* tp =
                            db.make<TemplateParams>(<br>
                            +            db.popTrailingNodeArray(begin_<wbr>idx));<br>
                            +        db.names.push_back(tp);<br>
                                 }<br>
                                 return first;<br>
                             }<br>
                            <br>
                            -// <nested-name> ::= N
                            [<CV-qualifiers>]
                            [<ref-qualifier>] <prefix>
                            <unqualified-name> E<br>
                            -//               ::= N
                            [<CV-qualifiers>]
                            [<ref-qualifier>]
                            <template-prefix>
                            <template-args> E<br>
                            +// <nested-name> ::= N
                            [<CV-Qualifiers>]
                            [<ref-qualifier>] <prefix>
                            <unqualified-name> E<br>
                            +//               ::= N
                            [<CV-Qualifiers>]
                            [<ref-qualifier>]
                            <template-prefix>
                            <template-args> E<br>
                             //<br>
                             // <prefix> ::= <prefix>
                            <unqualified-name><br>
                             //          ::= <template-prefix>
                            <template-args><br>
                            @@ -4099,32 +5167,29 @@
                            parse_nested_name(const char* first, con<br>
                             {<br>
                                 if (first != last && *first ==
                            'N')<br>
                                 {<br>
                            -        unsigned cv;<br>
                            +        Qualifiers cv;<br>
                                     const char* t0 =
                            parse_cv_qualifiers(first+1, last, cv);<br>
                                     if (t0 == last)<br>
                                         return first;<br>
                            -        db.ref = 0;<br>
                            +        db.ref = FrefQualNone;<br>
                                     if (*t0 == 'R')<br>
                                     {<br>
                            -            db.ref = 1;<br>
                            +            db.ref = FrefQualLValue;<br>
                                         ++t0;<br>
                                     }<br>
                                     else if (*t0 == 'O')<br>
                                     {<br>
                            -            db.ref = 2;<br>
                            +            db.ref = FrefQualRValue;<br>
                                         ++t0;<br>
                                     }<br>
                            -        db.names.emplace_back();<br>
                            +        db.names.push_back(db.make<Emp<wbr>tyName>());<br>
                                     if (last - t0 >= 2 &&
                            t0[0] == 'S' && t0[1] == 't')<br>
                                     {<br>
                                         t0 += 2;<br>
                            -            db.names.back().first = "std";<br>
                            +            db.names.back() =
                            db.make<NameType>("std");<br>
                                     }<br>
                                     if (t0 == last)<br>
                            -        {<br>
                            -            db.names.pop_back();<br>
                                         return first;<br>
                            -        }<br>
                                     bool pop_subs = false;<br>
                                     bool component_ends_with_template_a<wbr>rgs
                            = false;<br>
                                     while (*t0 != 'E')<br>
                            @@ -4139,17 +5204,18 @@
                            parse_nested_name(const char* first, con<br>
                                             t1 = parse_substitution(t0,
                            last, db);<br>
                                             if (t1 != t0 && t1
                            != last)<br>
                                             {<br>
                            -                    auto name =
                            db.names.back().move_full();<br>
                            +                    auto name =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    if
                            (!db.names.back().first.empty(<wbr>))<br>
                            +                    if
                            (db.names.back()->K != Node::KEmptyName)<br>
                                                 {<br>
                            -                       
                            db.names.back().first += "::" + name;<br>
                            -                       
                            db.subs.push_back(Db::sub_type<wbr>(1,
                            db.names.back(), db.names.get_allocator()));<br>
                            +                        db.names.back() =
                            db.make<QualifiedName>(<br>
                            +                           
                            db.names.back(), name);<br>
                            +                        db.subs.push_back(<br>
                            +                            Db::sub_type(1,
                            db.names.back(),<br>
                            +                                       
                             db.names.get_allocator()));<br>
                                                 }<br>
                                                 else<br>
                            -                       
                            db.names.back().first = name;<br>
                            +                        db.names.back() =
                            name;<br>
                                                 pop_subs = true;<br>
                                                 t0 = t1;<br>
                                             }<br>
                            @@ -4160,14 +5226,13 @@
                            parse_nested_name(const char* first, con<br>
                                             t1 =
                            parse_template_param(t0, last, db);<br>
                                             if (t1 != t0 && t1
                            != last)<br>
                                             {<br>
                            -                    auto name =
                            db.names.back().move_full();<br>
                            +                    auto name =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    if
                            (!db.names.back().first.empty(<wbr>))<br>
                            -                       
                            db.names.back().first += "::" + name;<br>
                            +                    if
                            (db.names.back()->K != Node::KEmptyName)<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            name);<br>
                                                 else<br>
                            -                       
                            db.names.back().first = name;<br>
                            +                        db.names.back() =
                            name;<br>
                                               
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                 pop_subs = true;<br>
                                                 t0 = t1;<br>
                            @@ -4181,14 +5246,13 @@
                            parse_nested_name(const char* first, con<br>
                                             t1 = parse_decltype(t0,
                            last, db);<br>
                                             if (t1 != t0 && t1
                            != last)<br>
                                             {<br>
                            -                    auto name =
                            db.names.back().move_full();<br>
                            +                    auto name =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    if
                            (!db.names.back().first.empty(<wbr>))<br>
                            -                       
                            db.names.back().first += "::" + name;<br>
                            +                    if
                            (db.names.back()->K != Node::KEmptyName)<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            name);<br>
                                                 else<br>
                            -                       
                            db.names.back().first = name;<br>
                            +                        db.names.back() =
                            name;<br>
                                               
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                 pop_subs = true;<br>
                                                 t0 = t1;<br>
                            @@ -4200,12 +5264,12 @@
                            parse_nested_name(const char* first, con<br>
                                             t1 =
                            parse_template_args(t0, last, db);<br>
                                             if (t1 != t0 && t1
                            != last)<br>
                                             {<br>
                            -                    auto name =
                            db.names.back().move_full();<br>
                            +                    auto name =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    db.names.back().first
                            += name;<br>
                            -                   
                            db.subs.push_back(Db::sub_type<wbr>(1,
                            db.names.back(), db.names.get_allocator()));<br>
                            +                    db.names.back() =
                            db.make<NameWithTemplateArgs>(<br>
                            +                        db.names.back(),
                            name);<br>
                            +                   
                            db.subs.push_back(Db::sub_type<wbr>(<br>
                            +                        1, db.names.back(),
                            db.names.get_allocator()));<br>
                                                 t0 = t1;<br>
                                               
                             component_ends_with_template_<wbr>args =
                            true;<br>
                                             }<br>
                            @@ -4221,14 +5285,13 @@
                            parse_nested_name(const char* first, con<br>
                                             t1 =
                            parse_unqualified_name(t0, last, db);<br>
                                             if (t1 != t0 && t1
                            != last)<br>
                                             {<br>
                            -                    auto name =
                            db.names.back().move_full();<br>
                            +                    auto name =
                            db.names.back();<br>
                                                 db.names.pop_back();<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    if
                            (!db.names.back().first.empty(<wbr>))<br>
                            -                       
                            db.names.back().first += "::" + name;<br>
                            +                    if
                            (db.names.back()->K != Node::KEmptyName)<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            name);<br>
                                                 else<br>
                            -                       
                            db.names.back().first = name;<br>
                            +                        db.names.back() =
                            name;<br>
                                               
                             db.subs.push_back(Db::sub_typ<wbr>e(1,
                            db.names.back(), db.names.get_allocator()));<br>
                                                 pop_subs = true;<br>
                                                 t0 = t1;<br>
                            @@ -4304,7 +5367,8 @@ parse_local_name(const
                            char* first, cons<br>
                                             first =
                            parse_discriminator(t+1, last);<br>
                                             if (db.names.empty())<br>
                                                 return first;<br>
                            -               
                            db.names.back().first.append("<wbr>::string
                            literal");<br>
                            +                db.names.back() =
                            db.make<QualifiedName>(<br>
                            +                    db.names.back(),
                            db.make<NameType>("string literal"));<br>
                                             break;<br>
                                         case 'd':<br>
                                             if (++t != last)<br>
                            @@ -4319,12 +5383,12 @@
                            parse_local_name(const char* first, cons<br>
                                                     {<br>
                                                         if
                            (db.names.size() < 2)<br>
                                                             return
                            first;<br>
                            -                            auto name =
                            db.names.back().move_full();<br>
                            +                            auto name =
                            db.names.back();<br>
                                                       
                             db.names.pop_back();<br>
                                                         if
                            (db.names.empty())<br>
                                                             return
                            first;<br>
                            -                           
                            db.names.back().first.append("<wbr>::");<br>
                            -                           
                            db.names.back().first.append(n<wbr>ame);<br>
                            +                            db.names.back()
                            =<br>
                            +                               
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            name);<br>
                                                         first = t1;<br>
                                                     }<br>
                                                     else if
                            (!db.names.empty())<br>
                            @@ -4342,12 +5406,12 @@
                            parse_local_name(const char* first, cons<br>
                                                     first =
                            parse_discriminator(t1, last);<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto name =
                            db.names.back().move_full();<br>
                            +                        auto name =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first.append("<wbr>::");<br>
                            -                       
                            db.names.back().first.append(n<wbr>ame);<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<QualifiedName>(<a
                              href="http://db.name" target="_blank"
                              moz-do-not-send="true">db.name</a><wbr>s.back(),
                            name);<br>
                                                 }<br>
                                                 else if
                            (!db.names.empty())<br>
                                                   
                             db.names.pop_back();<br>
                            @@ -4411,11 +5475,13 @@ parse_name(const
                            char* first, const char<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto tmp =
                            db.names.back().move_full();<br>
                            +                        auto tmp =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first += tmp;<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<NameWithTemplateArgs>(<br>
                            +                               
                            db.names.back(), tmp);<br>
                                                     first = t1;<br>
                                                     if
                            (ends_with_template_args)<br>
                                                       
                             *ends_with_template_args = true;<br>
                            @@ -4435,11 +5501,13 @@ parse_name(const
                            char* first, const char<br>
                                                 {<br>
                                                     if (db.names.size()
                            < 2)<br>
                                                         return first;<br>
                            -                        auto tmp =
                            db.names.back().move_full();<br>
                            +                        auto tmp =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                                                     if
                            (db.names.empty())<br>
                                                         return first;<br>
                            -                       
                            db.names.back().first += tmp;<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<NameWithTemplateArgs>(<br>
                            +                               
                            db.names.back(), tmp);<br>
                                                     first = t1;<br>
                                                     if
                            (ends_with_template_args)<br>
                                                       
                             *ends_with_template_args = true;<br>
                            @@ -4527,7 +5595,8 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>, "vtable
                            for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("vtable for ",
                            db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4538,7 +5607,8 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>, "VTT
                            for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("VTT for ",
                            db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4549,7 +5619,8 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "typeinfo for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("typeinfo for ",
                            db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4560,7 +5631,8 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "typeinfo name for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("typeinfo name
                            for ", db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4578,7 +5650,9 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "covariant return thunk to ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("covarian<wbr>t
                            return thunk to ",<br>
                            +                                           
                              db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                           }<br>
                            @@ -4596,13 +5670,12 @@
                            parse_special_name(const char* first, co<br>
                                                     {<br>
                                                         if
                            (db.names.size() < 2)<br>
                                                             return
                            first;<br>
                            -                            auto left =
                            db.names.back().move_full();<br>
                            +                            auto left =
                            db.names.back();<br>
                                                       
                             db.names.pop_back();<br>
                                                         if
                            (db.names.empty())<br>
                                                             return
                            first;<br>
                            -                           
                            db.names.back().first = "construction vtable
                            for " +<br>
                            -                                           
                                    std::move(left) + "-in-" +<br>
                            -                                           
                                    db.names.back().move_full();<br>
                            +                            db.names.back()
                            = db.make<CtorVtableSpecialName><wbr>(<br>
                            +                                left,
                            db.names.back());<br>
                                                         first = t1;<br>
                                                     }<br>
                                                 }<br>
                            @@ -4614,8 +5687,10 @@
                            parse_special_name(const char* first, co<br>
                                             if (t != first + 2)<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                            -                    return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "thread-local wrapper routine for ");<br>
                            +                        return first;<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("thread-l<wbr>ocal
                            wrapper routine for ",<br>
                            +                                           
                              db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4625,8 +5700,9 @@
                            parse_special_name(const char* first, co<br>
                                             if (t != first + 2)<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                            -                    return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "thread-local initialization routine for ");<br>
                            +                        return first;<br>
                            +                    db.names.back() =
                            db.make<SpecialName>(<br>
                            +                        "thread-local
                            initialization routine for ",
                            db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4643,12 +5719,16 @@
                            parse_special_name(const char* first, co<br>
                                                     return first;<br>
                                                 if (first[1] == 'v')<br>
                                                 {<br>
                            -                       
                            db.names.back().first.insert(0<wbr>,
                            "virtual thunk to ");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<SpecialName>("virtual thunk to
                            ",<br>
                            +                                           
                                  db.names.back());<br>
                                                     first = t;<br>
                                                 }<br>
                                                 else<br>
                                                 {<br>
                            -                       
                            db.names.back().first.insert(0<wbr>,
                            "non-virtual thunk to ");<br>
                            +                        db.names.back() =<br>
                            +                           
                            db.make<SpecialName>("non-virt<wbr>ual
                            thunk to ",<br>
                            +                                           
                                  db.names.back());<br>
                                                     first = t;<br>
                                                 }<br>
                                             }<br>
                            @@ -4666,7 +5746,8 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>, "guard
                            variable for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("guard variable
                            for ", db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4677,7 +5758,9 @@
                            parse_special_name(const char* first, co<br>
                                             {<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                   
                            db.names.back().first.insert(0<wbr>,
                            "reference temporary for ");<br>
                            +                    db.names.back() =<br>
                            +                       
                            db.make<SpecialName>("referenc<wbr>e
                            temporary for ",<br>
                            +                                           
                              db.names.back());<br>
                                                 first = t;<br>
                                             }<br>
                                             break;<br>
                            @@ -4735,8 +5818,10 @@ parse_encoding(const
                            char* first, const<br>
                                         bool ends_with_template_args =
                            false;<br>
                                         const char* t =
                            parse_name(first, last, db,<br>
                                                                   
                            &ends_with_template_args);<br>
                            -            unsigned cv = <a
                              href="http://db.cv" rel="noreferrer"
                              target="_blank" moz-do-not-send="true">db.cv</a>;<br>
                            -            unsigned ref = db.ref;<br>
                            +            if (db.names.empty())<br>
                            +                return first;<br>
                            +            Qualifiers cv = <a
                              href="http://db.cv" rel="noreferrer"
                              target="_blank" moz-do-not-send="true">db.cv</a>;<br>
                            +            FunctionRefQual ref = db.ref;<br>
                                         if (t != first)<br>
                                         {<br>
                                             if (t != last && *t
                            != 'E' && *t != '.')<br>
                            @@ -4744,87 +5829,59 @@ parse_encoding(const
                            char* first, const<br>
                                                 save_value<bool>
                            sb2(db.tag_templates);<br>
                                                 db.tag_templates =
                            false;<br>
                                                 const char* t2;<br>
                            -                    Db::String ret2;<br>
                                                 if (db.names.empty())<br>
                                                     return first;<br>
                            -                    const Db::String&
                            nm = db.names.back().first;<br>
                            -                    if (nm.empty())<br>
                            +                    if (!db.names.back())<br>
                                                     return first;<br>
                            +                    Node* return_type =
                            nullptr;<br>
                                                 if
                            (!db.parsed_ctor_dtor_cv &&
                            ends_with_template_args)<br>
                                                 {<br>
                                                     t2 = parse_type(t,
                            last, db);<br>
                                                     if (t2 == t)<br>
                                                         return first;<br>
                            -                        if (db.names.size()
                            < 2)<br>
                            +                        if (db.names.size()
                            < 1)<br>
                                                         return first;<br>
                            -                        auto ret1 =
                            std::move(db.names.back().firs<wbr>t);<br>
                            -                        ret2 =
                            std::move(db.names.back().seco<wbr>nd);<br>
                            -                        if (ret2.empty())<br>
                            -                            ret1 += ' ';<br>
                            +                        return_type =
                            db.names.back();<br>
                                                   
                             db.names.pop_back();<br>
                            -                        if
                            (db.names.empty())<br>
                            -                            return first;<br>
                            -<br>
                            -                       
                            db.names.back().first.insert(0<wbr>, ret1);<br>
                                                     t = t2;<br>
                                                 }<br>
                            -                    db.names.back().first
                            += '(';<br>
                            +<br>
                            +                    Node* result = nullptr;<br>
                            +<br>
                                                 if (t != last
                            && *t == 'v')<br>
                                                 {<br>
                                                     ++t;<br>
                            +                        Node* name =
                            db.names.back();<br>
                            +                       
                            db.names.pop_back();<br>
                            +                        result =
                            db.make<TopLevelFunctionDecl>(<br>
                            +                            return_type,
                            name, NodeArray());<br>
                                                 }<br>
                                                 else<br>
                                                 {<br>
                            -                        bool first_arg =
                            true;<br>
                            +                        size_t params_begin
                            = db.names.size();<br>
                                                     while (true)<br>
                                                     {<br>
                            -                            size_t k0 =
                            db.names.size();<br>
                                                         t2 =
                            parse_type(t, last, db);<br>
                            -                            size_t k1 =
                            db.names.size();<br>
                                                         if (t2 == t)<br>
                                                             break;<br>
                            -                            if (k1 > k0)<br>
                            -                            {<br>
                            -                                Db::String
                            tmp;<br>
                            -                                for (size_t
                            k = k0; k < k1; ++k)<br>
                            -                                {<br>
                            -                                    if
                            (!tmp.empty())<br>
                            -                                        tmp
                            += ", ";<br>
                            -                                    tmp +=
                            db.names[k].move_full();<br>
                            -                                }<br>
                            -                                for (size_t
                            k = k0; k < k1; ++k) {<br>
                            -                                    if
                            (db.names.empty())<br>
                            -                                       
                            return first;<br>
                            -                                   
                            db.names.pop_back();<br>
                            -                                }<br>
                            -                                if
                            (!tmp.empty())<br>
                            -                                {<br>
                            -                                    if
                            (db.names.empty())<br>
                            -                                       
                            return first;<br>
                            -                                    if
                            (!first_arg)<br>
                            -                                       
                            db.names.back().first += ", ";<br>
                            -                                    else<br>
                            -                                       
                            first_arg = false;<br>
                            -                                   
                            db.names.back().first += tmp;<br>
                            -                                }<br>
                            -                            }<br>
                                                         t = t2;<br>
                                                     }<br>
                            +                        if (db.names.size()
                            < params_begin)<br>
                            +                            return first;<br>
                            +                        NodeArray params =<br>
                            +                           
                            db.popTrailingNodeArray(params<wbr>_begin);<br>
                            +                        if
                            (db.names.empty())<br>
                            +                            return first;<br>
                            +                        Node* name =
                            db.names.back();<br>
                            +                       
                            db.names.pop_back();<br>
                            +                        result =
                            db.make<TopLevelFunctionDecl>(<br>
                            +                            return_type,
                            name, params);<br>
                                                 }<br>
                            -                    if (db.names.empty())<br>
                            -                        return first;<br>
                            -                    db.names.back().first
                            += ')';<br>
                            -                    if (cv & 1)<br>
                            -                       
                            db.names.back().first.append(" const");<br>
                            -                    if (cv & 2)<br>
                            -                       
                            db.names.back().first.append(" volatile");<br>
                            -                    if (cv & 4)<br>
                            -                       
                            db.names.back().first.append(" restrict");<br>
                            -                    if (ref == 1)<br>
                            -                       
                            db.names.back().first.append(" &");<br>
                            -                    else if (ref == 2)<br>
                            -                       
                            db.names.back().first.append(" &&");<br>
                            -                    db.names.back().first
                            += ret2;<br>
                            +                    if (ref !=
                            FrefQualNone)<br>
                            +                        result =
                            db.make<FunctionRefQualType>(r<wbr>esult,
                            ref);<br>
                            +                    if (cv != QualNone)<br>
                            +                        result =
                            db.make<FunctionQualType>(resu<wbr>lt,
                            cv);<br>
                            +                   
                            db.names.push_back(result);<br>
                                                 first = t;<br>
                                             }<br>
                                             else<br>
                            @@ -4846,6 +5903,7 @@
                            parse_block_invoke(const char* first, co<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>
                            @@ -4868,7 +5926,9 @@
                            parse_block_invoke(const char* first, co<br>
                                     }<br>
                                     if (db.names.empty())<br>
                                         return first;<br>
                            -        db.names.back().first.insert(0<wbr>,
                            "invocation function for block in ");<br>
                            +        db.names.back() =<br>
                            +           
                            db.make<SpecialName>("invocati<wbr>on
                            function for block in ",<br>
                            +                                 
                            db.names.back());<br>
                                     first = t;<br>
                                 }<br>
                                 return first;<br>
                            @@ -4884,7 +5944,8 @@ parse_dot_suffix(const
                            char* first, cons<br>
                                 {<br>
                                     if (db.names.empty())<br>
                                         return first;<br>
                            -        db.names.back().first += " (" +
                            Db::String(first, last) + ")";<br>
                            +        db.names.back() =<br>
                            +            db.make<DotSuffix>(<a
                              href="http://db.names.ba" target="_blank"
                              moz-do-not-send="true">db.names.ba</a><wbr>ck(),
                            StringView(first, last));<br>
                                     first = last;<br>
                                 }<br>
                                 return first;<br>
                            @@ -4963,6 +6024,7 @@ __cxa_demangle(const
                            char *mangled_name,<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.fix_forward_references
                            &&<br>
                                        !db.template_param.empty()
                            && !db.template_param.front().emp<wbr>ty())<br>
                                 {<br>
                            @@ -4974,30 +6036,25 @@ __cxa_demangle(const
                            char *mangled_name,<br>
                                     if (db.fix_forward_references)<br>
                                         internal_status =
                            invalid_mangled_name;<br>
                                 }<br>
                            +<br>
                                 if (internal_status == success)<br>
                                 {<br>
                            -        size_t sz = db.names.back().size()
                            + 1;<br>
                            -        if (sz > internal_size)<br>
                            +        if (!buf)<br>
                                     {<br>
                            -            char* newbuf =
                            static_cast<char*>(std::reallo<wbr>c(buf,
                            sz));<br>
                            -            if (newbuf == nullptr)<br>
                            -            {<br>
                            -                internal_status =
                            memory_alloc_failure;<br>
                            -                buf = nullptr;<br>
                            -            }<br>
                            -            else<br>
                            -            {<br>
                            -                buf = newbuf;<br>
                            -                if (n != nullptr)<br>
                            -                    *n = sz;<br>
                            -            }<br>
                            +            internal_size = 1024;<br>
                            +            buf =
                            static_cast<char*>(std::malloc<wbr>(internal_size));<br>
                                     }<br>
                            -        if (buf != nullptr)<br>
                            +<br>
                            +        if (buf)<br>
                                     {<br>
                            -            db.names.back().first +=
                            db.names.back().second;<br>
                            -            std::memcpy(buf,
                            db.names.back().first.data(), sz-1);<br>
                            -            buf[sz-1] = char(0);<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>
                            <br>
                            Modified: libcxxabi/trunk/test/test_dema<wbr>ngle.pass.cpp<br>
                            URL: <a
href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=309340&r1=309339&r2=309340&view=diff"
                              rel="noreferrer" target="_blank"
                              moz-do-not-send="true">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxxabi/trunk/test/tes<wbr>t_demangle.pass.cpp?rev=309340<wbr>&r1=309339&r2=309340&view=diff</a><br>
                            ==============================<wbr>==============================<wbr>==================<br>
                            --- libcxxabi/trunk/test/test_dema<wbr>ngle.pass.cpp
                            (original)<br>
                            +++ libcxxabi/trunk/test/test_dema<wbr>ngle.pass.cpp
                            Thu Jul 27 17:43:49 2017<br>
                            @@ -29600,8 +29600,7 @@ const char*
                            cases[][2] =<br>
                                 {"i", "int"},<br>
                            <br>
                                 {"PKFvRiE", "void (*)(int&)
                            const"},<br>
                            -    // FIXME(compnerd) pretty print this as
                            void (*)(unsigned long &) volatile
                            &&<br>
                            -    {"PVFvRmOE", "void (*)(unsigned
                            long&)  volatile&&"},<br>
                            +    {"PVFvRmOE", "void (*)(unsigned
                            long&) volatile &&"},<br>
                                 {"PFvRmOE", "void (*)(unsigned
                            long&) &&"},<br>
                                 {"_ZTW1x", "thread-local wrapper
                            routine for x"},<br>
                                 {"_ZTHN3fooE", "thread-local
                            initialization routine for foo"},<br>
                            <br>
                            <br>
                            ______________________________<wbr>_________________<br>
                            cfe-commits mailing list<br>
                            <a href="mailto:cfe-commits@lists.llvm.org"
                              target="_blank" 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>
                  </div>
                </blockquote>
              </div>
              <br>
            </div>
          </blockquote>
        </div>
        <br>
      </div>
    </blockquote>
    <br>
  </body>
</html>