<div dir="ltr">and one more: <div><a href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2837">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">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">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">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">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">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>
          <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)"></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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">cfe-commits@lists.llvm.org</a><br>
            <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
          </blockquote>
        </div>
        <br>
      </div>
    </blockquote>
    <br>
  </div>

</blockquote></div><br></div>
</blockquote></div><br></div>