v1.1.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fcb202d..93c90d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,18 +1,33 @@
 cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
 project(demumble C CXX)
-add_definitions(-D_LIBCXXABI_FUNC_VIS=)
 
 # TODO: Also do this for gcc once gcc 4.9 is common.
-if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja" AND
-    CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-  set(CMAKE_C_FLAGS "$CMAKE_C_FLAGS -fdiagnostics-color -Wall")
-  set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -fdiagnostics-color -Wall")
+if (${UNIX} AND ${CMAKE_GENERATOR} STREQUAL "Ninja" AND
+    ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color -Wall")
 endif()
 
+# 10.9 chosen somewhat arbitrary; it's the first target where clang defaults
+# to libc++ and ld64 defaults to stripping __TEXT,__eh_frame.
+if (APPLE)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.9")
+endif()
+
+# This is apparently the simplest way to statically link the CRT in CMake:
+if (WIN32)
+  string(TOUPPER "${CMAKE_BUILD_TYPE}" build)
+  set(flag_var "CMAKE_CXX_FLAGS_${build}")
+  if(${flag_var} MATCHES "/MD")
+    string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+  endif()
+endif()
+
+include_directories(third_party/llvm/include)
 add_executable(demumble
                demumble.cc
-               third_party/wine/undname.c
-               third_party/libcxxabi/cxa_demangle.cpp
+               third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
+               third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
+               third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
 )
 set_target_properties(demumble PROPERTIES CXX_STANDARD 11
                                           CXX_STANDARD_REQUIRED ON)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..131cb1d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2010
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
index 4a28598..29f7135 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,17 @@
 `demumble` demangles both POSIX and Visual Studio symbols. It runs on both
 POSIX and Windows.
 
-    $ ./demumble _Z4funcPci
+    $ demumble _Z4funcPci
     func(char*, int)
-    $ ./demumble "?Fx_i@@YAHP6AHH@Z@Z"
-    int __cdecl Fx_i(int (__cdecl*)(int))
+    $ demumble '?Fx_i@@YAHP6AHH@Z@Z'
+    int __cdecl Fx_i(int (__cdecl *)(int))
+    
+## Download
+
+There are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the
+[releases page](https://github.com/nico/demumble/releases).
+
+## But why
 
 It has several nice features that c++filt lacks (and lacks many of c++filt's
 features I never use).
@@ -46,7 +53,7 @@
 symbols (also when running on non-Windows).
 
     $ demumble '??2@YAPEAX_K@Z'
-    void * __ptr64 __cdecl operator new(unsigned __int64)
+    void * __cdecl operator new(unsigned __int64)
     $ c++filt '??2@YAPEAX_K@Z'
     ??2@YAPEAX_K@Z
 
@@ -56,7 +63,6 @@
     $ grep '^define' bitcode-win.ll  | demumble -m | head -1
     unsigned int __cdecl v8::RoundUpToPowerOfTwo32(unsigned int)
 
-
 ## Build instructions
 
 Use cmake to build: `cmake -G Ninja && ninja`
diff --git a/demumble.cc b/demumble.cc
index 68bd73f..61e89d5 100644
--- a/demumble.cc
+++ b/demumble.cc
@@ -4,23 +4,9 @@
 #include <string.h>
 #include <algorithm>
 
-extern "C" {
-char* __cxa_demangle(const char* mangled_name,
-                     char* buf,
-                     size_t* n,
-                     int* status);
+#include "llvm/Demangle/Demangle.h"
 
-typedef void* (*malloc_func_t)(size_t);
-typedef void (*free_func_t)(void*);
-char* __unDName(char* buffer,
-                const char* mangled,
-                int buflen,
-                malloc_func_t memget,
-                free_func_t memfree,
-                unsigned short int flags);
-}
-
-const char kDemumbleVersion[] = "1.0.0";
+const char kDemumbleVersion[] = "1.1.0";
 
 static void print_help(FILE* out) {
   fprintf(out,
@@ -29,8 +15,9 @@
 "if symbols are unspecified, reads from stdin.\n"
 "\n"
 "options:\n"
-"  -m        only print mangled names that were demangled, omit other output\n"
-"  -version  print demumble version (\"%s\")\n", kDemumbleVersion);
+"  -m         only print mangled names that were demangled, omit other output\n"
+"  -u         use unbuffered output\n"
+"  --version  print demumble version (\"%s\")\n", kDemumbleVersion);
 }
 
 static bool starts_with(const char* s, const char* prefix) {
@@ -41,10 +28,10 @@
   const char* cxa_in = s;
   if (starts_with(s, "__Z") || starts_with(s, "____Z"))
     cxa_in += 1;
-  if (char* itanium = __cxa_demangle(cxa_in, NULL, NULL, NULL)) {
+  if (char* itanium = llvm::itaniumDemangle(cxa_in, NULL, NULL, NULL)) {
     printf("%s", itanium);
     free(itanium);
-  } else if (char* ms = __unDName(NULL, s, 0, &malloc, &free, 0)) {
+  } else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL)) {
     printf("%s", ms);
     free(ms);
   } else {
@@ -80,6 +67,8 @@
       return 0;
     } else if (strcmp(argv[1], "-m") == 0) {
       print_mode = kPrintMatching;
+    } else if (strcmp(argv[1], "-u") == 0) {
+      setbuf(stdout, NULL);
     } else if (strcmp(argv[1], "--version") == 0) {
       printf("%s\n", kDemumbleVersion);
       return 0;
diff --git a/demumble_test.py b/demumble_test.py
index 25d7fde..e53d467 100755
--- a/demumble_test.py
+++ b/demumble_test.py
@@ -6,7 +6,9 @@
     ('demumble hello', 'hello\n'),
     ('demumble _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'),
     ('demumble < _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'),
-    ('demumble ?Fx_i@@YAHP6AHH@Z@Z', 'int __cdecl Fx_i(int (__cdecl*)(int))\n'),
+    ('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'),
+    ('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'),
+    ('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'),
     ('demumble __Znwi', 'operator new(int)\n'),  # Strip extra _ (for OS X)
     ('demumble < __Znwi', 'operator new(int)\n'),  # Also from stdin
     ('demumble -m hi _Z1fv ho _Z1gv', 'hi\nf()\nho\ng()\n'),
@@ -35,10 +37,11 @@
     cmd[0] = os.path.join(os.path.dirname(__file__) or '.', cmd[0])
     if '<' in cmd:
         p = subprocess.Popen(cmd[:cmd.index('<')], stdin=subprocess.PIPE,
-                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                             universal_newlines=True)
         out = p.communicate(input='\n'.join(cmd[cmd.index('<') + 1:]) + '\n')[0]
     else:
-        out = subprocess.check_output(cmd)
+        out = subprocess.check_output(cmd, universal_newlines=True)
     if (out != t[1] if isinstance(t[1], str) else t[1].match(out, re.M)):
         print("`%s`: Expected '%s', got '%s'" % (t[0], t[1], out))
         status = 1
diff --git a/third_party/libcxxabi/LICENSE.txt b/third_party/libcxxabi/LICENSE.txt
deleted file mode 100644
index 1545e00..0000000
--- a/third_party/libcxxabi/LICENSE.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-http://libcxxabi.llvm.org/
-All of the code in libc++abi is dual licensed under the MIT license and the
-UIUC License (a BSD-like license).
-
-http://llvm.org/docs/DeveloperPolicy.html#license
-
-
-The University of Illinois/NCSA Open Source License (NCSA)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
-Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
-Neither the names of <Name of Development Group, Name of Institution>, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
-
-
-
-The MIT License (MIT)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/third_party/libcxxabi/cxa_demangle.cpp b/third_party/libcxxabi/cxa_demangle.cpp
deleted file mode 100644
index dfca664..0000000
--- a/third_party/libcxxabi/cxa_demangle.cpp
+++ /dev/null
@@ -1,4992 +0,0 @@
-//===-------------------------- cxa_demangle.cpp --------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#define _LIBCPP_EXTERN_TEMPLATE(...)
-#define _LIBCPP_NO_EXCEPTIONS
-
-#include <vector>
-#include <algorithm>
-#include <string>
-#include <numeric>
-#include <cstdlib>
-#include <cstring>
-#include <cctype>
-
-#ifdef _MSC_VER
-// snprintf is implemented in VS 2015
-#if _MSC_VER < 1900
-#define snprintf _snprintf_s
-#endif
-#endif
-
-namespace __cxxabiv1
-{
-
-namespace
-{
-
-enum
-{
-    unknown_error = -4,
-    invalid_args = -3,
-    invalid_mangled_name,
-    memory_alloc_failure,
-    success
-};
-
-template <class C>
-    const char* parse_type(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_encoding(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_name(const char* first, const char* last, C& db,
-                           bool* ends_with_template_args = 0);
-template <class C>
-    const char* parse_expression(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_template_args(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_operator_name(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_unqualified_name(const char* first, const char* last, C& db);
-template <class C>
-    const char* parse_decltype(const char* first, const char* last, C& db);
-
-template <class C>
-void
-print_stack(const C& db)
-{
-    fprintf(stderr, "---------\n");
-    fprintf(stderr, "names:\n");
-    for (auto& s : db.names)
-        fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str());
-    int i = -1;
-    fprintf(stderr, "subs:\n");
-    for (auto& v : db.subs)
-    {
-        if (i >= 0)
-            fprintf(stderr, "S%i_ = {", i);
-        else
-            fprintf(stderr, "S_  = {");
-        for (auto& s : v)
-            fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
-        fprintf(stderr, "}\n");
-        ++i;
-    }
-    fprintf(stderr, "template_param:\n");
-    for (auto& t : db.template_param)
-    {
-        fprintf(stderr, "--\n");
-        i = -1;
-        for (auto& v : t)
-        {
-            if (i >= 0)
-                fprintf(stderr, "T%i_ = {", i);
-            else
-                fprintf(stderr, "T_  = {");
-            for (auto& s : v)
-                fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
-            fprintf(stderr, "}\n");
-            ++i;
-        }
-    }
-    fprintf(stderr, "---------\n\n");
-}
-
-template <class C>
-void
-print_state(const char* msg, const char* first, const char* last, const C& db)
-{
-    fprintf(stderr, "%s: ", msg);
-    for (; first != last; ++first)
-        fprintf(stderr, "%c", *first);
-    fprintf(stderr, "\n");
-    print_stack(db);
-}
-
-// <number> ::= [n] <non-negative decimal integer>
-
-const char*
-parse_number(const char* first, const char* last)
-{
-    if (first != last)
-    {
-        const char* t = first;
-        if (*t == 'n')
-            ++t;
-        if (t != last)
-        {
-            if (*t == '0')
-            {
-                first = t+1;
-            }
-            else if ('1' <= *t && *t <= '9')
-            {
-                first = t+1;
-                while (first != last && std::isdigit(*first))
-                    ++first;
-            }
-        }
-    }
-    return first;
-}
-
-template <class Float>
-struct float_data;
-
-template <>
-struct float_data<float>
-{
-    static const size_t mangled_size = 8;
-    static const size_t max_demangled_size = 24;
-    static constexpr const char* spec = "%af";
-};
-
-constexpr const char* float_data<float>::spec;
-
-template <>
-struct float_data<double>
-{
-    static const size_t mangled_size = 16;
-    static const size_t max_demangled_size = 32;
-    static constexpr const char* spec = "%a";
-};
-
-constexpr const char* float_data<double>::spec;
-
-template <>
-struct float_data<long double>
-{
-#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
-    defined(__wasm__)
-    static const size_t mangled_size = 32;
-#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
-    static const size_t mangled_size = 16;
-#else
-    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms
-#endif
-    static const size_t max_demangled_size = 40;
-    static constexpr const char* spec = "%LaL";
-};
-
-constexpr const char* float_data<long double>::spec;
-
-template <class Float, class C>
-const char*
-parse_floating_number(const char* first, const char* last, C& db)
-{
-    const size_t N = float_data<Float>::mangled_size;
-    if (static_cast<std::size_t>(last - first) > N)
-    {
-        last = first + N;
-        union
-        {
-            Float value;
-            char buf[sizeof(Float)];
-        };
-        const char* t = first;
-        char* e = buf;
-        for (; t != last; ++t, ++e)
-        {
-            if (!isxdigit(*t))
-                return first;
-            unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
-                                        static_cast<unsigned>(*t - 'a' + 10);
-            ++t;
-            unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
-                                        static_cast<unsigned>(*t - 'a' + 10);
-            *e = static_cast<char>((d1 << 4) + d0);
-        }
-        if (*t == 'E')
-        {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-            std::reverse(buf, e);
-#endif
-            char num[float_data<Float>::max_demangled_size] = {0};
-            int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
-            if (static_cast<std::size_t>(n) >= sizeof(num))
-                return first;
-            db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
-            first = t+1;
-        }
-    }
-    return first;
-}
-
-// <source-name> ::= <positive length number> <identifier>
-
-template <class C>
-const char*
-parse_source_name(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        char c = *first;
-        if (isdigit(c) && first+1 != last)
-        {
-            const char* t = first+1;
-            size_t n = static_cast<size_t>(c - '0');
-            for (c = *t; isdigit(c); c = *t)
-            {
-                n = n * 10 + static_cast<size_t>(c - '0');
-                if (++t == last)
-                    return first;
-            }
-            if (static_cast<size_t>(last - t) >= n)
-            {
-                typename C::String r(t, n);
-                if (r.substr(0, 10) == "_GLOBAL__N")
-                    db.names.push_back("(anonymous namespace)");
-                else
-                    db.names.push_back(std::move(r));
-                first = t + n;
-            }
-        }
-    }
-    return first;
-}
-
-// <substitution> ::= S <seq-id> _
-//                ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-//                                               ::std::char_traits<char>,
-//                                               ::std::allocator<char> >
-// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
-// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
-// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
-template <class C>
-const char*
-parse_substitution(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        if (*first == 'S')
-        {
-            switch (first[1])
-            {
-            case 'a':
-                db.names.push_back("std::allocator");
-                first += 2;
-                break;
-            case 'b':
-                db.names.push_back("std::basic_string");
-                first += 2;
-                break;
-            case 's':
-                db.names.push_back("std::string");
-                first += 2;
-                break;
-            case 'i':
-                db.names.push_back("std::istream");
-                first += 2;
-                break;
-            case 'o':
-                db.names.push_back("std::ostream");
-                first += 2;
-                break;
-            case 'd':
-                db.names.push_back("std::iostream");
-                first += 2;
-                break;
-            case '_':
-                if (!db.subs.empty())
-                {
-                    for (const auto& n : db.subs.front())
-                        db.names.push_back(n);
-                    first += 2;
-                }
-                break;
-            default:
-                if (std::isdigit(first[1]) || std::isupper(first[1]))
-                {
-                    size_t sub = 0;
-                    const char* t = first+1;
-                    if (std::isdigit(*t))
-                        sub = static_cast<size_t>(*t - '0');
-                    else
-                        sub = static_cast<size_t>(*t - 'A') + 10;
-                    for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
-                    {
-                        sub *= 36;
-                        if (std::isdigit(*t))
-                            sub += static_cast<size_t>(*t - '0');
-                        else
-                            sub += static_cast<size_t>(*t - 'A') + 10;
-                    }
-                    if (t == last || *t != '_')
-                        return first;
-                    ++sub;
-                    if (sub < db.subs.size())
-                    {
-                        for (const auto& n : db.subs[sub])
-                            db.names.push_back(n);
-                        first = t+1;
-                    }
-                }
-                break;
-            }
-        }
-    }
-    return first;
-}
-
-// <builtin-type> ::= v    # void
-//                ::= w    # wchar_t
-//                ::= b    # bool
-//                ::= c    # char
-//                ::= a    # signed char
-//                ::= h    # unsigned char
-//                ::= s    # short
-//                ::= t    # unsigned short
-//                ::= i    # int
-//                ::= j    # unsigned int
-//                ::= l    # long
-//                ::= m    # unsigned long
-//                ::= x    # long long, __int64
-//                ::= y    # unsigned long long, __int64
-//                ::= n    # __int128
-//                ::= o    # unsigned __int128
-//                ::= f    # float
-//                ::= d    # double
-//                ::= e    # long double, __float80
-//                ::= g    # __float128
-//                ::= z    # ellipsis
-//                ::= Dd   # IEEE 754r decimal floating point (64 bits)
-//                ::= De   # IEEE 754r decimal floating point (128 bits)
-//                ::= Df   # IEEE 754r decimal floating point (32 bits)
-//                ::= Dh   # IEEE 754r half-precision floating point (16 bits)
-//                ::= Di   # char32_t
-//                ::= Ds   # char16_t
-//                ::= Da   # auto (in dependent new-expressions)
-//                ::= Dc   # decltype(auto)
-//                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
-//                ::= u <source-name>    # vendor extended type
-
-template <class C>
-const char*
-parse_builtin_type(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        switch (*first)
-        {
-        case 'v':
-            db.names.push_back("void");
-            ++first;
-            break;
-        case 'w':
-            db.names.push_back("wchar_t");
-            ++first;
-            break;
-        case 'b':
-            db.names.push_back("bool");
-            ++first;
-            break;
-        case 'c':
-            db.names.push_back("char");
-            ++first;
-            break;
-        case 'a':
-            db.names.push_back("signed char");
-            ++first;
-            break;
-        case 'h':
-            db.names.push_back("unsigned char");
-            ++first;
-            break;
-        case 's':
-            db.names.push_back("short");
-            ++first;
-            break;
-        case 't':
-            db.names.push_back("unsigned short");
-            ++first;
-            break;
-        case 'i':
-            db.names.push_back("int");
-            ++first;
-            break;
-        case 'j':
-            db.names.push_back("unsigned int");
-            ++first;
-            break;
-        case 'l':
-            db.names.push_back("long");
-            ++first;
-            break;
-        case 'm':
-            db.names.push_back("unsigned long");
-            ++first;
-            break;
-        case 'x':
-            db.names.push_back("long long");
-            ++first;
-            break;
-        case 'y':
-            db.names.push_back("unsigned long long");
-            ++first;
-            break;
-        case 'n':
-            db.names.push_back("__int128");
-            ++first;
-            break;
-        case 'o':
-            db.names.push_back("unsigned __int128");
-            ++first;
-            break;
-        case 'f':
-            db.names.push_back("float");
-            ++first;
-            break;
-        case 'd':
-            db.names.push_back("double");
-            ++first;
-            break;
-        case 'e':
-            db.names.push_back("long double");
-            ++first;
-            break;
-        case 'g':
-            db.names.push_back("__float128");
-            ++first;
-            break;
-        case 'z':
-            db.names.push_back("...");
-            ++first;
-            break;
-        case 'u':
-            {
-                const char*t = parse_source_name(first+1, last, db);
-                if (t != first+1)
-                    first = t;
-            }
-            break;
-        case 'D':
-            if (first+1 != last)
-            {
-                switch (first[1])
-                {
-                case 'd':
-                    db.names.push_back("decimal64");
-                    first += 2;
-                    break;
-                case 'e':
-                    db.names.push_back("decimal128");
-                    first += 2;
-                    break;
-                case 'f':
-                    db.names.push_back("decimal32");
-                    first += 2;
-                    break;
-                case 'h':
-                    db.names.push_back("decimal16");
-                    first += 2;
-                    break;
-                case 'i':
-                    db.names.push_back("char32_t");
-                    first += 2;
-                    break;
-                case 's':
-                    db.names.push_back("char16_t");
-                    first += 2;
-                    break;
-                case 'a':
-                    db.names.push_back("auto");
-                    first += 2;
-                    break;
-                case 'c':
-                    db.names.push_back("decltype(auto)");
-                    first += 2;
-                    break;
-                case 'n':
-                    db.names.push_back("std::nullptr_t");
-                    first += 2;
-                    break;
-                }
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-// <CV-qualifiers> ::= [r] [V] [K]
-
-const char*
-parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
-{
-    cv = 0;
-    if (first != last)
-    {
-        if (*first == 'r')
-        {
-            cv |= 4;
-            ++first;
-        }
-        if (*first == 'V')
-        {
-            cv |= 2;
-            ++first;
-        }
-        if (*first == 'K')
-        {
-            cv |= 1;
-            ++first;
-        }
-    }
-    return first;
-}
-
-// <template-param> ::= T_    # first template parameter
-//                  ::= T <parameter-2 non-negative number> _
-
-template <class C>
-const char*
-parse_template_param(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        if (*first == 'T')
-        {
-            if (first[1] == '_')
-            {
-                if (db.template_param.empty())
-                    return first;
-                if (!db.template_param.back().empty())
-                {
-                    for (auto& t : db.template_param.back().front())
-                        db.names.push_back(t);
-                    first += 2;
-                }
-                else
-                {
-                    db.names.push_back("T_");
-                    first += 2;
-                    db.fix_forward_references = true;
-                }
-            }
-            else if (isdigit(first[1]))
-            {
-                const char* t = first+1;
-                size_t sub = static_cast<size_t>(*t - '0');
-                for (++t; t != last && isdigit(*t); ++t)
-                {
-                    sub *= 10;
-                    sub += static_cast<size_t>(*t - '0');
-                }
-                if (t == last || *t != '_' || db.template_param.empty())
-                    return first;
-                ++sub;
-                if (sub < db.template_param.back().size())
-                {
-                    for (auto& temp : db.template_param.back()[sub])
-                        db.names.push_back(temp);
-                    first = t+1;
-                }
-                else
-                {
-                    db.names.push_back(typename C::String(first, t+1));
-                    first = t+1;
-                    db.fix_forward_references = true;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// cc <type> <expression>                               # const_cast<type> (expression)
-
-template <class C>
-const char*
-parse_const_cast_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto expr = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// dc <type> <expression>                               # dynamic_cast<type> (expression)
-
-template <class C>
-const char*
-parse_dynamic_cast_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto expr = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// rc <type> <expression>                               # reinterpret_cast<type> (expression)
-
-template <class C>
-const char*
-parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto expr = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// sc <type> <expression>                               # static_cast<type> (expression)
-
-template <class C>
-const char*
-parse_static_cast_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto expr = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// sp <expression>                                  # pack expansion
-
-template <class C>
-const char*
-parse_pack_expansion(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-            first = t;
-    }
-    return first;
-}
-
-// st <type>                                            # sizeof (a type)
-
-template <class C>
-const char*
-parse_sizeof_type_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 't')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// sz <expr>                                            # sizeof (a expression)
-
-template <class C>
-const char*
-parse_sizeof_expr_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// sZ <template-param>                                  # size of a parameter pack
-
-template <class C>
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
-    {
-        size_t k0 = db.names.size();
-        const char* t = parse_template_param(first+2, last, db);
-        size_t k1 = db.names.size();
-        if (t != first+2)
-        {
-            typename C::String tmp("sizeof...(");
-            size_t k = k0;
-            if (k != k1)
-            {
-                tmp += db.names[k].move_full();
-                for (++k; k != k1; ++k)
-                    tmp += ", " + db.names[k].move_full();
-            }
-            tmp += ")";
-            for (; k1 != k0; --k1)
-                db.names.pop_back();
-            db.names.push_back(std::move(tmp));
-            first = t;
-        }
-    }
-    return first;
-}
-
-// <function-param> ::= fp <top-level CV-qualifiers> _                                     # L == 0, first parameter
-//                  ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters
-//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _         # L > 0, first parameter
-//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters
-
-template <class C>
-const char*
-parse_function_param(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && *first == 'f')
-    {
-        if (first[1] == 'p')
-        {
-            unsigned cv;
-            const char* t = parse_cv_qualifiers(first+2, last, cv);
-            const char* t1 = parse_number(t, last);
-            if (t1 != last && *t1 == '_')
-            {
-                db.names.push_back("fp" + typename C::String(t, t1));
-                first = t1+1;
-            }
-        }
-        else if (first[1] == 'L')
-        {
-            unsigned cv;
-            const char* t0 = parse_number(first+2, last);
-            if (t0 != last && *t0 == 'p')
-            {
-                ++t0;
-                const char* t = parse_cv_qualifiers(t0, last, cv);
-                const char* t1 = parse_number(t, last);
-                if (t1 != last && *t1 == '_')
-                {
-                    db.names.push_back("fp" + typename C::String(t, t1));
-                    first = t1+1;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// sZ <function-param>                                  # size of a function parameter pack
-
-template <class C>
-const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
-    {
-        const char* t = parse_function_param(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// te <expression>                                      # typeid (expression)
-// ti <type>                                            # typeid (type)
-
-template <class C>
-const char*
-parse_typeid_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
-    {
-        const char* t;
-        if (first[1] == 'e')
-            t = parse_expression(first+2, last, db);
-        else
-            t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back() = "typeid(" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// tw <expression>                                      # throw expression
-
-template <class C>
-const char*
-parse_throw_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back() = "throw " + db.names.back().move_full();
-            first = t;
-        }
-    }
-    return first;
-}
-
-// ds <expression> <expression>                         # expr.*expr
-
-template <class C>
-const char*
-parse_dot_star_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto expr = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += ".*" + expr;
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// <simple-id> ::= <source-name> [ <template-args> ]
-
-template <class C>
-const char*
-parse_simple_id(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        const char* t = parse_source_name(first, last, db);
-        if (t != first)
-        {
-            const char* t1 = parse_template_args(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto args = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += std::move(args);
-            }
-            first = t1;
-        }
-        else
-            first = t;
-    }
-    return first;
-}
-
-// <unresolved-type> ::= <template-param>
-//                   ::= <decltype>
-//                   ::= <substitution>
-
-template <class C>
-const char*
-parse_unresolved_type(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        const char* t = first;
-        switch (*first)
-        {
-        case 'T':
-          {
-            size_t k0 = db.names.size();
-            t = parse_template_param(first, last, db);
-            size_t k1 = db.names.size();
-            if (t != first && k1 == k0 + 1)
-            {
-                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                first = t;
-            }
-            else
-            {
-                for (; k1 != k0; --k1)
-                    db.names.pop_back();
-            }
-            break;
-          }
-        case 'D':
-            t = parse_decltype(first, last, db);
-            if (t != first)
-            {
-                if (db.names.empty())
-                    return first;
-                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                first = t;
-            }
-            break;
-        case 'S':
-            t = parse_substitution(first, last, db);
-            if (t != first)
-                first = t;
-            else
-            {
-                if (last - first > 2 && first[1] == 't')
-                {
-                    t = parse_unqualified_name(first+2, last, db);
-                    if (t != first+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first.insert(0, "std::");
-                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        first = t;
-                    }
-                }
-            }
-            break;
-       }
-    }
-    return first;
-}
-
-// <destructor-name> ::= <unresolved-type>                               # e.g., ~T or ~decltype(f())
-//                   ::= <simple-id>                                     # e.g., ~A<2*N>
-
-template <class C>
-const char*
-parse_destructor_name(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        const char* t = parse_unresolved_type(first, last, db);
-        if (t == first)
-            t = parse_simple_id(first, last, db);
-        if (t != first)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back().first.insert(0, "~");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// <base-unresolved-name> ::= <simple-id>                                # unresolved name
-//          extension     ::= <operator-name>                            # unresolved operator-function-id
-//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id
-//                        ::= on <operator-name>                         # unresolved operator-function-id
-//                        ::= on <operator-name> <template-args>         # unresolved operator template-id
-//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
-//                                                                         # e.g. ~X or ~X<N-1>
-
-template <class C>
-const char*
-parse_base_unresolved_name(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
-        {
-            if (first[0] == 'o')
-            {
-                const char* t = parse_operator_name(first+2, last, db);
-                if (t != first+2)
-                {
-                    first = parse_template_args(t, last, db);
-                    if (first != t)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto args = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += std::move(args);
-                    }
-                }
-            }
-            else
-            {
-                const char* t = parse_destructor_name(first+2, last, db);
-                if (t != first+2)
-                    first = t;
-            }
-        }
-        else
-        {
-            const char* t = parse_simple_id(first, last, db);
-            if (t == first)
-            {
-                t = parse_operator_name(first, last, db);
-                if (t != first)
-                {
-                    first = parse_template_args(t, last, db);
-                    if (first != t)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto args = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += std::move(args);
-                    }
-                }
-            }
-            else
-                first = t;
-        }
-    }
-    return first;
-}
-
-// <unresolved-qualifier-level> ::= <simple-id>
-
-template <class C>
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
-{
-    return parse_simple_id(first, last, db);
-}
-
-// <unresolved-name>
-//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
-//                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x
-//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>  
-//                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::"
-//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x
-//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>
-//                                                                       # T::N::x /decltype(p)::N::x
-//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
-
-template <class C>
-const char*
-parse_unresolved_name(const char* first, const char* last, C& db)
-{
-    if (last - first > 2)
-    {
-        const char* t = first;
-        bool global = false;
-        if (t[0] == 'g' && t[1] == 's')
-        {
-            global = true;
-            t += 2;
-        }
-        const char* t2 = parse_base_unresolved_name(t, last, db);
-        if (t2 != t)
-        {
-            if (global)
-            {
-                if (db.names.empty())
-                    return first;
-                db.names.back().first.insert(0, "::");
-            }
-            first = t2;
-        }
-        else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
-        {
-            if (t[2] == 'N')
-            {
-                t += 3;
-                const char* t1 = parse_unresolved_type(t, last, db);
-                if (t1 == t || t1 == last)
-                    return first;
-                t = t1;
-                t1 = parse_template_args(t, last, db);
-                if (t1 != t)
-                {
-                    if (db.names.size() < 2)
-                        return first;
-                    auto args = db.names.back().move_full();
-                    db.names.pop_back();
-                    db.names.back().first += std::move(args);
-                    t = t1;
-                    if (t == last)
-                    {
-                        db.names.pop_back();
-                        return first;
-                    }
-                }
-                while (*t != 'E')
-                {
-                    t1 = parse_unresolved_qualifier_level(t, last, db);
-                    if (t1 == t || t1 == last || db.names.size() < 2)
-                        return first;
-                    auto s = db.names.back().move_full();
-                    db.names.pop_back();
-                    db.names.back().first += "::" + std::move(s);
-                    t = t1;
-                }
-                ++t;
-                t1 = parse_base_unresolved_name(t, last, db);
-                if (t1 == t)
-                {
-                    if (!db.names.empty())
-                        db.names.pop_back();
-                    return first;
-                }
-                if (db.names.size() < 2)
-                    return first;
-                auto s = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += "::" + std::move(s);
-                first = t1;
-            }
-            else
-            {
-                t += 2;
-                const char* t1 = parse_unresolved_type(t, last, db);
-                if (t1 != t)
-                {
-                    t = t1;
-                    t1 = parse_template_args(t, last, db);
-                    if (t1 != t)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto args = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += std::move(args);
-                        t = t1;
-                    }
-                    t1 = parse_base_unresolved_name(t, last, db);
-                    if (t1 == t)
-                    {
-                        if (!db.names.empty())
-                            db.names.pop_back();
-                        return first;
-                    }
-                    if (db.names.size() < 2)
-                        return first;
-                    auto s = db.names.back().move_full();
-                    db.names.pop_back();
-                    db.names.back().first += "::" + std::move(s);
-                    first = t1;
-                }
-                else
-                {
-                    t1 = parse_unresolved_qualifier_level(t, last, db);
-                    if (t1 == t || t1 == last)
-                        return first;
-                    t = t1;
-                    if (global)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first.insert(0, "::");
-                    }
-                    while (*t != 'E')
-                    {
-                        t1 = parse_unresolved_qualifier_level(t, last, db);
-                        if (t1 == t || t1 == last || db.names.size() < 2)
-                            return first;
-                        auto s = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += "::" + std::move(s);
-                        t = t1;
-                    }
-                    ++t;
-                    t1 = parse_base_unresolved_name(t, last, db);
-                    if (t1 == t)
-                    {
-                        if (!db.names.empty())
-                            db.names.pop_back();
-                        return first;
-                    }
-                    if (db.names.size() < 2)
-                        return first;
-                    auto s = db.names.back().move_full();
-                    db.names.pop_back();
-                    db.names.back().first += "::" + std::move(s);
-                    first = t1;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// dt <expression> <unresolved-name>                    # expr.name
-
-template <class C>
-const char*
-parse_dot_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_unresolved_name(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto name = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += "." + name;
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-// cl <expression>+ E                                   # call
-
-template <class C>
-const char*
-parse_call_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            if (t == last)
-                return first;
-            if (db.names.empty())
-                return first;
-            db.names.back().first += db.names.back().second;
-            db.names.back().second = typename C::String();
-            db.names.back().first.append("(");
-            bool first_expr = true;
-            while (*t != 'E')
-            {
-                const char* t1 = parse_expression(t, last, db);
-                if (t1 == t || t1 == last)
-                    return first;
-                if (db.names.empty())
-                    return first;
-                auto tmp = db.names.back().move_full();
-                db.names.pop_back();
-                if (!tmp.empty())
-                {
-                    if (db.names.empty())
-                        return first;
-                    if (!first_expr)
-                    {
-                        db.names.back().first.append(", ");
-                        first_expr = false;
-                    }
-                    db.names.back().first.append(tmp);
-                }
-                t = t1;
-            }
-            ++t;
-            if (db.names.empty())
-                return first;
-            db.names.back().first.append(")");
-            first = t;
-        }
-    }
-    return first;
-}
-
-// [gs] nw <expression>* _ <type> E                     # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E                 # parenthesized initialization
-
-template <class C>
-const char*
-parse_new_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 4)
-    {
-        const char* t = first;
-        bool parsed_gs = false;
-        if (t[0] == 'g' && t[1] == 's')
-        {
-            t += 2;
-            parsed_gs = true;
-        }
-        if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
-        {
-            bool is_array = t[1] == 'a';
-            t += 2;
-            if (t == last)
-                return first;
-            bool has_expr_list = false;
-            bool first_expr = true;
-            while (*t != '_')
-            {
-                const char* t1 = parse_expression(t, last, db);
-                if (t1 == t || t1 == last)
-                    return first;
-                has_expr_list = true;
-                if (!first_expr)
-                {
-                    if (db.names.empty())
-                        return first;
-                    auto tmp = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!tmp.empty())
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first.append(", ");
-                        db.names.back().first.append(tmp);
-                        first_expr = false;
-                    }
-                }
-                t = t1;
-            }
-            ++t;
-            const char* t1 = parse_type(t, last, db);
-            if (t1 == t || t1 == last)
-                return first;
-            t = t1;
-            bool has_init = false;
-            if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
-            {
-                t += 2;
-                has_init = true;
-                first_expr = true;
-                while (*t != 'E')
-                {
-                    t1 = parse_expression(t, last, db);
-                    if (t1 == t || t1 == last)
-                        return first;
-                    if (!first_expr)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        auto tmp = db.names.back().move_full();
-                        db.names.pop_back();
-                        if (!tmp.empty())
-                        {
-                            if (db.names.empty())
-                                return first;
-                            db.names.back().first.append(", ");
-                            db.names.back().first.append(tmp);
-                            first_expr = false;
-                        }
-                    }
-                    t = t1;
-                }
-            }
-            if (*t != 'E')
-                return first;
-            typename C::String init_list;
-            if (has_init)
-            {
-                if (db.names.empty())
-                    return first;
-                init_list = db.names.back().move_full();
-                db.names.pop_back();
-            }
-            if (db.names.empty())
-                return first;
-            auto type = db.names.back().move_full();
-            db.names.pop_back();
-            typename C::String expr_list;
-            if (has_expr_list)
-            {
-                if (db.names.empty())
-                    return first;
-                expr_list = db.names.back().move_full();
-                db.names.pop_back();
-            }
-            typename C::String r;
-            if (parsed_gs)
-                r = "::";
-            if (is_array)
-                r += "[] ";
-            else
-                r += " ";
-            if (has_expr_list)
-                r += "(" + expr_list + ") ";
-            r += type;
-            if (has_init)
-                r += " (" + init_list + ")";
-            db.names.push_back(std::move(r));
-            first = t+1;
-        }
-    }
-    return first;
-}
-
-// cv <type> <expression>                               # conversion with one argument
-// cv <type> _ <expression>* E                          # conversion with a different number of arguments
-
-template <class C>
-const char*
-parse_conversion_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
-    {
-        bool try_to_parse_template_args = db.try_to_parse_template_args;
-        db.try_to_parse_template_args = false;
-        const char* t = parse_type(first+2, last, db);
-        db.try_to_parse_template_args = try_to_parse_template_args;
-        if (t != first+2 && t != last)
-        {
-            if (*t != '_')
-            {
-                const char* t1 = parse_expression(t, last, db);
-                if (t1 == t)
-                    return first;
-                t = t1;
-            }
-            else
-            {
-                ++t;
-                if (t == last)
-                    return first;
-                if (*t == 'E')
-                    db.names.emplace_back();
-                else
-                {
-                    bool first_expr = true;
-                    while (*t != 'E')
-                    {
-                        const char* t1 = parse_expression(t, last, db);
-                        if (t1 == t || t1 == last)
-                            return first;
-                        if (!first_expr)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            auto tmp = db.names.back().move_full();
-                            db.names.pop_back();
-                            if (!tmp.empty())
-                            {
-                                if (db.names.empty())
-                                    return first;
-                                db.names.back().first.append(", ");
-                                db.names.back().first.append(tmp);
-                                first_expr = false;
-                            }
-                        }
-                        t = t1;
-                    }
-                }
-                ++t;
-            }
-            if (db.names.size() < 2)
-                return first;
-            auto tmp = db.names.back().move_full();
-            db.names.pop_back();
-            db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// pt <expression> <expression>                    # expr->name
-
-template <class C>
-const char*
-parse_arrow_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            const char* t1 = parse_expression(t, last, db);
-            if (t1 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto tmp = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first += "->";
-                db.names.back().first += tmp;
-                first = t1;
-            }
-        }
-    }
-    return first;
-}
-
-//  <ref-qualifier> ::= R                   # & ref-qualifier
-//  <ref-qualifier> ::= O                   # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
-
-template <class C>
-const char*
-parse_function_type(const char* first, const char* last, C& db)
-{
-    if (first != last && *first == 'F')
-    {
-        const char* t = first+1;
-        if (t != last)
-        {
-            if (*t == 'Y')
-            {
-                /* extern "C" */
-                if (++t == last)
-                    return first;
-            }
-            const char* t1 = parse_type(t, last, db);
-            if (t1 != t)
-            {
-                t = t1;
-                typename C::String sig("(");
-                int ref_qual = 0;
-                while (true)
-                {
-                    if (t == last)
-                    {
-                        db.names.pop_back();
-                        return first;
-                    }
-                    if (*t == 'E')
-                    {
-                        ++t;
-                        break;
-                    }
-                    if (*t == 'v')
-                    {
-                        ++t;
-                        continue;
-                    }
-                    if (*t == 'R' && t+1 != last && t[1] == 'E')
-                    {
-                        ref_qual = 1;
-                        ++t;
-                        continue;
-                    }
-                    if (*t == 'O' && t+1 != last && t[1] == 'E')
-                    {
-                        ref_qual = 2;
-                        ++t;
-                        continue;
-                    }
-                    size_t k0 = db.names.size();
-                    t1 = parse_type(t, last, db);
-                    size_t k1 = db.names.size();
-                    if (t1 == t || t1 == last)
-                        return first;
-                    for (size_t k = k0; k < k1; ++k)
-                    {
-                        if (sig.size() > 1)
-                            sig += ", ";
-                        sig += db.names[k].move_full();
-                    }
-                    for (size_t k = k0; k < k1; ++k)
-                        db.names.pop_back();
-                    t = t1;
-                }
-                sig += ")";
-                switch (ref_qual)
-                {
-                case 1:
-                    sig += " &";
-                    break;
-                case 2:
-                    sig += " &&";
-                    break;
-                }
-                if (db.names.empty())
-                    return first;
-                db.names.back().first += " ";
-                db.names.back().second.insert(0, sig);
-                first = t;
-            }
-        }
-    }
-    return first;
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-template <class C>
-const char*
-parse_pointer_to_member_type(const char* first, const char* last, C& db)
-{
-    if (first != last && *first == 'M')
-    {
-        const char* t = parse_type(first+1, last, db);
-        if (t != first+1)
-        {
-            const char* t2 = parse_type(t, last, db);
-            if (t2 != t)
-            {
-                if (db.names.size() < 2)
-                    return first;
-                auto func = std::move(db.names.back());
-                db.names.pop_back();
-                auto class_type = std::move(db.names.back());
-                if (!func.second.empty() && func.second.front() == '(')
-                {
-                    db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
-                    db.names.back().second = ")" + std::move(func.second);
-                }
-                else
-                {
-                    db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
-                    db.names.back().second = std::move(func.second);
-                }
-                first = t2;
-            }
-        }
-    }
-    return first;
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-//              ::= A [<dimension expression>] _ <element type>
-
-template <class C>
-const char*
-parse_array_type(const char* first, const char* last, C& db)
-{
-    if (first != last && *first == 'A' && first+1 != last)
-    {
-        if (first[1] == '_')
-        {
-            const char* t = parse_type(first+2, last, db);
-            if (t != first+2)
-            {
-                if (db.names.empty())
-                    return first;
-                if (db.names.back().second.substr(0, 2) == " [")
-                    db.names.back().second.erase(0, 1);
-                db.names.back().second.insert(0, " []");
-                first = t;
-            }
-        }
-        else if ('1' <= first[1] && first[1] <= '9')
-        {
-            const char* t = parse_number(first+1, last);
-            if (t != last && *t == '_')
-            {
-                const char* t2 = parse_type(t+1, last, db);
-                if (t2 != t+1)
-                {
-                    if (db.names.empty())
-                        return first;
-                    if (db.names.back().second.substr(0, 2) == " [")
-                        db.names.back().second.erase(0, 1);
-                    db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
-                    first = t2;
-                }
-            }
-        }
-        else
-        {
-            const char* t = parse_expression(first+1, last, db);
-            if (t != first+1 && t != last && *t == '_')
-            {
-                const char* t2 = parse_type(++t, last, db);
-                if (t2 != t)
-                {
-                    if (db.names.size() < 2)
-                        return first;
-                    auto type = std::move(db.names.back());
-                    db.names.pop_back();
-                    auto expr = std::move(db.names.back());
-                    db.names.back().first = std::move(type.first);
-                    if (type.second.substr(0, 2) == " [")
-                        type.second.erase(0, 1);
-                    db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
-                    first = t2;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
-//             ::= DT <expression> E  # decltype of an expression (C++0x)
-
-template <class C>
-const char*
-parse_decltype(const char* first, const char* last, C& db)
-{
-    if (last - first >= 4 && first[0] == 'D')
-    {
-        switch (first[1])
-        {
-        case 't':
-        case 'T':
-            {
-                const char* t = parse_expression(first+2, last, db);
-                if (t != first+2 && t != last && *t == 'E')
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back() = "decltype(" + db.names.back().move_full() + ")";
-                    first = t+1;
-                }
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-// extension:
-// <vector-type>           ::= Dv <positive dimension number> _
-//                                    <extended element type>
-//                         ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-//                         ::= p # AltiVec vector pixel
-
-template <class C>
-const char*
-parse_vector_type(const char* first, const char* last, C& db)
-{
-    if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
-    {
-        if ('1' <= first[2] && first[2] <= '9')
-        {
-            const char* t = parse_number(first+2, last);
-            if (t == last || *t != '_')
-                return first;
-            const char* num = first + 2;
-            size_t sz = static_cast<size_t>(t - num);
-            if (++t != last)
-            {
-                if (*t != 'p')
-                {
-                    const char* t1 = parse_type(t, last, db);
-                    if (t1 != t)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
-                        first = t1;
-                    }
-                }
-                else
-                {
-                    ++t;
-                    db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
-                    first = t;
-                }
-            }
-        }
-        else
-        {
-            typename C::String num;
-            const char* t1 = first+2;
-            if (*t1 != '_')
-            {
-                const char* t = parse_expression(t1, last, db);
-                if (t != t1)
-                {
-                    if (db.names.empty())
-                        return first;
-                    num = db.names.back().move_full();
-                    db.names.pop_back();
-                    t1 = t;
-                }
-            }
-            if (t1 != last && *t1 == '_' && ++t1 != last)
-            {
-                const char* t = parse_type(t1, last, db);
-                if (t != t1)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first += " vector[" + num + "]";
-                    first = t;
-                }
-            }
-        }
-    }
-    return first;
-}
-
-// <type> ::= <builtin-type>
-//        ::= <function-type>
-//        ::= <class-enum-type>
-//        ::= <array-type>
-//        ::= <pointer-to-member-type>
-//        ::= <template-param>
-//        ::= <template-template-param> <template-args>
-//        ::= <decltype>
-//        ::= <substitution>
-//        ::= <CV-qualifiers> <type>
-//        ::= P <type>        # pointer-to
-//        ::= R <type>        # reference-to
-//        ::= O <type>        # rvalue reference-to (C++0x)
-//        ::= C <type>        # complex pair (C 2000)
-//        ::= G <type>        # imaginary (C 2000)
-//        ::= Dp <type>       # pack expansion (C++0x)
-//        ::= U <source-name> <type>  # vendor extended type qualifier
-// extension := U <objc-name> <objc-type>  # objc-type<identifier>
-// extension := <vector-type> # <vector-type> starts with Dv
-
-// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1
-// <objc-type> := <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
-template <class C>
-const char*
-parse_type(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        switch (*first)
-        {
-            case 'r':
-            case 'V':
-            case 'K':
-              {
-                unsigned cv = 0;
-                const char* t = parse_cv_qualifiers(first, last, cv);
-                if (t != first)
-                {
-                    bool is_function = *t == 'F';
-                    size_t k0 = db.names.size();
-                    const char* t1 = parse_type(t, last, db);
-                    size_t k1 = db.names.size();
-                    if (t1 != t)
-                    {
-                        if (is_function)
-                            db.subs.pop_back();
-                        db.subs.emplace_back(db.names.get_allocator());
-                        for (size_t k = k0; k < k1; ++k)
-                        {
-                            if (is_function)
-                            {
-                                size_t p = db.names[k].second.size();
-                                if (db.names[k].second[p-2] == '&')
-                                    p -= 3;
-                                else if (db.names[k].second.back() == '&')
-                                    p -= 2;
-                                if (cv & 1)
-                                {
-                                    db.names[k].second.insert(p, " const");
-                                    p += 6;
-                                }
-                                if (cv & 2)
-                                {
-                                    db.names[k].second.insert(p, " volatile");
-                                    p += 9;
-                                }
-                                if (cv & 4)
-                                    db.names[k].second.insert(p, " restrict");
-                            }
-                            else
-                            {
-                                if (cv & 1)
-                                    db.names[k].first.append(" const");
-                                if (cv & 2)
-                                    db.names[k].first.append(" volatile");
-                                if (cv & 4)
-                                    db.names[k].first.append(" restrict");
-                            }
-                            db.subs.back().push_back(db.names[k]);
-                        }
-                        first = t1;
-                    }
-                }
-              }
-                break;
-            default:
-              {
-                const char* t = parse_builtin_type(first, last, db);
-                if (t != first)
-                {
-                    first = t;
-                }
-                else
-                {
-                    switch (*first)
-                    {
-                    case 'A':
-                        t = parse_array_type(first, last, db);
-                        if (t != first)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            first = t;
-                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        }
-                        break;
-                    case 'C':
-                        t = parse_type(first+1, last, db);
-                        if (t != first+1)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            db.names.back().first.append(" complex");
-                            first = t;
-                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        }
-                        break;
-                    case 'F':
-                        t = parse_function_type(first, last, db);
-                        if (t != first)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            first = t;
-                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        }
-                        break;
-                    case 'G':
-                        t = parse_type(first+1, last, db);
-                        if (t != first+1)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            db.names.back().first.append(" imaginary");
-                            first = t;
-                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        }
-                        break;
-                    case 'M':
-                        t = parse_pointer_to_member_type(first, last, db);
-                        if (t != first)
-                        {
-                            if (db.names.empty())
-                                return first;
-                            first = t;
-                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                        }
-                        break;
-                    case 'O':
-                      {
-                        size_t k0 = db.names.size();
-                        t = parse_type(first+1, last, db);
-                        size_t k1 = db.names.size();
-                        if (t != first+1)
-                        {
-                            db.subs.emplace_back(db.names.get_allocator());
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                if (db.names[k].second.substr(0, 2) == " [")
-                                {
-                                    db.names[k].first += " (";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                else if (!db.names[k].second.empty() &&
-                                          db.names[k].second.front() == '(')
-                                {
-                                    db.names[k].first += "(";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                db.names[k].first.append("&&");
-                                db.subs.back().push_back(db.names[k]);
-                            }
-                            first = t;
-                        }
-                        break;
-                      }
-                    case 'P':
-                      {
-                        size_t k0 = db.names.size();
-                        t = parse_type(first+1, last, db);
-                        size_t k1 = db.names.size();
-                        if (t != first+1)
-                        {
-                            db.subs.emplace_back(db.names.get_allocator());
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                if (db.names[k].second.substr(0, 2) == " [")
-                                {
-                                    db.names[k].first += " (";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                else if (!db.names[k].second.empty() &&
-                                          db.names[k].second.front() == '(')
-                                {
-                                    db.names[k].first += "(";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
-                                {
-                                    db.names[k].first.append("*");
-                                }
-                                else
-                                {
-                                    db.names[k].first.replace(0, 11, "id");
-                                }
-                                db.subs.back().push_back(db.names[k]);
-                            }
-                            first = t;
-                        }
-                        break;
-                      }
-                    case 'R':
-                      {
-                        size_t k0 = db.names.size();
-                        t = parse_type(first+1, last, db);
-                        size_t k1 = db.names.size();
-                        if (t != first+1)
-                        {
-                            db.subs.emplace_back(db.names.get_allocator());
-                            for (size_t k = k0; k < k1; ++k)
-                            {
-                                if (db.names[k].second.substr(0, 2) == " [")
-                                {
-                                    db.names[k].first += " (";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                else if (!db.names[k].second.empty() &&
-                                          db.names[k].second.front() == '(')
-                                {
-                                    db.names[k].first += "(";
-                                    db.names[k].second.insert(0, ")");
-                                }
-                                db.names[k].first.append("&");
-                                db.subs.back().push_back(db.names[k]);
-                            }
-                            first = t;
-                        }
-                        break;
-                      }
-                    case 'T':
-                      {
-                        size_t k0 = db.names.size();
-                        t = parse_template_param(first, last, db);
-                        size_t k1 = db.names.size();
-                        if (t != first)
-                        {
-                            db.subs.emplace_back(db.names.get_allocator());
-                            for (size_t k = k0; k < k1; ++k)
-                                db.subs.back().push_back(db.names[k]);
-                            if (db.try_to_parse_template_args && k1 == k0+1)
-                            {
-                                const char* t1 = parse_template_args(t, last, db);
-                                if (t1 != t)
-                                {
-                                    auto args = db.names.back().move_full();
-                                    db.names.pop_back();
-                                    db.names.back().first += std::move(args);
-                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                    t = t1;
-                                }
-                            }
-                            first = t;
-                        }
-                        break;
-                      }
-                    case 'U':
-                        if (first+1 != last)
-                        {
-                            t = parse_source_name(first+1, last, db);
-                            if (t != first+1)
-                            {
-                                const char* t2 = parse_type(t, last, db);
-                                if (t2 != t)
-                                {
-                                    if (db.names.size() < 2)
-                                        return first;
-                                    auto type = db.names.back().move_full();
-                                    db.names.pop_back();
-                                    if (db.names.back().first.substr(0, 9) != "objcproto")
-                                    {
-                                        db.names.back() = type + " " + db.names.back().move_full();
-                                    }
-                                    else
-                                    {
-                                        auto proto = db.names.back().move_full();
-                                        db.names.pop_back();
-                                        t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
-                                        if (t != proto.data() + 9)
-                                        {
-                                            db.names.back() = type + "<" + db.names.back().move_full() + ">";
-                                        }
-                                        else
-                                        {
-                                            db.names.push_back(type + " " + proto);
-                                        }
-                                    }
-                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                    first = t2;
-                                }
-                            }
-                        }
-                        break;
-                    case 'S':
-                        if (first+1 != last && first[1] == 't')
-                        {
-                            t = parse_name(first, last, db);
-                            if (t != first)
-                            {
-                                if (db.names.empty())
-                                    return first;
-                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                first = t;
-                            }
-                        }
-                        else
-                        {
-                            t = parse_substitution(first, last, db);
-                            if (t != first)
-                            {
-                                first = t;
-                                // Parsed a substitution.  If the substitution is a
-                                //  <template-param> it might be followed by <template-args>.
-                                t = parse_template_args(first, last, db);
-                                if (t != first)
-                                {
-                                    if (db.names.size() < 2)
-                                        return first;
-                                    auto template_args = db.names.back().move_full();
-                                    db.names.pop_back();
-                                    db.names.back().first += template_args;
-                                    // Need to create substitution for <template-template-param> <template-args>
-                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                    first = t;
-                                }
-                            }
-                        }
-                        break;
-                    case 'D':
-                        if (first+1 != last)
-                        {
-                            switch (first[1])
-                            {
-                            case 'p':
-                              {
-                                size_t k0 = db.names.size();
-                                t = parse_type(first+2, last, db);
-                                size_t k1 = db.names.size();
-                                if (t != first+2)
-                                {
-                                    db.subs.emplace_back(db.names.get_allocator());
-                                    for (size_t k = k0; k < k1; ++k)
-                                        db.subs.back().push_back(db.names[k]);
-                                    first = t;
-                                    return first;
-                                }
-                                break;
-                              }
-                            case 't':
-                            case 'T':
-                                t = parse_decltype(first, last, db);
-                                if (t != first)
-                                {
-                                    if (db.names.empty())
-                                        return first;
-                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                    first = t;
-                                    return first;
-                                }
-                                break;
-                            case 'v':
-                                t = parse_vector_type(first, last, db);
-                                if (t != first)
-                                {
-                                    if (db.names.empty())
-                                        return first;
-                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                    first = t;
-                                    return first;
-                                }
-                                break;
-                            }
-                        }
-                        // drop through
-                    default:
-                        // must check for builtin-types before class-enum-types to avoid
-                        // ambiguities with operator-names
-                        t = parse_builtin_type(first, last, db);
-                        if (t != first)
-                        {
-                            first = t;
-                        }
-                        else
-                        {
-                            t = parse_name(first, last, db);
-                            if (t != first)
-                            {
-                                if (db.names.empty())
-                                    return first;
-                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                                first = t;
-                            }
-                        }
-                        break;
-                    }
-              }
-                break;
-            }
-        }
-    }
-    return first;
-}
-
-//   <operator-name>
-//                   ::= aa    # &&            
-//                   ::= ad    # & (unary)     
-//                   ::= an    # &             
-//                   ::= aN    # &=            
-//                   ::= aS    # =             
-//                   ::= cl    # ()            
-//                   ::= cm    # ,             
-//                   ::= co    # ~             
-//                   ::= cv <type>    # (cast)        
-//                   ::= da    # delete[]      
-//                   ::= de    # * (unary)     
-//                   ::= dl    # delete        
-//                   ::= dv    # /             
-//                   ::= dV    # /=            
-//                   ::= eo    # ^             
-//                   ::= eO    # ^=            
-//                   ::= eq    # ==            
-//                   ::= ge    # >=            
-//                   ::= gt    # >             
-//                   ::= ix    # []            
-//                   ::= le    # <=            
-//                   ::= li <source-name>  # operator ""
-//                   ::= ls    # <<            
-//                   ::= lS    # <<=           
-//                   ::= lt    # <             
-//                   ::= mi    # -             
-//                   ::= mI    # -=            
-//                   ::= ml    # *             
-//                   ::= mL    # *=            
-//                   ::= mm    # -- (postfix in <expression> context)           
-//                   ::= na    # new[]
-//                   ::= ne    # !=            
-//                   ::= ng    # - (unary)     
-//                   ::= nt    # !             
-//                   ::= nw    # new           
-//                   ::= oo    # ||            
-//                   ::= or    # |             
-//                   ::= oR    # |=            
-//                   ::= pm    # ->*           
-//                   ::= pl    # +             
-//                   ::= pL    # +=            
-//                   ::= pp    # ++ (postfix in <expression> context)
-//                   ::= ps    # + (unary)
-//                   ::= pt    # ->            
-//                   ::= qu    # ?             
-//                   ::= rm    # %             
-//                   ::= rM    # %=            
-//                   ::= rs    # >>            
-//                   ::= rS    # >>=           
-//                   ::= v <digit> <source-name>        # vendor extended operator
-
-template <class C>
-const char*
-parse_operator_name(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        switch (first[0])
-        {
-        case 'a':
-            switch (first[1])
-            {
-            case 'a':
-                db.names.push_back("operator&&");
-                first += 2;
-                break;
-            case 'd':
-            case 'n':
-                db.names.push_back("operator&");
-                first += 2;
-                break;
-            case 'N':
-                db.names.push_back("operator&=");
-                first += 2;
-                break;
-            case 'S':
-                db.names.push_back("operator=");
-                first += 2;
-                break;
-            }
-            break;
-        case 'c':
-            switch (first[1])
-            {
-            case 'l':
-                db.names.push_back("operator()");
-                first += 2;
-                break;
-            case 'm':
-                db.names.push_back("operator,");
-                first += 2;
-                break;
-            case 'o':
-                db.names.push_back("operator~");
-                first += 2;
-                break;
-            case 'v':
-                {
-                    bool try_to_parse_template_args = db.try_to_parse_template_args;
-                    db.try_to_parse_template_args = false;
-                    const char* t = parse_type(first+2, last, db);
-                    db.try_to_parse_template_args = try_to_parse_template_args;
-                    if (t != first+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first.insert(0, "operator ");
-                        db.parsed_ctor_dtor_cv = true;
-                        first = t;
-                    }
-                }
-                break;
-            }
-            break;
-        case 'd':
-            switch (first[1])
-            {
-            case 'a':
-                db.names.push_back("operator delete[]");
-                first += 2;
-                break;
-            case 'e':
-                db.names.push_back("operator*");
-                first += 2;
-                break;
-            case 'l':
-                db.names.push_back("operator delete");
-                first += 2;
-                break;
-            case 'v':
-                db.names.push_back("operator/");
-                first += 2;
-                break;
-            case 'V':
-                db.names.push_back("operator/=");
-                first += 2;
-                break;
-            }
-            break;
-        case 'e':
-            switch (first[1])
-            {
-            case 'o':
-                db.names.push_back("operator^");
-                first += 2;
-                break;
-            case 'O':
-                db.names.push_back("operator^=");
-                first += 2;
-                break;
-            case 'q':
-                db.names.push_back("operator==");
-                first += 2;
-                break;
-            }
-            break;
-        case 'g':
-            switch (first[1])
-            {
-            case 'e':
-                db.names.push_back("operator>=");
-                first += 2;
-                break;
-            case 't':
-                db.names.push_back("operator>");
-                first += 2;
-                break;
-            }
-            break;
-        case 'i':
-            if (first[1] == 'x')
-            {
-                db.names.push_back("operator[]");
-                first += 2;
-            }
-            break;
-        case 'l':
-            switch (first[1])
-            {
-            case 'e':
-                db.names.push_back("operator<=");
-                first += 2;
-                break;
-            case 'i':
-                {
-                    const char* t = parse_source_name(first+2, last, db);
-                    if (t != first+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first.insert(0, "operator\"\" ");
-                        first = t;
-                    }
-                }
-                break;
-            case 's':
-                db.names.push_back("operator<<");
-                first += 2;
-                break;
-            case 'S':
-                db.names.push_back("operator<<=");
-                first += 2;
-                break;
-            case 't':
-                db.names.push_back("operator<");
-                first += 2;
-                break;
-            }
-            break;
-        case 'm':
-            switch (first[1])
-            {
-            case 'i':
-                db.names.push_back("operator-");
-                first += 2;
-                break;
-            case 'I':
-                db.names.push_back("operator-=");
-                first += 2;
-                break;
-            case 'l':
-                db.names.push_back("operator*");
-                first += 2;
-                break;
-            case 'L':
-                db.names.push_back("operator*=");
-                first += 2;
-                break;
-            case 'm':
-                db.names.push_back("operator--");
-                first += 2;
-                break;
-            }
-            break;
-        case 'n':
-            switch (first[1])
-            {
-            case 'a':
-                db.names.push_back("operator new[]");
-                first += 2;
-                break;
-            case 'e':
-                db.names.push_back("operator!=");
-                first += 2;
-                break;
-            case 'g':
-                db.names.push_back("operator-");
-                first += 2;
-                break;
-            case 't':
-                db.names.push_back("operator!");
-                first += 2;
-                break;
-            case 'w':
-                db.names.push_back("operator new");
-                first += 2;
-                break;
-            }
-            break;
-        case 'o':
-            switch (first[1])
-            {
-            case 'o':
-                db.names.push_back("operator||");
-                first += 2;
-                break;
-            case 'r':
-                db.names.push_back("operator|");
-                first += 2;
-                break;
-            case 'R':
-                db.names.push_back("operator|=");
-                first += 2;
-                break;
-            }
-            break;
-        case 'p':
-            switch (first[1])
-            {
-            case 'm':
-                db.names.push_back("operator->*");
-                first += 2;
-                break;
-            case 'l':
-                db.names.push_back("operator+");
-                first += 2;
-                break;
-            case 'L':
-                db.names.push_back("operator+=");
-                first += 2;
-                break;
-            case 'p':
-                db.names.push_back("operator++");
-                first += 2;
-                break;
-            case 's':
-                db.names.push_back("operator+");
-                first += 2;
-                break;
-            case 't':
-                db.names.push_back("operator->");
-                first += 2;
-                break;
-            }
-            break;
-        case 'q':
-            if (first[1] == 'u')
-            {
-                db.names.push_back("operator?");
-                first += 2;
-            }
-            break;
-        case 'r':
-            switch (first[1])
-            {
-            case 'm':
-                db.names.push_back("operator%");
-                first += 2;
-                break;
-            case 'M':
-                db.names.push_back("operator%=");
-                first += 2;
-                break;
-            case 's':
-                db.names.push_back("operator>>");
-                first += 2;
-                break;
-            case 'S':
-                db.names.push_back("operator>>=");
-                first += 2;
-                break;
-            }
-            break;
-        case 'v':
-            if (std::isdigit(first[1]))
-            {
-                const char* t = parse_source_name(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "operator ");
-                    first = t;
-                }
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-template <class C>
-const char*
-parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
-{
-    const char* t = parse_number(first, last);
-    if (t != first && t != last && *t == 'E')
-    {
-        if (lit.size() > 3)
-            db.names.push_back("(" + lit + ")");
-        else
-            db.names.emplace_back();
-        if (*first == 'n')
-        {
-            db.names.back().first += '-';
-            ++first;
-        }
-        db.names.back().first.append(first, t);
-        if (lit.size() <= 3)
-            db.names.back().first += lit;
-        first = t+1;
-    }
-    return first;
-}
-
-// <expr-primary> ::= L <type> <value number> E                          # integer literal
-//                ::= L <type> <value float> E                           # floating literal
-//                ::= L <string type> E                                  # string literal
-//                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
-//                ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
-//                ::= L <mangled-name> E                                 # external name
-
-template <class C>
-const char*
-parse_expr_primary(const char* first, const char* last, C& db)
-{
-    if (last - first >= 4 && *first == 'L')
-    {
-        switch (first[1])
-        {
-        case 'w':
-            {
-            const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'b':
-            if (first[3] == 'E')
-            {
-                switch (first[2])
-                {
-                case '0':
-                    db.names.push_back("false");
-                    first += 4;
-                    break;
-                case '1':
-                    db.names.push_back("true");
-                    first += 4;
-                    break;
-                }
-            }
-            break;
-        case 'c':
-            {
-            const char* t = parse_integer_literal(first+2, last, "char", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'a':
-            {
-            const char* t = parse_integer_literal(first+2, last, "signed char", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'h':
-            {
-            const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 's':
-            {
-            const char* t = parse_integer_literal(first+2, last, "short", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 't':
-            {
-            const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'i':
-            {
-            const char* t = parse_integer_literal(first+2, last, "", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'j':
-            {
-            const char* t = parse_integer_literal(first+2, last, "u", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'l':
-            {
-            const char* t = parse_integer_literal(first+2, last, "l", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'm':
-            {
-            const char* t = parse_integer_literal(first+2, last, "ul", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'x':
-            {
-            const char* t = parse_integer_literal(first+2, last, "ll", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'y':
-            {
-            const char* t = parse_integer_literal(first+2, last, "ull", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'n':
-            {
-            const char* t = parse_integer_literal(first+2, last, "__int128", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'o':
-            {
-            const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'f':
-            {
-            const char* t = parse_floating_number<float>(first+2, last, db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case 'd':
-            {
-            const char* t = parse_floating_number<double>(first+2, last, db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-         case 'e':
-            {
-            const char* t = parse_floating_number<long double>(first+2, last, db);
-            if (t != first+2)
-                first = t;
-            }
-            break;
-        case '_':
-            if (first[2] == 'Z')
-            {
-                const char* t = parse_encoding(first+3, last, db);
-                if (t != first+3 && t != last && *t == 'E')
-                    first = t+1;
-            }
-            break;
-        case 'T':
-            // Invalid mangled name per
-            //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
-            break;
-        default:
-            {
-                // might be named type
-                const char* t = parse_type(first+1, last, db);
-                if (t != first+1 && t != last)
-                {
-                    if (*t != 'E')
-                    {
-                        const char* n = t;
-                        for (; n != last && isdigit(*n); ++n)
-                            ;
-                        if (n != t && n != last && *n == 'E')
-                        {
-                            if (db.names.empty())
-                                return first;
-                            db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
-                            first = n+1;
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        first = t+1;
-                        break;
-                    }
-                }
-            }
-        }
-    }
-    return first;
-}
-
-template <class String>
-String
-base_name(String& s)
-{
-    if (s.empty())
-        return s;
-    if (s == "std::string")
-    {
-        s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
-        return "basic_string";
-    }
-    if (s == "std::istream")
-    {
-        s = "std::basic_istream<char, std::char_traits<char> >";
-        return "basic_istream";
-    }
-    if (s == "std::ostream")
-    {
-        s = "std::basic_ostream<char, std::char_traits<char> >";
-        return "basic_ostream";
-    }
-    if (s == "std::iostream")
-    {
-        s = "std::basic_iostream<char, std::char_traits<char> >";
-        return "basic_iostream";
-    }
-    const char* const pf = s.data();
-    const char* pe = pf + s.size();
-    if (pe[-1] == '>')
-    {
-        unsigned c = 1;
-        while (true)
-        {
-            if (--pe == pf)
-                return String();
-            if (pe[-1] == '<')
-            {
-                if (--c == 0)
-                {
-                    --pe;
-                    break;
-                }
-            }
-            else if (pe[-1] == '>')
-                ++c;
-        }
-    }
-    const char* p0 = pe - 1;
-    for (; p0 != pf; --p0)
-    {
-        if (*p0 == ':')
-        {
-            ++p0;
-            break;
-        }
-    }
-    return String(p0, pe);
-}
-
-// <ctor-dtor-name> ::= C1    # complete object constructor
-//                  ::= C2    # base object constructor
-//                  ::= C3    # complete object allocating constructor
-//   extension      ::= C5    # ?
-//                  ::= D0    # deleting destructor
-//                  ::= D1    # complete object destructor
-//                  ::= D2    # base object destructor
-//   extension      ::= D5    # ?
-
-template <class C>
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, C& db)
-{
-    if (last-first >= 2 && !db.names.empty())
-    {
-        switch (first[0])
-        {
-        case 'C':
-            switch (first[1])
-            {
-            case '1':
-            case '2':
-            case '3':
-            case '5':
-                if (db.names.empty())
-                    return first;
-                db.names.push_back(base_name(db.names.back().first));
-                first += 2;
-                db.parsed_ctor_dtor_cv = true;
-                break;
-            }
-            break;
-        case 'D':
-            switch (first[1])
-            {
-            case '0':
-            case '1':
-            case '2':
-            case '5':
-                if (db.names.empty())
-                    return first;
-                db.names.push_back("~" + base_name(db.names.back().first));
-                first += 2;
-                db.parsed_ctor_dtor_cv = true;
-                break;
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
-//                     ::= <closure-type-name>
-// 
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ 
-// 
-// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
-
-template <class C>
-const char*
-parse_unnamed_type_name(const char* first, const char* last, C& db)
-{
-    if (last - first > 2 && first[0] == 'U')
-    {
-        char type = first[1];
-        switch (type)
-        {
-        case 't':
-          {
-            db.names.push_back(typename C::String("'unnamed"));
-            const char* t0 = first+2;
-            if (t0 == last)
-            {
-                db.names.pop_back();
-                return first;
-            }
-            if (std::isdigit(*t0))
-            {
-                const char* t1 = t0 + 1;
-                while (t1 != last && std::isdigit(*t1))
-                    ++t1;
-                db.names.back().first.append(t0, t1);
-                t0 = t1;
-            }
-            db.names.back().first.push_back('\'');
-            if (t0 == last || *t0 != '_')
-            {
-                db.names.pop_back();
-                return first;
-            }
-            first = t0 + 1;
-          }
-            break;
-        case 'l':
-          {
-            db.names.push_back(typename C::String("'lambda'("));
-            const char* t0 = first+2;
-            if (first[2] == 'v')
-            {
-                db.names.back().first += ')';
-                ++t0;
-            }
-            else
-            {
-                const char* t1 = parse_type(t0, last, db);
-                if (t1 == t0)
-                {
-                    db.names.pop_back();
-                    return first;
-                }
-                if (db.names.size() < 2)
-                    return first;
-                auto tmp = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first.append(tmp);
-                t0 = t1;
-                while (true)
-                {
-                    t1 = parse_type(t0, last, db);
-                    if (t1 == t0)
-                        break;
-                    if (db.names.size() < 2)
-                        return first;
-                    tmp = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!tmp.empty())
-                    {
-                        db.names.back().first.append(", ");
-                        db.names.back().first.append(tmp);
-                    }
-                    t0 = t1;
-                }
-                db.names.back().first.append(")");
-            }
-            if (t0 == last || *t0 != 'E')
-            {
-                db.names.pop_back();
-                return first;
-            }
-            ++t0;
-            if (t0 == last)
-            {
-                db.names.pop_back();
-                return first;
-            }
-            if (std::isdigit(*t0))
-            {
-                const char* t1 = t0 + 1;
-                while (t1 != last && std::isdigit(*t1))
-                    ++t1;
-                db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
-                t0 = t1;
-            }
-            if (t0 == last || *t0 != '_')
-            {
-                db.names.pop_back();
-                return first;
-            }
-            first = t0 + 1;
-          }
-            break;
-        }
-    }
-    return first;
-}
-
-// <unqualified-name> ::= <operator-name>
-//                    ::= <ctor-dtor-name>
-//                    ::= <source-name>   
-//                    ::= <unnamed-type-name>
-
-template <class C>
-const char*
-parse_unqualified_name(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        const char* t;
-        switch (*first)
-        {
-        case 'C':
-        case 'D':
-            t = parse_ctor_dtor_name(first, last, db);
-            if (t != first)
-                first = t;
-            break;
-        case 'U':
-            t = parse_unnamed_type_name(first, last, db);
-            if (t != first)
-                first = t;
-            break;
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-            t = parse_source_name(first, last, db);
-            if (t != first)
-                first = t;
-            break;
-        default:
-            t = parse_operator_name(first, last, db);
-            if (t != first)
-                first = t;
-            break;
-        };
-    }
-    return first;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-//                 ::= St <unqualified-name>   # ::std::
-// extension       ::= StL<unqualified-name>
-
-template <class C>
-const char*
-parse_unscoped_name(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        const char* t0 = first;
-        bool St = false;
-        if (first[0] == 'S' && first[1] == 't')
-        {
-            t0 += 2;
-            St = true;
-            if (t0 != last && *t0 == 'L')
-                ++t0;
-        }
-        const char* t1 = parse_unqualified_name(t0, last, db);
-        if (t1 != t0)
-        {
-            if (St)
-            {
-                if (db.names.empty())
-                    return first;
-                db.names.back().first.insert(0, "std::");
-            }
-            first = t1;
-        }
-    }
-    return first;
-}
-
-// at <type>                                            # alignof (a type)
-
-template <class C>
-const char*
-parse_alignof_type(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
-    {
-        const char* t = parse_type(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-// az <expression>                                            # alignof (a expression)
-
-template <class C>
-const char*
-parse_alignof_expr(const char* first, const char* last, C& db)
-{
-    if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
-    {
-        const char* t = parse_expression(first+2, last, db);
-        if (t != first+2)
-        {
-            if (db.names.empty())
-                return first;
-            db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
-            first = t;
-        }
-    }
-    return first;
-}
-
-template <class C>
-const char*
-parse_noexcept_expression(const char* first, const char* last, C& db)
-{
-    const char* t1 = parse_expression(first, last, db);
-    if (t1 != first)
-    {
-        if (db.names.empty())
-            return first;
-        db.names.back().first =  "noexcept (" + db.names.back().move_full() + ")";
-        first = t1;
-    }
-    return first;
-}
-
-template <class C>
-const char*
-parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
-    const char* t1 = parse_expression(first, last, db);
-    if (t1 != first)
-    {
-        if (db.names.empty())
-            return first;
-        db.names.back().first =  op + "(" + db.names.back().move_full() + ")";
-        first = t1;
-    }
-    return first;
-}
-
-template <class C>
-const char*
-parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
-    const char* t1 = parse_expression(first, last, db);
-    if (t1 != first)
-    {
-        const char* t2 = parse_expression(t1, last, db);
-        if (t2 != t1)
-        {
-            if (db.names.size() < 2)
-                return first;
-            auto op2 = db.names.back().move_full();
-            db.names.pop_back();
-            auto op1 = db.names.back().move_full();
-            auto& nm = db.names.back().first;
-            nm.clear();
-            if (op == ">")
-                nm += '(';
-            nm += "(" + op1 + ") " + op + " (" + op2 + ")";
-            if (op == ">")
-                nm += ')';
-            first = t2;
-        }
-        else
-            db.names.pop_back();
-    }
-    return first;
-}
-
-// <expression> ::= <unary operator-name> <expression>
-//              ::= <binary operator-name> <expression> <expression>
-//              ::= <ternary operator-name> <expression> <expression> <expression>
-//              ::= cl <expression>+ E                                   # call
-//              ::= cv <type> <expression>                               # conversion with one argument
-//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
-//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
-//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
-//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
-//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
-//              ::= [gs] dl <expression>                                 # delete expression
-//              ::= [gs] da <expression>                                 # delete[] expression
-//              ::= pp_ <expression>                                     # prefix ++
-//              ::= mm_ <expression>                                     # prefix --
-//              ::= ti <type>                                            # typeid (type)
-//              ::= te <expression>                                      # typeid (expression)
-//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)
-//              ::= sc <type> <expression>                               # static_cast<type> (expression)
-//              ::= cc <type> <expression>                               # const_cast<type> (expression)
-//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)
-//              ::= st <type>                                            # sizeof (a type)
-//              ::= sz <expression>                                      # sizeof (an expression)
-//              ::= at <type>                                            # alignof (a type)
-//              ::= az <expression>                                      # alignof (an expression)
-//              ::= nx <expression>                                      # noexcept (expression)
-//              ::= <template-param>
-//              ::= <function-param>
-//              ::= dt <expression> <unresolved-name>                    # expr.name
-//              ::= pt <expression> <unresolved-name>                    # expr->name
-//              ::= ds <expression> <expression>                         # expr.*expr
-//              ::= sZ <template-param>                                  # size of a parameter pack
-//              ::= sZ <function-param>                                  # size of a function parameter pack
-//              ::= sp <expression>                                      # pack expansion
-//              ::= tw <expression>                                      # throw expression
-//              ::= tr                                                   # throw with no operand (rethrow)
-//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),
-//                                                                       # freestanding dependent name (e.g., T::x),
-//                                                                       # objectless nonstatic member reference
-//              ::= <expr-primary>
-
-template <class C>
-const char*
-parse_expression(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2)
-    {
-        const char* t = first;
-        bool parsed_gs = false;
-        if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
-        {
-            t += 2;
-            parsed_gs = true;
-        }
-        switch (*t)
-        {
-        case 'L':
-            first = parse_expr_primary(first, last, db);
-            break;
-        case 'T':
-            first = parse_template_param(first, last, db);
-            break;
-        case 'f':
-            first = parse_function_param(first, last, db);
-            break;
-        case 'a':
-            switch (t[1])
-            {
-            case 'a':
-                t = parse_binary_expression(first+2, last, "&&", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'd':
-                t = parse_prefix_expression(first+2, last, "&", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'n':
-                t = parse_binary_expression(first+2, last, "&", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'N':
-                t = parse_binary_expression(first+2, last, "&=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'S':
-                t = parse_binary_expression(first+2, last, "=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 't':
-                first = parse_alignof_type(first, last, db);
-                break;
-            case 'z':
-                first = parse_alignof_expr(first, last, db);
-                break;
-            }
-            break;
-        case 'c':
-            switch (t[1])
-            {
-            case 'c':
-                first = parse_const_cast_expr(first, last, db);
-                break;
-            case 'l':
-                first = parse_call_expr(first, last, db);
-                break;
-            case 'm':
-                t = parse_binary_expression(first+2, last, ",", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'o':
-                t = parse_prefix_expression(first+2, last, "~", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'v':
-                first = parse_conversion_expr(first, last, db);
-                break;
-            }
-            break;
-        case 'd':
-            switch (t[1])
-            {
-            case 'a':
-                {
-                    const char* t1 = parse_expression(t+2, last, db);
-                    if (t1 != t+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
-                                          "delete[] " + db.names.back().move_full();
-                        first = t1;
-                    }
-                }
-                break;
-            case 'c':
-                first = parse_dynamic_cast_expr(first, last, db);
-                break;
-            case 'e':
-                t = parse_prefix_expression(first+2, last, "*", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'l':
-                {
-                    const char* t1 = parse_expression(t+2, last, db);
-                    if (t1 != t+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
-                                          "delete " + db.names.back().move_full();
-                        first = t1;
-                    }
-                }
-                break;
-            case 'n':
-                return parse_unresolved_name(first, last, db);
-            case 's':
-                first = parse_dot_star_expr(first, last, db);
-                break;
-            case 't':
-                first = parse_dot_expr(first, last, db);
-                break;
-            case 'v':
-                t = parse_binary_expression(first+2, last, "/", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'V':
-                t = parse_binary_expression(first+2, last, "/=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'e':
-            switch (t[1])
-            {
-            case 'o':
-                t = parse_binary_expression(first+2, last, "^", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'O':
-                t = parse_binary_expression(first+2, last, "^=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'q':
-                t = parse_binary_expression(first+2, last, "==", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'g':
-            switch (t[1])
-            {
-            case 'e':
-                t = parse_binary_expression(first+2, last, ">=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 't':
-                t = parse_binary_expression(first+2, last, ">", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'i':
-            if (t[1] == 'x')
-            {
-                const char* t1 = parse_expression(first+2, last, db);
-                if (t1 != first+2)
-                {
-                    const char* t2 = parse_expression(t1, last, db);
-                    if (t2 != t1)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto op2 = db.names.back().move_full();
-                        db.names.pop_back();
-                        auto op1 = db.names.back().move_full();
-                        db.names.back() = "(" + op1 + ")[" + op2 + "]";
-                        first = t2;
-                    }
-                    else
-                        db.names.pop_back();
-                }
-            }
-            break;
-        case 'l':
-            switch (t[1])
-            {
-            case 'e':
-                t = parse_binary_expression(first+2, last, "<=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 's':
-                t = parse_binary_expression(first+2, last, "<<", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'S':
-                t = parse_binary_expression(first+2, last, "<<=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 't':
-                t = parse_binary_expression(first+2, last, "<", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'm':
-            switch (t[1])
-            {
-            case 'i':
-                t = parse_binary_expression(first+2, last, "-", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'I':
-                t = parse_binary_expression(first+2, last, "-=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'l':
-                t = parse_binary_expression(first+2, last, "*", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'L':
-                t = parse_binary_expression(first+2, last, "*=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'm':
-                if (first+2 != last && first[2] == '_')
-                {
-                    t = parse_prefix_expression(first+3, last, "--", db);
-                    if (t != first+3)
-                        first = t;
-                }
-                else
-                {
-                    const char* t1 = parse_expression(first+2, last, db);
-                    if (t1 != first+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back() = "(" + db.names.back().move_full() + ")--";
-                        first = t1;
-                    }
-                }
-                break;
-            }
-            break;
-        case 'n':
-            switch (t[1])
-            {
-            case 'a':
-            case 'w':
-                first = parse_new_expr(first, last, db);
-                break;
-            case 'e':
-                t = parse_binary_expression(first+2, last, "!=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'g':
-                t = parse_prefix_expression(first+2, last, "-", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 't':
-                t = parse_prefix_expression(first+2, last, "!", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'x':
-                t = parse_noexcept_expression(first+2, last, db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'o':
-            switch (t[1])
-            {
-            case 'n':
-                return parse_unresolved_name(first, last, db);
-            case 'o':
-                t = parse_binary_expression(first+2, last, "||", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'r':
-                t = parse_binary_expression(first+2, last, "|", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'R':
-                t = parse_binary_expression(first+2, last, "|=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 'p':
-            switch (t[1])
-            {
-            case 'm':
-                t = parse_binary_expression(first+2, last, "->*", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'l':
-                t = parse_binary_expression(first+2, last, "+", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'L':
-                t = parse_binary_expression(first+2, last, "+=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'p':
-                if (first+2 != last && first[2] == '_')
-                {
-                    t = parse_prefix_expression(first+3, last, "++", db);
-                    if (t != first+3)
-                        first = t;
-                }
-                else
-                {
-                    const char* t1 = parse_expression(first+2, last, db);
-                    if (t1 != first+2)
-                    {
-                        if (db.names.empty())
-                            return first;
-                        db.names.back() = "(" + db.names.back().move_full() + ")++";
-                        first = t1;
-                    }
-                }
-                break;
-            case 's':
-                t = parse_prefix_expression(first+2, last, "+", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 't':
-                first = parse_arrow_expr(first, last, db);
-                break;
-            }
-            break;
-        case 'q':
-            if (t[1] == 'u')
-            {
-                const char* t1 = parse_expression(first+2, last, db);
-                if (t1 != first+2)
-                {
-                    const char* t2 = parse_expression(t1, last, db);
-                    if (t2 != t1)
-                    {
-                        const char* t3 = parse_expression(t2, last, db);
-                        if (t3 != t2)
-                        {
-                            if (db.names.size() < 3)
-                                return first;
-                            auto op3 = db.names.back().move_full();
-                            db.names.pop_back();
-                            auto op2 = db.names.back().move_full();
-                            db.names.pop_back();
-                            auto op1 = db.names.back().move_full();
-                            db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
-                            first = t3;
-                        }
-                        else
-                        {
-                            db.names.pop_back();
-                            db.names.pop_back();
-                        }
-                    }
-                    else
-                        db.names.pop_back();
-                }
-            }
-            break;
-        case 'r':
-            switch (t[1])
-            {
-            case 'c':
-                first = parse_reinterpret_cast_expr(first, last, db);
-                break;
-            case 'm':
-                t = parse_binary_expression(first+2, last, "%", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'M':
-                t = parse_binary_expression(first+2, last, "%=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 's':
-                t = parse_binary_expression(first+2, last, ">>", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            case 'S':
-                t = parse_binary_expression(first+2, last, ">>=", db);
-                if (t != first+2)
-                    first = t;
-                break;
-            }
-            break;
-        case 's':
-            switch (t[1])
-            {
-            case 'c':
-                first = parse_static_cast_expr(first, last, db);
-                break;
-            case 'p':
-                first = parse_pack_expansion(first, last, db);
-                break;
-            case 'r':
-                return parse_unresolved_name(first, last, db);
-            case 't':
-                first = parse_sizeof_type_expr(first, last, db);
-                break;
-            case 'z':
-                first = parse_sizeof_expr_expr(first, last, db);
-                break;
-            case 'Z':
-                if (last - t >= 3)
-                {
-                    switch (t[2])
-                    {
-                    case 'T':
-                        first = parse_sizeof_param_pack_expr(first, last, db);
-                        break;
-                    case 'f':
-                        first = parse_sizeof_function_param_pack_expr(first, last, db);
-                        break;
-                    }
-                }
-                break;
-            }
-            break;
-        case 't':
-            switch (t[1])
-            {
-            case 'e':
-            case 'i':
-                first = parse_typeid_expr(first, last, db);
-                break;
-            case 'r':
-                db.names.push_back("throw");
-                first += 2;
-                break;
-            case 'w':
-                first = parse_throw_expr(first, last, db);
-                break;
-            }
-            break;
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-            return parse_unresolved_name(first, last, db);
-        }
-    }
-    return first;
-}
-
-// <template-arg> ::= <type>                                             # type or template
-//                ::= X <expression> E                                   # expression
-//                ::= <expr-primary>                                     # simple expressions
-//                ::= J <template-arg>* E                                # argument pack
-//                ::= LZ <encoding> E                                    # extension
-
-template <class C>
-const char*
-parse_template_arg(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        const char* t;
-        switch (*first)
-        {
-        case 'X':
-            t = parse_expression(first+1, last, db);
-            if (t != first+1)
-            {
-                if (t != last && *t == 'E')
-                    first = t+1;
-            }
-            break;
-        case 'J':
-            t = first+1;
-            if (t == last)
-                return first;
-            while (*t != 'E')
-            {
-                const char* t1 = parse_template_arg(t, last, db);
-                if (t1 == t)
-                    return first;
-                t = t1;
-            }
-            first = t+1;
-            break;
-        case 'L':
-            // <expr-primary> or LZ <encoding> E
-            if (first+1 != last && first[1] == 'Z')
-            {
-                t = parse_encoding(first+2, last, db);
-                if (t != first+2 && t != last && *t == 'E')
-                    first = t+1;
-            }
-            else
-                first = parse_expr_primary(first, last, db);
-            break;
-        default:
-            // <type>
-            first = parse_type(first, last, db);
-            break;
-        }
-    }
-    return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-//     extension, the abi says <template-arg>+
-
-template <class C>
-const char*
-parse_template_args(const char* first, const char* last, C& db)
-{
-    if (last - first >= 2 && *first == 'I')
-    {
-        if (db.tag_templates)
-            db.template_param.back().clear();
-        const char* t = first+1;
-        typename C::String args("<");
-        while (*t != 'E')
-        {
-            if (db.tag_templates)
-                db.template_param.emplace_back(db.names.get_allocator());
-            size_t k0 = db.names.size();
-            const char* t1 = parse_template_arg(t, last, db);
-            size_t k1 = db.names.size();
-            if (db.tag_templates)
-                db.template_param.pop_back();
-            if (t1 == t || t1 == last)
-                return first;
-            if (db.tag_templates)
-            {
-                db.template_param.back().emplace_back(db.names.get_allocator());
-                for (size_t k = k0; k < k1; ++k)
-                    db.template_param.back().back().push_back(db.names[k]);
-            }
-            for (size_t k = k0; k < k1; ++k)
-            {
-                if (args.size() > 1)
-                    args += ", ";
-                args += db.names[k].move_full();
-            }
-            for (; k1 != k0; --k1)
-                db.names.pop_back();
-            t = t1;
-        }
-        first = t + 1;
-        if (args.back() != '>')
-            args += ">";
-        else
-            args += " >";
-        db.names.push_back(std::move(args));
-        
-    }
-    return first;
-}
-
-// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
-// 
-// <prefix> ::= <prefix> <unqualified-name>
-//          ::= <template-prefix> <template-args>
-//          ::= <template-param>
-//          ::= <decltype>
-//          ::= # empty
-//          ::= <substitution>
-//          ::= <prefix> <data-member-prefix>
-//  extension ::= L
-// 
-// <template-prefix> ::= <prefix> <template unqualified-name>
-//                   ::= <template-param>
-//                   ::= <substitution>
-
-template <class C>
-const char*
-parse_nested_name(const char* first, const char* last, C& db,
-                  bool* ends_with_template_args)
-{
-    if (first != last && *first == 'N')
-    {
-        unsigned cv;
-        const char* t0 = parse_cv_qualifiers(first+1, last, cv);
-        if (t0 == last)
-            return first;
-        db.ref = 0;
-        if (*t0 == 'R')
-        {
-            db.ref = 1;
-            ++t0;
-        }
-        else if (*t0 == 'O')
-        {
-            db.ref = 2;
-            ++t0;
-        }
-        db.names.emplace_back();
-        if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
-        {
-            t0 += 2;
-            db.names.back().first = "std";
-        }
-        if (t0 == last)
-        {
-            db.names.pop_back();
-            return first;
-        }
-        bool pop_subs = false;
-        bool component_ends_with_template_args = false;
-        while (*t0 != 'E')
-        {
-            component_ends_with_template_args = false;
-            const char* t1;
-            switch (*t0)
-            {
-            case 'S':
-                if (t0 + 1 != last && t0[1] == 't')
-                    goto do_parse_unqualified_name;
-                t1 = parse_substitution(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    auto name = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!db.names.back().first.empty())
-                    {
-                        db.names.back().first += "::" + name;
-                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    }
-                    else
-                        db.names.back().first = name;
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'T':
-                t1 = parse_template_param(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    auto name = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!db.names.back().first.empty())
-                        db.names.back().first += "::" + name;
-                    else
-                        db.names.back().first = name;
-                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'D':
-                if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
-                    goto do_parse_unqualified_name;
-                t1 = parse_decltype(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    auto name = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!db.names.back().first.empty())
-                        db.names.back().first += "::" + name;
-                    else
-                        db.names.back().first = name;
-                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-                break;
-            case 'I':
-                t1 = parse_template_args(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    auto name = db.names.back().move_full();
-                    db.names.pop_back();
-                    db.names.back().first += name;
-                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    t0 = t1;
-                    component_ends_with_template_args = true;
-                }
-                else
-                    return first;
-                break;
-            case 'L':
-                if (++t0 == last)
-                    return first;
-                break;
-            default:
-            do_parse_unqualified_name:
-                t1 = parse_unqualified_name(t0, last, db);
-                if (t1 != t0 && t1 != last)
-                {
-                    auto name = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!db.names.back().first.empty())
-                        db.names.back().first += "::" + name;
-                    else
-                        db.names.back().first = name;
-                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    pop_subs = true;
-                    t0 = t1;
-                }
-                else
-                    return first;
-            }
-        }
-        first = t0 + 1;
-        db.cv = cv;
-        if (pop_subs && !db.subs.empty())
-            db.subs.pop_back();
-        if (ends_with_template_args)
-            *ends_with_template_args = component_ends_with_template_args;
-    }
-    return first;
-}
-
-// <discriminator> := _ <non-negative number>      # when number < 10
-//                 := __ <non-negative number> _   # when number >= 10
-//  extension      := decimal-digit+               # at the end of string
-
-const char*
-parse_discriminator(const char* first, const char* last)
-{
-    // parse but ignore discriminator
-    if (first != last)
-    {
-        if (*first == '_')
-        {
-            const char* t1 = first+1;
-            if (t1 != last)
-            {
-                if (std::isdigit(*t1))
-                    first = t1+1;
-                else if (*t1 == '_')
-                {
-                    for (++t1; t1 != last && std::isdigit(*t1); ++t1)
-                        ;
-                    if (t1 != last && *t1 == '_')
-                        first = t1 + 1;
-                }
-            }
-        }
-        else if (std::isdigit(*first))
-        {
-            const char* t1 = first+1;
-            for (; t1 != last && std::isdigit(*t1); ++t1)
-                ;
-            if (t1 == last)
-                first = last;
-        }
-    }
-    return first;
-}
-
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-//              := Z <function encoding> E s [<discriminator>]
-//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
-template <class C>
-const char*
-parse_local_name(const char* first, const char* last, C& db,
-                 bool* ends_with_template_args)
-{
-    if (first != last && *first == 'Z')
-    {
-        const char* t = parse_encoding(first+1, last, db);
-        if (t != first+1 && t != last && *t == 'E' && ++t != last)
-        {
-            switch (*t)
-            {
-            case 's':
-                first = parse_discriminator(t+1, last);
-                if (db.names.empty())
-                    return first;
-                db.names.back().first.append("::string literal");
-                break;
-            case 'd':
-                if (++t != last)
-                {
-                    const char* t1 = parse_number(t, last);
-                    if (t1 != last && *t1 == '_')
-                    {
-                        t = t1 + 1;
-                        t1 = parse_name(t, last, db,
-                                        ends_with_template_args);
-                        if (t1 != t)
-                        {
-                            if (db.names.size() < 2)
-                                return first;
-                            auto name = db.names.back().move_full();
-                            db.names.pop_back();
-                            db.names.back().first.append("::");
-                            db.names.back().first.append(name);
-                            first = t1;
-                        }
-                        else
-                            db.names.pop_back();
-                    }
-                }
-                break;
-            default:
-                {
-                    const char* t1 = parse_name(t, last, db,
-                                                ends_with_template_args);
-                    if (t1 != t)
-                    {
-                        // parse but ignore discriminator
-                        first = parse_discriminator(t1, last);
-                        if (db.names.size() < 2)
-                            return first;
-                        auto name = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first.append("::");
-                        db.names.back().first.append(name);
-                    }
-                    else
-                        db.names.pop_back();
-                }
-                break;
-            }
-        }
-    }
-    return first;
-}
-
-// <name> ::= <nested-name> // N
-//        ::= <local-name> # See Scope Encoding below  // Z
-//        ::= <unscoped-template-name> <template-args>
-//        ::= <unscoped-name>
-
-// <unscoped-template-name> ::= <unscoped-name>
-//                          ::= <substitution>
-
-template <class C>
-const char*
-parse_name(const char* first, const char* last, C& db,
-           bool* ends_with_template_args)
-{
-    if (last - first >= 2)
-    {
-        const char* t0 = first;
-        // extension: ignore L here
-        if (*t0 == 'L')
-            ++t0;
-        switch (*t0)
-        {
-        case 'N':
-          {
-            const char* t1 = parse_nested_name(t0, last, db,
-                                               ends_with_template_args);
-            if (t1 != t0)
-                first = t1;
-            break;
-          }
-        case 'Z':
-          {
-            const char* t1 = parse_local_name(t0, last, db,
-                                              ends_with_template_args);
-            if (t1 != t0)
-                first = t1;
-            break;
-          }
-        default:
-          {
-            const char* t1 = parse_unscoped_name(t0, last, db);
-            if (t1 != t0)
-            {
-                if (t1 != last && *t1 == 'I')  // <unscoped-template-name> <template-args>
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
-                    t0 = t1;
-                    t1 = parse_template_args(t0, last, db);
-                    if (t1 != t0)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto tmp = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += tmp;
-                        first = t1;
-                        if (ends_with_template_args)
-                            *ends_with_template_args = true;
-                    }
-                }
-                else   // <unscoped-name>
-                    first = t1;
-            }
-            else
-            {   // try <substitution> <template-args>
-                t1 = parse_substitution(t0, last, db);
-                if (t1 != t0 && t1 != last && *t1 == 'I')
-                {
-                    t0 = t1;
-                    t1 = parse_template_args(t0, last, db);
-                    if (t1 != t0)
-                    {
-                        if (db.names.size() < 2)
-                            return first;
-                        auto tmp = db.names.back().move_full();
-                        db.names.pop_back();
-                        db.names.back().first += tmp;
-                        first = t1;
-                        if (ends_with_template_args)
-                            *ends_with_template_args = true;
-                    }
-                }
-            }
-            break;
-          }
-        }
-    }
-    return first;
-}
-
-// <call-offset> ::= h <nv-offset> _
-//               ::= v <v-offset> _
-// 
-// <nv-offset> ::= <offset number>
-//               # non-virtual base override
-// 
-// <v-offset>  ::= <offset number> _ <virtual offset number>
-//               # virtual base override, with vcall offset
-
-const char*
-parse_call_offset(const char* first, const char* last)
-{
-    if (first != last)
-    {
-        switch (*first)
-        {
-        case 'h':
-            {
-            const char* t = parse_number(first + 1, last);
-            if (t != first + 1 && t != last && *t == '_')
-                first = t + 1;
-            }
-            break;
-        case 'v':
-            {
-            const char* t = parse_number(first + 1, last);
-            if (t != first + 1 && t != last && *t == '_')
-            {
-                const char* t2 = parse_number(++t, last);
-                if (t2 != t && t2 != last && *t2 == '_')
-                    first = t2 + 1;
-            }
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-// <special-name> ::= TV <type>    # virtual table
-//                ::= TT <type>    # VTT structure (construction vtable index)
-//                ::= TI <type>    # typeinfo structure
-//                ::= TS <type>    # typeinfo name (null-terminated byte string)
-//                ::= Tc <call-offset> <call-offset> <base encoding>
-//                    # base is the nominal target function of thunk
-//                    # first call-offset is 'this' adjustment
-//                    # second call-offset is result adjustment
-//                ::= T <call-offset> <base encoding>
-//                    # base is the nominal target function of thunk
-//                ::= GV <object name> # Guard variable for one-time initialization
-//                                     # No <type>
-//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-//      extension ::= GR <object name> # reference temporary for object
-
-template <class C>
-const char*
-parse_special_name(const char* first, const char* last, C& db)
-{
-    if (last - first > 2)
-    {
-        const char* t;
-        switch (*first)
-        {
-        case 'T':
-            switch (first[1])
-            {
-            case 'V':
-                // TV <type>    # virtual table
-                t = parse_type(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "vtable for ");
-                    first = t;
-                }
-                break;
-            case 'T':
-                // TT <type>    # VTT structure (construction vtable index)
-                t = parse_type(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "VTT for ");
-                    first = t;
-                }
-                break;
-            case 'I':
-                // TI <type>    # typeinfo structure
-                t = parse_type(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "typeinfo for ");
-                    first = t;
-                }
-                break;
-            case 'S':
-                // TS <type>    # typeinfo name (null-terminated byte string)
-                t = parse_type(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "typeinfo name for ");
-                    first = t;
-                }
-                break;
-            case 'c':
-                // Tc <call-offset> <call-offset> <base encoding>
-              {
-                const char* t0 = parse_call_offset(first+2, last);
-                if (t0 == first+2)
-                    break;
-                const char* t1 = parse_call_offset(t0, last);
-                if (t1 == t0)
-                    break;
-                t = parse_encoding(t1, last, db);
-                if (t != t1)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "covariant return thunk to ");
-                    first = t;
-                }
-              }
-                break;
-            case 'C':
-                // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-                t = parse_type(first+2, last, db);
-                if (t != first+2)
-                {
-                    const char* t0 = parse_number(t, last);
-                    if (t0 != t && t0 != last && *t0 == '_')
-                    {
-                        const char* t1 = parse_type(++t0, last, db);
-                        if (t1 != t0)
-                        {
-                            if (db.names.size() < 2)
-                                return first;
-                            auto left = db.names.back().move_full();
-                            db.names.pop_back();
-                            db.names.back().first = "construction vtable for " +
-                                                    std::move(left) + "-in-" +
-                                                    db.names.back().move_full();
-                            first = t1;
-                        }
-                    }
-                }
-                break;
-            default:
-                // T <call-offset> <base encoding>
-                {
-                const char* t0 = parse_call_offset(first+1, last);
-                if (t0 == first+1)
-                    break;
-                t = parse_encoding(t0, last, db);
-                if (t != t0)
-                {
-                    if (db.names.empty())
-                        return first;
-                    if (first[1] == 'v')
-                    {
-                        db.names.back().first.insert(0, "virtual thunk to ");
-                        first = t;
-                    }
-                    else
-                    {
-                        db.names.back().first.insert(0, "non-virtual thunk to ");
-                        first = t;
-                    }
-                }
-                }
-                break;
-            }
-            break;
-        case 'G':
-            switch (first[1])
-            {
-            case 'V':
-                // GV <object name> # Guard variable for one-time initialization
-                t = parse_name(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "guard variable for ");
-                    first = t;
-                }
-                break;
-            case 'R':
-                // extension ::= GR <object name> # reference temporary for object
-                t = parse_name(first+2, last, db);
-                if (t != first+2)
-                {
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first.insert(0, "reference temporary for ");
-                    first = t;
-                }
-                break;
-            }
-            break;
-        }
-    }
-    return first;
-}
-
-template <class T>
-class save_value
-{
-    T& restore_;
-    T original_value_;
-public:
-    save_value(T& restore)
-        : restore_(restore),
-          original_value_(restore)
-        {}
-
-    ~save_value()
-    {
-        restore_ = std::move(original_value_);
-    }
-
-    save_value(const save_value&) = delete;
-    save_value& operator=(const save_value&) = delete;
-};
-
-// <encoding> ::= <function name> <bare-function-type>
-//            ::= <data name>
-//            ::= <special-name>
-
-template <class C>
-const char*
-parse_encoding(const char* first, const char* last, C& db)
-{
-    if (first != last)
-    {
-        save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
-        ++db.encoding_depth;
-        save_value<decltype(db.tag_templates)> sb(db.tag_templates);
-        if (db.encoding_depth > 1)
-            db.tag_templates = true;
-        switch (*first)
-        {
-        case 'G':
-        case 'T':
-            first = parse_special_name(first, last, db);
-            break;
-        default:
-          {
-            bool ends_with_template_args = false;
-            const char* t = parse_name(first, last, db,
-                                       &ends_with_template_args);
-            unsigned cv = db.cv;
-            unsigned ref = db.ref;
-            if (t != first)
-            {
-                if (t != last && *t != 'E' && *t != '.')
-                {
-                    save_value<bool> sb2(db.tag_templates);
-                    db.tag_templates = false;
-                    const char* t2;
-                    typename C::String ret2;
-                    if (db.names.empty())
-                        return first;
-                    const typename C::String& nm = db.names.back().first;
-                    if (nm.empty())
-                        return first;
-                    if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
-                    {
-                        t2 = parse_type(t, last, db);
-                        if (t2 == t)
-                            return first;
-                        if (db.names.size() < 2)
-                            return first;
-                        auto ret1 = std::move(db.names.back().first);
-                        ret2 = std::move(db.names.back().second);
-                        if (ret2.empty())
-                            ret1 += ' ';
-                        db.names.pop_back();
-                        db.names.back().first.insert(0, ret1);
-                        t = t2;
-                    }
-                    db.names.back().first += '(';
-                    if (t != last && *t == 'v')
-                    {
-                        ++t;
-                    }
-                    else
-                    {
-                        bool first_arg = true;
-                        while (true)
-                        {
-                            size_t k0 = db.names.size();
-                            t2 = parse_type(t, last, db);
-                            size_t k1 = db.names.size();
-                            if (t2 == t)
-                                break;
-                            if (k1 > k0)
-                            {
-                                typename C::String tmp;
-                                for (size_t k = k0; k < k1; ++k)
-                                {
-                                    if (!tmp.empty())
-                                        tmp += ", ";
-                                    tmp += db.names[k].move_full();
-                                }
-                                for (size_t k = k0; k < k1; ++k)
-                                    db.names.pop_back();
-                                if (!tmp.empty())
-                                {
-                                    if (db.names.empty())
-                                        return first;
-                                    if (!first_arg)
-                                        db.names.back().first += ", ";
-                                    else
-                                        first_arg = false;
-                                    db.names.back().first += tmp;
-                                }
-                            }
-                            t = t2;
-                        }
-                    }
-                    if (db.names.empty())
-                        return first;
-                    db.names.back().first += ')';
-                    if (cv & 1)
-                        db.names.back().first.append(" const");
-                    if (cv & 2)
-                        db.names.back().first.append(" volatile");
-                    if (cv & 4)
-                        db.names.back().first.append(" restrict");
-                    if (ref == 1)
-                        db.names.back().first.append(" &");
-                    else if (ref == 2)
-                        db.names.back().first.append(" &&");
-                    db.names.back().first += ret2;
-                    first = t;
-                }
-                else
-                    first = t;
-            }
-            break;
-          }
-        }
-    }
-    return first;
-}
-
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
-
-template <class C>
-const char*
-parse_block_invoke(const char* first, const char* last, C& db)
-{
-    if (last - first >= 13)
-    {
-        const char test[] = "_block_invoke";
-        const char* t = first;
-        for (int i = 0; i < 13; ++i, ++t)
-        {
-            if (*t != test[i])
-                return first;
-        }
-        if (t != last)
-        {
-            if (*t == '_')
-            {
-                // must have at least 1 decimal digit
-                if (++t == last || !std::isdigit(*t))
-                    return first;
-                ++t;
-            }
-            // parse zero or more digits
-            while (t != last && isdigit(*t))
-                ++t;
-        }
-        if (db.names.empty())
-            return first;
-        db.names.back().first.insert(0, "invocation function for block in ");
-        first = t;
-    }
-    return first;
-}
-
-// extension
-// <dot-suffix> := .<anything and everything>
-
-template <class C>
-const char*
-parse_dot_suffix(const char* first, const char* last, C& db)
-{
-    if (first != last && *first == '.')
-    {
-        if (db.names.empty())
-            return first;
-        db.names.back().first += " (" + typename C::String(first, last) + ")";
-        first = last;
-    }
-    return first;
-}
-
-// <block-involcaton-function> ___Z<encoding>_block_invoke
-// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
-// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
-// <mangled-name> ::= _Z<encoding>
-//                ::= <type>
-
-template <class C>
-void
-demangle(const char* first, const char* last, C& db, int& status)
-{
-    if (first >= last)
-    {
-        status = invalid_mangled_name;
-        return;
-    }
-    if (*first == '_')
-    {
-        if (last - first >= 4)
-        {
-            if (first[1] == 'Z')
-            {
-                const char* t = parse_encoding(first+2, last, db);
-                if (t != first+2 && t != last && *t == '.')
-                    t = parse_dot_suffix(t, last, db);
-                if (t != last)
-                    status = invalid_mangled_name;
-            }
-            else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
-            {
-                const char* t = parse_encoding(first+4, last, db);
-                if (t != first+4 && t != last)
-                {
-                    const char* t1 = parse_block_invoke(t, last, db);
-                    if (t1 != last)
-                        status = invalid_mangled_name;
-                }
-                else
-                    status = invalid_mangled_name;
-            }
-            else
-                status = invalid_mangled_name;
-        }
-        else
-            status = invalid_mangled_name;
-    }
-    else
-    {
-        const char* t = parse_type(first, last, db);
-        if (t != last)
-            status = invalid_mangled_name;
-    }
-    if (status == success && db.names.empty())
-        status = invalid_mangled_name;
-}
-
-template <std::size_t N>
-class arena
-{
-    static const std::size_t alignment = 16;
-    alignas(alignment) char buf_[N];
-    char* ptr_;
-
-    std::size_t 
-    align_up(std::size_t n) noexcept
-        {return (n + (alignment-1)) & ~(alignment-1);}
-
-    bool
-    pointer_in_buffer(char* p) noexcept
-        {return buf_ <= p && p <= buf_ + N;}
-
-public:
-    arena() noexcept : ptr_(buf_) {}
-    ~arena() {ptr_ = nullptr;}
-    arena(const arena&) = delete;
-    arena& operator=(const arena&) = delete;
-
-    char* allocate(std::size_t n);
-    void deallocate(char* p, std::size_t n) noexcept;
-
-    static constexpr std::size_t size() {return N;}
-    std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
-    void reset() {ptr_ = buf_;}
-};
-
-template <std::size_t N>
-char*
-arena<N>::allocate(std::size_t n)
-{
-    n = align_up(n);
-    if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
-    {
-        char* r = ptr_;
-        ptr_ += n;
-        return r;
-    }
-    return static_cast<char*>(std::malloc(n));
-}
-
-template <std::size_t N>
-void
-arena<N>::deallocate(char* p, std::size_t n) noexcept
-{
-    if (pointer_in_buffer(p))
-    {
-        n = align_up(n);
-        if (p + n == ptr_)
-            ptr_ = p;
-    }
-    else
-        std::free(p);
-}
-
-template <class T, std::size_t N>
-class short_alloc
-{
-    arena<N>& a_;
-public:
-    typedef T value_type;
-
-public:
-    template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
-
-    short_alloc(arena<N>& a) noexcept : a_(a) {}
-    template <class U>
-        short_alloc(const short_alloc<U, N>& a) noexcept
-            : a_(a.a_) {}
-    short_alloc(const short_alloc&) = default;
-    short_alloc& operator=(const short_alloc&) = delete;
-
-    T* allocate(std::size_t n)
-    {
-        return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
-    }
-    void deallocate(T* p, std::size_t n) noexcept
-    {
-        a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
-    }
-
-    template <class T1, std::size_t N1, class U, std::size_t M>
-    friend
-    bool
-    operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
-
-    template <class U, std::size_t M> friend class short_alloc;
-};
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
-    return N == M && &x.a_ == &y.a_;
-}
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
-    return !(x == y);
-}
-
-template <class T>
-class malloc_alloc
-{
-public:
-    typedef T value_type;
-    typedef T& reference;
-    typedef const T& const_reference;
-    typedef T* pointer;
-    typedef const T* const_pointer;
-    typedef std::size_t size_type;
-    typedef std::ptrdiff_t difference_type;
-
-    malloc_alloc() = default;
-    template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
-
-    T* allocate(std::size_t n)
-    {
-        return static_cast<T*>(std::malloc(n*sizeof(T)));
-    }
-    void deallocate(T* p, std::size_t) noexcept
-    {
-        std::free(p);
-    }
-
-    template <class U> struct rebind { using other = malloc_alloc<U>; };
-    template <class U, class... Args>
-    void construct(U* p, Args&&... args)
-    {
-        ::new ((void*)p) U(std::forward<Args>(args)...);
-    }
-    void destroy(T* p)
-    {
-        p->~T();
-    }
-};
-
-template <class T, class U>
-inline
-bool
-operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
-{
-    return true;
-}
-
-template <class T, class U>
-inline
-bool
-operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
-{
-    return !(x == y);
-}
-
-const size_t bs = 4 * 1024;
-template <class T> using Alloc = short_alloc<T, bs>;
-template <class T> using Vector = std::vector<T, Alloc<T>>;
-
-template <class StrT>
-struct string_pair
-{
-    StrT first;
-    StrT second;
-
-    string_pair() = default;
-    string_pair(StrT f) : first(std::move(f)) {}
-    string_pair(StrT f, StrT s)
-        : first(std::move(f)), second(std::move(s)) {}
-    template <size_t N>
-        string_pair(const char (&s)[N]) : first(s, N-1) {}
-
-    size_t size() const {return first.size() + second.size();}
-    StrT full() const {return first + second;}
-    StrT move_full() {return std::move(first) + std::move(second);}
-};
-
-struct Db
-{
-    typedef std::basic_string<char, std::char_traits<char>,
-                              malloc_alloc<char>> String;
-    typedef Vector<string_pair<String>> sub_type;
-    typedef Vector<sub_type> template_param_type;
-    sub_type names;
-    template_param_type subs;
-    Vector<template_param_type> template_param;
-    unsigned cv;
-    unsigned ref;
-    unsigned encoding_depth;
-    bool parsed_ctor_dtor_cv;
-    bool tag_templates;
-    bool fix_forward_references;
-    bool try_to_parse_template_args;
-
-    template <size_t N>
-    Db(arena<N>& ar) :
-        names(ar),
-        subs(0, names, ar),
-        template_param(0, subs, ar)
-    {}
-};
-
-}  // unnamed namespace
-
-extern "C" _LIBCXXABI_FUNC_VIS char *
-__cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) {
-    if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
-    {
-        if (status)
-            *status = invalid_args;
-        return nullptr;
-    }
-    size_t internal_size = buf != nullptr ? *n : 0;
-    arena<bs> a;
-    Db db(a);
-    db.cv = 0;
-    db.ref = 0;
-    db.encoding_depth = 0;
-    db.parsed_ctor_dtor_cv = false;
-    db.tag_templates = true;
-    db.template_param.emplace_back(a);
-    db.fix_forward_references = false;
-    db.try_to_parse_template_args = true;
-    int internal_status = success;
-    size_t len = std::strlen(mangled_name);
-    demangle(mangled_name, mangled_name + len, db,
-             internal_status);
-    if (internal_status == success && db.fix_forward_references &&
-           !db.template_param.empty() && !db.template_param.front().empty())
-    {
-        db.fix_forward_references = false;
-        db.tag_templates = false;
-        db.names.clear();
-        db.subs.clear();
-        demangle(mangled_name, mangled_name + len, db, internal_status);
-        if (db.fix_forward_references)
-            internal_status = invalid_mangled_name;
-    }
-    if (internal_status == success)
-    {
-        size_t sz = db.names.back().size() + 1;
-        if (sz > internal_size)
-        {
-            char* newbuf = static_cast<char*>(std::realloc(buf, sz));
-            if (newbuf == nullptr)
-            {
-                internal_status = memory_alloc_failure;
-                buf = nullptr;
-            }
-            else
-            {
-                buf = newbuf;
-                if (n != nullptr)
-                    *n = sz;
-            }
-        }
-        if (buf != nullptr)
-        {
-            db.names.back().first += db.names.back().second;
-            std::memcpy(buf, db.names.back().first.data(), sz-1);
-            buf[sz-1] = char(0);
-        }
-    }
-    else
-        buf = nullptr;
-    if (status)
-        *status = internal_status;
-    return buf;
-}
-
-}  // __cxxabiv1
diff --git a/third_party/llvm/LICENSE.txt b/third_party/llvm/LICENSE.txt
new file mode 100644
index 0000000..57a8005
--- /dev/null
+++ b/third_party/llvm/LICENSE.txt
@@ -0,0 +1,43 @@
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2018 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
diff --git a/third_party/llvm/include/llvm/Demangle/Compiler.h b/third_party/llvm/include/llvm/Demangle/Compiler.h
new file mode 100644
index 0000000..248d6e3
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/Compiler.h
@@ -0,0 +1,93 @@
+//===--- Compiler.h ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//
+// This file contains a variety of feature test macros copied from
+// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take
+// a dependency on LLVMSupport.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_COMPILER_H
+#define LLVM_DEMANGLE_COMPILER_H
+
+#ifdef _MSC_VER
+// snprintf is implemented in VS 2015
+#if _MSC_VER < 1900
+#define snprintf _snprintf_s
+#endif
+#endif
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#ifndef __has_cpp_attribute
+#define __has_cpp_attribute(x) 0
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#ifndef LLVM_GNUC_PREREQ
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+#define LLVM_GNUC_PREREQ(maj, min, patch)                                      \
+  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >=          \
+   ((maj) << 20) + ((min) << 10) + (patch))
+#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define LLVM_GNUC_PREREQ(maj, min, patch)                                      \
+  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+#else
+#define LLVM_GNUC_PREREQ(maj, min, patch) 0
+#endif
+#endif
+
+#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
+#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define LLVM_ATTRIBUTE_USED
+#endif
+
+#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
+#define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define LLVM_BUILTIN_UNREACHABLE __assume(false)
+#endif
+
+#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
+#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
+#else
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif __has_cpp_attribute(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif !__cplusplus
+// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
+// error when __has_cpp_attribute is given a scoped attribute in C mode.
+#define LLVM_FALLTHROUGH
+#elif __has_cpp_attribute(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+
+#endif
diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h
new file mode 100644
index 0000000..b9b4d15
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/Demangle.h
@@ -0,0 +1,101 @@
+//===--- Demangle.h ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_DEMANGLE_H
+#define LLVM_DEMANGLE_DEMANGLE_H
+
+#include <cstddef>
+
+namespace llvm {
+/// This is a llvm local version of __cxa_demangle. Other than the name and
+/// being in the llvm namespace it is identical.
+///
+/// The mangled_name is demangled into buf and returned. If the buffer is not
+/// large enough, realloc is used to expand it.
+///
+/// The *status will be set to a value from the following enumeration
+enum : int {
+  demangle_unknown_error = -4,
+  demangle_invalid_args = -3,
+  demangle_invalid_mangled_name = -2,
+  demangle_memory_alloc_failure = -1,
+  demangle_success = 0,
+};
+
+char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
+                      int *status);
+
+/// Calls the callback \c Callback with \c Ctx as an argument whenever a type is
+/// encountered. Returns true if \c MangledName couldn't be parsed.
+bool itaniumFindTypesInMangledName(const char *MangledName, void *Ctx,
+                                   void (*Callback)(void *, const char *));
+
+
+enum MSDemangleFlags { MSDF_None = 0, MSDF_DumpBackrefs = 1 << 0 };
+char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
+                        int *status, MSDemangleFlags Flags = MSDF_None);
+
+/// "Partial" demangler. This supports demangling a string into an AST
+/// (typically an intermediate stage in itaniumDemangle) and querying certain
+/// properties or partially printing the demangled name.
+struct ItaniumPartialDemangler {
+  ItaniumPartialDemangler();
+
+  ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
+  ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
+
+  /// Demangle into an AST. Subsequent calls to the rest of the member functions
+  /// implicitly operate on the AST this produces.
+  /// \return true on error, false otherwise
+  bool partialDemangle(const char *MangledName);
+
+  /// Just print the entire mangled name into Buf. Buf and N behave like the
+  /// second and third parameters to itaniumDemangle.
+  char *finishDemangle(char *Buf, size_t *N) const;
+
+  /// Get the base name of a function. This doesn't include trailing template
+  /// arguments, ie for "a::b<int>" this function returns "b".
+  char *getFunctionBaseName(char *Buf, size_t *N) const;
+
+  /// Get the context name for a function. For "a::b::c", this function returns
+  /// "a::b".
+  char *getFunctionDeclContextName(char *Buf, size_t *N) const;
+
+  /// Get the entire name of this function.
+  char *getFunctionName(char *Buf, size_t *N) const;
+
+  /// Get the parameters for this function.
+  char *getFunctionParameters(char *Buf, size_t *N) const;
+  char *getFunctionReturnType(char *Buf, size_t *N) const;
+
+  /// If this function has any any cv or reference qualifiers. These imply that
+  /// the function is a non-static member function.
+  bool hasFunctionQualifiers() const;
+
+  /// If this symbol describes a constructor or destructor.
+  bool isCtorOrDtor() const;
+
+  /// If this symbol describes a function.
+  bool isFunction() const;
+
+  /// If this symbol describes a variable.
+  bool isData() const;
+
+  /// If this symbol is a <special-name>. These are generally implicitly
+  /// generated by the implementation, such as vtables and typeinfo names.
+  bool isSpecialName() const;
+
+  ~ItaniumPartialDemangler();
+private:
+  void *RootNode;
+  void *Context;
+};
+} // namespace llvm
+
+#endif
diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
new file mode 100644
index 0000000..c5619a1
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -0,0 +1,5190 @@
+//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H
+#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H
+
+// FIXME: (possibly) incomplete list of features that clang mangles that this
+// file does not yet support:
+//   - C++ modules TS
+
+#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/StringView.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <numeric>
+#include <utility>
+
+#define FOR_EACH_NODE_KIND(X) \
+    X(NodeArrayNode) \
+    X(DotSuffix) \
+    X(VendorExtQualType) \
+    X(QualType) \
+    X(ConversionOperatorType) \
+    X(PostfixQualifiedType) \
+    X(ElaboratedTypeSpefType) \
+    X(NameType) \
+    X(AbiTagAttr) \
+    X(EnableIfAttr) \
+    X(ObjCProtoName) \
+    X(PointerType) \
+    X(ReferenceType) \
+    X(PointerToMemberType) \
+    X(ArrayType) \
+    X(FunctionType) \
+    X(NoexceptSpec) \
+    X(DynamicExceptionSpec) \
+    X(FunctionEncoding) \
+    X(LiteralOperator) \
+    X(SpecialName) \
+    X(CtorVtableSpecialName) \
+    X(QualifiedName) \
+    X(NestedName) \
+    X(LocalName) \
+    X(VectorType) \
+    X(PixelVectorType) \
+    X(ParameterPack) \
+    X(TemplateArgumentPack) \
+    X(ParameterPackExpansion) \
+    X(TemplateArgs) \
+    X(ForwardTemplateReference) \
+    X(NameWithTemplateArgs) \
+    X(GlobalQualifiedName) \
+    X(StdQualifiedName) \
+    X(ExpandedSpecialSubstitution) \
+    X(SpecialSubstitution) \
+    X(CtorDtorName) \
+    X(DtorName) \
+    X(UnnamedTypeName) \
+    X(ClosureTypeName) \
+    X(StructuredBindingName) \
+    X(BinaryExpr) \
+    X(ArraySubscriptExpr) \
+    X(PostfixExpr) \
+    X(ConditionalExpr) \
+    X(MemberExpr) \
+    X(EnclosingExpr) \
+    X(CastExpr) \
+    X(SizeofParamPackExpr) \
+    X(CallExpr) \
+    X(NewExpr) \
+    X(DeleteExpr) \
+    X(PrefixExpr) \
+    X(FunctionParam) \
+    X(ConversionExpr) \
+    X(InitListExpr) \
+    X(FoldExpr) \
+    X(ThrowExpr) \
+    X(BoolExpr) \
+    X(IntegerCastExpr) \
+    X(IntegerLiteral) \
+    X(FloatLiteral) \
+    X(DoubleLiteral) \
+    X(LongDoubleLiteral) \
+    X(BracedExpr) \
+    X(BracedRangeExpr)
+
+namespace llvm {
+namespace itanium_demangle {
+// Base class of all AST nodes. The AST is built by the parser, then is
+// traversed by the printLeft/Right functions to produce a demangled string.
+class Node {
+public:
+  enum Kind : unsigned char {
+#define ENUMERATOR(NodeKind) K ## NodeKind,
+    FOR_EACH_NODE_KIND(ENUMERATOR)
+#undef ENUMERATOR
+  };
+
+  /// Three-way bool to track a cached value. Unknown is possible if this node
+  /// has an unexpanded parameter pack below it that may affect this cache.
+  enum class Cache : unsigned char { Yes, No, Unknown, };
+
+private:
+  Kind K;
+
+  // FIXME: Make these protected.
+public:
+  /// Tracks if this node has a component on its right side, in which case we
+  /// need to call printRight.
+  Cache RHSComponentCache;
+
+  /// Track if this node is a (possibly qualified) array type. This can affect
+  /// how we format the output string.
+  Cache ArrayCache;
+
+  /// Track if this node is a (possibly qualified) function type. This can
+  /// affect how we format the output string.
+  Cache FunctionCache;
+
+public:
+  Node(Kind K_, Cache RHSComponentCache_ = Cache::No,
+       Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)
+      : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
+        FunctionCache(FunctionCache_) {}
+
+  /// Visit the most-derived object corresponding to this object.
+  template<typename Fn> void visit(Fn F) const;
+
+  // The following function is provided by all derived classes:
+  //
+  // Call F with arguments that, when passed to the constructor of this node,
+  // would construct an equivalent node.
+  //template<typename Fn> void match(Fn F) const;
+
+  bool hasRHSComponent(OutputStream &S) const {
+    if (RHSComponentCache != Cache::Unknown)
+      return RHSComponentCache == Cache::Yes;
+    return hasRHSComponentSlow(S);
+  }
+
+  bool hasArray(OutputStream &S) const {
+    if (ArrayCache != Cache::Unknown)
+      return ArrayCache == Cache::Yes;
+    return hasArraySlow(S);
+  }
+
+  bool hasFunction(OutputStream &S) const {
+    if (FunctionCache != Cache::Unknown)
+      return FunctionCache == Cache::Yes;
+    return hasFunctionSlow(S);
+  }
+
+  Kind getKind() const { return K; }
+
+  virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
+  virtual bool hasArraySlow(OutputStream &) const { return false; }
+  virtual bool hasFunctionSlow(OutputStream &) const { return false; }
+
+  // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
+  // get at a node that actually represents some concrete syntax.
+  virtual const Node *getSyntaxNode(OutputStream &) const {
+    return this;
+  }
+
+  void print(OutputStream &S) const {
+    printLeft(S);
+    if (RHSComponentCache != Cache::No)
+      printRight(S);
+  }
+
+  // Print the "left" side of this Node into OutputStream.
+  virtual void printLeft(OutputStream &) const = 0;
+
+  // Print the "right". This distinction is necessary to represent C++ types
+  // that appear on the RHS of their subtype, such as arrays or functions.
+  // Since most types don't have such a component, provide a default
+  // implementation.
+  virtual void printRight(OutputStream &) const {}
+
+  virtual StringView getBaseName() const { return StringView(); }
+
+  // Silence compiler warnings, this dtor will never be called.
+  virtual ~Node() = default;
+
+#ifndef NDEBUG
+  LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+class NodeArray {
+  Node **Elements;
+  size_t NumElements;
+
+public:
+  NodeArray() : Elements(nullptr), NumElements(0) {}
+  NodeArray(Node **Elements_, size_t NumElements_)
+      : Elements(Elements_), NumElements(NumElements_) {}
+
+  bool empty() const { return NumElements == 0; }
+  size_t size() const { return NumElements; }
+
+  Node **begin() const { return Elements; }
+  Node **end() const { return Elements + NumElements; }
+
+  Node *operator[](size_t Idx) const { return Elements[Idx]; }
+
+  void printWithComma(OutputStream &S) const {
+    bool FirstElement = true;
+    for (size_t Idx = 0; Idx != NumElements; ++Idx) {
+      size_t BeforeComma = S.getCurrentPosition();
+      if (!FirstElement)
+        S += ", ";
+      size_t AfterComma = S.getCurrentPosition();
+      Elements[Idx]->print(S);
+
+      // Elements[Idx] is an empty parameter pack expansion, we should erase the
+      // comma we just printed.
+      if (AfterComma == S.getCurrentPosition()) {
+        S.setCurrentPosition(BeforeComma);
+        continue;
+      }
+
+      FirstElement = false;
+    }
+  }
+};
+
+struct NodeArrayNode : Node {
+  NodeArray Array;
+  NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Array); }
+
+  void printLeft(OutputStream &S) const override {
+    Array.printWithComma(S);
+  }
+};
+
+class DotSuffix final : public Node {
+  const Node *Prefix;
+  const StringView Suffix;
+
+public:
+  DotSuffix(const Node *Prefix_, StringView Suffix_)
+      : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }
+
+  void printLeft(OutputStream &s) const override {
+    Prefix->print(s);
+    s += " (";
+    s += Suffix;
+    s += ")";
+  }
+};
+
+class VendorExtQualType final : public Node {
+  const Node *Ty;
+  StringView Ext;
+
+public:
+  VendorExtQualType(const Node *Ty_, StringView Ext_)
+      : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty, Ext); }
+
+  void printLeft(OutputStream &S) const override {
+    Ty->print(S);
+    S += " ";
+    S += Ext;
+  }
+};
+
+enum FunctionRefQual : unsigned char {
+  FrefQualNone,
+  FrefQualLValue,
+  FrefQualRValue,
+};
+
+enum Qualifiers {
+  QualNone = 0,
+  QualConst = 0x1,
+  QualVolatile = 0x2,
+  QualRestrict = 0x4,
+};
+
+inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) {
+  return Q1 = static_cast<Qualifiers>(Q1 | Q2);
+}
+
+class QualType : public Node {
+protected:
+  const Qualifiers Quals;
+  const Node *Child;
+
+  void printQuals(OutputStream &S) const {
+    if (Quals & QualConst)
+      S += " const";
+    if (Quals & QualVolatile)
+      S += " volatile";
+    if (Quals & QualRestrict)
+      S += " restrict";
+  }
+
+public:
+  QualType(const Node *Child_, Qualifiers Quals_)
+      : Node(KQualType, Child_->RHSComponentCache,
+             Child_->ArrayCache, Child_->FunctionCache),
+        Quals(Quals_), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Child, Quals); }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Child->hasRHSComponent(S);
+  }
+  bool hasArraySlow(OutputStream &S) const override {
+    return Child->hasArray(S);
+  }
+  bool hasFunctionSlow(OutputStream &S) const override {
+    return Child->hasFunction(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Child->printLeft(S);
+    printQuals(S);
+  }
+
+  void printRight(OutputStream &S) const override { Child->printRight(S); }
+};
+
+class ConversionOperatorType final : public Node {
+  const Node *Ty;
+
+public:
+  ConversionOperatorType(const Node *Ty_)
+      : Node(KConversionOperatorType), Ty(Ty_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "operator ";
+    Ty->print(S);
+  }
+};
+
+class PostfixQualifiedType final : public Node {
+  const Node *Ty;
+  const StringView Postfix;
+
+public:
+  PostfixQualifiedType(Node *Ty_, StringView Postfix_)
+      : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
+
+  void printLeft(OutputStream &s) const override {
+    Ty->printLeft(s);
+    s += Postfix;
+  }
+};
+
+class NameType final : public Node {
+  const StringView Name;
+
+public:
+  NameType(StringView Name_) : Node(KNameType), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Name); }
+
+  StringView getName() const { return Name; }
+  StringView getBaseName() const override { return Name; }
+
+  void printLeft(OutputStream &s) const override { s += Name; }
+};
+
+class ElaboratedTypeSpefType : public Node {
+  StringView Kind;
+  Node *Child;
+public:
+  ElaboratedTypeSpefType(StringView Kind_, Node *Child_)
+      : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Kind, Child); }
+
+  void printLeft(OutputStream &S) const override {
+    S += Kind;
+    S += ' ';
+    Child->print(S);
+  }
+};
+
+struct AbiTagAttr : Node {
+  Node *Base;
+  StringView Tag;
+
+  AbiTagAttr(Node* Base_, StringView Tag_)
+      : Node(KAbiTagAttr, Base_->RHSComponentCache,
+             Base_->ArrayCache, Base_->FunctionCache),
+        Base(Base_), Tag(Tag_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Base, Tag); }
+
+  void printLeft(OutputStream &S) const override {
+    Base->printLeft(S);
+    S += "[abi:";
+    S += Tag;
+    S += "]";
+  }
+};
+
+class EnableIfAttr : public Node {
+  NodeArray Conditions;
+public:
+  EnableIfAttr(NodeArray Conditions_)
+      : Node(KEnableIfAttr), Conditions(Conditions_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Conditions); }
+
+  void printLeft(OutputStream &S) const override {
+    S += " [enable_if:";
+    Conditions.printWithComma(S);
+    S += ']';
+  }
+};
+
+class ObjCProtoName : public Node {
+  const Node *Ty;
+  StringView Protocol;
+
+  friend class PointerType;
+
+public:
+  ObjCProtoName(const Node *Ty_, StringView Protocol_)
+      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty, Protocol); }
+
+  bool isObjCObject() const {
+    return Ty->getKind() == KNameType &&
+           static_cast<const NameType *>(Ty)->getName() == "objc_object";
+  }
+
+  void printLeft(OutputStream &S) const override {
+    Ty->print(S);
+    S += "<";
+    S += Protocol;
+    S += ">";
+  }
+};
+
+class PointerType final : public Node {
+  const Node *Pointee;
+
+public:
+  PointerType(const Node *Pointee_)
+      : Node(KPointerType, Pointee_->RHSComponentCache),
+        Pointee(Pointee_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Pointee); }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &s) const override {
+    // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
+    if (Pointee->getKind() != KObjCProtoName ||
+        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+      Pointee->printLeft(s);
+      if (Pointee->hasArray(s))
+        s += " ";
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+        s += "(";
+      s += "*";
+    } else {
+      const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
+      s += "id<";
+      s += objcProto->Protocol;
+      s += ">";
+    }
+  }
+
+  void printRight(OutputStream &s) const override {
+    if (Pointee->getKind() != KObjCProtoName ||
+        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+      if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+        s += ")";
+      Pointee->printRight(s);
+    }
+  }
+};
+
+enum class ReferenceKind {
+  LValue,
+  RValue,
+};
+
+// Represents either a LValue or an RValue reference type.
+class ReferenceType : public Node {
+  const Node *Pointee;
+  ReferenceKind RK;
+
+  mutable bool Printing = false;
+
+  // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
+  // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
+  // other combination collapses to a lvalue ref.
+  std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const {
+    auto SoFar = std::make_pair(RK, Pointee);
+    for (;;) {
+      const Node *SN = SoFar.second->getSyntaxNode(S);
+      if (SN->getKind() != KReferenceType)
+        break;
+      auto *RT = static_cast<const ReferenceType *>(SN);
+      SoFar.second = RT->Pointee;
+      SoFar.first = std::min(SoFar.first, RT->RK);
+    }
+    return SoFar;
+  }
+
+public:
+  ReferenceType(const Node *Pointee_, ReferenceKind RK_)
+      : Node(KReferenceType, Pointee_->RHSComponentCache),
+        Pointee(Pointee_), RK(RK_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Pointee, RK); }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return Pointee->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &s) const override {
+    if (Printing)
+      return;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
+    Collapsed.second->printLeft(s);
+    if (Collapsed.second->hasArray(s))
+      s += " ";
+    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
+      s += "(";
+
+    s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
+  }
+  void printRight(OutputStream &s) const override {
+    if (Printing)
+      return;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
+    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
+      s += ")";
+    Collapsed.second->printRight(s);
+  }
+};
+
+class PointerToMemberType final : public Node {
+  const Node *ClassType;
+  const Node *MemberType;
+
+public:
+  PointerToMemberType(const Node *ClassType_, const Node *MemberType_)
+      : Node(KPointerToMemberType, MemberType_->RHSComponentCache),
+        ClassType(ClassType_), MemberType(MemberType_) {}
+
+  template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    return MemberType->hasRHSComponent(S);
+  }
+
+  void printLeft(OutputStream &s) const override {
+    MemberType->printLeft(s);
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+      s += "(";
+    else
+      s += " ";
+    ClassType->print(s);
+    s += "::*";
+  }
+
+  void printRight(OutputStream &s) const override {
+    if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+      s += ")";
+    MemberType->printRight(s);
+  }
+};
+
+class NodeOrString {
+  const void *First;
+  const void *Second;
+
+public:
+  /* implicit */ NodeOrString(StringView Str) {
+    const char *FirstChar = Str.begin();
+    const char *SecondChar = Str.end();
+    if (SecondChar == nullptr) {
+      assert(FirstChar == SecondChar);
+      ++FirstChar, ++SecondChar;
+    }
+    First = static_cast<const void *>(FirstChar);
+    Second = static_cast<const void *>(SecondChar);
+  }
+
+  /* implicit */ NodeOrString(Node *N)
+      : First(static_cast<const void *>(N)), Second(nullptr) {}
+  NodeOrString() : First(nullptr), Second(nullptr) {}
+
+  bool isString() const { return Second && First; }
+  bool isNode() const { return First && !Second; }
+  bool isEmpty() const { return !First && !Second; }
+
+  StringView asString() const {
+    assert(isString());
+    return StringView(static_cast<const char *>(First),
+                      static_cast<const char *>(Second));
+  }
+
+  const Node *asNode() const {
+    assert(isNode());
+    return static_cast<const Node *>(First);
+  }
+};
+
+class ArrayType final : public Node {
+  const Node *Base;
+  NodeOrString Dimension;
+
+public:
+  ArrayType(const Node *Base_, NodeOrString Dimension_)
+      : Node(KArrayType,
+             /*RHSComponentCache=*/Cache::Yes,
+             /*ArrayCache=*/Cache::Yes),
+        Base(Base_), Dimension(Dimension_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Base, Dimension); }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasArraySlow(OutputStream &) const override { return true; }
+
+  void printLeft(OutputStream &S) const override { Base->printLeft(S); }
+
+  void printRight(OutputStream &S) const override {
+    if (S.back() != ']')
+      S += " ";
+    S += "[";
+    if (Dimension.isString())
+      S += Dimension.asString();
+    else if (Dimension.isNode())
+      Dimension.asNode()->print(S);
+    S += "]";
+    Base->printRight(S);
+  }
+};
+
+class FunctionType final : public Node {
+  const Node *Ret;
+  NodeArray Params;
+  Qualifiers CVQuals;
+  FunctionRefQual RefQual;
+  const Node *ExceptionSpec;
+
+public:
+  FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,
+               FunctionRefQual RefQual_, const Node *ExceptionSpec_)
+      : Node(KFunctionType,
+             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+             /*FunctionCache=*/Cache::Yes),
+        Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),
+        ExceptionSpec(ExceptionSpec_) {}
+
+  template<typename Fn> void match(Fn F) const {
+    F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
+  }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+  // Handle C++'s ... quirky decl grammar by using the left & right
+  // distinction. Consider:
+  //   int (*f(float))(char) {}
+  // f is a function that takes a float and returns a pointer to a function
+  // that takes a char and returns an int. If we're trying to print f, start
+  // by printing out the return types's left, then print our parameters, then
+  // finally print right of the return type.
+  void printLeft(OutputStream &S) const override {
+    Ret->printLeft(S);
+    S += " ";
+  }
+
+  void printRight(OutputStream &S) const override {
+    S += "(";
+    Params.printWithComma(S);
+    S += ")";
+    Ret->printRight(S);
+
+    if (CVQuals & QualConst)
+      S += " const";
+    if (CVQuals & QualVolatile)
+      S += " volatile";
+    if (CVQuals & QualRestrict)
+      S += " restrict";
+
+    if (RefQual == FrefQualLValue)
+      S += " &";
+    else if (RefQual == FrefQualRValue)
+      S += " &&";
+
+    if (ExceptionSpec != nullptr) {
+      S += ' ';
+      ExceptionSpec->print(S);
+    }
+  }
+};
+
+class NoexceptSpec : public Node {
+  const Node *E;
+public:
+  NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {}
+
+  template<typename Fn> void match(Fn F) const { F(E); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "noexcept(";
+    E->print(S);
+    S += ")";
+  }
+};
+
+class DynamicExceptionSpec : public Node {
+  NodeArray Types;
+public:
+  DynamicExceptionSpec(NodeArray Types_)
+      : Node(KDynamicExceptionSpec), Types(Types_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Types); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "throw(";
+    Types.printWithComma(S);
+    S += ')';
+  }
+};
+
+class FunctionEncoding final : public Node {
+  const Node *Ret;
+  const Node *Name;
+  NodeArray Params;
+  const Node *Attrs;
+  Qualifiers CVQuals;
+  FunctionRefQual RefQual;
+
+public:
+  FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
+                   const Node *Attrs_, Qualifiers CVQuals_,
+                   FunctionRefQual RefQual_)
+      : Node(KFunctionEncoding,
+             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+             /*FunctionCache=*/Cache::Yes),
+        Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
+        CVQuals(CVQuals_), RefQual(RefQual_) {}
+
+  template<typename Fn> void match(Fn F) const {
+    F(Ret, Name, Params, Attrs, CVQuals, RefQual);
+  }
+
+  Qualifiers getCVQuals() const { return CVQuals; }
+  FunctionRefQual getRefQual() const { return RefQual; }
+  NodeArray getParams() const { return Params; }
+  const Node *getReturnType() const { return Ret; }
+
+  bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+  bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+  const Node *getName() const { return Name; }
+
+  void printLeft(OutputStream &S) const override {
+    if (Ret) {
+      Ret->printLeft(S);
+      if (!Ret->hasRHSComponent(S))
+        S += " ";
+    }
+    Name->print(S);
+  }
+
+  void printRight(OutputStream &S) const override {
+    S += "(";
+    Params.printWithComma(S);
+    S += ")";
+    if (Ret)
+      Ret->printRight(S);
+
+    if (CVQuals & QualConst)
+      S += " const";
+    if (CVQuals & QualVolatile)
+      S += " volatile";
+    if (CVQuals & QualRestrict)
+      S += " restrict";
+
+    if (RefQual == FrefQualLValue)
+      S += " &";
+    else if (RefQual == FrefQualRValue)
+      S += " &&";
+
+    if (Attrs != nullptr)
+      Attrs->print(S);
+  }
+};
+
+class LiteralOperator : public Node {
+  const Node *OpName;
+
+public:
+  LiteralOperator(const Node *OpName_)
+      : Node(KLiteralOperator), OpName(OpName_) {}
+
+  template<typename Fn> void match(Fn F) const { F(OpName); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "operator\"\" ";
+    OpName->print(S);
+  }
+};
+
+class SpecialName final : public Node {
+  const StringView Special;
+  const Node *Child;
+
+public:
+  SpecialName(StringView Special_, const Node *Child_)
+      : Node(KSpecialName), Special(Special_), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Special, Child); }
+
+  void printLeft(OutputStream &S) const override {
+    S += Special;
+    Child->print(S);
+  }
+};
+
+class CtorVtableSpecialName final : public Node {
+  const Node *FirstType;
+  const Node *SecondType;
+
+public:
+  CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_)
+      : Node(KCtorVtableSpecialName),
+        FirstType(FirstType_), SecondType(SecondType_) {}
+
+  template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "construction vtable for ";
+    FirstType->print(S);
+    S += "-in-";
+    SecondType->print(S);
+  }
+};
+
+struct NestedName : Node {
+  Node *Qual;
+  Node *Name;
+
+  NestedName(Node *Qual_, Node *Name_)
+      : Node(KNestedName), Qual(Qual_), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Qual, Name); }
+
+  StringView getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    Qual->print(S);
+    S += "::";
+    Name->print(S);
+  }
+};
+
+struct LocalName : Node {
+  Node *Encoding;
+  Node *Entity;
+
+  LocalName(Node *Encoding_, Node *Entity_)
+      : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Encoding, Entity); }
+
+  void printLeft(OutputStream &S) const override {
+    Encoding->print(S);
+    S += "::";
+    Entity->print(S);
+  }
+};
+
+class QualifiedName final : public Node {
+  // qualifier::name
+  const Node *Qualifier;
+  const Node *Name;
+
+public:
+  QualifiedName(const Node *Qualifier_, const Node *Name_)
+      : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Qualifier, Name); }
+
+  StringView getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    Qualifier->print(S);
+    S += "::";
+    Name->print(S);
+  }
+};
+
+class VectorType final : public Node {
+  const Node *BaseType;
+  const NodeOrString Dimension;
+
+public:
+  VectorType(const Node *BaseType_, NodeOrString Dimension_)
+      : Node(KVectorType), BaseType(BaseType_),
+        Dimension(Dimension_) {}
+
+  template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
+
+  void printLeft(OutputStream &S) const override {
+    BaseType->print(S);
+    S += " vector[";
+    if (Dimension.isNode())
+      Dimension.asNode()->print(S);
+    else if (Dimension.isString())
+      S += Dimension.asString();
+    S += "]";
+  }
+};
+
+class PixelVectorType final : public Node {
+  const NodeOrString Dimension;
+
+public:
+  PixelVectorType(NodeOrString Dimension_)
+      : Node(KPixelVectorType), Dimension(Dimension_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Dimension); }
+
+  void printLeft(OutputStream &S) const override {
+    // FIXME: This should demangle as "vector pixel".
+    S += "pixel vector[";
+    S += Dimension.asString();
+    S += "]";
+  }
+};
+
+/// An unexpanded parameter pack (either in the expression or type context). If
+/// this AST is correct, this node will have a ParameterPackExpansion node above
+/// it.
+///
+/// This node is created when some <template-args> are found that apply to an
+/// <encoding>, and is stored in the TemplateParams table. In order for this to
+/// appear in the final AST, it has to referenced via a <template-param> (ie,
+/// T_).
+class ParameterPack final : public Node {
+  NodeArray Data;
+
+  // Setup OutputStream for a pack expansion unless we're already expanding one.
+  void initializePackExpansion(OutputStream &S) const {
+    if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
+      S.CurrentPackMax = static_cast<unsigned>(Data.size());
+      S.CurrentPackIndex = 0;
+    }
+  }
+
+public:
+  ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {
+    ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->ArrayCache == Cache::No;
+        }))
+      ArrayCache = Cache::No;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->FunctionCache == Cache::No;
+        }))
+      FunctionCache = Cache::No;
+    if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+          return P->RHSComponentCache == Cache::No;
+        }))
+      RHSComponentCache = Cache::No;
+  }
+
+  template<typename Fn> void match(Fn F) const { F(Data); }
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
+  }
+  bool hasArraySlow(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasArray(S);
+  }
+  bool hasFunctionSlow(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() && Data[Idx]->hasFunction(S);
+  }
+  const Node *getSyntaxNode(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    if (Idx < Data.size())
+      Data[Idx]->printLeft(S);
+  }
+  void printRight(OutputStream &S) const override {
+    initializePackExpansion(S);
+    size_t Idx = S.CurrentPackIndex;
+    if (Idx < Data.size())
+      Data[Idx]->printRight(S);
+  }
+};
+
+/// A variadic template argument. This node represents an occurrence of
+/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
+/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// TemplateParams table if the <template-args> this pack belongs to apply to an
+/// <encoding>.
+class TemplateArgumentPack final : public Node {
+  NodeArray Elements;
+public:
+  TemplateArgumentPack(NodeArray Elements_)
+      : Node(KTemplateArgumentPack), Elements(Elements_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Elements); }
+
+  NodeArray getElements() const { return Elements; }
+
+  void printLeft(OutputStream &S) const override {
+    Elements.printWithComma(S);
+  }
+};
+
+/// A pack expansion. Below this node, there are some unexpanded ParameterPacks
+/// which each have Child->ParameterPackSize elements.
+class ParameterPackExpansion final : public Node {
+  const Node *Child;
+
+public:
+  ParameterPackExpansion(const Node *Child_)
+      : Node(KParameterPackExpansion), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Child); }
+
+  const Node *getChild() const { return Child; }
+
+  void printLeft(OutputStream &S) const override {
+    constexpr unsigned Max = std::numeric_limits<unsigned>::max();
+    SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);
+    SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);
+    size_t StreamPos = S.getCurrentPosition();
+
+    // Print the first element in the pack. If Child contains a ParameterPack,
+    // it will set up S.CurrentPackMax and print the first element.
+    Child->print(S);
+
+    // No ParameterPack was found in Child. This can occur if we've found a pack
+    // expansion on a <function-param>.
+    if (S.CurrentPackMax == Max) {
+      S += "...";
+      return;
+    }
+
+    // We found a ParameterPack, but it has no elements. Erase whatever we may
+    // of printed.
+    if (S.CurrentPackMax == 0) {
+      S.setCurrentPosition(StreamPos);
+      return;
+    }
+
+    // Else, iterate through the rest of the elements in the pack.
+    for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
+      S += ", ";
+      S.CurrentPackIndex = I;
+      Child->print(S);
+    }
+  }
+};
+
+class TemplateArgs final : public Node {
+  NodeArray Params;
+
+public:
+  TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Params); }
+
+  NodeArray getParams() { return Params; }
+
+  void printLeft(OutputStream &S) const override {
+    S += "<";
+    Params.printWithComma(S);
+    if (S.back() == '>')
+      S += " ";
+    S += ">";
+  }
+};
+
+/// A forward-reference to a template argument that was not known at the point
+/// where the template parameter name was parsed in a mangling.
+///
+/// This is created when demangling the name of a specialization of a
+/// conversion function template:
+///
+/// \code
+/// struct A {
+///   template<typename T> operator T*();
+/// };
+/// \endcode
+///
+/// When demangling a specialization of the conversion function template, we
+/// encounter the name of the template (including the \c T) before we reach
+/// the template argument list, so we cannot substitute the parameter name
+/// for the corresponding argument while parsing. Instead, we create a
+/// \c ForwardTemplateReference node that is resolved after we parse the
+/// template arguments.
+struct ForwardTemplateReference : Node {
+  size_t Index;
+  Node *Ref = nullptr;
+
+  // If we're currently printing this node. It is possible (though invalid) for
+  // a forward template reference to refer to itself via a substitution. This
+  // creates a cyclic AST, which will stack overflow printing. To fix this, bail
+  // out if more than one print* function is active.
+  mutable bool Printing = false;
+
+  ForwardTemplateReference(size_t Index_)
+      : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown,
+             Cache::Unknown),
+        Index(Index_) {}
+
+  // We don't provide a matcher for these, because the value of the node is
+  // not determined by its construction parameters, and it generally needs
+  // special handling.
+  template<typename Fn> void match(Fn F) const = delete;
+
+  bool hasRHSComponentSlow(OutputStream &S) const override {
+    if (Printing)
+      return false;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    return Ref->hasRHSComponent(S);
+  }
+  bool hasArraySlow(OutputStream &S) const override {
+    if (Printing)
+      return false;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    return Ref->hasArray(S);
+  }
+  bool hasFunctionSlow(OutputStream &S) const override {
+    if (Printing)
+      return false;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    return Ref->hasFunction(S);
+  }
+  const Node *getSyntaxNode(OutputStream &S) const override {
+    if (Printing)
+      return this;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    return Ref->getSyntaxNode(S);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (Printing)
+      return;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    Ref->printLeft(S);
+  }
+  void printRight(OutputStream &S) const override {
+    if (Printing)
+      return;
+    SwapAndRestore<bool> SavePrinting(Printing, true);
+    Ref->printRight(S);
+  }
+};
+
+struct NameWithTemplateArgs : Node {
+  // name<template_args>
+  Node *Name;
+  Node *TemplateArgs;
+
+  NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
+      : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); }
+
+  StringView getBaseName() const override { return Name->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    Name->print(S);
+    TemplateArgs->print(S);
+  }
+};
+
+class GlobalQualifiedName final : public Node {
+  Node *Child;
+
+public:
+  GlobalQualifiedName(Node* Child_)
+      : Node(KGlobalQualifiedName), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Child); }
+
+  StringView getBaseName() const override { return Child->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "::";
+    Child->print(S);
+  }
+};
+
+struct StdQualifiedName : Node {
+  Node *Child;
+
+  StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Child); }
+
+  StringView getBaseName() const override { return Child->getBaseName(); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "std::";
+    Child->print(S);
+  }
+};
+
+enum class SpecialSubKind {
+  allocator,
+  basic_string,
+  string,
+  istream,
+  ostream,
+  iostream,
+};
+
+class ExpandedSpecialSubstitution final : public Node {
+  SpecialSubKind SSK;
+
+public:
+  ExpandedSpecialSubstitution(SpecialSubKind SSK_)
+      : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
+
+  template<typename Fn> void match(Fn F) const { F(SSK); }
+
+  StringView getBaseName() const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      return StringView("allocator");
+    case SpecialSubKind::basic_string:
+      return StringView("basic_string");
+    case SpecialSubKind::string:
+      return StringView("basic_string");
+    case SpecialSubKind::istream:
+      return StringView("basic_istream");
+    case SpecialSubKind::ostream:
+      return StringView("basic_ostream");
+    case SpecialSubKind::iostream:
+      return StringView("basic_iostream");
+    }
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      S += "std::allocator";
+      break;
+    case SpecialSubKind::basic_string:
+      S += "std::basic_string";
+      break;
+    case SpecialSubKind::string:
+      S += "std::basic_string<char, std::char_traits<char>, "
+           "std::allocator<char> >";
+      break;
+    case SpecialSubKind::istream:
+      S += "std::basic_istream<char, std::char_traits<char> >";
+      break;
+    case SpecialSubKind::ostream:
+      S += "std::basic_ostream<char, std::char_traits<char> >";
+      break;
+    case SpecialSubKind::iostream:
+      S += "std::basic_iostream<char, std::char_traits<char> >";
+      break;
+    }
+  }
+};
+
+class SpecialSubstitution final : public Node {
+public:
+  SpecialSubKind SSK;
+
+  SpecialSubstitution(SpecialSubKind SSK_)
+      : Node(KSpecialSubstitution), SSK(SSK_) {}
+
+  template<typename Fn> void match(Fn F) const { F(SSK); }
+
+  StringView getBaseName() const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      return StringView("allocator");
+    case SpecialSubKind::basic_string:
+      return StringView("basic_string");
+    case SpecialSubKind::string:
+      return StringView("string");
+    case SpecialSubKind::istream:
+      return StringView("istream");
+    case SpecialSubKind::ostream:
+      return StringView("ostream");
+    case SpecialSubKind::iostream:
+      return StringView("iostream");
+    }
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+
+  void printLeft(OutputStream &S) const override {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      S += "std::allocator";
+      break;
+    case SpecialSubKind::basic_string:
+      S += "std::basic_string";
+      break;
+    case SpecialSubKind::string:
+      S += "std::string";
+      break;
+    case SpecialSubKind::istream:
+      S += "std::istream";
+      break;
+    case SpecialSubKind::ostream:
+      S += "std::ostream";
+      break;
+    case SpecialSubKind::iostream:
+      S += "std::iostream";
+      break;
+    }
+  }
+};
+
+class CtorDtorName final : public Node {
+  const Node *Basename;
+  const bool IsDtor;
+  const int Variant;
+
+public:
+  CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_)
+      : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_),
+        Variant(Variant_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsDtor)
+      S += "~";
+    S += Basename->getBaseName();
+  }
+};
+
+class DtorName : public Node {
+  const Node *Base;
+
+public:
+  DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Base); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "~";
+    Base->printLeft(S);
+  }
+};
+
+class UnnamedTypeName : public Node {
+  const StringView Count;
+
+public:
+  UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Count); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "'unnamed";
+    S += Count;
+    S += "\'";
+  }
+};
+
+class ClosureTypeName : public Node {
+  NodeArray Params;
+  StringView Count;
+
+public:
+  ClosureTypeName(NodeArray Params_, StringView Count_)
+      : Node(KClosureTypeName), Params(Params_), Count(Count_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Params, Count); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "\'lambda";
+    S += Count;
+    S += "\'(";
+    Params.printWithComma(S);
+    S += ")";
+  }
+};
+
+class StructuredBindingName : public Node {
+  NodeArray Bindings;
+public:
+  StructuredBindingName(NodeArray Bindings_)
+      : Node(KStructuredBindingName), Bindings(Bindings_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Bindings); }
+
+  void printLeft(OutputStream &S) const override {
+    S += '[';
+    Bindings.printWithComma(S);
+    S += ']';
+  }
+};
+
+// -- Expression Nodes --
+
+class BinaryExpr : public Node {
+  const Node *LHS;
+  const StringView InfixOperator;
+  const Node *RHS;
+
+public:
+  BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_)
+      : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {
+  }
+
+  template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }
+
+  void printLeft(OutputStream &S) const override {
+    // might be a template argument expression, then we need to disambiguate
+    // with parens.
+    if (InfixOperator == ">")
+      S += "(";
+
+    S += "(";
+    LHS->print(S);
+    S += ") ";
+    S += InfixOperator;
+    S += " (";
+    RHS->print(S);
+    S += ")";
+
+    if (InfixOperator == ">")
+      S += ")";
+  }
+};
+
+class ArraySubscriptExpr : public Node {
+  const Node *Op1;
+  const Node *Op2;
+
+public:
+  ArraySubscriptExpr(const Node *Op1_, const Node *Op2_)
+      : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Op1, Op2); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Op1->print(S);
+    S += ")[";
+    Op2->print(S);
+    S += "]";
+  }
+};
+
+class PostfixExpr : public Node {
+  const Node *Child;
+  const StringView Operator;
+
+public:
+  PostfixExpr(const Node *Child_, StringView Operator_)
+      : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Child, Operator); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Child->print(S);
+    S += ")";
+    S += Operator;
+  }
+};
+
+class ConditionalExpr : public Node {
+  const Node *Cond;
+  const Node *Then;
+  const Node *Else;
+
+public:
+  ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_)
+      : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Cond->print(S);
+    S += ") ? (";
+    Then->print(S);
+    S += ") : (";
+    Else->print(S);
+    S += ")";
+  }
+};
+
+class MemberExpr : public Node {
+  const Node *LHS;
+  const StringView Kind;
+  const Node *RHS;
+
+public:
+  MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_)
+      : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
+
+  template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }
+
+  void printLeft(OutputStream &S) const override {
+    LHS->print(S);
+    S += Kind;
+    RHS->print(S);
+  }
+};
+
+class EnclosingExpr : public Node {
+  const StringView Prefix;
+  const Node *Infix;
+  const StringView Postfix;
+
+public:
+  EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
+      : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_),
+        Postfix(Postfix_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }
+
+  void printLeft(OutputStream &S) const override {
+    S += Prefix;
+    Infix->print(S);
+    S += Postfix;
+  }
+};
+
+class CastExpr : public Node {
+  // cast_kind<to>(from)
+  const StringView CastKind;
+  const Node *To;
+  const Node *From;
+
+public:
+  CastExpr(StringView CastKind_, const Node *To_, const Node *From_)
+      : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {}
+
+  template<typename Fn> void match(Fn F) const { F(CastKind, To, From); }
+
+  void printLeft(OutputStream &S) const override {
+    S += CastKind;
+    S += "<";
+    To->printLeft(S);
+    S += ">(";
+    From->printLeft(S);
+    S += ")";
+  }
+};
+
+class SizeofParamPackExpr : public Node {
+  const Node *Pack;
+
+public:
+  SizeofParamPackExpr(const Node *Pack_)
+      : Node(KSizeofParamPackExpr), Pack(Pack_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Pack); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "sizeof...(";
+    ParameterPackExpansion PPE(Pack);
+    PPE.printLeft(S);
+    S += ")";
+  }
+};
+
+class CallExpr : public Node {
+  const Node *Callee;
+  NodeArray Args;
+
+public:
+  CallExpr(const Node *Callee_, NodeArray Args_)
+      : Node(KCallExpr), Callee(Callee_), Args(Args_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Callee, Args); }
+
+  void printLeft(OutputStream &S) const override {
+    Callee->print(S);
+    S += "(";
+    Args.printWithComma(S);
+    S += ")";
+  }
+};
+
+class NewExpr : public Node {
+  // new (expr_list) type(init_list)
+  NodeArray ExprList;
+  Node *Type;
+  NodeArray InitList;
+  bool IsGlobal; // ::operator new ?
+  bool IsArray;  // new[] ?
+public:
+  NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
+          bool IsArray_)
+      : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_),
+        IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+
+  template<typename Fn> void match(Fn F) const {
+    F(ExprList, Type, InitList, IsGlobal, IsArray);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsGlobal)
+      S += "::operator ";
+    S += "new";
+    if (IsArray)
+      S += "[]";
+    S += ' ';
+    if (!ExprList.empty()) {
+      S += "(";
+      ExprList.printWithComma(S);
+      S += ")";
+    }
+    Type->print(S);
+    if (!InitList.empty()) {
+      S += "(";
+      InitList.printWithComma(S);
+      S += ")";
+    }
+
+  }
+};
+
+class DeleteExpr : public Node {
+  Node *Op;
+  bool IsGlobal;
+  bool IsArray;
+
+public:
+  DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
+      : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsGlobal)
+      S += "::";
+    S += "delete";
+    if (IsArray)
+      S += "[] ";
+    Op->print(S);
+  }
+};
+
+class PrefixExpr : public Node {
+  StringView Prefix;
+  Node *Child;
+
+public:
+  PrefixExpr(StringView Prefix_, Node *Child_)
+      : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Prefix, Child); }
+
+  void printLeft(OutputStream &S) const override {
+    S += Prefix;
+    S += "(";
+    Child->print(S);
+    S += ")";
+  }
+};
+
+class FunctionParam : public Node {
+  StringView Number;
+
+public:
+  FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Number); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "fp";
+    S += Number;
+  }
+};
+
+class ConversionExpr : public Node {
+  const Node *Type;
+  NodeArray Expressions;
+
+public:
+  ConversionExpr(const Node *Type_, NodeArray Expressions_)
+      : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Type, Expressions); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Type->print(S);
+    S += ")(";
+    Expressions.printWithComma(S);
+    S += ")";
+  }
+};
+
+class InitListExpr : public Node {
+  const Node *Ty;
+  NodeArray Inits;
+public:
+  InitListExpr(const Node *Ty_, NodeArray Inits_)
+      : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty, Inits); }
+
+  void printLeft(OutputStream &S) const override {
+    if (Ty)
+      Ty->print(S);
+    S += '{';
+    Inits.printWithComma(S);
+    S += '}';
+  }
+};
+
+class BracedExpr : public Node {
+  const Node *Elem;
+  const Node *Init;
+  bool IsArray;
+public:
+  BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_)
+      : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }
+
+  void printLeft(OutputStream &S) const override {
+    if (IsArray) {
+      S += '[';
+      Elem->print(S);
+      S += ']';
+    } else {
+      S += '.';
+      Elem->print(S);
+    }
+    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+      S += " = ";
+    Init->print(S);
+  }
+};
+
+class BracedRangeExpr : public Node {
+  const Node *First;
+  const Node *Last;
+  const Node *Init;
+public:
+  BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_)
+      : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}
+
+  template<typename Fn> void match(Fn F) const { F(First, Last, Init); }
+
+  void printLeft(OutputStream &S) const override {
+    S += '[';
+    First->print(S);
+    S += " ... ";
+    Last->print(S);
+    S += ']';
+    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+      S += " = ";
+    Init->print(S);
+  }
+};
+
+class FoldExpr : public Node {
+  const Node *Pack, *Init;
+  StringView OperatorName;
+  bool IsLeftFold;
+
+public:
+  FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_,
+           const Node *Init_)
+      : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_),
+        IsLeftFold(IsLeftFold_) {}
+
+  template<typename Fn> void match(Fn F) const {
+    F(IsLeftFold, OperatorName, Pack, Init);
+  }
+
+  void printLeft(OutputStream &S) const override {
+    auto PrintPack = [&] {
+      S += '(';
+      ParameterPackExpansion(Pack).print(S);
+      S += ')';
+    };
+
+    S += '(';
+
+    if (IsLeftFold) {
+      // init op ... op pack
+      if (Init != nullptr) {
+        Init->print(S);
+        S += ' ';
+        S += OperatorName;
+        S += ' ';
+      }
+      // ... op pack
+      S += "... ";
+      S += OperatorName;
+      S += ' ';
+      PrintPack();
+    } else { // !IsLeftFold
+      // pack op ...
+      PrintPack();
+      S += ' ';
+      S += OperatorName;
+      S += " ...";
+      // pack op ... op init
+      if (Init != nullptr) {
+        S += ' ';
+        S += OperatorName;
+        S += ' ';
+        Init->print(S);
+      }
+    }
+    S += ')';
+  }
+};
+
+class ThrowExpr : public Node {
+  const Node *Op;
+
+public:
+  ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Op); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "throw ";
+    Op->print(S);
+  }
+};
+
+class BoolExpr : public Node {
+  bool Value;
+
+public:
+  BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Value); }
+
+  void printLeft(OutputStream &S) const override {
+    S += Value ? StringView("true") : StringView("false");
+  }
+};
+
+class IntegerCastExpr : public Node {
+  // ty(integer)
+  const Node *Ty;
+  StringView Integer;
+
+public:
+  IntegerCastExpr(const Node *Ty_, StringView Integer_)
+      : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
+
+  void printLeft(OutputStream &S) const override {
+    S += "(";
+    Ty->print(S);
+    S += ")";
+    S += Integer;
+  }
+};
+
+class IntegerLiteral : public Node {
+  StringView Type;
+  StringView Value;
+
+public:
+  IntegerLiteral(StringView Type_, StringView Value_)
+      : Node(KIntegerLiteral), Type(Type_), Value(Value_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Type, Value); }
+
+  void printLeft(OutputStream &S) const override {
+    if (Type.size() > 3) {
+      S += "(";
+      S += Type;
+      S += ")";
+    }
+
+    if (Value[0] == 'n') {
+      S += "-";
+      S += Value.dropFront(1);
+    } else
+      S += Value;
+
+    if (Type.size() <= 3)
+      S += Type;
+  }
+};
+
+template <class Float> struct FloatData;
+
+namespace float_literal_impl {
+constexpr Node::Kind getFloatLiteralKind(float *) {
+  return Node::KFloatLiteral;
+}
+constexpr Node::Kind getFloatLiteralKind(double *) {
+  return Node::KDoubleLiteral;
+}
+constexpr Node::Kind getFloatLiteralKind(long double *) {
+  return Node::KLongDoubleLiteral;
+}
+}
+
+template <class Float> class FloatLiteralImpl : public Node {
+  const StringView Contents;
+
+  static constexpr Kind KindForClass =
+      float_literal_impl::getFloatLiteralKind((Float *)nullptr);
+
+public:
+  FloatLiteralImpl(StringView Contents_)
+      : Node(KindForClass), Contents(Contents_) {}
+
+  template<typename Fn> void match(Fn F) const { F(Contents); }
+
+  void printLeft(OutputStream &s) const override {
+    const char *first = Contents.begin();
+    const char *last = Contents.end() + 1;
+
+    const size_t N = FloatData<Float>::mangled_size;
+    if (static_cast<std::size_t>(last - first) > N) {
+      last = first + N;
+      union {
+        Float value;
+        char buf[sizeof(Float)];
+      };
+      const char *t = first;
+      char *e = buf;
+      for (; t != last; ++t, ++e) {
+        unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
+                                  : static_cast<unsigned>(*t - 'a' + 10);
+        ++t;
+        unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
+                                  : static_cast<unsigned>(*t - 'a' + 10);
+        *e = static_cast<char>((d1 << 4) + d0);
+      }
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      std::reverse(buf, e);
+#endif
+      char num[FloatData<Float>::max_demangled_size] = {0};
+      int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
+      s += StringView(num, num + n);
+    }
+  }
+};
+
+using FloatLiteral = FloatLiteralImpl<float>;
+using DoubleLiteral = FloatLiteralImpl<double>;
+using LongDoubleLiteral = FloatLiteralImpl<long double>;
+
+/// Visit the node. Calls \c F(P), where \c P is the node cast to the
+/// appropriate derived class.
+template<typename Fn>
+void Node::visit(Fn F) const {
+  switch (K) {
+#define CASE(X) case K ## X: return F(static_cast<const X*>(this));
+    FOR_EACH_NODE_KIND(CASE)
+#undef CASE
+  }
+  assert(0 && "unknown mangling node kind");
+}
+
+/// Determine the kind of a node from its type.
+template<typename NodeT> struct NodeKind;
+#define SPECIALIZATION(X) \
+  template<> struct NodeKind<X> { \
+    static constexpr Node::Kind Kind = Node::K##X; \
+    static constexpr const char *name() { return #X; } \
+  };
+FOR_EACH_NODE_KIND(SPECIALIZATION)
+#undef SPECIALIZATION
+
+#undef FOR_EACH_NODE_KIND
+
+template <class T, size_t N>
+class PODSmallVector {
+  static_assert(std::is_pod<T>::value,
+                "T is required to be a plain old data type");
+
+  T* First;
+  T* Last;
+  T* Cap;
+  T Inline[N];
+
+  bool isInline() const { return First == Inline; }
+
+  void clearInline() {
+    First = Inline;
+    Last = Inline;
+    Cap = Inline + N;
+  }
+
+  void reserve(size_t NewCap) {
+    size_t S = size();
+    if (isInline()) {
+      auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
+      if (Tmp == nullptr)
+        std::terminate();
+      std::copy(First, Last, Tmp);
+      First = Tmp;
+    } else {
+      First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
+      if (First == nullptr)
+        std::terminate();
+    }
+    Last = First + S;
+    Cap = First + NewCap;
+  }
+
+public:
+  PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
+
+  PODSmallVector(const PODSmallVector&) = delete;
+  PODSmallVector& operator=(const PODSmallVector&) = delete;
+
+  PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
+    if (Other.isInline()) {
+      std::copy(Other.begin(), Other.end(), First);
+      Last = First + Other.size();
+      Other.clear();
+      return;
+    }
+
+    First = Other.First;
+    Last = Other.Last;
+    Cap = Other.Cap;
+    Other.clearInline();
+  }
+
+  PODSmallVector& operator=(PODSmallVector&& Other) {
+    if (Other.isInline()) {
+      if (!isInline()) {
+        std::free(First);
+        clearInline();
+      }
+      std::copy(Other.begin(), Other.end(), First);
+      Last = First + Other.size();
+      Other.clear();
+      return *this;
+    }
+
+    if (isInline()) {
+      First = Other.First;
+      Last = Other.Last;
+      Cap = Other.Cap;
+      Other.clearInline();
+      return *this;
+    }
+
+    std::swap(First, Other.First);
+    std::swap(Last, Other.Last);
+    std::swap(Cap, Other.Cap);
+    Other.clear();
+    return *this;
+  }
+
+  void push_back(const T& Elem) {
+    if (Last == Cap)
+      reserve(size() * 2);
+    *Last++ = Elem;
+  }
+
+  void pop_back() {
+    assert(Last != First && "Popping empty vector!");
+    --Last;
+  }
+
+  void dropBack(size_t Index) {
+    assert(Index <= size() && "dropBack() can't expand!");
+    Last = First + Index;
+  }
+
+  T* begin() { return First; }
+  T* end() { return Last; }
+
+  bool empty() const { return First == Last; }
+  size_t size() const { return static_cast<size_t>(Last - First); }
+  T& back() {
+    assert(Last != First && "Calling back() on empty vector!");
+    return *(Last - 1);
+  }
+  T& operator[](size_t Index) {
+    assert(Index < size() && "Invalid access!");
+    return *(begin() + Index);
+  }
+  void clear() { Last = First; }
+
+  ~PODSmallVector() {
+    if (!isInline())
+      std::free(First);
+  }
+};
+
+template <typename Derived, typename Alloc> struct AbstractManglingParser {
+  const char *First;
+  const char *Last;
+
+  // Name stack, this is used by the parser to hold temporary names that were
+  // parsed. The parser collapses multiple names into new nodes to construct
+  // the AST. Once the parser is finished, names.size() == 1.
+  PODSmallVector<Node *, 32> Names;
+
+  // Substitution table. Itanium supports name substitutions as a means of
+  // compression. The string "S42_" refers to the 44nd entry (base-36) in this
+  // table.
+  PODSmallVector<Node *, 32> Subs;
+
+  // Template parameter table. Like the above, but referenced like "T42_".
+  // This has a smaller size compared to Subs and Names because it can be
+  // stored on the stack.
+  PODSmallVector<Node *, 8> TemplateParams;
+
+  // Set of unresolved forward <template-param> references. These can occur in a
+  // conversion operator's type, and are resolved in the enclosing <encoding>.
+  PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
+
+  void (*TypeCallback)(void *, const char *) = nullptr;
+  void *TypeCallbackContext = nullptr;
+
+  bool TryToParseTemplateArgs = true;
+  bool PermitForwardTemplateReferences = false;
+  bool ParsingLambdaParams = false;
+
+  Alloc ASTAllocator;
+
+  AbstractManglingParser(const char *First_, const char *Last_)
+      : First(First_), Last(Last_) {}
+
+  Derived &getDerived() { return static_cast<Derived &>(*this); }
+
+  void reset(const char *First_, const char *Last_) {
+    First = First_;
+    Last = Last_;
+    Names.clear();
+    Subs.clear();
+    TemplateParams.clear();
+    ParsingLambdaParams = false;
+    TryToParseTemplateArgs = true;
+    PermitForwardTemplateReferences = false;
+    ASTAllocator.reset();
+  }
+
+  template <class T, class... Args> Node *make(Args &&... args) {
+    return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...);
+  }
+
+  template <class It> NodeArray makeNodeArray(It begin, It end) {
+    size_t sz = static_cast<size_t>(end - begin);
+    void *mem = ASTAllocator.allocateNodeArray(sz);
+    Node **data = new (mem) Node *[sz];
+    std::copy(begin, end, data);
+    return NodeArray(data, sz);
+  }
+
+  NodeArray popTrailingNodeArray(size_t FromPosition) {
+    assert(FromPosition <= Names.size());
+    NodeArray res =
+        makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+    Names.dropBack(FromPosition);
+    return res;
+  }
+
+  bool consumeIf(StringView S) {
+    if (StringView(First, Last).startsWith(S)) {
+      First += S.size();
+      return true;
+    }
+    return false;
+  }
+
+  bool consumeIf(char C) {
+    if (First != Last && *First == C) {
+      ++First;
+      return true;
+    }
+    return false;
+  }
+
+  char consume() { return First != Last ? *First++ : '\0'; }
+
+  char look(unsigned Lookahead = 0) {
+    if (static_cast<size_t>(Last - First) <= Lookahead)
+      return '\0';
+    return First[Lookahead];
+  }
+
+  size_t numLeft() const { return static_cast<size_t>(Last - First); }
+
+  StringView parseNumber(bool AllowNegative = false);
+  Qualifiers parseCVQualifiers();
+  bool parsePositiveInteger(size_t *Out);
+  StringView parseBareSourceName();
+
+  bool parseSeqId(size_t *Out);
+  Node *parseSubstitution();
+  Node *parseTemplateParam();
+  Node *parseTemplateArgs(bool TagTemplates = false);
+  Node *parseTemplateArg();
+
+  /// Parse the <expr> production.
+  Node *parseExpr();
+  Node *parsePrefixExpr(StringView Kind);
+  Node *parseBinaryExpr(StringView Kind);
+  Node *parseIntegerLiteral(StringView Lit);
+  Node *parseExprPrimary();
+  template <class Float> Node *parseFloatingLiteral();
+  Node *parseFunctionParam();
+  Node *parseNewExpr();
+  Node *parseConversionExpr();
+  Node *parseBracedExpr();
+  Node *parseFoldExpr();
+
+  /// Parse the <type> production.
+  Node *parseType();
+  Node *parseFunctionType();
+  Node *parseVectorType();
+  Node *parseDecltype();
+  Node *parseArrayType();
+  Node *parsePointerToMemberType();
+  Node *parseClassEnumType();
+  Node *parseQualifiedType();
+
+  Node *parseEncoding();
+  bool parseCallOffset();
+  Node *parseSpecialName();
+
+  /// Holds some extra information about a <name> that is being parsed. This
+  /// information is only pertinent if the <name> refers to an <encoding>.
+  struct NameState {
+    bool CtorDtorConversion = false;
+    bool EndsWithTemplateArgs = false;
+    Qualifiers CVQualifiers = QualNone;
+    FunctionRefQual ReferenceQualifier = FrefQualNone;
+    size_t ForwardTemplateRefsBegin;
+
+    NameState(AbstractManglingParser *Enclosing)
+        : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
+  };
+
+  bool resolveForwardTemplateRefs(NameState &State) {
+    size_t I = State.ForwardTemplateRefsBegin;
+    size_t E = ForwardTemplateRefs.size();
+    for (; I < E; ++I) {
+      size_t Idx = ForwardTemplateRefs[I]->Index;
+      if (Idx >= TemplateParams.size())
+        return true;
+      ForwardTemplateRefs[I]->Ref = TemplateParams[Idx];
+    }
+    ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+    return false;
+  }
+
+  /// Parse the <name> production>
+  Node *parseName(NameState *State = nullptr);
+  Node *parseLocalName(NameState *State);
+  Node *parseOperatorName(NameState *State);
+  Node *parseUnqualifiedName(NameState *State);
+  Node *parseUnnamedTypeName(NameState *State);
+  Node *parseSourceName(NameState *State);
+  Node *parseUnscopedName(NameState *State);
+  Node *parseNestedName(NameState *State);
+  Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
+  Node *parseAbiTags(Node *N);
+
+  /// Parse the <unresolved-name> production.
+  Node *parseUnresolvedName();
+  Node *parseSimpleId();
+  Node *parseBaseUnresolvedName();
+  Node *parseUnresolvedType();
+  Node *parseDestructorName();
+
+  /// Top-level entry point into the parser.
+  Node *parse();
+};
+
+const char* parse_discriminator(const char* first, const char* last);
+
+// <name> ::= <nested-name> // N
+//        ::= <local-name> # See Scope Encoding below  // Z
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) {
+  consumeIf('L'); // extension
+
+  if (look() == 'N')
+    return getDerived().parseNestedName(State);
+  if (look() == 'Z')
+    return getDerived().parseLocalName(State);
+
+  //        ::= <unscoped-template-name> <template-args>
+  if (look() == 'S' && look(1) != 't') {
+    Node *S = getDerived().parseSubstitution();
+    if (S == nullptr)
+      return nullptr;
+    if (look() != 'I')
+      return nullptr;
+    Node *TA = getDerived().parseTemplateArgs(State != nullptr);
+    if (TA == nullptr)
+      return nullptr;
+    if (State) State->EndsWithTemplateArgs = true;
+    return make<NameWithTemplateArgs>(S, TA);
+  }
+
+  Node *N = getDerived().parseUnscopedName(State);
+  if (N == nullptr)
+    return nullptr;
+  //        ::= <unscoped-template-name> <template-args>
+  if (look() == 'I') {
+    Subs.push_back(N);
+    Node *TA = getDerived().parseTemplateArgs(State != nullptr);
+    if (TA == nullptr)
+      return nullptr;
+    if (State) State->EndsWithTemplateArgs = true;
+    return make<NameWithTemplateArgs>(N, TA);
+  }
+  //        ::= <unscoped-name>
+  return N;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+//              := Z <function encoding> E s [<discriminator>]
+//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
+  if (!consumeIf('Z'))
+    return nullptr;
+  Node *Encoding = getDerived().parseEncoding();
+  if (Encoding == nullptr || !consumeIf('E'))
+    return nullptr;
+
+  if (consumeIf('s')) {
+    First = parse_discriminator(First, Last);
+    auto *StringLitName = make<NameType>("string literal");
+    if (!StringLitName)
+      return nullptr;
+    return make<LocalName>(Encoding, StringLitName);
+  }
+
+  if (consumeIf('d')) {
+    parseNumber(true);
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *N = getDerived().parseName(State);
+    if (N == nullptr)
+      return nullptr;
+    return make<LocalName>(Encoding, N);
+  }
+
+  Node *Entity = getDerived().parseName(State);
+  if (Entity == nullptr)
+    return nullptr;
+  First = parse_discriminator(First, Last);
+  return make<LocalName>(Encoding, Entity);
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>   # ::std::
+// extension       ::= StL<unqualified-name>
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) {
+  if (consumeIf("StL") || consumeIf("St")) {
+    Node *R = getDerived().parseUnqualifiedName(State);
+    if (R == nullptr)
+      return nullptr;
+    return make<StdQualifiedName>(R);
+  }
+  return getDerived().parseUnqualifiedName(State);
+}
+
+// <unqualified-name> ::= <operator-name> [abi-tags]
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <unnamed-type-name>
+//                    ::= DC <source-name>+ E      # structured binding declaration
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
+  // <ctor-dtor-name>s are special-cased in parseNestedName().
+  Node *Result;
+  if (look() == 'U')
+    Result = getDerived().parseUnnamedTypeName(State);
+  else if (look() >= '1' && look() <= '9')
+    Result = getDerived().parseSourceName(State);
+  else if (consumeIf("DC")) {
+    size_t BindingsBegin = Names.size();
+    do {
+      Node *Binding = getDerived().parseSourceName(State);
+      if (Binding == nullptr)
+        return nullptr;
+      Names.push_back(Binding);
+    } while (!consumeIf('E'));
+    Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
+  } else
+    Result = getDerived().parseOperatorName(State);
+  if (Result != nullptr)
+    Result = getDerived().parseAbiTags(Result);
+  return Result;
+}
+
+// <unnamed-type-name> ::= Ut [<nonnegative number>] _
+//                     ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) {
+  if (consumeIf("Ut")) {
+    StringView Count = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<UnnamedTypeName>(Count);
+  }
+  if (consumeIf("Ul")) {
+    NodeArray Params;
+    SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);
+    if (!consumeIf("vE")) {
+      size_t ParamsBegin = Names.size();
+      do {
+        Node *P = getDerived().parseType();
+        if (P == nullptr)
+          return nullptr;
+        Names.push_back(P);
+      } while (!consumeIf('E'));
+      Params = popTrailingNodeArray(ParamsBegin);
+    }
+    StringView Count = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<ClosureTypeName>(Params, Count);
+  }
+  return nullptr;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
+  size_t Length = 0;
+  if (parsePositiveInteger(&Length))
+    return nullptr;
+  if (numLeft() < Length || Length == 0)
+    return nullptr;
+  StringView Name(First, First + Length);
+  First += Length;
+  if (Name.startsWith("_GLOBAL__N"))
+    return make<NameType>("(anonymous namespace)");
+  return make<NameType>(Name);
+}
+
+//   <operator-name> ::= aa    # &&
+//                   ::= ad    # & (unary)
+//                   ::= an    # &
+//                   ::= aN    # &=
+//                   ::= aS    # =
+//                   ::= cl    # ()
+//                   ::= cm    # ,
+//                   ::= co    # ~
+//                   ::= cv <type>    # (cast)
+//                   ::= da    # delete[]
+//                   ::= de    # * (unary)
+//                   ::= dl    # delete
+//                   ::= dv    # /
+//                   ::= dV    # /=
+//                   ::= eo    # ^
+//                   ::= eO    # ^=
+//                   ::= eq    # ==
+//                   ::= ge    # >=
+//                   ::= gt    # >
+//                   ::= ix    # []
+//                   ::= le    # <=
+//                   ::= li <source-name>  # operator ""
+//                   ::= ls    # <<
+//                   ::= lS    # <<=
+//                   ::= lt    # <
+//                   ::= mi    # -
+//                   ::= mI    # -=
+//                   ::= ml    # *
+//                   ::= mL    # *=
+//                   ::= mm    # -- (postfix in <expression> context)
+//                   ::= na    # new[]
+//                   ::= ne    # !=
+//                   ::= ng    # - (unary)
+//                   ::= nt    # !
+//                   ::= nw    # new
+//                   ::= oo    # ||
+//                   ::= or    # |
+//                   ::= oR    # |=
+//                   ::= pm    # ->*
+//                   ::= pl    # +
+//                   ::= pL    # +=
+//                   ::= pp    # ++ (postfix in <expression> context)
+//                   ::= ps    # + (unary)
+//                   ::= pt    # ->
+//                   ::= qu    # ?
+//                   ::= rm    # %
+//                   ::= rM    # %=
+//                   ::= rs    # >>
+//                   ::= rS    # >>=
+//                   ::= ss    # <=> C++2a
+//                   ::= v <digit> <source-name>        # vendor extended operator
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
+  switch (look()) {
+  case 'a':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator&&");
+    case 'd':
+    case 'n':
+      First += 2;
+      return make<NameType>("operator&");
+    case 'N':
+      First += 2;
+      return make<NameType>("operator&=");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator=");
+    }
+    return nullptr;
+  case 'c':
+    switch (look(1)) {
+    case 'l':
+      First += 2;
+      return make<NameType>("operator()");
+    case 'm':
+      First += 2;
+      return make<NameType>("operator,");
+    case 'o':
+      First += 2;
+      return make<NameType>("operator~");
+    //                   ::= cv <type>    # (cast)
+    case 'v': {
+      First += 2;
+      SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+      // If we're parsing an encoding, State != nullptr and the conversion
+      // operators' <type> could have a <template-param> that refers to some
+      // <template-arg>s further ahead in the mangled name.
+      SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
+                                      PermitForwardTemplateReferences ||
+                                          State != nullptr);
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      if (State) State->CtorDtorConversion = true;
+      return make<ConversionOperatorType>(Ty);
+    }
+    }
+    return nullptr;
+  case 'd':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator delete[]");
+    case 'e':
+      First += 2;
+      return make<NameType>("operator*");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator delete");
+    case 'v':
+      First += 2;
+      return make<NameType>("operator/");
+    case 'V':
+      First += 2;
+      return make<NameType>("operator/=");
+    }
+    return nullptr;
+  case 'e':
+    switch (look(1)) {
+    case 'o':
+      First += 2;
+      return make<NameType>("operator^");
+    case 'O':
+      First += 2;
+      return make<NameType>("operator^=");
+    case 'q':
+      First += 2;
+      return make<NameType>("operator==");
+    }
+    return nullptr;
+  case 'g':
+    switch (look(1)) {
+    case 'e':
+      First += 2;
+      return make<NameType>("operator>=");
+    case 't':
+      First += 2;
+      return make<NameType>("operator>");
+    }
+    return nullptr;
+  case 'i':
+    if (look(1) == 'x') {
+      First += 2;
+      return make<NameType>("operator[]");
+    }
+    return nullptr;
+  case 'l':
+    switch (look(1)) {
+    case 'e':
+      First += 2;
+      return make<NameType>("operator<=");
+    //                   ::= li <source-name>  # operator ""
+    case 'i': {
+      First += 2;
+      Node *SN = getDerived().parseSourceName(State);
+      if (SN == nullptr)
+        return nullptr;
+      return make<LiteralOperator>(SN);
+    }
+    case 's':
+      First += 2;
+      return make<NameType>("operator<<");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator<<=");
+    case 't':
+      First += 2;
+      return make<NameType>("operator<");
+    }
+    return nullptr;
+  case 'm':
+    switch (look(1)) {
+    case 'i':
+      First += 2;
+      return make<NameType>("operator-");
+    case 'I':
+      First += 2;
+      return make<NameType>("operator-=");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator*");
+    case 'L':
+      First += 2;
+      return make<NameType>("operator*=");
+    case 'm':
+      First += 2;
+      return make<NameType>("operator--");
+    }
+    return nullptr;
+  case 'n':
+    switch (look(1)) {
+    case 'a':
+      First += 2;
+      return make<NameType>("operator new[]");
+    case 'e':
+      First += 2;
+      return make<NameType>("operator!=");
+    case 'g':
+      First += 2;
+      return make<NameType>("operator-");
+    case 't':
+      First += 2;
+      return make<NameType>("operator!");
+    case 'w':
+      First += 2;
+      return make<NameType>("operator new");
+    }
+    return nullptr;
+  case 'o':
+    switch (look(1)) {
+    case 'o':
+      First += 2;
+      return make<NameType>("operator||");
+    case 'r':
+      First += 2;
+      return make<NameType>("operator|");
+    case 'R':
+      First += 2;
+      return make<NameType>("operator|=");
+    }
+    return nullptr;
+  case 'p':
+    switch (look(1)) {
+    case 'm':
+      First += 2;
+      return make<NameType>("operator->*");
+    case 'l':
+      First += 2;
+      return make<NameType>("operator+");
+    case 'L':
+      First += 2;
+      return make<NameType>("operator+=");
+    case 'p':
+      First += 2;
+      return make<NameType>("operator++");
+    case 's':
+      First += 2;
+      return make<NameType>("operator+");
+    case 't':
+      First += 2;
+      return make<NameType>("operator->");
+    }
+    return nullptr;
+  case 'q':
+    if (look(1) == 'u') {
+      First += 2;
+      return make<NameType>("operator?");
+    }
+    return nullptr;
+  case 'r':
+    switch (look(1)) {
+    case 'm':
+      First += 2;
+      return make<NameType>("operator%");
+    case 'M':
+      First += 2;
+      return make<NameType>("operator%=");
+    case 's':
+      First += 2;
+      return make<NameType>("operator>>");
+    case 'S':
+      First += 2;
+      return make<NameType>("operator>>=");
+    }
+    return nullptr;
+  case 's':
+    if (look(1) == 's') {
+      First += 2;
+      return make<NameType>("operator<=>");
+    }
+    return nullptr;
+  // ::= v <digit> <source-name>        # vendor extended operator
+  case 'v':
+    if (std::isdigit(look(1))) {
+      First += 2;
+      Node *SN = getDerived().parseSourceName(State);
+      if (SN == nullptr)
+        return nullptr;
+      return make<ConversionOperatorType>(SN);
+    }
+    return nullptr;
+  }
+  return nullptr;
+}
+
+// <ctor-dtor-name> ::= C1  # complete object constructor
+//                  ::= C2  # base object constructor
+//                  ::= C3  # complete object allocating constructor
+//   extension      ::= C5    # ?
+//                  ::= D0  # deleting destructor
+//                  ::= D1  # complete object destructor
+//                  ::= D2  # base object destructor
+//   extension      ::= D5    # ?
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
+                                                          NameState *State) {
+  if (SoFar->getKind() == Node::KSpecialSubstitution) {
+    auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
+    switch (SSK) {
+    case SpecialSubKind::string:
+    case SpecialSubKind::istream:
+    case SpecialSubKind::ostream:
+    case SpecialSubKind::iostream:
+      SoFar = make<ExpandedSpecialSubstitution>(SSK);
+      if (!SoFar)
+        return nullptr;
+      break;
+    default:
+      break;
+    }
+  }
+
+  if (consumeIf('C')) {
+    bool IsInherited = consumeIf('I');
+    if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+      return nullptr;
+    int Variant = look() - '0';
+    ++First;
+    if (State) State->CtorDtorConversion = true;
+    if (IsInherited) {
+      if (getDerived().parseName(State) == nullptr)
+        return nullptr;
+    }
+    return make<CtorDtorName>(SoFar, false, Variant);
+  }
+
+  if (look() == 'D' &&
+      (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
+    int Variant = look(1) - '0';
+    First += 2;
+    if (State) State->CtorDtorConversion = true;
+    return make<CtorDtorName>(SoFar, true, Variant);
+  }
+
+  return nullptr;
+}
+
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+//               ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <decltype>
+//          ::= # empty
+//          ::= <substitution>
+//          ::= <prefix> <data-member-prefix>
+//  extension ::= L
+//
+// <data-member-prefix> := <member source-name> [<template-args>] M
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
+  if (!consumeIf('N'))
+    return nullptr;
+
+  Qualifiers CVTmp = parseCVQualifiers();
+  if (State) State->CVQualifiers = CVTmp;
+
+  if (consumeIf('O')) {
+    if (State) State->ReferenceQualifier = FrefQualRValue;
+  } else if (consumeIf('R')) {
+    if (State) State->ReferenceQualifier = FrefQualLValue;
+  } else
+    if (State) State->ReferenceQualifier = FrefQualNone;
+
+  Node *SoFar = nullptr;
+  auto PushComponent = [&](Node *Comp) {
+    if (!Comp) return false;
+    if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
+    else       SoFar = Comp;
+    if (State) State->EndsWithTemplateArgs = false;
+    return SoFar != nullptr;
+  };
+
+  if (consumeIf("St")) {
+    SoFar = make<NameType>("std");
+    if (!SoFar)
+      return nullptr;
+  }
+
+  while (!consumeIf('E')) {
+    consumeIf('L'); // extension
+
+    // <data-member-prefix> := <member source-name> [<template-args>] M
+    if (consumeIf('M')) {
+      if (SoFar == nullptr)
+        return nullptr;
+      continue;
+    }
+
+    //          ::= <template-param>
+    if (look() == 'T') {
+      if (!PushComponent(getDerived().parseTemplateParam()))
+        return nullptr;
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <template-prefix> <template-args>
+    if (look() == 'I') {
+      Node *TA = getDerived().parseTemplateArgs(State != nullptr);
+      if (TA == nullptr || SoFar == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+      if (!SoFar)
+        return nullptr;
+      if (State) State->EndsWithTemplateArgs = true;
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <decltype>
+    if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+      if (!PushComponent(getDerived().parseDecltype()))
+        return nullptr;
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <substitution>
+    if (look() == 'S' && look(1) != 't') {
+      Node *S = getDerived().parseSubstitution();
+      if (!PushComponent(S))
+        return nullptr;
+      if (SoFar != S)
+        Subs.push_back(S);
+      continue;
+    }
+
+    // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
+    if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
+      if (SoFar == nullptr)
+        return nullptr;
+      if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
+        return nullptr;
+      SoFar = getDerived().parseAbiTags(SoFar);
+      if (SoFar == nullptr)
+        return nullptr;
+      Subs.push_back(SoFar);
+      continue;
+    }
+
+    //          ::= <prefix> <unqualified-name>
+    if (!PushComponent(getDerived().parseUnqualifiedName(State)))
+      return nullptr;
+    Subs.push_back(SoFar);
+  }
+
+  if (SoFar == nullptr || Subs.empty())
+    return nullptr;
+
+  Subs.pop_back();
+  return SoFar;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() {
+  Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr);
+  if (SN == nullptr)
+    return nullptr;
+  if (look() == 'I') {
+    Node *TA = getDerived().parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    return make<NameWithTemplateArgs>(SN, TA);
+  }
+  return SN;
+}
+
+// <destructor-name> ::= <unresolved-type>  # e.g., ~T or ~decltype(f())
+//                   ::= <simple-id>        # e.g., ~A<2*N>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() {
+  Node *Result;
+  if (std::isdigit(look()))
+    Result = getDerived().parseSimpleId();
+  else
+    Result = getDerived().parseUnresolvedType();
+  if (Result == nullptr)
+    return nullptr;
+  return make<DtorName>(Result);
+}
+
+// <unresolved-type> ::= <template-param>
+//                   ::= <decltype>
+//                   ::= <substitution>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() {
+  if (look() == 'T') {
+    Node *TP = getDerived().parseTemplateParam();
+    if (TP == nullptr)
+      return nullptr;
+    Subs.push_back(TP);
+    return TP;
+  }
+  if (look() == 'D') {
+    Node *DT = getDerived().parseDecltype();
+    if (DT == nullptr)
+      return nullptr;
+    Subs.push_back(DT);
+    return DT;
+  }
+  return getDerived().parseSubstitution();
+}
+
+// <base-unresolved-name> ::= <simple-id>                                # unresolved name
+//          extension     ::= <operator-name>                            # unresolved operator-function-id
+//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id
+//                        ::= on <operator-name>                         # unresolved operator-function-id
+//                        ::= on <operator-name> <template-args>         # unresolved operator template-id
+//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
+//                                                                         # e.g. ~X or ~X<N-1>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
+  if (std::isdigit(look()))
+    return getDerived().parseSimpleId();
+
+  if (consumeIf("dn"))
+    return getDerived().parseDestructorName();
+
+  consumeIf("on");
+
+  Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr);
+  if (Oper == nullptr)
+    return nullptr;
+  if (look() == 'I') {
+    Node *TA = getDerived().parseTemplateArgs();
+    if (TA == nullptr)
+      return nullptr;
+    return make<NameWithTemplateArgs>(Oper, TA);
+  }
+  return Oper;
+}
+
+// <unresolved-name>
+//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+//                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x
+//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+//                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::"
+//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x
+//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+//                                                                       # T::N::x /decltype(p)::N::x
+//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
+//
+// <unresolved-qualifier-level> ::= <simple-id>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
+  Node *SoFar = nullptr;
+
+  // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+  // srN <unresolved-type>                   <unresolved-qualifier-level>+ E <base-unresolved-name>
+  if (consumeIf("srN")) {
+    SoFar = getDerived().parseUnresolvedType();
+    if (SoFar == nullptr)
+      return nullptr;
+
+    if (look() == 'I') {
+      Node *TA = getDerived().parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+      if (!SoFar)
+        return nullptr;
+    }
+
+    while (!consumeIf('E')) {
+      Node *Qual = getDerived().parseSimpleId();
+      if (Qual == nullptr)
+        return nullptr;
+      SoFar = make<QualifiedName>(SoFar, Qual);
+      if (!SoFar)
+        return nullptr;
+    }
+
+    Node *Base = getDerived().parseBaseUnresolvedName();
+    if (Base == nullptr)
+      return nullptr;
+    return make<QualifiedName>(SoFar, Base);
+  }
+
+  bool Global = consumeIf("gs");
+
+  // [gs] <base-unresolved-name>                     # x or (with "gs") ::x
+  if (!consumeIf("sr")) {
+    SoFar = getDerived().parseBaseUnresolvedName();
+    if (SoFar == nullptr)
+      return nullptr;
+    if (Global)
+      SoFar = make<GlobalQualifiedName>(SoFar);
+    return SoFar;
+  }
+
+  // [gs] sr <unresolved-qualifier-level>+ E   <base-unresolved-name>
+  if (std::isdigit(look())) {
+    do {
+      Node *Qual = getDerived().parseSimpleId();
+      if (Qual == nullptr)
+        return nullptr;
+      if (SoFar)
+        SoFar = make<QualifiedName>(SoFar, Qual);
+      else if (Global)
+        SoFar = make<GlobalQualifiedName>(Qual);
+      else
+        SoFar = Qual;
+      if (!SoFar)
+        return nullptr;
+    } while (!consumeIf('E'));
+  }
+  //      sr <unresolved-type>                 <base-unresolved-name>
+  //      sr <unresolved-type> <template-args> <base-unresolved-name>
+  else {
+    SoFar = getDerived().parseUnresolvedType();
+    if (SoFar == nullptr)
+      return nullptr;
+
+    if (look() == 'I') {
+      Node *TA = getDerived().parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+      if (!SoFar)
+        return nullptr;
+    }
+  }
+
+  assert(SoFar != nullptr);
+
+  Node *Base = getDerived().parseBaseUnresolvedName();
+  if (Base == nullptr)
+    return nullptr;
+  return make<QualifiedName>(SoFar, Base);
+}
+
+// <abi-tags> ::= <abi-tag> [<abi-tags>]
+// <abi-tag> ::= B <source-name>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
+  while (consumeIf('B')) {
+    StringView SN = parseBareSourceName();
+    if (SN.empty())
+      return nullptr;
+    N = make<AbiTagAttr>(N, SN);
+    if (!N)
+      return nullptr;
+  }
+  return N;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+template <typename Alloc, typename Derived>
+StringView
+AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) {
+  const char *Tmp = First;
+  if (AllowNegative)
+    consumeIf('n');
+  if (numLeft() == 0 || !std::isdigit(*First))
+    return StringView();
+  while (numLeft() != 0 && std::isdigit(*First))
+    ++First;
+  return StringView(Tmp, First);
+}
+
+// <positive length number> ::= [0-9]*
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) {
+  *Out = 0;
+  if (look() < '0' || look() > '9')
+    return true;
+  while (look() >= '0' && look() <= '9') {
+    *Out *= 10;
+    *Out += static_cast<size_t>(consume() - '0');
+  }
+  return false;
+}
+
+template <typename Alloc, typename Derived>
+StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() {
+  size_t Int = 0;
+  if (parsePositiveInteger(&Int) || numLeft() < Int)
+    return StringView();
+  StringView R(First, First + Int);
+  First += Int;
+  return R;
+}
+
+// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
+//
+// <exception-spec> ::= Do                # non-throwing exception-specification (e.g., noexcept, throw())
+//                  ::= DO <expression> E # computed (instantiation-dependent) noexcept
+//                  ::= Dw <type>+ E      # dynamic exception specification with instantiation-dependent types
+//
+// <ref-qualifier> ::= R                   # & ref-qualifier
+// <ref-qualifier> ::= O                   # && ref-qualifier
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() {
+  Qualifiers CVQuals = parseCVQualifiers();
+
+  Node *ExceptionSpec = nullptr;
+  if (consumeIf("Do")) {
+    ExceptionSpec = make<NameType>("noexcept");
+    if (!ExceptionSpec)
+      return nullptr;
+  } else if (consumeIf("DO")) {
+    Node *E = getDerived().parseExpr();
+    if (E == nullptr || !consumeIf('E'))
+      return nullptr;
+    ExceptionSpec = make<NoexceptSpec>(E);
+    if (!ExceptionSpec)
+      return nullptr;
+  } else if (consumeIf("Dw")) {
+    size_t SpecsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *T = getDerived().parseType();
+      if (T == nullptr)
+        return nullptr;
+      Names.push_back(T);
+    }
+    ExceptionSpec =
+      make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
+    if (!ExceptionSpec)
+      return nullptr;
+  }
+
+  consumeIf("Dx"); // transaction safe
+
+  if (!consumeIf('F'))
+    return nullptr;
+  consumeIf('Y'); // extern "C"
+  Node *ReturnType = getDerived().parseType();
+  if (ReturnType == nullptr)
+    return nullptr;
+
+  FunctionRefQual ReferenceQualifier = FrefQualNone;
+  size_t ParamsBegin = Names.size();
+  while (true) {
+    if (consumeIf('E'))
+      break;
+    if (consumeIf('v'))
+      continue;
+    if (consumeIf("RE")) {
+      ReferenceQualifier = FrefQualLValue;
+      break;
+    }
+    if (consumeIf("OE")) {
+      ReferenceQualifier = FrefQualRValue;
+      break;
+    }
+    Node *T = getDerived().parseType();
+    if (T == nullptr)
+      return nullptr;
+    Names.push_back(T);
+  }
+
+  NodeArray Params = popTrailingNodeArray(ParamsBegin);
+  return make<FunctionType>(ReturnType, Params, CVQuals,
+                            ReferenceQualifier, ExceptionSpec);
+}
+
+// extension:
+// <vector-type>           ::= Dv <positive dimension number> _ <extended element type>
+//                         ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+//                         ::= p # AltiVec vector pixel
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() {
+  if (!consumeIf("Dv"))
+    return nullptr;
+  if (look() >= '1' && look() <= '9') {
+    StringView DimensionNumber = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    if (consumeIf('p'))
+      return make<PixelVectorType>(DimensionNumber);
+    Node *ElemType = getDerived().parseType();
+    if (ElemType == nullptr)
+      return nullptr;
+    return make<VectorType>(ElemType, DimensionNumber);
+  }
+
+  if (!consumeIf('_')) {
+    Node *DimExpr = getDerived().parseExpr();
+    if (!DimExpr)
+      return nullptr;
+    if (!consumeIf('_'))
+      return nullptr;
+    Node *ElemType = getDerived().parseType();
+    if (!ElemType)
+      return nullptr;
+    return make<VectorType>(ElemType, DimExpr);
+  }
+  Node *ElemType = getDerived().parseType();
+  if (!ElemType)
+    return nullptr;
+  return make<VectorType>(ElemType, StringView());
+}
+
+// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
+//             ::= DT <expression> E  # decltype of an expression (C++0x)
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() {
+  if (!consumeIf('D'))
+    return nullptr;
+  if (!consumeIf('t') && !consumeIf('T'))
+    return nullptr;
+  Node *E = getDerived().parseExpr();
+  if (E == nullptr)
+    return nullptr;
+  if (!consumeIf('E'))
+    return nullptr;
+  return make<EnclosingExpr>("decltype(", E, ")");
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+//              ::= A [<dimension expression>] _ <element type>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() {
+  if (!consumeIf('A'))
+    return nullptr;
+
+  NodeOrString Dimension;
+
+  if (std::isdigit(look())) {
+    Dimension = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+  } else if (!consumeIf('_')) {
+    Node *DimExpr = getDerived().parseExpr();
+    if (DimExpr == nullptr)
+      return nullptr;
+    if (!consumeIf('_'))
+      return nullptr;
+    Dimension = DimExpr;
+  }
+
+  Node *Ty = getDerived().parseType();
+  if (Ty == nullptr)
+    return nullptr;
+  return make<ArrayType>(Ty, Dimension);
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() {
+  if (!consumeIf('M'))
+    return nullptr;
+  Node *ClassType = getDerived().parseType();
+  if (ClassType == nullptr)
+    return nullptr;
+  Node *MemberType = getDerived().parseType();
+  if (MemberType == nullptr)
+    return nullptr;
+  return make<PointerToMemberType>(ClassType, MemberType);
+}
+
+// <class-enum-type> ::= <name>     # non-dependent type name, dependent type name, or dependent typename-specifier
+//                   ::= Ts <name>  # dependent elaborated type specifier using 'struct' or 'class'
+//                   ::= Tu <name>  # dependent elaborated type specifier using 'union'
+//                   ::= Te <name>  # dependent elaborated type specifier using 'enum'
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
+  StringView ElabSpef;
+  if (consumeIf("Ts"))
+    ElabSpef = "struct";
+  else if (consumeIf("Tu"))
+    ElabSpef = "union";
+  else if (consumeIf("Te"))
+    ElabSpef = "enum";
+
+  Node *Name = getDerived().parseName();
+  if (Name == nullptr)
+    return nullptr;
+
+  if (!ElabSpef.empty())
+    return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+
+  return Name;
+}
+
+// <qualified-type>     ::= <qualifiers> <type>
+// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
+// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
+  if (consumeIf('U')) {
+    StringView Qual = parseBareSourceName();
+    if (Qual.empty())
+      return nullptr;
+
+    // FIXME parse the optional <template-args> here!
+
+    // extension            ::= U <objc-name> <objc-type>  # objc-type<identifier>
+    if (Qual.startsWith("objcproto")) {
+      StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
+      StringView Proto;
+      {
+        SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
+                                     SaveLast(Last, ProtoSourceName.end());
+        Proto = parseBareSourceName();
+      }
+      if (Proto.empty())
+        return nullptr;
+      Node *Child = getDerived().parseQualifiedType();
+      if (Child == nullptr)
+        return nullptr;
+      return make<ObjCProtoName>(Child, Proto);
+    }
+
+    Node *Child = getDerived().parseQualifiedType();
+    if (Child == nullptr)
+      return nullptr;
+    return make<VendorExtQualType>(Child, Qual);
+  }
+
+  Qualifiers Quals = parseCVQualifiers();
+  Node *Ty = getDerived().parseType();
+  if (Ty == nullptr)
+    return nullptr;
+  if (Quals != QualNone)
+    Ty = make<QualType>(Ty, Quals);
+  return Ty;
+}
+
+// <type>      ::= <builtin-type>
+//             ::= <qualified-type>
+//             ::= <function-type>
+//             ::= <class-enum-type>
+//             ::= <array-type>
+//             ::= <pointer-to-member-type>
+//             ::= <template-param>
+//             ::= <template-template-param> <template-args>
+//             ::= <decltype>
+//             ::= P <type>        # pointer
+//             ::= R <type>        # l-value reference
+//             ::= O <type>        # r-value reference (C++11)
+//             ::= C <type>        # complex pair (C99)
+//             ::= G <type>        # imaginary (C99)
+//             ::= <substitution>  # See Compression below
+// extension   ::= U <objc-name> <objc-type>  # objc-type<identifier>
+// extension   ::= <vector-type> # <vector-type> starts with Dv
+//
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> ::= <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseType() {
+  Node *Result = nullptr;
+
+  if (TypeCallback != nullptr)
+    TypeCallback(TypeCallbackContext, First);
+
+  switch (look()) {
+  //             ::= <qualified-type>
+  case 'r':
+  case 'V':
+  case 'K': {
+    unsigned AfterQuals = 0;
+    if (look(AfterQuals) == 'r') ++AfterQuals;
+    if (look(AfterQuals) == 'V') ++AfterQuals;
+    if (look(AfterQuals) == 'K') ++AfterQuals;
+
+    if (look(AfterQuals) == 'F' ||
+        (look(AfterQuals) == 'D' &&
+         (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
+          look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
+      Result = getDerived().parseFunctionType();
+      break;
+    }
+    LLVM_FALLTHROUGH;
+  }
+  case 'U': {
+    Result = getDerived().parseQualifiedType();
+    break;
+  }
+  // <builtin-type> ::= v    # void
+  case 'v':
+    ++First;
+    return make<NameType>("void");
+  //                ::= w    # wchar_t
+  case 'w':
+    ++First;
+    return make<NameType>("wchar_t");
+  //                ::= b    # bool
+  case 'b':
+    ++First;
+    return make<NameType>("bool");
+  //                ::= c    # char
+  case 'c':
+    ++First;
+    return make<NameType>("char");
+  //                ::= a    # signed char
+  case 'a':
+    ++First;
+    return make<NameType>("signed char");
+  //                ::= h    # unsigned char
+  case 'h':
+    ++First;
+    return make<NameType>("unsigned char");
+  //                ::= s    # short
+  case 's':
+    ++First;
+    return make<NameType>("short");
+  //                ::= t    # unsigned short
+  case 't':
+    ++First;
+    return make<NameType>("unsigned short");
+  //                ::= i    # int
+  case 'i':
+    ++First;
+    return make<NameType>("int");
+  //                ::= j    # unsigned int
+  case 'j':
+    ++First;
+    return make<NameType>("unsigned int");
+  //                ::= l    # long
+  case 'l':
+    ++First;
+    return make<NameType>("long");
+  //                ::= m    # unsigned long
+  case 'm':
+    ++First;
+    return make<NameType>("unsigned long");
+  //                ::= x    # long long, __int64
+  case 'x':
+    ++First;
+    return make<NameType>("long long");
+  //                ::= y    # unsigned long long, __int64
+  case 'y':
+    ++First;
+    return make<NameType>("unsigned long long");
+  //                ::= n    # __int128
+  case 'n':
+    ++First;
+    return make<NameType>("__int128");
+  //                ::= o    # unsigned __int128
+  case 'o':
+    ++First;
+    return make<NameType>("unsigned __int128");
+  //                ::= f    # float
+  case 'f':
+    ++First;
+    return make<NameType>("float");
+  //                ::= d    # double
+  case 'd':
+    ++First;
+    return make<NameType>("double");
+  //                ::= e    # long double, __float80
+  case 'e':
+    ++First;
+    return make<NameType>("long double");
+  //                ::= g    # __float128
+  case 'g':
+    ++First;
+    return make<NameType>("__float128");
+  //                ::= z    # ellipsis
+  case 'z':
+    ++First;
+    return make<NameType>("...");
+
+  // <builtin-type> ::= u <source-name>    # vendor extended type
+  case 'u': {
+    ++First;
+    StringView Res = parseBareSourceName();
+    if (Res.empty())
+      return nullptr;
+    return make<NameType>(Res);
+  }
+  case 'D':
+    switch (look(1)) {
+    //                ::= Dd   # IEEE 754r decimal floating point (64 bits)
+    case 'd':
+      First += 2;
+      return make<NameType>("decimal64");
+    //                ::= De   # IEEE 754r decimal floating point (128 bits)
+    case 'e':
+      First += 2;
+      return make<NameType>("decimal128");
+    //                ::= Df   # IEEE 754r decimal floating point (32 bits)
+    case 'f':
+      First += 2;
+      return make<NameType>("decimal32");
+    //                ::= Dh   # IEEE 754r half-precision floating point (16 bits)
+    case 'h':
+      First += 2;
+      return make<NameType>("decimal16");
+    //                ::= Di   # char32_t
+    case 'i':
+      First += 2;
+      return make<NameType>("char32_t");
+    //                ::= Ds   # char16_t
+    case 's':
+      First += 2;
+      return make<NameType>("char16_t");
+    //                ::= Da   # auto (in dependent new-expressions)
+    case 'a':
+      First += 2;
+      return make<NameType>("auto");
+    //                ::= Dc   # decltype(auto)
+    case 'c':
+      First += 2;
+      return make<NameType>("decltype(auto)");
+    //                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
+    case 'n':
+      First += 2;
+      return make<NameType>("std::nullptr_t");
+
+    //             ::= <decltype>
+    case 't':
+    case 'T': {
+      Result = getDerived().parseDecltype();
+      break;
+    }
+    // extension   ::= <vector-type> # <vector-type> starts with Dv
+    case 'v': {
+      Result = getDerived().parseVectorType();
+      break;
+    }
+    //           ::= Dp <type>       # pack expansion (C++0x)
+    case 'p': {
+      First += 2;
+      Node *Child = getDerived().parseType();
+      if (!Child)
+        return nullptr;
+      Result = make<ParameterPackExpansion>(Child);
+      break;
+    }
+    // Exception specifier on a function type.
+    case 'o':
+    case 'O':
+    case 'w':
+    // Transaction safe function type.
+    case 'x':
+      Result = getDerived().parseFunctionType();
+      break;
+    }
+    break;
+  //             ::= <function-type>
+  case 'F': {
+    Result = getDerived().parseFunctionType();
+    break;
+  }
+  //             ::= <array-type>
+  case 'A': {
+    Result = getDerived().parseArrayType();
+    break;
+  }
+  //             ::= <pointer-to-member-type>
+  case 'M': {
+    Result = getDerived().parsePointerToMemberType();
+    break;
+  }
+  //             ::= <template-param>
+  case 'T': {
+    // This could be an elaborate type specifier on a <class-enum-type>.
+    if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
+      Result = getDerived().parseClassEnumType();
+      break;
+    }
+
+    Result = getDerived().parseTemplateParam();
+    if (Result == nullptr)
+      return nullptr;
+
+    // Result could be either of:
+    //   <type>        ::= <template-param>
+    //   <type>        ::= <template-template-param> <template-args>
+    //
+    //   <template-template-param> ::= <template-param>
+    //                             ::= <substitution>
+    //
+    // If this is followed by some <template-args>, and we're permitted to
+    // parse them, take the second production.
+
+    if (TryToParseTemplateArgs && look() == 'I') {
+      Node *TA = getDerived().parseTemplateArgs();
+      if (TA == nullptr)
+        return nullptr;
+      Result = make<NameWithTemplateArgs>(Result, TA);
+    }
+    break;
+  }
+  //             ::= P <type>        # pointer
+  case 'P': {
+    ++First;
+    Node *Ptr = getDerived().parseType();
+    if (Ptr == nullptr)
+      return nullptr;
+    Result = make<PointerType>(Ptr);
+    break;
+  }
+  //             ::= R <type>        # l-value reference
+  case 'R': {
+    ++First;
+    Node *Ref = getDerived().parseType();
+    if (Ref == nullptr)
+      return nullptr;
+    Result = make<ReferenceType>(Ref, ReferenceKind::LValue);
+    break;
+  }
+  //             ::= O <type>        # r-value reference (C++11)
+  case 'O': {
+    ++First;
+    Node *Ref = getDerived().parseType();
+    if (Ref == nullptr)
+      return nullptr;
+    Result = make<ReferenceType>(Ref, ReferenceKind::RValue);
+    break;
+  }
+  //             ::= C <type>        # complex pair (C99)
+  case 'C': {
+    ++First;
+    Node *P = getDerived().parseType();
+    if (P == nullptr)
+      return nullptr;
+    Result = make<PostfixQualifiedType>(P, " complex");
+    break;
+  }
+  //             ::= G <type>        # imaginary (C99)
+  case 'G': {
+    ++First;
+    Node *P = getDerived().parseType();
+    if (P == nullptr)
+      return P;
+    Result = make<PostfixQualifiedType>(P, " imaginary");
+    break;
+  }
+  //             ::= <substitution>  # See Compression below
+  case 'S': {
+    if (look(1) && look(1) != 't') {
+      Node *Sub = getDerived().parseSubstitution();
+      if (Sub == nullptr)
+        return nullptr;
+
+      // Sub could be either of:
+      //   <type>        ::= <substitution>
+      //   <type>        ::= <template-template-param> <template-args>
+      //
+      //   <template-template-param> ::= <template-param>
+      //                             ::= <substitution>
+      //
+      // If this is followed by some <template-args>, and we're permitted to
+      // parse them, take the second production.
+
+      if (TryToParseTemplateArgs && look() == 'I') {
+        Node *TA = getDerived().parseTemplateArgs();
+        if (TA == nullptr)
+          return nullptr;
+        Result = make<NameWithTemplateArgs>(Sub, TA);
+        break;
+      }
+
+      // If all we parsed was a substitution, don't re-insert into the
+      // substitution table.
+      return Sub;
+    }
+    LLVM_FALLTHROUGH;
+  }
+  //        ::= <class-enum-type>
+  default: {
+    Result = getDerived().parseClassEnumType();
+    break;
+  }
+  }
+
+  // If we parsed a type, insert it into the substitution table. Note that all
+  // <builtin-type>s and <substitution>s have already bailed out, because they
+  // don't get substitutions.
+  if (Result != nullptr)
+    Subs.push_back(Result);
+  return Result;
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) {
+  Node *E = getDerived().parseExpr();
+  if (E == nullptr)
+    return nullptr;
+  return make<PrefixExpr>(Kind, E);
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) {
+  Node *LHS = getDerived().parseExpr();
+  if (LHS == nullptr)
+    return nullptr;
+  Node *RHS = getDerived().parseExpr();
+  if (RHS == nullptr)
+    return nullptr;
+  return make<BinaryExpr>(LHS, Kind, RHS);
+}
+
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) {
+  StringView Tmp = parseNumber(true);
+  if (!Tmp.empty() && consumeIf('E'))
+    return make<IntegerLiteral>(Lit, Tmp);
+  return nullptr;
+}
+
+// <CV-Qualifiers> ::= [r] [V] [K]
+template <typename Alloc, typename Derived>
+Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() {
+  Qualifiers CVR = QualNone;
+  if (consumeIf('r'))
+    CVR |= QualRestrict;
+  if (consumeIf('V'))
+    CVR |= QualVolatile;
+  if (consumeIf('K'))
+    CVR |= QualConst;
+  return CVR;
+}
+
+// <function-param> ::= fp <top-level CV-Qualifiers> _                                     # L == 0, first parameter
+//                  ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters
+//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _         # L > 0, first parameter
+//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
+  if (consumeIf("fp")) {
+    parseCVQualifiers();
+    StringView Num = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<FunctionParam>(Num);
+  }
+  if (consumeIf("fL")) {
+    if (parseNumber().empty())
+      return nullptr;
+    if (!consumeIf('p'))
+      return nullptr;
+    parseCVQualifiers();
+    StringView Num = parseNumber();
+    if (!consumeIf('_'))
+      return nullptr;
+    return make<FunctionParam>(Num);
+  }
+  return nullptr;
+}
+
+// [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E                 # parenthesized initialization
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
+  bool Global = consumeIf("gs");
+  bool IsArray = look(1) == 'a';
+  if (!consumeIf("nw") && !consumeIf("na"))
+    return nullptr;
+  size_t Exprs = Names.size();
+  while (!consumeIf('_')) {
+    Node *Ex = getDerived().parseExpr();
+    if (Ex == nullptr)
+      return nullptr;
+    Names.push_back(Ex);
+  }
+  NodeArray ExprList = popTrailingNodeArray(Exprs);
+  Node *Ty = getDerived().parseType();
+  if (Ty == nullptr)
+    return Ty;
+  if (consumeIf("pi")) {
+    size_t InitsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *Init = getDerived().parseExpr();
+      if (Init == nullptr)
+        return Init;
+      Names.push_back(Init);
+    }
+    NodeArray Inits = popTrailingNodeArray(InitsBegin);
+    return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
+  } else if (!consumeIf('E'))
+    return nullptr;
+  return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
+}
+
+// cv <type> <expression>                               # conversion with one argument
+// cv <type> _ <expression>* E                          # conversion with a different number of arguments
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() {
+  if (!consumeIf("cv"))
+    return nullptr;
+  Node *Ty;
+  {
+    SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+    Ty = getDerived().parseType();
+  }
+
+  if (Ty == nullptr)
+    return nullptr;
+
+  if (consumeIf('_')) {
+    size_t ExprsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *E = getDerived().parseExpr();
+      if (E == nullptr)
+        return E;
+      Names.push_back(E);
+    }
+    NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+    return make<ConversionExpr>(Ty, Exprs);
+  }
+
+  Node *E[1] = {getDerived().parseExpr()};
+  if (E[0] == nullptr)
+    return nullptr;
+  return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
+}
+
+// <expr-primary> ::= L <type> <value number> E                          # integer literal
+//                ::= L <type> <value float> E                           # floating literal
+//                ::= L <string type> E                                  # string literal
+//                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
+// FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
+//                ::= L <mangled-name> E                                 # external name
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
+  if (!consumeIf('L'))
+    return nullptr;
+  switch (look()) {
+  case 'w':
+    ++First;
+    return getDerived().parseIntegerLiteral("wchar_t");
+  case 'b':
+    if (consumeIf("b0E"))
+      return make<BoolExpr>(0);
+    if (consumeIf("b1E"))
+      return make<BoolExpr>(1);
+    return nullptr;
+  case 'c':
+    ++First;
+    return getDerived().parseIntegerLiteral("char");
+  case 'a':
+    ++First;
+    return getDerived().parseIntegerLiteral("signed char");
+  case 'h':
+    ++First;
+    return getDerived().parseIntegerLiteral("unsigned char");
+  case 's':
+    ++First;
+    return getDerived().parseIntegerLiteral("short");
+  case 't':
+    ++First;
+    return getDerived().parseIntegerLiteral("unsigned short");
+  case 'i':
+    ++First;
+    return getDerived().parseIntegerLiteral("");
+  case 'j':
+    ++First;
+    return getDerived().parseIntegerLiteral("u");
+  case 'l':
+    ++First;
+    return getDerived().parseIntegerLiteral("l");
+  case 'm':
+    ++First;
+    return getDerived().parseIntegerLiteral("ul");
+  case 'x':
+    ++First;
+    return getDerived().parseIntegerLiteral("ll");
+  case 'y':
+    ++First;
+    return getDerived().parseIntegerLiteral("ull");
+  case 'n':
+    ++First;
+    return getDerived().parseIntegerLiteral("__int128");
+  case 'o':
+    ++First;
+    return getDerived().parseIntegerLiteral("unsigned __int128");
+  case 'f':
+    ++First;
+    return getDerived().template parseFloatingLiteral<float>();
+  case 'd':
+    ++First;
+    return getDerived().template parseFloatingLiteral<double>();
+  case 'e':
+    ++First;
+    return getDerived().template parseFloatingLiteral<long double>();
+  case '_':
+    if (consumeIf("_Z")) {
+      Node *R = getDerived().parseEncoding();
+      if (R != nullptr && consumeIf('E'))
+        return R;
+    }
+    return nullptr;
+  case 'T':
+    // Invalid mangled name per
+    //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+    return nullptr;
+  default: {
+    // might be named type
+    Node *T = getDerived().parseType();
+    if (T == nullptr)
+      return nullptr;
+    StringView N = parseNumber();
+    if (!N.empty()) {
+      if (!consumeIf('E'))
+        return nullptr;
+      return make<IntegerCastExpr>(T, N);
+    }
+    if (consumeIf('E'))
+      return T;
+    return nullptr;
+  }
+  }
+}
+
+// <braced-expression> ::= <expression>
+//                     ::= di <field source-name> <braced-expression>    # .name = expr
+//                     ::= dx <index expression> <braced-expression>     # [expr] = expr
+//                     ::= dX <range begin expression> <range end expression> <braced-expression>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() {
+  if (look() == 'd') {
+    switch (look(1)) {
+    case 'i': {
+      First += 2;
+      Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr);
+      if (Field == nullptr)
+        return nullptr;
+      Node *Init = getDerived().parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedExpr>(Field, Init, /*isArray=*/false);
+    }
+    case 'x': {
+      First += 2;
+      Node *Index = getDerived().parseExpr();
+      if (Index == nullptr)
+        return nullptr;
+      Node *Init = getDerived().parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedExpr>(Index, Init, /*isArray=*/true);
+    }
+    case 'X': {
+      First += 2;
+      Node *RangeBegin = getDerived().parseExpr();
+      if (RangeBegin == nullptr)
+        return nullptr;
+      Node *RangeEnd = getDerived().parseExpr();
+      if (RangeEnd == nullptr)
+        return nullptr;
+      Node *Init = getDerived().parseBracedExpr();
+      if (Init == nullptr)
+        return nullptr;
+      return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
+    }
+    }
+  }
+  return getDerived().parseExpr();
+}
+
+// (not yet in the spec)
+// <fold-expr> ::= fL <binary-operator-name> <expression> <expression>
+//             ::= fR <binary-operator-name> <expression> <expression>
+//             ::= fl <binary-operator-name> <expression>
+//             ::= fr <binary-operator-name> <expression>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
+  if (!consumeIf('f'))
+    return nullptr;
+
+  char FoldKind = look();
+  bool IsLeftFold, HasInitializer;
+  HasInitializer = FoldKind == 'L' || FoldKind == 'R';
+  if (FoldKind == 'l' || FoldKind == 'L')
+    IsLeftFold = true;
+  else if (FoldKind == 'r' || FoldKind == 'R')
+    IsLeftFold = false;
+  else
+    return nullptr;
+  ++First;
+
+  // FIXME: This map is duplicated in parseOperatorName and parseExpr.
+  StringView OperatorName;
+  if      (consumeIf("aa")) OperatorName = "&&";
+  else if (consumeIf("an")) OperatorName = "&";
+  else if (consumeIf("aN")) OperatorName = "&=";
+  else if (consumeIf("aS")) OperatorName = "=";
+  else if (consumeIf("cm")) OperatorName = ",";
+  else if (consumeIf("ds")) OperatorName = ".*";
+  else if (consumeIf("dv")) OperatorName = "/";
+  else if (consumeIf("dV")) OperatorName = "/=";
+  else if (consumeIf("eo")) OperatorName = "^";
+  else if (consumeIf("eO")) OperatorName = "^=";
+  else if (consumeIf("eq")) OperatorName = "==";
+  else if (consumeIf("ge")) OperatorName = ">=";
+  else if (consumeIf("gt")) OperatorName = ">";
+  else if (consumeIf("le")) OperatorName = "<=";
+  else if (consumeIf("ls")) OperatorName = "<<";
+  else if (consumeIf("lS")) OperatorName = "<<=";
+  else if (consumeIf("lt")) OperatorName = "<";
+  else if (consumeIf("mi")) OperatorName = "-";
+  else if (consumeIf("mI")) OperatorName = "-=";
+  else if (consumeIf("ml")) OperatorName = "*";
+  else if (consumeIf("mL")) OperatorName = "*=";
+  else if (consumeIf("ne")) OperatorName = "!=";
+  else if (consumeIf("oo")) OperatorName = "||";
+  else if (consumeIf("or")) OperatorName = "|";
+  else if (consumeIf("oR")) OperatorName = "|=";
+  else if (consumeIf("pl")) OperatorName = "+";
+  else if (consumeIf("pL")) OperatorName = "+=";
+  else if (consumeIf("rm")) OperatorName = "%";
+  else if (consumeIf("rM")) OperatorName = "%=";
+  else if (consumeIf("rs")) OperatorName = ">>";
+  else if (consumeIf("rS")) OperatorName = ">>=";
+  else return nullptr;
+
+  Node *Pack = getDerived().parseExpr(), *Init = nullptr;
+  if (Pack == nullptr)
+    return nullptr;
+  if (HasInitializer) {
+    Init = getDerived().parseExpr();
+    if (Init == nullptr)
+      return nullptr;
+  }
+
+  if (IsLeftFold && Init)
+    std::swap(Pack, Init);
+
+  return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
+}
+
+// <expression> ::= <unary operator-name> <expression>
+//              ::= <binary operator-name> <expression> <expression>
+//              ::= <ternary operator-name> <expression> <expression> <expression>
+//              ::= cl <expression>+ E                                   # call
+//              ::= cv <type> <expression>                               # conversion with one argument
+//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
+//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
+//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
+//              ::= [gs] dl <expression>                                 # delete expression
+//              ::= [gs] da <expression>                                 # delete[] expression
+//              ::= pp_ <expression>                                     # prefix ++
+//              ::= mm_ <expression>                                     # prefix --
+//              ::= ti <type>                                            # typeid (type)
+//              ::= te <expression>                                      # typeid (expression)
+//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)
+//              ::= sc <type> <expression>                               # static_cast<type> (expression)
+//              ::= cc <type> <expression>                               # const_cast<type> (expression)
+//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)
+//              ::= st <type>                                            # sizeof (a type)
+//              ::= sz <expression>                                      # sizeof (an expression)
+//              ::= at <type>                                            # alignof (a type)
+//              ::= az <expression>                                      # alignof (an expression)
+//              ::= nx <expression>                                      # noexcept (expression)
+//              ::= <template-param>
+//              ::= <function-param>
+//              ::= dt <expression> <unresolved-name>                    # expr.name
+//              ::= pt <expression> <unresolved-name>                    # expr->name
+//              ::= ds <expression> <expression>                         # expr.*expr
+//              ::= sZ <template-param>                                  # size of a parameter pack
+//              ::= sZ <function-param>                                  # size of a function parameter pack
+//              ::= sP <template-arg>* E                                 # sizeof...(T), size of a captured template parameter pack from an alias template
+//              ::= sp <expression>                                      # pack expansion
+//              ::= tw <expression>                                      # throw expression
+//              ::= tr                                                   # throw with no operand (rethrow)
+//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),
+//                                                                       # freestanding dependent name (e.g., T::x),
+//                                                                       # objectless nonstatic member reference
+//              ::= fL <binary-operator-name> <expression> <expression>
+//              ::= fR <binary-operator-name> <expression> <expression>
+//              ::= fl <binary-operator-name> <expression>
+//              ::= fr <binary-operator-name> <expression>
+//              ::= <expr-primary>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
+  bool Global = consumeIf("gs");
+  if (numLeft() < 2)
+    return nullptr;
+
+  switch (*First) {
+  case 'L':
+    return getDerived().parseExprPrimary();
+  case 'T':
+    return getDerived().parseTemplateParam();
+  case 'f': {
+    // Disambiguate a fold expression from a <function-param>.
+    if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
+      return getDerived().parseFunctionParam();
+    return getDerived().parseFoldExpr();
+  }
+  case 'a':
+    switch (First[1]) {
+    case 'a':
+      First += 2;
+      return getDerived().parseBinaryExpr("&&");
+    case 'd':
+      First += 2;
+      return getDerived().parsePrefixExpr("&");
+    case 'n':
+      First += 2;
+      return getDerived().parseBinaryExpr("&");
+    case 'N':
+      First += 2;
+      return getDerived().parseBinaryExpr("&=");
+    case 'S':
+      First += 2;
+      return getDerived().parseBinaryExpr("=");
+    case 't': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<EnclosingExpr>("alignof (", Ty, ")");
+    }
+    case 'z': {
+      First += 2;
+      Node *Ty = getDerived().parseExpr();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<EnclosingExpr>("alignof (", Ty, ")");
+    }
+    }
+    return nullptr;
+  case 'c':
+    switch (First[1]) {
+    // cc <type> <expression>                               # const_cast<type>(expression)
+    case 'c': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return Ty;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("const_cast", Ty, Ex);
+    }
+    // cl <expression>+ E                                   # call
+    case 'l': {
+      First += 2;
+      Node *Callee = getDerived().parseExpr();
+      if (Callee == nullptr)
+        return Callee;
+      size_t ExprsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = getDerived().parseExpr();
+        if (E == nullptr)
+          return E;
+        Names.push_back(E);
+      }
+      return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
+    }
+    case 'm':
+      First += 2;
+      return getDerived().parseBinaryExpr(",");
+    case 'o':
+      First += 2;
+      return getDerived().parsePrefixExpr("~");
+    case 'v':
+      return getDerived().parseConversionExpr();
+    }
+    return nullptr;
+  case 'd':
+    switch (First[1]) {
+    case 'a': {
+      First += 2;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
+    }
+    case 'c': {
+      First += 2;
+      Node *T = getDerived().parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("dynamic_cast", T, Ex);
+    }
+    case 'e':
+      First += 2;
+      return getDerived().parsePrefixExpr("*");
+    case 'l': {
+      First += 2;
+      Node *E = getDerived().parseExpr();
+      if (E == nullptr)
+        return E;
+      return make<DeleteExpr>(E, Global, /*is_array=*/false);
+    }
+    case 'n':
+      return getDerived().parseUnresolvedName();
+    case 's': {
+      First += 2;
+      Node *LHS = getDerived().parseExpr();
+      if (LHS == nullptr)
+        return nullptr;
+      Node *RHS = getDerived().parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<MemberExpr>(LHS, ".*", RHS);
+    }
+    case 't': {
+      First += 2;
+      Node *LHS = getDerived().parseExpr();
+      if (LHS == nullptr)
+        return LHS;
+      Node *RHS = getDerived().parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<MemberExpr>(LHS, ".", RHS);
+    }
+    case 'v':
+      First += 2;
+      return getDerived().parseBinaryExpr("/");
+    case 'V':
+      First += 2;
+      return getDerived().parseBinaryExpr("/=");
+    }
+    return nullptr;
+  case 'e':
+    switch (First[1]) {
+    case 'o':
+      First += 2;
+      return getDerived().parseBinaryExpr("^");
+    case 'O':
+      First += 2;
+      return getDerived().parseBinaryExpr("^=");
+    case 'q':
+      First += 2;
+      return getDerived().parseBinaryExpr("==");
+    }
+    return nullptr;
+  case 'g':
+    switch (First[1]) {
+    case 'e':
+      First += 2;
+      return getDerived().parseBinaryExpr(">=");
+    case 't':
+      First += 2;
+      return getDerived().parseBinaryExpr(">");
+    }
+    return nullptr;
+  case 'i':
+    switch (First[1]) {
+    case 'x': {
+      First += 2;
+      Node *Base = getDerived().parseExpr();
+      if (Base == nullptr)
+        return nullptr;
+      Node *Index = getDerived().parseExpr();
+      if (Index == nullptr)
+        return Index;
+      return make<ArraySubscriptExpr>(Base, Index);
+    }
+    case 'l': {
+      First += 2;
+      size_t InitsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = getDerived().parseBracedExpr();
+        if (E == nullptr)
+          return nullptr;
+        Names.push_back(E);
+      }
+      return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+    }
+    }
+    return nullptr;
+  case 'l':
+    switch (First[1]) {
+    case 'e':
+      First += 2;
+      return getDerived().parseBinaryExpr("<=");
+    case 's':
+      First += 2;
+      return getDerived().parseBinaryExpr("<<");
+    case 'S':
+      First += 2;
+      return getDerived().parseBinaryExpr("<<=");
+    case 't':
+      First += 2;
+      return getDerived().parseBinaryExpr("<");
+    }
+    return nullptr;
+  case 'm':
+    switch (First[1]) {
+    case 'i':
+      First += 2;
+      return getDerived().parseBinaryExpr("-");
+    case 'I':
+      First += 2;
+      return getDerived().parseBinaryExpr("-=");
+    case 'l':
+      First += 2;
+      return getDerived().parseBinaryExpr("*");
+    case 'L':
+      First += 2;
+      return getDerived().parseBinaryExpr("*=");
+    case 'm':
+      First += 2;
+      if (consumeIf('_'))
+        return getDerived().parsePrefixExpr("--");
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return nullptr;
+      return make<PostfixExpr>(Ex, "--");
+    }
+    return nullptr;
+  case 'n':
+    switch (First[1]) {
+    case 'a':
+    case 'w':
+      return getDerived().parseNewExpr();
+    case 'e':
+      First += 2;
+      return getDerived().parseBinaryExpr("!=");
+    case 'g':
+      First += 2;
+      return getDerived().parsePrefixExpr("-");
+    case 't':
+      First += 2;
+      return getDerived().parsePrefixExpr("!");
+    case 'x':
+      First += 2;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("noexcept (", Ex, ")");
+    }
+    return nullptr;
+  case 'o':
+    switch (First[1]) {
+    case 'n':
+      return getDerived().parseUnresolvedName();
+    case 'o':
+      First += 2;
+      return getDerived().parseBinaryExpr("||");
+    case 'r':
+      First += 2;
+      return getDerived().parseBinaryExpr("|");
+    case 'R':
+      First += 2;
+      return getDerived().parseBinaryExpr("|=");
+    }
+    return nullptr;
+  case 'p':
+    switch (First[1]) {
+    case 'm':
+      First += 2;
+      return getDerived().parseBinaryExpr("->*");
+    case 'l':
+      First += 2;
+      return getDerived().parseBinaryExpr("+");
+    case 'L':
+      First += 2;
+      return getDerived().parseBinaryExpr("+=");
+    case 'p': {
+      First += 2;
+      if (consumeIf('_'))
+        return getDerived().parsePrefixExpr("++");
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<PostfixExpr>(Ex, "++");
+    }
+    case 's':
+      First += 2;
+      return getDerived().parsePrefixExpr("+");
+    case 't': {
+      First += 2;
+      Node *L = getDerived().parseExpr();
+      if (L == nullptr)
+        return nullptr;
+      Node *R = getDerived().parseExpr();
+      if (R == nullptr)
+        return nullptr;
+      return make<MemberExpr>(L, "->", R);
+    }
+    }
+    return nullptr;
+  case 'q':
+    if (First[1] == 'u') {
+      First += 2;
+      Node *Cond = getDerived().parseExpr();
+      if (Cond == nullptr)
+        return nullptr;
+      Node *LHS = getDerived().parseExpr();
+      if (LHS == nullptr)
+        return nullptr;
+      Node *RHS = getDerived().parseExpr();
+      if (RHS == nullptr)
+        return nullptr;
+      return make<ConditionalExpr>(Cond, LHS, RHS);
+    }
+    return nullptr;
+  case 'r':
+    switch (First[1]) {
+    case 'c': {
+      First += 2;
+      Node *T = getDerived().parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("reinterpret_cast", T, Ex);
+    }
+    case 'm':
+      First += 2;
+      return getDerived().parseBinaryExpr("%");
+    case 'M':
+      First += 2;
+      return getDerived().parseBinaryExpr("%=");
+    case 's':
+      First += 2;
+      return getDerived().parseBinaryExpr(">>");
+    case 'S':
+      First += 2;
+      return getDerived().parseBinaryExpr(">>=");
+    }
+    return nullptr;
+  case 's':
+    switch (First[1]) {
+    case 'c': {
+      First += 2;
+      Node *T = getDerived().parseType();
+      if (T == nullptr)
+        return T;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<CastExpr>("static_cast", T, Ex);
+    }
+    case 'p': {
+      First += 2;
+      Node *Child = getDerived().parseExpr();
+      if (Child == nullptr)
+        return nullptr;
+      return make<ParameterPackExpansion>(Child);
+    }
+    case 'r':
+      return getDerived().parseUnresolvedName();
+    case 't': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return Ty;
+      return make<EnclosingExpr>("sizeof (", Ty, ")");
+    }
+    case 'z': {
+      First += 2;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("sizeof (", Ex, ")");
+    }
+    case 'Z':
+      First += 2;
+      if (look() == 'T') {
+        Node *R = getDerived().parseTemplateParam();
+        if (R == nullptr)
+          return nullptr;
+        return make<SizeofParamPackExpr>(R);
+      } else if (look() == 'f') {
+        Node *FP = getDerived().parseFunctionParam();
+        if (FP == nullptr)
+          return nullptr;
+        return make<EnclosingExpr>("sizeof... (", FP, ")");
+      }
+      return nullptr;
+    case 'P': {
+      First += 2;
+      size_t ArgsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *Arg = getDerived().parseTemplateArg();
+        if (Arg == nullptr)
+          return nullptr;
+        Names.push_back(Arg);
+      }
+      auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
+      if (!Pack)
+        return nullptr;
+      return make<EnclosingExpr>("sizeof... (", Pack, ")");
+    }
+    }
+    return nullptr;
+  case 't':
+    switch (First[1]) {
+    case 'e': {
+      First += 2;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return Ex;
+      return make<EnclosingExpr>("typeid (", Ex, ")");
+    }
+    case 'i': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return Ty;
+      return make<EnclosingExpr>("typeid (", Ty, ")");
+    }
+    case 'l': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      size_t InitsBegin = Names.size();
+      while (!consumeIf('E')) {
+        Node *E = getDerived().parseBracedExpr();
+        if (E == nullptr)
+          return nullptr;
+        Names.push_back(E);
+      }
+      return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+    }
+    case 'r':
+      First += 2;
+      return make<NameType>("throw");
+    case 'w': {
+      First += 2;
+      Node *Ex = getDerived().parseExpr();
+      if (Ex == nullptr)
+        return nullptr;
+      return make<ThrowExpr>(Ex);
+    }
+    }
+    return nullptr;
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    return getDerived().parseUnresolvedName();
+  }
+  return nullptr;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+//               # non-virtual base override
+//
+// <v-offset>  ::= <offset number> _ <virtual offset number>
+//               # virtual base override, with vcall offset
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() {
+  // Just scan through the call offset, we never add this information into the
+  // output.
+  if (consumeIf('h'))
+    return parseNumber(true).empty() || !consumeIf('_');
+  if (consumeIf('v'))
+    return parseNumber(true).empty() || !consumeIf('_') ||
+           parseNumber(true).empty() || !consumeIf('_');
+  return true;
+}
+
+// <special-name> ::= TV <type>    # virtual table
+//                ::= TT <type>    # VTT structure (construction vtable index)
+//                ::= TI <type>    # typeinfo structure
+//                ::= TS <type>    # typeinfo name (null-terminated byte string)
+//                ::= Tc <call-offset> <call-offset> <base encoding>
+//                    # base is the nominal target function of thunk
+//                    # first call-offset is 'this' adjustment
+//                    # second call-offset is result adjustment
+//                ::= T <call-offset> <base encoding>
+//                    # base is the nominal target function of thunk
+//                ::= GV <object name> # Guard variable for one-time initialization
+//                                     # No <type>
+//                ::= TW <object name> # Thread-local wrapper
+//                ::= TH <object name> # Thread-local initialization
+//                ::= GR <object name> _             # First temporary
+//                ::= GR <object name> <seq-id> _    # Subsequent temporaries
+//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+//      extension ::= GR <object name> # reference temporary for object
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
+  switch (look()) {
+  case 'T':
+    switch (look(1)) {
+    // TV <type>    # virtual table
+    case 'V': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("vtable for ", Ty);
+    }
+    // TT <type>    # VTT structure (construction vtable index)
+    case 'T': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("VTT for ", Ty);
+    }
+    // TI <type>    # typeinfo structure
+    case 'I': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("typeinfo for ", Ty);
+    }
+    // TS <type>    # typeinfo name (null-terminated byte string)
+    case 'S': {
+      First += 2;
+      Node *Ty = getDerived().parseType();
+      if (Ty == nullptr)
+        return nullptr;
+      return make<SpecialName>("typeinfo name for ", Ty);
+    }
+    // Tc <call-offset> <call-offset> <base encoding>
+    case 'c': {
+      First += 2;
+      if (parseCallOffset() || parseCallOffset())
+        return nullptr;
+      Node *Encoding = getDerived().parseEncoding();
+      if (Encoding == nullptr)
+        return nullptr;
+      return make<SpecialName>("covariant return thunk to ", Encoding);
+    }
+    // extension ::= TC <first type> <number> _ <second type>
+    //               # construction vtable for second-in-first
+    case 'C': {
+      First += 2;
+      Node *FirstType = getDerived().parseType();
+      if (FirstType == nullptr)
+        return nullptr;
+      if (parseNumber(true).empty() || !consumeIf('_'))
+        return nullptr;
+      Node *SecondType = getDerived().parseType();
+      if (SecondType == nullptr)
+        return nullptr;
+      return make<CtorVtableSpecialName>(SecondType, FirstType);
+    }
+    // TW <object name> # Thread-local wrapper
+    case 'W': {
+      First += 2;
+      Node *Name = getDerived().parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("thread-local wrapper routine for ", Name);
+    }
+    // TH <object name> # Thread-local initialization
+    case 'H': {
+      First += 2;
+      Node *Name = getDerived().parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("thread-local initialization routine for ", Name);
+    }
+    // T <call-offset> <base encoding>
+    default: {
+      ++First;
+      bool IsVirt = look() == 'v';
+      if (parseCallOffset())
+        return nullptr;
+      Node *BaseEncoding = getDerived().parseEncoding();
+      if (BaseEncoding == nullptr)
+        return nullptr;
+      if (IsVirt)
+        return make<SpecialName>("virtual thunk to ", BaseEncoding);
+      else
+        return make<SpecialName>("non-virtual thunk to ", BaseEncoding);
+    }
+    }
+  case 'G':
+    switch (look(1)) {
+    // GV <object name> # Guard variable for one-time initialization
+    case 'V': {
+      First += 2;
+      Node *Name = getDerived().parseName();
+      if (Name == nullptr)
+        return nullptr;
+      return make<SpecialName>("guard variable for ", Name);
+    }
+    // GR <object name> # reference temporary for object
+    // GR <object name> _             # First temporary
+    // GR <object name> <seq-id> _    # Subsequent temporaries
+    case 'R': {
+      First += 2;
+      Node *Name = getDerived().parseName();
+      if (Name == nullptr)
+        return nullptr;
+      size_t Count;
+      bool ParsedSeqId = !parseSeqId(&Count);
+      if (!consumeIf('_') && ParsedSeqId)
+        return nullptr;
+      return make<SpecialName>("reference temporary for ", Name);
+    }
+    }
+  }
+  return nullptr;
+}
+
+// <encoding> ::= <function name> <bare-function-type>
+//            ::= <data name>
+//            ::= <special-name>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+  if (look() == 'G' || look() == 'T')
+    return getDerived().parseSpecialName();
+
+  auto IsEndOfEncoding = [&] {
+    // The set of chars that can potentially follow an <encoding> (none of which
+    // can start a <type>). Enumerating these allows us to avoid speculative
+    // parsing.
+    return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';
+  };
+
+  NameState NameInfo(this);
+  Node *Name = getDerived().parseName(&NameInfo);
+  if (Name == nullptr)
+    return nullptr;
+
+  if (resolveForwardTemplateRefs(NameInfo))
+    return nullptr;
+
+  if (IsEndOfEncoding())
+    return Name;
+
+  Node *Attrs = nullptr;
+  if (consumeIf("Ua9enable_ifI")) {
+    size_t BeforeArgs = Names.size();
+    while (!consumeIf('E')) {
+      Node *Arg = getDerived().parseTemplateArg();
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+    }
+    Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));
+    if (!Attrs)
+      return nullptr;
+  }
+
+  Node *ReturnType = nullptr;
+  if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
+    ReturnType = getDerived().parseType();
+    if (ReturnType == nullptr)
+      return nullptr;
+  }
+
+  if (consumeIf('v'))
+    return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
+                                  Attrs, NameInfo.CVQualifiers,
+                                  NameInfo.ReferenceQualifier);
+
+  size_t ParamsBegin = Names.size();
+  do {
+    Node *Ty = getDerived().parseType();
+    if (Ty == nullptr)
+      return nullptr;
+    Names.push_back(Ty);
+  } while (!IsEndOfEncoding());
+
+  return make<FunctionEncoding>(ReturnType, Name,
+                                popTrailingNodeArray(ParamsBegin),
+                                Attrs, NameInfo.CVQualifiers,
+                                NameInfo.ReferenceQualifier);
+}
+
+template <class Float>
+struct FloatData;
+
+template <>
+struct FloatData<float>
+{
+    static const size_t mangled_size = 8;
+    static const size_t max_demangled_size = 24;
+    static constexpr const char* spec = "%af";
+};
+
+template <>
+struct FloatData<double>
+{
+    static const size_t mangled_size = 16;
+    static const size_t max_demangled_size = 32;
+    static constexpr const char* spec = "%a";
+};
+
+template <>
+struct FloatData<long double>
+{
+#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
+    defined(__wasm__)
+    static const size_t mangled_size = 32;
+#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
+    static const size_t mangled_size = 16;
+#else
+    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms
+#endif
+    static const size_t max_demangled_size = 40;
+    static constexpr const char *spec = "%LaL";
+};
+
+template <typename Alloc, typename Derived>
+template <class Float>
+Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() {
+  const size_t N = FloatData<Float>::mangled_size;
+  if (numLeft() <= N)
+    return nullptr;
+  StringView Data(First, First + N);
+  for (char C : Data)
+    if (!std::isxdigit(C))
+      return nullptr;
+  First += N;
+  if (!consumeIf('E'))
+    return nullptr;
+  return make<FloatLiteralImpl<Float>>(Data);
+}
+
+// <seq-id> ::= <0-9A-Z>+
+template <typename Alloc, typename Derived>
+bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) {
+  if (!(look() >= '0' && look() <= '9') &&
+      !(look() >= 'A' && look() <= 'Z'))
+    return true;
+
+  size_t Id = 0;
+  while (true) {
+    if (look() >= '0' && look() <= '9') {
+      Id *= 36;
+      Id += static_cast<size_t>(look() - '0');
+    } else if (look() >= 'A' && look() <= 'Z') {
+      Id *= 36;
+      Id += static_cast<size_t>(look() - 'A') + 10;
+    } else {
+      *Out = Id;
+      return false;
+    }
+    ++First;
+  }
+}
+
+// <substitution> ::= S <seq-id> _
+//                ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+//                                               ::std::char_traits<char>,
+//                                               ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
+  if (!consumeIf('S'))
+    return nullptr;
+
+  if (std::islower(look())) {
+    Node *SpecialSub;
+    switch (look()) {
+    case 'a':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
+      break;
+    case 'b':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
+      break;
+    case 's':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
+      break;
+    case 'i':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
+      break;
+    case 'o':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
+      break;
+    case 'd':
+      ++First;
+      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
+      break;
+    default:
+      return nullptr;
+    }
+    if (!SpecialSub)
+      return nullptr;
+    // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
+    // has ABI tags, the tags are appended to the substitution; the result is a
+    // substitutable component.
+    Node *WithTags = getDerived().parseAbiTags(SpecialSub);
+    if (WithTags != SpecialSub) {
+      Subs.push_back(WithTags);
+      SpecialSub = WithTags;
+    }
+    return SpecialSub;
+  }
+
+  //                ::= S_
+  if (consumeIf('_')) {
+    if (Subs.empty())
+      return nullptr;
+    return Subs[0];
+  }
+
+  //                ::= S <seq-id> _
+  size_t Index = 0;
+  if (parseSeqId(&Index))
+    return nullptr;
+  ++Index;
+  if (!consumeIf('_') || Index >= Subs.size())
+    return nullptr;
+  return Subs[Index];
+}
+
+// <template-param> ::= T_    # first template parameter
+//                  ::= T <parameter-2 non-negative number> _
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
+  if (!consumeIf('T'))
+    return nullptr;
+
+  size_t Index = 0;
+  if (!consumeIf('_')) {
+    if (parsePositiveInteger(&Index))
+      return nullptr;
+    ++Index;
+    if (!consumeIf('_'))
+      return nullptr;
+  }
+
+  // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list
+  // are mangled as the corresponding artificial template type parameter.
+  if (ParsingLambdaParams)
+    return make<NameType>("auto");
+
+  // If we're in a context where this <template-param> refers to a
+  // <template-arg> further ahead in the mangled name (currently just conversion
+  // operator types), then we should only look it up in the right context.
+  if (PermitForwardTemplateReferences) {
+    Node *ForwardRef = make<ForwardTemplateReference>(Index);
+    if (!ForwardRef)
+      return nullptr;
+    assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
+    ForwardTemplateRefs.push_back(
+        static_cast<ForwardTemplateReference *>(ForwardRef));
+    return ForwardRef;
+  }
+
+  if (Index >= TemplateParams.size())
+    return nullptr;
+  return TemplateParams[Index];
+}
+
+// <template-arg> ::= <type>                    # type or template
+//                ::= X <expression> E          # expression
+//                ::= <expr-primary>            # simple expressions
+//                ::= J <template-arg>* E       # argument pack
+//                ::= LZ <encoding> E           # extension
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
+  switch (look()) {
+  case 'X': {
+    ++First;
+    Node *Arg = getDerived().parseExpr();
+    if (Arg == nullptr || !consumeIf('E'))
+      return nullptr;
+    return Arg;
+  }
+  case 'J': {
+    ++First;
+    size_t ArgsBegin = Names.size();
+    while (!consumeIf('E')) {
+      Node *Arg = getDerived().parseTemplateArg();
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+    }
+    NodeArray Args = popTrailingNodeArray(ArgsBegin);
+    return make<TemplateArgumentPack>(Args);
+  }
+  case 'L': {
+    //                ::= LZ <encoding> E           # extension
+    if (look(1) == 'Z') {
+      First += 2;
+      Node *Arg = getDerived().parseEncoding();
+      if (Arg == nullptr || !consumeIf('E'))
+        return nullptr;
+      return Arg;
+    }
+    //                ::= <expr-primary>            # simple expressions
+    return getDerived().parseExprPrimary();
+  }
+  default:
+    return getDerived().parseType();
+  }
+}
+
+// <template-args> ::= I <template-arg>* E
+//     extension, the abi says <template-arg>+
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
+  if (!consumeIf('I'))
+    return nullptr;
+
+  // <template-params> refer to the innermost <template-args>. Clear out any
+  // outer args that we may have inserted into TemplateParams.
+  if (TagTemplates)
+    TemplateParams.clear();
+
+  size_t ArgsBegin = Names.size();
+  while (!consumeIf('E')) {
+    if (TagTemplates) {
+      auto OldParams = std::move(TemplateParams);
+      Node *Arg = getDerived().parseTemplateArg();
+      TemplateParams = std::move(OldParams);
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+      Node *TableEntry = Arg;
+      if (Arg->getKind() == Node::KTemplateArgumentPack) {
+        TableEntry = make<ParameterPack>(
+            static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
+        if (!TableEntry)
+          return nullptr;
+      }
+      TemplateParams.push_back(TableEntry);
+    } else {
+      Node *Arg = getDerived().parseTemplateArg();
+      if (Arg == nullptr)
+        return nullptr;
+      Names.push_back(Arg);
+    }
+  }
+  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
+}
+
+// <mangled-name> ::= _Z <encoding>
+//                ::= <type>
+// extension      ::= ___Z <encoding> _block_invoke
+// extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
+// extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parse() {
+  if (consumeIf("_Z")) {
+    Node *Encoding = getDerived().parseEncoding();
+    if (Encoding == nullptr)
+      return nullptr;
+    if (look() == '.') {
+      Encoding = make<DotSuffix>(Encoding, StringView(First, Last));
+      First = Last;
+    }
+    if (numLeft() != 0)
+      return nullptr;
+    return Encoding;
+  }
+
+  if (consumeIf("___Z")) {
+    Node *Encoding = getDerived().parseEncoding();
+    if (Encoding == nullptr || !consumeIf("_block_invoke"))
+      return nullptr;
+    bool RequireNumber = consumeIf('_');
+    if (parseNumber().empty() && RequireNumber)
+      return nullptr;
+    if (look() == '.')
+      First = Last;
+    if (numLeft() != 0)
+      return nullptr;
+    return make<SpecialName>("invocation function for block in ", Encoding);
+  }
+
+  Node *Ty = getDerived().parseType();
+  if (numLeft() != 0)
+    return nullptr;
+  return Ty;
+}
+
+template <typename Alloc>
+struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
+  using AbstractManglingParser<ManglingParser<Alloc>,
+                               Alloc>::AbstractManglingParser;
+};
+
+}  // namespace itanium_demangle
+}  // namespace llvm
+
+#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H
diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
new file mode 100644
index 0000000..b186758
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
@@ -0,0 +1,276 @@
+//===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
+#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
+
+#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/MicrosoftDemangleNodes.h"
+#include "llvm/Demangle/StringView.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <utility>
+
+namespace llvm {
+namespace ms_demangle {
+// This memory allocator is extremely fast, but it doesn't call dtors
+// for allocated objects. That means you can't use STL containers
+// (such as std::vector) with this allocator. But it pays off --
+// the demangler is 3x faster with this allocator compared to one with
+// STL containers.
+constexpr size_t AllocUnit = 4096;
+
+class ArenaAllocator {
+  struct AllocatorNode {
+    uint8_t *Buf = nullptr;
+    size_t Used = 0;
+    size_t Capacity = 0;
+    AllocatorNode *Next = nullptr;
+  };
+
+  void addNode(size_t Capacity) {
+    AllocatorNode *NewHead = new AllocatorNode;
+    NewHead->Buf = new uint8_t[Capacity];
+    NewHead->Next = Head;
+    NewHead->Capacity = Capacity;
+    Head = NewHead;
+    NewHead->Used = 0;
+  }
+
+public:
+  ArenaAllocator() { addNode(AllocUnit); }
+
+  ~ArenaAllocator() {
+    while (Head) {
+      assert(Head->Buf);
+      delete[] Head->Buf;
+      AllocatorNode *Next = Head->Next;
+      delete Head;
+      Head = Next;
+    }
+  }
+
+  char *allocUnalignedBuffer(size_t Length) {
+    uint8_t *Buf = Head->Buf + Head->Used;
+
+    Head->Used += Length;
+    if (Head->Used > Head->Capacity) {
+      // It's possible we need a buffer which is larger than our default unit
+      // size, so we need to be careful to add a node with capacity that is at
+      // least as large as what we need.
+      addNode(std::max(AllocUnit, Length));
+      Head->Used = Length;
+      Buf = Head->Buf;
+    }
+
+    return reinterpret_cast<char *>(Buf);
+  }
+
+  template <typename T, typename... Args> T *allocArray(size_t Count) {
+
+    size_t Size = Count * sizeof(T);
+    assert(Head && Head->Buf);
+
+    size_t P = (size_t)Head->Buf + Head->Used;
+    uintptr_t AlignedP =
+        (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
+    uint8_t *PP = (uint8_t *)AlignedP;
+    size_t Adjustment = AlignedP - P;
+
+    Head->Used += Size + Adjustment;
+    if (Head->Used < Head->Capacity)
+      return new (PP) T[Count]();
+
+    addNode(AllocUnit);
+    Head->Used = Size;
+    return new (Head->Buf) T[Count]();
+  }
+
+  template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
+
+    size_t Size = sizeof(T);
+    assert(Head && Head->Buf);
+
+    size_t P = (size_t)Head->Buf + Head->Used;
+    uintptr_t AlignedP =
+        (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
+    uint8_t *PP = (uint8_t *)AlignedP;
+    size_t Adjustment = AlignedP - P;
+
+    Head->Used += Size + Adjustment;
+    if (Head->Used < Head->Capacity)
+      return new (PP) T(std::forward<Args>(ConstructorArgs)...);
+
+    addNode(AllocUnit);
+    Head->Used = Size;
+    return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
+  }
+
+private:
+  AllocatorNode *Head = nullptr;
+};
+
+struct BackrefContext {
+  static constexpr size_t Max = 10;
+
+  TypeNode *FunctionParams[Max];
+  size_t FunctionParamCount = 0;
+
+  // The first 10 BackReferences in a mangled name can be back-referenced by
+  // special name @[0-9]. This is a storage for the first 10 BackReferences.
+  NamedIdentifierNode *Names[Max];
+  size_t NamesCount = 0;
+};
+
+enum class QualifierMangleMode { Drop, Mangle, Result };
+
+enum NameBackrefBehavior : uint8_t {
+  NBB_None = 0,          // don't save any names as backrefs.
+  NBB_Template = 1 << 0, // save template instanations.
+  NBB_Simple = 1 << 1,   // save simple names.
+};
+
+enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder };
+
+// Demangler class takes the main role in demangling symbols.
+// It has a set of functions to parse mangled symbols into Type instances.
+// It also has a set of functions to convert Type instances to strings.
+class Demangler {
+public:
+  Demangler() = default;
+  virtual ~Demangler() = default;
+
+  // You are supposed to call parse() first and then check if error is true.  If
+  // it is false, call output() to write the formatted name to the given stream.
+  SymbolNode *parse(StringView &MangledName);
+
+  TagTypeNode *parseTagUniqueName(StringView &MangledName);
+
+  // True if an error occurred.
+  bool Error = false;
+
+  void dumpBackReferences();
+
+private:
+  SymbolNode *demangleEncodedSymbol(StringView &MangledName,
+                                    QualifiedNameNode *QN);
+
+  VariableSymbolNode *demangleVariableEncoding(StringView &MangledName,
+                                               StorageClass SC);
+  FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName);
+
+  Qualifiers demanglePointerExtQualifiers(StringView &MangledName);
+
+  // Parser functions. This is a recursive-descent parser.
+  TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM);
+  PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName);
+  CustomTypeNode *demangleCustomType(StringView &MangledName);
+  TagTypeNode *demangleClassType(StringView &MangledName);
+  PointerTypeNode *demanglePointerType(StringView &MangledName);
+  PointerTypeNode *demangleMemberPointerType(StringView &MangledName);
+  FunctionSignatureNode *demangleFunctionType(StringView &MangledName,
+                                              bool HasThisQuals);
+
+  ArrayTypeNode *demangleArrayType(StringView &MangledName);
+
+  NodeArrayNode *demangleTemplateParameterList(StringView &MangledName);
+  NodeArrayNode *demangleFunctionParameterList(StringView &MangledName);
+
+  std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);
+  uint64_t demangleUnsigned(StringView &MangledName);
+  int64_t demangleSigned(StringView &MangledName);
+
+  void memorizeString(StringView s);
+  void memorizeIdentifier(IdentifierNode *Identifier);
+
+  /// Allocate a copy of \p Borrowed into memory that we own.
+  StringView copyString(StringView Borrowed);
+
+  QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName);
+  QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName);
+
+  IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName,
+                                              bool Memorize);
+  IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName,
+                                                NameBackrefBehavior NBB);
+
+  QualifiedNameNode *demangleNameScopeChain(StringView &MangledName,
+                                            IdentifierNode *UnqualifiedName);
+  IdentifierNode *demangleNameScopePiece(StringView &MangledName);
+
+  NamedIdentifierNode *demangleBackRefName(StringView &MangledName);
+  IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName,
+                                                    NameBackrefBehavior NBB);
+  IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName);
+  IdentifierNode *
+  demangleFunctionIdentifierCode(StringView &MangledName,
+                                 FunctionIdentifierCodeGroup Group);
+  StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName,
+                                                     bool IsDestructor);
+  ConversionOperatorIdentifierNode *
+  demangleConversionOperatorIdentifier(StringView &MangledName);
+  LiteralOperatorIdentifierNode *
+  demangleLiteralOperatorIdentifier(StringView &MangledName);
+
+  SymbolNode *demangleSpecialIntrinsic(StringView &MangledName);
+  SpecialTableSymbolNode *
+  demangleSpecialTableSymbolNode(StringView &MangledName,
+                                 SpecialIntrinsicKind SIK);
+  LocalStaticGuardVariableNode *
+  demangleLocalStaticGuard(StringView &MangledName);
+  VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,
+                                              StringView &MangledName,
+                                              StringView VariableName);
+  VariableSymbolNode *
+  demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
+                                      StringView &MangledName);
+  FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName,
+                                           bool IsDestructor);
+
+  NamedIdentifierNode *demangleSimpleName(StringView &MangledName,
+                                          bool Memorize);
+  NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName);
+  NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName);
+  EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName);
+  FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName);
+
+  StringView demangleSimpleString(StringView &MangledName, bool Memorize);
+
+  FuncClass demangleFunctionClass(StringView &MangledName);
+  CallingConv demangleCallingConvention(StringView &MangledName);
+  StorageClass demangleVariableStorageClass(StringView &MangledName);
+  void demangleThrowSpecification(StringView &MangledName);
+  wchar_t demangleWcharLiteral(StringView &MangledName);
+  uint8_t demangleCharLiteral(StringView &MangledName);
+
+  std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName);
+
+  // Memory allocator.
+  ArenaAllocator Arena;
+
+  // A single type uses one global back-ref table for all function params.
+  // This means back-refs can even go "into" other types.  Examples:
+  //
+  //  // Second int* is a back-ref to first.
+  //  void foo(int *, int*);
+  //
+  //  // Second int* is not a back-ref to first (first is not a function param).
+  //  int* foo(int*);
+  //
+  //  // Second int* is a back-ref to first (ALL function types share the same
+  //  // back-ref map.
+  //  using F = void(*)(int*);
+  //  F G(int *);
+  BackrefContext Backrefs;
+};
+
+} // namespace ms_demangle
+} // namespace llvm
+
+#endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
new file mode 100644
index 0000000..1d0b66a
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -0,0 +1,599 @@
+#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
+#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
+
+#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/StringView.h"
+#include <array>
+
+class OutputStream;
+
+namespace llvm {
+namespace ms_demangle {
+
+// Storage classes
+enum Qualifiers : uint8_t {
+  Q_None = 0,
+  Q_Const = 1 << 0,
+  Q_Volatile = 1 << 1,
+  Q_Far = 1 << 2,
+  Q_Huge = 1 << 3,
+  Q_Unaligned = 1 << 4,
+  Q_Restrict = 1 << 5,
+  Q_Pointer64 = 1 << 6
+};
+
+enum class StorageClass : uint8_t {
+  None,
+  PrivateStatic,
+  ProtectedStatic,
+  PublicStatic,
+  Global,
+  FunctionLocalStatic,
+};
+
+enum class PointerAffinity { None, Pointer, Reference, RValueReference };
+enum class FunctionRefQualifier { None, Reference, RValueReference };
+
+// Calling conventions
+enum class CallingConv : uint8_t {
+  None,
+  Cdecl,
+  Pascal,
+  Thiscall,
+  Stdcall,
+  Fastcall,
+  Clrcall,
+  Eabi,
+  Vectorcall,
+  Regcall,
+};
+
+enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
+
+enum OutputFlags {
+  OF_Default = 0,
+  OF_NoCallingConvention = 1,
+};
+
+// Types
+enum class PrimitiveKind {
+  Void,
+  Bool,
+  Char,
+  Schar,
+  Uchar,
+  Char16,
+  Char32,
+  Short,
+  Ushort,
+  Int,
+  Uint,
+  Long,
+  Ulong,
+  Int64,
+  Uint64,
+  Wchar,
+  Float,
+  Double,
+  Ldouble,
+  Nullptr,
+};
+
+enum class CharKind {
+  Char,
+  Char16,
+  Char32,
+  Wchar,
+};
+
+enum class IntrinsicFunctionKind : uint8_t {
+  None,
+  New,                        // ?2 # operator new
+  Delete,                     // ?3 # operator delete
+  Assign,                     // ?4 # operator=
+  RightShift,                 // ?5 # operator>>
+  LeftShift,                  // ?6 # operator<<
+  LogicalNot,                 // ?7 # operator!
+  Equals,                     // ?8 # operator==
+  NotEquals,                  // ?9 # operator!=
+  ArraySubscript,             // ?A # operator[]
+  Pointer,                    // ?C # operator->
+  Dereference,                // ?D # operator*
+  Increment,                  // ?E # operator++
+  Decrement,                  // ?F # operator--
+  Minus,                      // ?G # operator-
+  Plus,                       // ?H # operator+
+  BitwiseAnd,                 // ?I # operator&
+  MemberPointer,              // ?J # operator->*
+  Divide,                     // ?K # operator/
+  Modulus,                    // ?L # operator%
+  LessThan,                   // ?M operator<
+  LessThanEqual,              // ?N operator<=
+  GreaterThan,                // ?O operator>
+  GreaterThanEqual,           // ?P operator>=
+  Comma,                      // ?Q operator,
+  Parens,                     // ?R operator()
+  BitwiseNot,                 // ?S operator~
+  BitwiseXor,                 // ?T operator^
+  BitwiseOr,                  // ?U operator|
+  LogicalAnd,                 // ?V operator&&
+  LogicalOr,                  // ?W operator||
+  TimesEqual,                 // ?X operator*=
+  PlusEqual,                  // ?Y operator+=
+  MinusEqual,                 // ?Z operator-=
+  DivEqual,                   // ?_0 operator/=
+  ModEqual,                   // ?_1 operator%=
+  RshEqual,                   // ?_2 operator>>=
+  LshEqual,                   // ?_3 operator<<=
+  BitwiseAndEqual,            // ?_4 operator&=
+  BitwiseOrEqual,             // ?_5 operator|=
+  BitwiseXorEqual,            // ?_6 operator^=
+  VbaseDtor,                  // ?_D # vbase destructor
+  VecDelDtor,                 // ?_E # vector deleting destructor
+  DefaultCtorClosure,         // ?_F # default constructor closure
+  ScalarDelDtor,              // ?_G # scalar deleting destructor
+  VecCtorIter,                // ?_H # vector constructor iterator
+  VecDtorIter,                // ?_I # vector destructor iterator
+  VecVbaseCtorIter,           // ?_J # vector vbase constructor iterator
+  VdispMap,                   // ?_K # virtual displacement map
+  EHVecCtorIter,              // ?_L # eh vector constructor iterator
+  EHVecDtorIter,              // ?_M # eh vector destructor iterator
+  EHVecVbaseCtorIter,         // ?_N # eh vector vbase constructor iterator
+  CopyCtorClosure,            // ?_O # copy constructor closure
+  LocalVftableCtorClosure,    // ?_T # local vftable constructor closure
+  ArrayNew,                   // ?_U operator new[]
+  ArrayDelete,                // ?_V operator delete[]
+  ManVectorCtorIter,          // ?__A managed vector ctor iterator
+  ManVectorDtorIter,          // ?__B managed vector dtor iterator
+  EHVectorCopyCtorIter,       // ?__C EH vector copy ctor iterator
+  EHVectorVbaseCopyCtorIter,  // ?__D EH vector vbase copy ctor iterator
+  VectorCopyCtorIter,         // ?__G vector copy constructor iterator
+  VectorVbaseCopyCtorIter,    // ?__H vector vbase copy constructor iterator
+  ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor
+  CoAwait,                    // ?__L co_await
+  Spaceship,                  // operator<=>
+  MaxIntrinsic
+};
+
+enum class SpecialIntrinsicKind {
+  None,
+  Vftable,
+  Vbtable,
+  Typeof,
+  VcallThunk,
+  LocalStaticGuard,
+  StringLiteralSymbol,
+  UdtReturning,
+  Unknown,
+  DynamicInitializer,
+  DynamicAtexitDestructor,
+  RttiTypeDescriptor,
+  RttiBaseClassDescriptor,
+  RttiBaseClassArray,
+  RttiClassHierarchyDescriptor,
+  RttiCompleteObjLocator,
+  LocalVftable,
+  LocalStaticThreadGuard,
+};
+
+// Function classes
+enum FuncClass : uint16_t {
+  FC_None = 0,
+  FC_Public = 1 << 0,
+  FC_Protected = 1 << 1,
+  FC_Private = 1 << 2,
+  FC_Global = 1 << 3,
+  FC_Static = 1 << 4,
+  FC_Virtual = 1 << 5,
+  FC_Far = 1 << 6,
+  FC_ExternC = 1 << 7,
+  FC_NoParameterList = 1 << 8,
+  FC_VirtualThisAdjust = 1 << 9,
+  FC_VirtualThisAdjustEx = 1 << 10,
+  FC_StaticThisAdjust = 1 << 11,
+};
+
+enum class TagKind { Class, Struct, Union, Enum };
+
+enum class NodeKind {
+  Unknown,
+  Md5Symbol,
+  PrimitiveType,
+  FunctionSignature,
+  Identifier,
+  NamedIdentifier,
+  VcallThunkIdentifier,
+  LocalStaticGuardIdentifier,
+  IntrinsicFunctionIdentifier,
+  ConversionOperatorIdentifier,
+  DynamicStructorIdentifier,
+  StructorIdentifier,
+  LiteralOperatorIdentifier,
+  ThunkSignature,
+  PointerType,
+  TagType,
+  ArrayType,
+  Custom,
+  IntrinsicType,
+  NodeArray,
+  QualifiedName,
+  TemplateParameterReference,
+  EncodedStringLiteral,
+  IntegerLiteral,
+  RttiBaseClassDescriptor,
+  LocalStaticGuardVariable,
+  FunctionSymbol,
+  VariableSymbol,
+  SpecialTableSymbol
+};
+
+struct Node {
+  explicit Node(NodeKind K) : Kind(K) {}
+  virtual ~Node() = default;
+
+  NodeKind kind() const { return Kind; }
+
+  virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;
+
+private:
+  NodeKind Kind;
+};
+
+struct TypeNode;
+struct PrimitiveTypeNode;
+struct FunctionSignatureNode;
+struct IdentifierNode;
+struct NamedIdentifierNode;
+struct VcallThunkIdentifierNode;
+struct IntrinsicFunctionIdentifierNode;
+struct LiteralOperatorIdentifierNode;
+struct ConversionOperatorIdentifierNode;
+struct StructorIdentifierNode;
+struct ThunkSignatureNode;
+struct PointerTypeNode;
+struct ArrayTypeNode;
+struct CustomNode;
+struct TagTypeNode;
+struct IntrinsicTypeNode;
+struct NodeArrayNode;
+struct QualifiedNameNode;
+struct TemplateParameterReferenceNode;
+struct EncodedStringLiteralNode;
+struct IntegerLiteralNode;
+struct RttiBaseClassDescriptorNode;
+struct LocalStaticGuardVariableNode;
+struct SymbolNode;
+struct FunctionSymbolNode;
+struct VariableSymbolNode;
+struct SpecialTableSymbolNode;
+
+struct TypeNode : public Node {
+  explicit TypeNode(NodeKind K) : Node(K) {}
+
+  virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;
+  virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;
+
+  void output(OutputStream &OS, OutputFlags Flags) const override {
+    outputPre(OS, Flags);
+    outputPost(OS, Flags);
+  }
+
+  void outputQuals(bool SpaceBefore, bool SpaceAfter) const;
+
+  Qualifiers Quals = Q_None;
+};
+
+struct PrimitiveTypeNode : public TypeNode {
+  explicit PrimitiveTypeNode(PrimitiveKind K)
+      : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const {}
+
+  PrimitiveKind PrimKind;
+};
+
+struct FunctionSignatureNode : public TypeNode {
+  explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
+  FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+
+  // Valid if this FunctionTypeNode is the Pointee of a PointerType or
+  // MemberPointerType.
+  PointerAffinity Affinity = PointerAffinity::None;
+
+  // The function's calling convention.
+  CallingConv CallConvention = CallingConv::None;
+
+  // Function flags (gloabl, public, etc)
+  FuncClass FunctionClass = FC_Global;
+
+  FunctionRefQualifier RefQualifier = FunctionRefQualifier::None;
+
+  // The return type of the function.
+  TypeNode *ReturnType = nullptr;
+
+  // True if this is a C-style ... varargs function.
+  bool IsVariadic = false;
+
+  // Function parameters
+  NodeArrayNode *Params = nullptr;
+};
+
+struct IdentifierNode : public Node {
+  explicit IdentifierNode(NodeKind K) : Node(K) {}
+
+  NodeArrayNode *TemplateParams = nullptr;
+
+protected:
+  void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;
+};
+
+struct VcallThunkIdentifierNode : public IdentifierNode {
+  VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  uint64_t OffsetInVTable = 0;
+};
+
+struct DynamicStructorIdentifierNode : public IdentifierNode {
+  DynamicStructorIdentifierNode()
+      : IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  VariableSymbolNode *Variable = nullptr;
+  QualifiedNameNode *Name = nullptr;
+  bool IsDestructor = false;
+};
+
+struct NamedIdentifierNode : public IdentifierNode {
+  NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  StringView Name;
+};
+
+struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
+  explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator)
+      : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
+        Operator(Operator) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  IntrinsicFunctionKind Operator;
+};
+
+struct LiteralOperatorIdentifierNode : public IdentifierNode {
+  LiteralOperatorIdentifierNode()
+      : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  StringView Name;
+};
+
+struct LocalStaticGuardIdentifierNode : public IdentifierNode {
+  LocalStaticGuardIdentifierNode()
+      : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  uint32_t ScopeIndex = 0;
+};
+
+struct ConversionOperatorIdentifierNode : public IdentifierNode {
+  ConversionOperatorIdentifierNode()
+      : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  // The type that this operator converts too.
+  TypeNode *TargetType = nullptr;
+};
+
+struct StructorIdentifierNode : public IdentifierNode {
+  StructorIdentifierNode() : IdentifierNode(NodeKind::StructorIdentifier) {}
+  explicit StructorIdentifierNode(bool IsDestructor)
+      : IdentifierNode(NodeKind::StructorIdentifier),
+        IsDestructor(IsDestructor) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  // The name of the class that this is a structor of.
+  IdentifierNode *Class = nullptr;
+  bool IsDestructor = false;
+};
+
+struct ThunkSignatureNode : public FunctionSignatureNode {
+  ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+
+  struct ThisAdjustor {
+    uint32_t StaticOffset = 0;
+    int32_t VBPtrOffset = 0;
+    int32_t VBOffsetOffset = 0;
+    int32_t VtordispOffset = 0;
+  };
+
+  ThisAdjustor ThisAdjust;
+};
+
+struct PointerTypeNode : public TypeNode {
+  PointerTypeNode() : TypeNode(NodeKind::PointerType) {}
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+
+  // Is this a pointer, reference, or rvalue-reference?
+  PointerAffinity Affinity = PointerAffinity::None;
+
+  // If this is a member pointer, this is the class that the member is in.
+  QualifiedNameNode *ClassParent = nullptr;
+
+  // Represents a type X in "a pointer to X", "a reference to X", or
+  // "rvalue-reference to X"
+  TypeNode *Pointee = nullptr;
+};
+
+struct TagTypeNode : public TypeNode {
+  explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const;
+
+  QualifiedNameNode *QualifiedName = nullptr;
+  TagKind Tag;
+};
+
+struct ArrayTypeNode : public TypeNode {
+  ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const;
+
+  void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;
+  void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;
+
+  // A list of array dimensions.  e.g. [3,4,5] in `int Foo[3][4][5]`
+  NodeArrayNode *Dimensions = nullptr;
+
+  // The type of array element.
+  TypeNode *ElementType = nullptr;
+};
+
+struct IntrinsicNode : public TypeNode {
+  IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}
+  void output(OutputStream &OS, OutputFlags Flags) const override {}
+};
+
+struct CustomTypeNode : public TypeNode {
+  CustomTypeNode() : TypeNode(NodeKind::Custom) {}
+
+  void outputPre(OutputStream &OS, OutputFlags Flags) const override;
+  void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+
+  IdentifierNode *Identifier;
+};
+
+struct NodeArrayNode : public Node {
+  NodeArrayNode() : Node(NodeKind::NodeArray) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const;
+
+  Node **Nodes = 0;
+  size_t Count = 0;
+};
+
+struct QualifiedNameNode : public Node {
+  QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  NodeArrayNode *Components = nullptr;
+
+  IdentifierNode *getUnqualifiedIdentifier() {
+    Node *LastComponent = Components->Nodes[Components->Count - 1];
+    return static_cast<IdentifierNode *>(LastComponent);
+  }
+};
+
+struct TemplateParameterReferenceNode : public Node {
+  TemplateParameterReferenceNode()
+      : Node(NodeKind::TemplateParameterReference) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  SymbolNode *Symbol = nullptr;
+
+  int ThunkOffsetCount = 0;
+  std::array<int64_t, 3> ThunkOffsets;
+  PointerAffinity Affinity = PointerAffinity::None;
+  bool IsMemberPointer = false;
+};
+
+struct IntegerLiteralNode : public Node {
+  IntegerLiteralNode() : Node(NodeKind::IntegerLiteral) {}
+  IntegerLiteralNode(uint64_t Value, bool IsNegative)
+      : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  uint64_t Value = 0;
+  bool IsNegative = false;
+};
+
+struct RttiBaseClassDescriptorNode : public IdentifierNode {
+  RttiBaseClassDescriptorNode()
+      : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  uint32_t NVOffset = 0;
+  int32_t VBPtrOffset = 0;
+  uint32_t VBTableOffset = 0;
+  uint32_t Flags = 0;
+};
+
+struct SymbolNode : public Node {
+  explicit SymbolNode(NodeKind K) : Node(K) {}
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+  QualifiedNameNode *Name = nullptr;
+};
+
+struct SpecialTableSymbolNode : public SymbolNode {
+  explicit SpecialTableSymbolNode()
+      : SymbolNode(NodeKind::SpecialTableSymbol) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+  QualifiedNameNode *TargetName = nullptr;
+  Qualifiers Quals;
+};
+
+struct LocalStaticGuardVariableNode : public SymbolNode {
+  LocalStaticGuardVariableNode()
+      : SymbolNode(NodeKind::LocalStaticGuardVariable) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  bool IsVisible = false;
+};
+
+struct EncodedStringLiteralNode : public SymbolNode {
+  EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  StringView DecodedString;
+  bool IsTruncated = false;
+  CharKind Char = CharKind::Char;
+};
+
+struct VariableSymbolNode : public SymbolNode {
+  VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  StorageClass SC = StorageClass::None;
+  TypeNode *Type = nullptr;
+};
+
+struct FunctionSymbolNode : public SymbolNode {
+  FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
+
+  void output(OutputStream &OS, OutputFlags Flags) const override;
+
+  FunctionSignatureNode *Signature = nullptr;
+};
+
+} // namespace ms_demangle
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/third_party/llvm/include/llvm/Demangle/StringView.h b/third_party/llvm/include/llvm/Demangle/StringView.h
new file mode 100644
index 0000000..a89deda
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/StringView.h
@@ -0,0 +1,121 @@
+//===--- StringView.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//
+// This file contains a limited version of LLVM's StringView class.  It is
+// copied here so that LLVMDemangle need not take a dependency on LLVMSupport.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_STRINGVIEW_H
+#define LLVM_DEMANGLE_STRINGVIEW_H
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+class StringView {
+  const char *First;
+  const char *Last;
+
+public:
+  static const size_t npos = ~size_t(0);
+
+  template <size_t N>
+  StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
+  StringView(const char *First_, const char *Last_)
+      : First(First_), Last(Last_) {}
+  StringView(const char *First_, size_t Len)
+      : First(First_), Last(First_ + Len) {}
+  StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
+  StringView() : First(nullptr), Last(nullptr) {}
+
+  StringView substr(size_t From) const {
+    return StringView(begin() + From, size() - From);
+  }
+
+  size_t find(char C, size_t From = 0) const {
+    size_t FindBegin = std::min(From, size());
+    // Avoid calling memchr with nullptr.
+    if (FindBegin < size()) {
+      // Just forward to memchr, which is faster than a hand-rolled loop.
+      if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
+        return static_cast<const char *>(P) - First;
+    }
+    return npos;
+  }
+
+  StringView substr(size_t From, size_t To) const {
+    if (To >= size())
+      To = size() - 1;
+    if (From >= size())
+      From = size() - 1;
+    return StringView(First + From, First + To);
+  }
+
+  StringView dropFront(size_t N = 1) const {
+    if (N >= size())
+      N = size();
+    return StringView(First + N, Last);
+  }
+
+  StringView dropBack(size_t N = 1) const {
+    if (N >= size())
+      N = size();
+    return StringView(First, Last - N);
+  }
+
+  char front() const {
+    assert(!empty());
+    return *begin();
+  }
+
+  char back() const {
+    assert(!empty());
+    return *(end() - 1);
+  }
+
+  char popFront() {
+    assert(!empty());
+    return *First++;
+  }
+
+  bool consumeFront(char C) {
+    if (!startsWith(C))
+      return false;
+    *this = dropFront(1);
+    return true;
+  }
+
+  bool consumeFront(StringView S) {
+    if (!startsWith(S))
+      return false;
+    *this = dropFront(S.size());
+    return true;
+  }
+
+  bool startsWith(char C) const { return !empty() && *begin() == C; }
+
+  bool startsWith(StringView Str) const {
+    if (Str.size() > size())
+      return false;
+    return std::equal(Str.begin(), Str.end(), begin());
+  }
+
+  const char &operator[](size_t Idx) const { return *(begin() + Idx); }
+
+  const char *begin() const { return First; }
+  const char *end() const { return Last; }
+  size_t size() const { return static_cast<size_t>(Last - First); }
+  bool empty() const { return First == Last; }
+};
+
+inline bool operator==(const StringView &LHS, const StringView &RHS) {
+  return LHS.size() == RHS.size() &&
+         std::equal(LHS.begin(), LHS.end(), RHS.begin());
+}
+
+#endif
diff --git a/third_party/llvm/include/llvm/Demangle/Utility.h b/third_party/llvm/include/llvm/Demangle/Utility.h
new file mode 100644
index 0000000..1d1601c
--- /dev/null
+++ b/third_party/llvm/include/llvm/Demangle/Utility.h
@@ -0,0 +1,187 @@
+//===--- Utility.h ----------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//
+// This file contains several utility classes used by the demangle library.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_UTILITY_H
+#define LLVM_DEMANGLE_UTILITY_H
+
+#include "StringView.h"
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+
+// Stream that AST nodes write their string representation into after the AST
+// has been parsed.
+class OutputStream {
+  char *Buffer;
+  size_t CurrentPosition;
+  size_t BufferCapacity;
+
+  // Ensure there is at least n more positions in buffer.
+  void grow(size_t N) {
+    if (N + CurrentPosition >= BufferCapacity) {
+      BufferCapacity *= 2;
+      if (BufferCapacity < N + CurrentPosition)
+        BufferCapacity = N + CurrentPosition;
+      Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
+      if (Buffer == nullptr)
+        std::terminate();
+    }
+  }
+
+  void writeUnsigned(uint64_t N, bool isNeg = false) {
+    // Handle special case...
+    if (N == 0) {
+      *this << '0';
+      return;
+    }
+
+    char Temp[21];
+    char *TempPtr = std::end(Temp);
+
+    while (N) {
+      *--TempPtr = '0' + char(N % 10);
+      N /= 10;
+    }
+
+    // Add negative sign...
+    if (isNeg)
+      *--TempPtr = '-';
+    this->operator<<(StringView(TempPtr, std::end(Temp)));
+  }
+
+public:
+  OutputStream(char *StartBuf, size_t Size)
+      : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
+  OutputStream() = default;
+  void reset(char *Buffer_, size_t BufferCapacity_) {
+    CurrentPosition = 0;
+    Buffer = Buffer_;
+    BufferCapacity = BufferCapacity_;
+  }
+
+  /// If a ParameterPackExpansion (or similar type) is encountered, the offset
+  /// into the pack that we're currently printing.
+  unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
+  unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
+
+  OutputStream &operator+=(StringView R) {
+    size_t Size = R.size();
+    if (Size == 0)
+      return *this;
+    grow(Size);
+    std::memmove(Buffer + CurrentPosition, R.begin(), Size);
+    CurrentPosition += Size;
+    return *this;
+  }
+
+  OutputStream &operator+=(char C) {
+    grow(1);
+    Buffer[CurrentPosition++] = C;
+    return *this;
+  }
+
+  OutputStream &operator<<(StringView R) { return (*this += R); }
+
+  OutputStream &operator<<(char C) { return (*this += C); }
+
+  OutputStream &operator<<(long long N) {
+    if (N < 0)
+      writeUnsigned(static_cast<unsigned long long>(-N), true);
+    else
+      writeUnsigned(static_cast<unsigned long long>(N));
+    return *this;
+  }
+
+  OutputStream &operator<<(unsigned long long N) {
+    writeUnsigned(N, false);
+    return *this;
+  }
+
+  OutputStream &operator<<(long N) {
+    return this->operator<<(static_cast<long long>(N));
+  }
+
+  OutputStream &operator<<(unsigned long N) {
+    return this->operator<<(static_cast<unsigned long long>(N));
+  }
+
+  OutputStream &operator<<(int N) {
+    return this->operator<<(static_cast<long long>(N));
+  }
+
+  OutputStream &operator<<(unsigned int N) {
+    return this->operator<<(static_cast<unsigned long long>(N));
+  }
+
+  size_t getCurrentPosition() const { return CurrentPosition; }
+  void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
+
+  char back() const {
+    return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
+  }
+
+  bool empty() const { return CurrentPosition == 0; }
+
+  char *getBuffer() { return Buffer; }
+  char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
+  size_t getBufferCapacity() { return BufferCapacity; }
+};
+
+template <class T> class SwapAndRestore {
+  T &Restore;
+  T OriginalValue;
+  bool ShouldRestore = true;
+
+public:
+  SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
+
+  SwapAndRestore(T &Restore_, T NewVal)
+      : Restore(Restore_), OriginalValue(Restore) {
+    Restore = std::move(NewVal);
+  }
+  ~SwapAndRestore() {
+    if (ShouldRestore)
+      Restore = std::move(OriginalValue);
+  }
+
+  void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
+
+  void restoreNow(bool Force) {
+    if (!Force && !ShouldRestore)
+      return;
+
+    Restore = std::move(OriginalValue);
+    ShouldRestore = false;
+  }
+
+  SwapAndRestore(const SwapAndRestore &) = delete;
+  SwapAndRestore &operator=(const SwapAndRestore &) = delete;
+};
+
+inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
+                                   size_t InitSize) {
+  size_t BufferSize;
+  if (Buf == nullptr) {
+    Buf = static_cast<char *>(std::malloc(InitSize));
+    if (Buf == nullptr)
+      return false;
+    BufferSize = InitSize;
+  } else
+    BufferSize = *N;
+
+  S.reset(Buf, BufferSize);
+  return true;
+}
+
+#endif
diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
new file mode 100644
index 0000000..e3bd3b8
--- /dev/null
+++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -0,0 +1,587 @@
+//===------------------------- ItaniumDemangle.cpp ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: (possibly) incomplete list of features that clang mangles that this
+// file does not yet support:
+//   - C++ modules TS
+
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Demangle/ItaniumDemangle.h"
+
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <numeric>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::itanium_demangle;
+
+constexpr const char *itanium_demangle::FloatData<float>::spec;
+constexpr const char *itanium_demangle::FloatData<double>::spec;
+constexpr const char *itanium_demangle::FloatData<long double>::spec;
+
+// <discriminator> := _ <non-negative number>      # when number < 10
+//                 := __ <non-negative number> _   # when number >= 10
+//  extension      := decimal-digit+               # at the end of string
+const char *itanium_demangle::parse_discriminator(const char *first,
+                                                  const char *last) {
+  // parse but ignore discriminator
+  if (first != last) {
+    if (*first == '_') {
+      const char *t1 = first + 1;
+      if (t1 != last) {
+        if (std::isdigit(*t1))
+          first = t1 + 1;
+        else if (*t1 == '_') {
+          for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+            ;
+          if (t1 != last && *t1 == '_')
+            first = t1 + 1;
+        }
+      }
+    } else if (std::isdigit(*first)) {
+      const char *t1 = first + 1;
+      for (; t1 != last && std::isdigit(*t1); ++t1)
+        ;
+      if (t1 == last)
+        first = last;
+    }
+  }
+  return first;
+}
+
+#ifndef NDEBUG
+namespace {
+struct DumpVisitor {
+  unsigned Depth = 0;
+  bool PendingNewline = false;
+
+  template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
+    return true;
+  }
+  static bool wantsNewline(NodeArray A) { return !A.empty(); }
+  static constexpr bool wantsNewline(...) { return false; }
+
+  template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
+    for (bool B : {wantsNewline(Vs)...})
+      if (B)
+        return true;
+    return false;
+  }
+
+  void printStr(const char *S) { fprintf(stderr, "%s", S); }
+  void print(StringView SV) {
+    fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
+  }
+  void print(const Node *N) {
+    if (N)
+      N->visit(std::ref(*this));
+    else
+      printStr("<null>");
+  }
+  void print(NodeOrString NS) {
+    if (NS.isNode())
+      print(NS.asNode());
+    else if (NS.isString())
+      print(NS.asString());
+    else
+      printStr("NodeOrString()");
+  }
+  void print(NodeArray A) {
+    ++Depth;
+    printStr("{");
+    bool First = true;
+    for (const Node *N : A) {
+      if (First)
+        print(N);
+      else
+        printWithComma(N);
+      First = false;
+    }
+    printStr("}");
+    --Depth;
+  }
+
+  // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
+  void print(bool B) { printStr(B ? "true" : "false"); }
+
+  template <class T>
+  typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
+    fprintf(stderr, "%llu", (unsigned long long)N);
+  }
+
+  template <class T>
+  typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
+    fprintf(stderr, "%lld", (long long)N);
+  }
+
+  void print(ReferenceKind RK) {
+    switch (RK) {
+    case ReferenceKind::LValue:
+      return printStr("ReferenceKind::LValue");
+    case ReferenceKind::RValue:
+      return printStr("ReferenceKind::RValue");
+    }
+  }
+  void print(FunctionRefQual RQ) {
+    switch (RQ) {
+    case FunctionRefQual::FrefQualNone:
+      return printStr("FunctionRefQual::FrefQualNone");
+    case FunctionRefQual::FrefQualLValue:
+      return printStr("FunctionRefQual::FrefQualLValue");
+    case FunctionRefQual::FrefQualRValue:
+      return printStr("FunctionRefQual::FrefQualRValue");
+    }
+  }
+  void print(Qualifiers Qs) {
+    if (!Qs) return printStr("QualNone");
+    struct QualName { Qualifiers Q; const char *Name; } Names[] = {
+      {QualConst, "QualConst"},
+      {QualVolatile, "QualVolatile"},
+      {QualRestrict, "QualRestrict"},
+    };
+    for (QualName Name : Names) {
+      if (Qs & Name.Q) {
+        printStr(Name.Name);
+        Qs = Qualifiers(Qs & ~Name.Q);
+        if (Qs) printStr(" | ");
+      }
+    }
+  }
+  void print(SpecialSubKind SSK) {
+    switch (SSK) {
+    case SpecialSubKind::allocator:
+      return printStr("SpecialSubKind::allocator");
+    case SpecialSubKind::basic_string:
+      return printStr("SpecialSubKind::basic_string");
+    case SpecialSubKind::string:
+      return printStr("SpecialSubKind::string");
+    case SpecialSubKind::istream:
+      return printStr("SpecialSubKind::istream");
+    case SpecialSubKind::ostream:
+      return printStr("SpecialSubKind::ostream");
+    case SpecialSubKind::iostream:
+      return printStr("SpecialSubKind::iostream");
+    }
+  }
+
+  void newLine() {
+    printStr("\n");
+    for (unsigned I = 0; I != Depth; ++I)
+      printStr(" ");
+    PendingNewline = false;
+  }
+
+  template<typename T> void printWithPendingNewline(T V) {
+    print(V);
+    if (wantsNewline(V))
+      PendingNewline = true;
+  }
+
+  template<typename T> void printWithComma(T V) {
+    if (PendingNewline || wantsNewline(V)) {
+      printStr(",");
+      newLine();
+    } else {
+      printStr(", ");
+    }
+
+    printWithPendingNewline(V);
+  }
+
+  struct CtorArgPrinter {
+    DumpVisitor &Visitor;
+
+    template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
+      if (Visitor.anyWantNewline(V, Vs...))
+        Visitor.newLine();
+      Visitor.printWithPendingNewline(V);
+      int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
+      (void)PrintInOrder;
+    }
+  };
+
+  template<typename NodeT> void operator()(const NodeT *Node) {
+    Depth += 2;
+    fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
+    Node->match(CtorArgPrinter{*this});
+    fprintf(stderr, ")");
+    Depth -= 2;
+  }
+
+  void operator()(const ForwardTemplateReference *Node) {
+    Depth += 2;
+    fprintf(stderr, "ForwardTemplateReference(");
+    if (Node->Ref && !Node->Printing) {
+      Node->Printing = true;
+      CtorArgPrinter{*this}(Node->Ref);
+      Node->Printing = false;
+    } else {
+      CtorArgPrinter{*this}(Node->Index);
+    }
+    fprintf(stderr, ")");
+    Depth -= 2;
+  }
+};
+}
+
+void itanium_demangle::Node::dump() const {
+  DumpVisitor V;
+  visit(std::ref(V));
+  V.newLine();
+}
+#endif
+
+namespace {
+class BumpPointerAllocator {
+  struct BlockMeta {
+    BlockMeta* Next;
+    size_t Current;
+  };
+
+  static constexpr size_t AllocSize = 4096;
+  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
+
+  alignas(long double) char InitialBuffer[AllocSize];
+  BlockMeta* BlockList = nullptr;
+
+  void grow() {
+    char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
+    if (NewMeta == nullptr)
+      std::terminate();
+    BlockList = new (NewMeta) BlockMeta{BlockList, 0};
+  }
+
+  void* allocateMassive(size_t NBytes) {
+    NBytes += sizeof(BlockMeta);
+    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
+    if (NewMeta == nullptr)
+      std::terminate();
+    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
+    return static_cast<void*>(NewMeta + 1);
+  }
+
+public:
+  BumpPointerAllocator()
+      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
+
+  void* allocate(size_t N) {
+    N = (N + 15u) & ~15u;
+    if (N + BlockList->Current >= UsableAllocSize) {
+      if (N > UsableAllocSize)
+        return allocateMassive(N);
+      grow();
+    }
+    BlockList->Current += N;
+    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
+                              BlockList->Current - N);
+  }
+
+  void reset() {
+    while (BlockList) {
+      BlockMeta* Tmp = BlockList;
+      BlockList = BlockList->Next;
+      if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
+        std::free(Tmp);
+    }
+    BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
+  }
+
+  ~BumpPointerAllocator() { reset(); }
+};
+
+class DefaultAllocator {
+  BumpPointerAllocator Alloc;
+
+public:
+  void reset() { Alloc.reset(); }
+
+  template<typename T, typename ...Args> T *makeNode(Args &&...args) {
+    return new (Alloc.allocate(sizeof(T)))
+        T(std::forward<Args>(args)...);
+  }
+
+  void *allocateNodeArray(size_t sz) {
+    return Alloc.allocate(sizeof(Node *) * sz);
+  }
+};
+}  // unnamed namespace
+
+//===----------------------------------------------------------------------===//
+// Code beyond this point should not be synchronized with libc++abi.
+//===----------------------------------------------------------------------===//
+
+using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
+
+char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
+                            size_t *N, int *Status) {
+  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
+    if (Status)
+      *Status = demangle_invalid_args;
+    return nullptr;
+  }
+
+  int InternalStatus = demangle_success;
+  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
+  OutputStream S;
+
+  Node *AST = Parser.parse();
+
+  if (AST == nullptr)
+    InternalStatus = demangle_invalid_mangled_name;
+  else if (!initializeOutputStream(Buf, N, S, 1024))
+    InternalStatus = demangle_memory_alloc_failure;
+  else {
+    assert(Parser.ForwardTemplateRefs.empty());
+    AST->print(S);
+    S += '\0';
+    if (N != nullptr)
+      *N = S.getCurrentPosition();
+    Buf = S.getBuffer();
+  }
+
+  if (Status)
+    *Status = InternalStatus;
+  return InternalStatus == demangle_success ? Buf : nullptr;
+}
+
+bool llvm::itaniumFindTypesInMangledName(const char *MangledName, void *Ctx,
+                                         void (*Callback)(void *,
+                                                          const char *)) {
+  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
+  Parser.TypeCallback = Callback;
+  Parser.TypeCallbackContext = Ctx;
+  return Parser.parse() == nullptr;
+}
+
+ItaniumPartialDemangler::ItaniumPartialDemangler()
+    : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
+
+ItaniumPartialDemangler::~ItaniumPartialDemangler() {
+  delete static_cast<Demangler *>(Context);
+}
+
+ItaniumPartialDemangler::ItaniumPartialDemangler(
+    ItaniumPartialDemangler &&Other)
+    : RootNode(Other.RootNode), Context(Other.Context) {
+  Other.Context = Other.RootNode = nullptr;
+}
+
+ItaniumPartialDemangler &ItaniumPartialDemangler::
+operator=(ItaniumPartialDemangler &&Other) {
+  std::swap(RootNode, Other.RootNode);
+  std::swap(Context, Other.Context);
+  return *this;
+}
+
+// Demangle MangledName into an AST, storing it into this->RootNode.
+bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
+  Demangler *Parser = static_cast<Demangler *>(Context);
+  size_t Len = std::strlen(MangledName);
+  Parser->reset(MangledName, MangledName + Len);
+  RootNode = Parser->parse();
+  return RootNode == nullptr;
+}
+
+static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
+  OutputStream S;
+  if (!initializeOutputStream(Buf, N, S, 128))
+    return nullptr;
+  RootNode->print(S);
+  S += '\0';
+  if (N != nullptr)
+    *N = S.getCurrentPosition();
+  return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
+  if (!isFunction())
+    return nullptr;
+
+  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
+
+  while (true) {
+    switch (Name->getKind()) {
+    case Node::KAbiTagAttr:
+      Name = static_cast<const AbiTagAttr *>(Name)->Base;
+      continue;
+    case Node::KStdQualifiedName:
+      Name = static_cast<const StdQualifiedName *>(Name)->Child;
+      continue;
+    case Node::KNestedName:
+      Name = static_cast<const NestedName *>(Name)->Name;
+      continue;
+    case Node::KLocalName:
+      Name = static_cast<const LocalName *>(Name)->Entity;
+      continue;
+    case Node::KNameWithTemplateArgs:
+      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
+      continue;
+    default:
+      return printNode(Name, Buf, N);
+    }
+  }
+}
+
+char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
+                                                          size_t *N) const {
+  if (!isFunction())
+    return nullptr;
+  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
+
+  OutputStream S;
+  if (!initializeOutputStream(Buf, N, S, 128))
+    return nullptr;
+
+ KeepGoingLocalFunction:
+  while (true) {
+    if (Name->getKind() == Node::KAbiTagAttr) {
+      Name = static_cast<const AbiTagAttr *>(Name)->Base;
+      continue;
+    }
+    if (Name->getKind() == Node::KNameWithTemplateArgs) {
+      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
+      continue;
+    }
+    break;
+  }
+
+  switch (Name->getKind()) {
+  case Node::KStdQualifiedName:
+    S += "std";
+    break;
+  case Node::KNestedName:
+    static_cast<const NestedName *>(Name)->Qual->print(S);
+    break;
+  case Node::KLocalName: {
+    auto *LN = static_cast<const LocalName *>(Name);
+    LN->Encoding->print(S);
+    S += "::";
+    Name = LN->Entity;
+    goto KeepGoingLocalFunction;
+  }
+  default:
+    break;
+  }
+  S += '\0';
+  if (N != nullptr)
+    *N = S.getCurrentPosition();
+  return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
+  if (!isFunction())
+    return nullptr;
+  auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
+  return printNode(Name, Buf, N);
+}
+
+char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
+                                                     size_t *N) const {
+  if (!isFunction())
+    return nullptr;
+  NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
+
+  OutputStream S;
+  if (!initializeOutputStream(Buf, N, S, 128))
+    return nullptr;
+
+  S += '(';
+  Params.printWithComma(S);
+  S += ')';
+  S += '\0';
+  if (N != nullptr)
+    *N = S.getCurrentPosition();
+  return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionReturnType(
+    char *Buf, size_t *N) const {
+  if (!isFunction())
+    return nullptr;
+
+  OutputStream S;
+  if (!initializeOutputStream(Buf, N, S, 128))
+    return nullptr;
+
+  if (const Node *Ret =
+          static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
+    Ret->print(S);
+
+  S += '\0';
+  if (N != nullptr)
+    *N = S.getCurrentPosition();
+  return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
+  assert(RootNode != nullptr && "must call partialDemangle()");
+  return printNode(static_cast<Node *>(RootNode), Buf, N);
+}
+
+bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
+  assert(RootNode != nullptr && "must call partialDemangle()");
+  if (!isFunction())
+    return false;
+  auto *E = static_cast<const FunctionEncoding *>(RootNode);
+  return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
+}
+
+bool ItaniumPartialDemangler::isCtorOrDtor() const {
+  const Node *N = static_cast<const Node *>(RootNode);
+  while (N) {
+    switch (N->getKind()) {
+    default:
+      return false;
+    case Node::KCtorDtorName:
+      return true;
+
+    case Node::KAbiTagAttr:
+      N = static_cast<const AbiTagAttr *>(N)->Base;
+      break;
+    case Node::KFunctionEncoding:
+      N = static_cast<const FunctionEncoding *>(N)->getName();
+      break;
+    case Node::KLocalName:
+      N = static_cast<const LocalName *>(N)->Entity;
+      break;
+    case Node::KNameWithTemplateArgs:
+      N = static_cast<const NameWithTemplateArgs *>(N)->Name;
+      break;
+    case Node::KNestedName:
+      N = static_cast<const NestedName *>(N)->Name;
+      break;
+    case Node::KStdQualifiedName:
+      N = static_cast<const StdQualifiedName *>(N)->Child;
+      break;
+    }
+  }
+  return false;
+}
+
+bool ItaniumPartialDemangler::isFunction() const {
+  assert(RootNode != nullptr && "must call partialDemangle()");
+  return static_cast<const Node *>(RootNode)->getKind() ==
+         Node::KFunctionEncoding;
+}
+
+bool ItaniumPartialDemangler::isSpecialName() const {
+  assert(RootNode != nullptr && "must call partialDemangle()");
+  auto K = static_cast<const Node *>(RootNode)->getKind();
+  return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
+}
+
+bool ItaniumPartialDemangler::isData() const {
+  return !isFunction() && !isSpecialName();
+}
diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
new file mode 100644
index 0000000..4a45bfa
--- /dev/null
+++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -0,0 +1,2210 @@
+//===- MicrosoftDemangle.cpp ----------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a demangler for MSVC-style mangled symbols.
+//
+// This file has no dependencies on the rest of LLVM so that it can be
+// easily reused in other programs such as libcxxabi.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/MicrosoftDemangle.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Demangle/MicrosoftDemangleNodes.h"
+
+#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/StringView.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <array>
+#include <cctype>
+#include <cstdio>
+#include <tuple>
+
+using namespace llvm;
+using namespace ms_demangle;
+
+static bool startsWithDigit(StringView S) {
+  return !S.empty() && std::isdigit(S.front());
+}
+
+
+struct NodeList {
+  Node *N = nullptr;
+  NodeList *Next = nullptr;
+};
+
+static bool isMemberPointer(StringView MangledName) {
+  switch (MangledName.popFront()) {
+  case '$':
+    // This is probably an rvalue reference (e.g. $$Q), and you cannot have an
+    // rvalue reference to a member.
+    return false;
+  case 'A':
+    // 'A' indicates a reference, and you cannot have a reference to a member
+    // function or member.
+    return false;
+  case 'P':
+  case 'Q':
+  case 'R':
+  case 'S':
+    // These 4 values indicate some kind of pointer, but we still don't know
+    // what.
+    break;
+  default:
+    assert(false && "Ty is not a pointer type!");
+  }
+
+  // If it starts with a number, then 6 indicates a non-member function
+  // pointer, and 8 indicates a member function pointer.
+  if (startsWithDigit(MangledName)) {
+    assert(MangledName[0] == '6' || MangledName[0] == '8');
+    return (MangledName[0] == '8');
+  }
+
+  // Remove ext qualifiers since those can appear on either type and are
+  // therefore not indicative.
+  MangledName.consumeFront('E'); // 64-bit
+  MangledName.consumeFront('I'); // restrict
+  MangledName.consumeFront('F'); // unaligned
+
+  assert(!MangledName.empty());
+
+  // The next value should be either ABCD (non-member) or QRST (member).
+  switch (MangledName.front()) {
+  case 'A':
+  case 'B':
+  case 'C':
+  case 'D':
+    return false;
+  case 'Q':
+  case 'R':
+  case 'S':
+  case 'T':
+    return true;
+  default:
+    assert(false);
+  }
+  return false;
+}
+
+static SpecialIntrinsicKind
+consumeSpecialIntrinsicKind(StringView &MangledName) {
+  if (MangledName.consumeFront("?_7"))
+    return SpecialIntrinsicKind::Vftable;
+  if (MangledName.consumeFront("?_8"))
+    return SpecialIntrinsicKind::Vbtable;
+  if (MangledName.consumeFront("?_9"))
+    return SpecialIntrinsicKind::VcallThunk;
+  if (MangledName.consumeFront("?_A"))
+    return SpecialIntrinsicKind::Typeof;
+  if (MangledName.consumeFront("?_B"))
+    return SpecialIntrinsicKind::LocalStaticGuard;
+  if (MangledName.consumeFront("?_C"))
+    return SpecialIntrinsicKind::StringLiteralSymbol;
+  if (MangledName.consumeFront("?_P"))
+    return SpecialIntrinsicKind::UdtReturning;
+  if (MangledName.consumeFront("?_R0"))
+    return SpecialIntrinsicKind::RttiTypeDescriptor;
+  if (MangledName.consumeFront("?_R1"))
+    return SpecialIntrinsicKind::RttiBaseClassDescriptor;
+  if (MangledName.consumeFront("?_R2"))
+    return SpecialIntrinsicKind::RttiBaseClassArray;
+  if (MangledName.consumeFront("?_R3"))
+    return SpecialIntrinsicKind::RttiClassHierarchyDescriptor;
+  if (MangledName.consumeFront("?_R4"))
+    return SpecialIntrinsicKind::RttiCompleteObjLocator;
+  if (MangledName.consumeFront("?_S"))
+    return SpecialIntrinsicKind::LocalVftable;
+  if (MangledName.consumeFront("?__E"))
+    return SpecialIntrinsicKind::DynamicInitializer;
+  if (MangledName.consumeFront("?__F"))
+    return SpecialIntrinsicKind::DynamicAtexitDestructor;
+  if (MangledName.consumeFront("?__J"))
+    return SpecialIntrinsicKind::LocalStaticThreadGuard;
+  return SpecialIntrinsicKind::None;
+}
+
+static bool startsWithLocalScopePattern(StringView S) {
+  if (!S.consumeFront('?'))
+    return false;
+  if (S.size() < 2)
+    return false;
+
+  size_t End = S.find('?');
+  if (End == StringView::npos)
+    return false;
+  StringView Candidate = S.substr(0, End);
+  if (Candidate.empty())
+    return false;
+
+  // \?[0-9]\?
+  // ?@? is the discriminator 0.
+  if (Candidate.size() == 1)
+    return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9');
+
+  // If it's not 0-9, then it's an encoded number terminated with an @
+  if (Candidate.back() != '@')
+    return false;
+  Candidate = Candidate.dropBack();
+
+  // An encoded number starts with B-P and all subsequent digits are in A-P.
+  // Note that the reason the first digit cannot be A is two fold.  First, it
+  // would create an ambiguity with ?A which delimits the beginning of an
+  // anonymous namespace.  Second, A represents 0, and you don't start a multi
+  // digit number with a leading 0.  Presumably the anonymous namespace
+  // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J.
+  if (Candidate[0] < 'B' || Candidate[0] > 'P')
+    return false;
+  Candidate = Candidate.dropFront();
+  while (!Candidate.empty()) {
+    if (Candidate[0] < 'A' || Candidate[0] > 'P')
+      return false;
+    Candidate = Candidate.dropFront();
+  }
+
+  return true;
+}
+
+static bool isTagType(StringView S) {
+  switch (S.front()) {
+  case 'T': // union
+  case 'U': // struct
+  case 'V': // class
+  case 'W': // enum
+    return true;
+  }
+  return false;
+}
+
+static bool isCustomType(StringView S) { return S[0] == '?'; }
+
+static bool isPointerType(StringView S) {
+  if (S.startsWith("$$Q")) // foo &&
+    return true;
+
+  switch (S.front()) {
+  case 'A': // foo &
+  case 'P': // foo *
+  case 'Q': // foo *const
+  case 'R': // foo *volatile
+  case 'S': // foo *const volatile
+    return true;
+  }
+  return false;
+}
+
+static bool isArrayType(StringView S) { return S[0] == 'Y'; }
+
+static bool isFunctionType(StringView S) {
+  return S.startsWith("$$A8@@") || S.startsWith("$$A6");
+}
+
+static FunctionRefQualifier
+demangleFunctionRefQualifier(StringView &MangledName) {
+  if (MangledName.consumeFront('G'))
+    return FunctionRefQualifier::Reference;
+  else if (MangledName.consumeFront('H'))
+    return FunctionRefQualifier::RValueReference;
+  return FunctionRefQualifier::None;
+}
+
+static std::pair<Qualifiers, PointerAffinity>
+demanglePointerCVQualifiers(StringView &MangledName) {
+  if (MangledName.consumeFront("$$Q"))
+    return std::make_pair(Q_None, PointerAffinity::RValueReference);
+
+  switch (MangledName.popFront()) {
+  case 'A':
+    return std::make_pair(Q_None, PointerAffinity::Reference);
+  case 'P':
+    return std::make_pair(Q_None, PointerAffinity::Pointer);
+  case 'Q':
+    return std::make_pair(Q_Const, PointerAffinity::Pointer);
+  case 'R':
+    return std::make_pair(Q_Volatile, PointerAffinity::Pointer);
+  case 'S':
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile),
+                          PointerAffinity::Pointer);
+  default:
+    assert(false && "Ty is not a pointer type!");
+  }
+  return std::make_pair(Q_None, PointerAffinity::Pointer);
+}
+
+StringView Demangler::copyString(StringView Borrowed) {
+  char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);
+  std::strcpy(Stable, Borrowed.begin());
+
+  return {Stable, Borrowed.size()};
+}
+
+SpecialTableSymbolNode *
+Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
+                                          SpecialIntrinsicKind K) {
+  NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();
+  switch (K) {
+  case SpecialIntrinsicKind::Vftable:
+    NI->Name = "`vftable'";
+    break;
+  case SpecialIntrinsicKind::Vbtable:
+    NI->Name = "`vbtable'";
+    break;
+  case SpecialIntrinsicKind::LocalVftable:
+    NI->Name = "`local vftable'";
+    break;
+  case SpecialIntrinsicKind::RttiCompleteObjLocator:
+    NI->Name = "`RTTI Complete Object Locator'";
+    break;
+  default:
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
+  SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();
+  STSN->Name = QN;
+  bool IsMember = false;
+  char Front = MangledName.popFront();
+  if (Front != '6' && Front != '7') {
+    Error = true;
+    return nullptr;
+  }
+
+  std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
+  if (!MangledName.consumeFront('@'))
+    STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);
+  return STSN;
+}
+
+LocalStaticGuardVariableNode *
+Demangler::demangleLocalStaticGuard(StringView &MangledName) {
+  LocalStaticGuardIdentifierNode *LSGI =
+      Arena.alloc<LocalStaticGuardIdentifierNode>();
+  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);
+  LocalStaticGuardVariableNode *LSGVN =
+      Arena.alloc<LocalStaticGuardVariableNode>();
+  LSGVN->Name = QN;
+
+  if (MangledName.consumeFront("4IA"))
+    LSGVN->IsVisible = false;
+  else if (MangledName.consumeFront("5"))
+    LSGVN->IsVisible = true;
+  else {
+    Error = true;
+    return nullptr;
+  }
+
+  if (!MangledName.empty())
+    LSGI->ScopeIndex = demangleUnsigned(MangledName);
+  return LSGVN;
+}
+
+static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,
+                                                      StringView Name) {
+  NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();
+  Id->Name = Name;
+  return Id;
+}
+
+static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,
+                                                  IdentifierNode *Identifier) {
+  QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();
+  QN->Components = Arena.alloc<NodeArrayNode>();
+  QN->Components->Count = 1;
+  QN->Components->Nodes = Arena.allocArray<Node *>(1);
+  QN->Components->Nodes[0] = Identifier;
+  return QN;
+}
+
+static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,
+                                                  StringView Name) {
+  NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name);
+  return synthesizeQualifiedName(Arena, Id);
+}
+
+static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,
+                                              TypeNode *Type,
+                                              StringView VariableName) {
+  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+  VSN->Type = Type;
+  VSN->Name = synthesizeQualifiedName(Arena, VariableName);
+  return VSN;
+}
+
+VariableSymbolNode *Demangler::demangleUntypedVariable(
+    ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) {
+  NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName);
+  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
+  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+  VSN->Name = QN;
+  if (MangledName.consumeFront("8"))
+    return VSN;
+
+  Error = true;
+  return nullptr;
+}
+
+VariableSymbolNode *
+Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
+                                               StringView &MangledName) {
+  RttiBaseClassDescriptorNode *RBCDN =
+      Arena.alloc<RttiBaseClassDescriptorNode>();
+  RBCDN->NVOffset = demangleUnsigned(MangledName);
+  RBCDN->VBPtrOffset = demangleSigned(MangledName);
+  RBCDN->VBTableOffset = demangleUnsigned(MangledName);
+  RBCDN->Flags = demangleUnsigned(MangledName);
+  if (Error)
+    return nullptr;
+
+  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+  VSN->Name = demangleNameScopeChain(MangledName, RBCDN);
+  MangledName.consumeFront('8');
+  return VSN;
+}
+
+FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,
+                                                    bool IsDestructor) {
+  DynamicStructorIdentifierNode *DSIN =
+      Arena.alloc<DynamicStructorIdentifierNode>();
+  DSIN->IsDestructor = IsDestructor;
+
+  bool IsKnownStaticDataMember = false;
+  if (MangledName.consumeFront('?'))
+    IsKnownStaticDataMember = true;
+
+  QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
+
+  SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
+  FunctionSymbolNode *FSN = nullptr;
+  Symbol->Name = QN;
+
+  if (Symbol->kind() == NodeKind::VariableSymbol) {
+    DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol);
+
+    // Older versions of clang mangled this type of symbol incorrectly.  They
+    // would omit the leading ? and they would only emit a single @ at the end.
+    // The correct mangling is a leading ? and 2 trailing @ signs.  Handle
+    // both cases.
+    int AtCount = IsKnownStaticDataMember ? 2 : 1;
+    for (int I = 0; I < AtCount; ++I) {
+      if (MangledName.consumeFront('@'))
+        continue;
+      Error = true;
+      return nullptr;
+    }
+
+    FSN = demangleFunctionEncoding(MangledName);
+    FSN->Name = synthesizeQualifiedName(Arena, DSIN);
+  } else {
+    if (IsKnownStaticDataMember) {
+      // This was supposed to be a static data member, but we got a function.
+      Error = true;
+      return nullptr;
+    }
+
+    FSN = static_cast<FunctionSymbolNode *>(Symbol);
+    DSIN->Name = Symbol->Name;
+    FSN->Name = synthesizeQualifiedName(Arena, DSIN);
+  }
+
+  return FSN;
+}
+
+SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
+  SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);
+  if (SIK == SpecialIntrinsicKind::None)
+    return nullptr;
+
+  switch (SIK) {
+  case SpecialIntrinsicKind::StringLiteralSymbol:
+    return demangleStringLiteral(MangledName);
+  case SpecialIntrinsicKind::Vftable:
+  case SpecialIntrinsicKind::Vbtable:
+  case SpecialIntrinsicKind::LocalVftable:
+  case SpecialIntrinsicKind::RttiCompleteObjLocator:
+    return demangleSpecialTableSymbolNode(MangledName, SIK);
+  case SpecialIntrinsicKind::VcallThunk:
+    return demangleVcallThunkNode(MangledName);
+  case SpecialIntrinsicKind::LocalStaticGuard:
+    return demangleLocalStaticGuard(MangledName);
+  case SpecialIntrinsicKind::RttiTypeDescriptor: {
+    TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);
+    if (Error)
+      break;
+    if (!MangledName.consumeFront("@8"))
+      break;
+    if (!MangledName.empty())
+      break;
+    return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'");
+  }
+  case SpecialIntrinsicKind::RttiBaseClassArray:
+    return demangleUntypedVariable(Arena, MangledName,
+                                   "`RTTI Base Class Array'");
+  case SpecialIntrinsicKind::RttiClassHierarchyDescriptor:
+    return demangleUntypedVariable(Arena, MangledName,
+                                   "`RTTI Class Hierarchy Descriptor'");
+  case SpecialIntrinsicKind::RttiBaseClassDescriptor:
+    return demangleRttiBaseClassDescriptorNode(Arena, MangledName);
+  case SpecialIntrinsicKind::DynamicInitializer:
+    return demangleInitFiniStub(MangledName, false);
+  case SpecialIntrinsicKind::DynamicAtexitDestructor:
+    return demangleInitFiniStub(MangledName, true);
+  default:
+    break;
+  }
+  Error = true;
+  return nullptr;
+}
+
+IdentifierNode *
+Demangler::demangleFunctionIdentifierCode(StringView &MangledName) {
+  assert(MangledName.startsWith('?'));
+  MangledName = MangledName.dropFront();
+
+  if (MangledName.consumeFront("__"))
+    return demangleFunctionIdentifierCode(
+        MangledName, FunctionIdentifierCodeGroup::DoubleUnder);
+  else if (MangledName.consumeFront("_"))
+    return demangleFunctionIdentifierCode(MangledName,
+                                          FunctionIdentifierCodeGroup::Under);
+  return demangleFunctionIdentifierCode(MangledName,
+                                        FunctionIdentifierCodeGroup::Basic);
+}
+
+StructorIdentifierNode *
+Demangler::demangleStructorIdentifier(StringView &MangledName,
+                                      bool IsDestructor) {
+  StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();
+  N->IsDestructor = IsDestructor;
+  return N;
+}
+
+ConversionOperatorIdentifierNode *
+Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) {
+  ConversionOperatorIdentifierNode *N =
+      Arena.alloc<ConversionOperatorIdentifierNode>();
+  return N;
+}
+
+LiteralOperatorIdentifierNode *
+Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {
+  LiteralOperatorIdentifierNode *N =
+      Arena.alloc<LiteralOperatorIdentifierNode>();
+  N->Name = demangleSimpleString(MangledName, false);
+  return N;
+}
+
+static IntrinsicFunctionKind
+translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {
+  // Not all ? identifiers are intrinsics *functions*.  This function only maps
+  // operator codes for the special functions, all others are handled elsewhere,
+  // hence the IFK::None entries in the table.
+  using IFK = IntrinsicFunctionKind;
+  static IFK Basic[36] = {
+      IFK::None,             // ?0 # Foo::Foo()
+      IFK::None,             // ?1 # Foo::~Foo()
+      IFK::New,              // ?2 # operator new
+      IFK::Delete,           // ?3 # operator delete
+      IFK::Assign,           // ?4 # operator=
+      IFK::RightShift,       // ?5 # operator>>
+      IFK::LeftShift,        // ?6 # operator<<
+      IFK::LogicalNot,       // ?7 # operator!
+      IFK::Equals,           // ?8 # operator==
+      IFK::NotEquals,        // ?9 # operator!=
+      IFK::ArraySubscript,   // ?A # operator[]
+      IFK::None,             // ?B # Foo::operator <type>()
+      IFK::Pointer,          // ?C # operator->
+      IFK::Dereference,      // ?D # operator*
+      IFK::Increment,        // ?E # operator++
+      IFK::Decrement,        // ?F # operator--
+      IFK::Minus,            // ?G # operator-
+      IFK::Plus,             // ?H # operator+
+      IFK::BitwiseAnd,       // ?I # operator&
+      IFK::MemberPointer,    // ?J # operator->*
+      IFK::Divide,           // ?K # operator/
+      IFK::Modulus,          // ?L # operator%
+      IFK::LessThan,         // ?M operator<
+      IFK::LessThanEqual,    // ?N operator<=
+      IFK::GreaterThan,      // ?O operator>
+      IFK::GreaterThanEqual, // ?P operator>=
+      IFK::Comma,            // ?Q operator,
+      IFK::Parens,           // ?R operator()
+      IFK::BitwiseNot,       // ?S operator~
+      IFK::BitwiseXor,       // ?T operator^
+      IFK::BitwiseOr,        // ?U operator|
+      IFK::LogicalAnd,       // ?V operator&&
+      IFK::LogicalOr,        // ?W operator||
+      IFK::TimesEqual,       // ?X operator*=
+      IFK::PlusEqual,        // ?Y operator+=
+      IFK::MinusEqual,       // ?Z operator-=
+  };
+  static IFK Under[36] = {
+      IFK::DivEqual,           // ?_0 operator/=
+      IFK::ModEqual,           // ?_1 operator%=
+      IFK::RshEqual,           // ?_2 operator>>=
+      IFK::LshEqual,           // ?_3 operator<<=
+      IFK::BitwiseAndEqual,    // ?_4 operator&=
+      IFK::BitwiseOrEqual,     // ?_5 operator|=
+      IFK::BitwiseXorEqual,    // ?_6 operator^=
+      IFK::None,               // ?_7 # vftable
+      IFK::None,               // ?_8 # vbtable
+      IFK::None,               // ?_9 # vcall
+      IFK::None,               // ?_A # typeof
+      IFK::None,               // ?_B # local static guard
+      IFK::None,               // ?_C # string literal
+      IFK::VbaseDtor,          // ?_D # vbase destructor
+      IFK::VecDelDtor,         // ?_E # vector deleting destructor
+      IFK::DefaultCtorClosure, // ?_F # default constructor closure
+      IFK::ScalarDelDtor,      // ?_G # scalar deleting destructor
+      IFK::VecCtorIter,        // ?_H # vector constructor iterator
+      IFK::VecDtorIter,        // ?_I # vector destructor iterator
+      IFK::VecVbaseCtorIter,   // ?_J # vector vbase constructor iterator
+      IFK::VdispMap,           // ?_K # virtual displacement map
+      IFK::EHVecCtorIter,      // ?_L # eh vector constructor iterator
+      IFK::EHVecDtorIter,      // ?_M # eh vector destructor iterator
+      IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator
+      IFK::CopyCtorClosure,    // ?_O # copy constructor closure
+      IFK::None,               // ?_P<name> # udt returning <name>
+      IFK::None,               // ?_Q # <unknown>
+      IFK::None,               // ?_R0 - ?_R4 # RTTI Codes
+      IFK::None,               // ?_S # local vftable
+      IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure
+      IFK::ArrayNew,                // ?_U operator new[]
+      IFK::ArrayDelete,             // ?_V operator delete[]
+      IFK::None,                    // ?_W <unused>
+      IFK::None,                    // ?_X <unused>
+      IFK::None,                    // ?_Y <unused>
+      IFK::None,                    // ?_Z <unused>
+  };
+  static IFK DoubleUnder[36] = {
+      IFK::None,                       // ?__0 <unused>
+      IFK::None,                       // ?__1 <unused>
+      IFK::None,                       // ?__2 <unused>
+      IFK::None,                       // ?__3 <unused>
+      IFK::None,                       // ?__4 <unused>
+      IFK::None,                       // ?__5 <unused>
+      IFK::None,                       // ?__6 <unused>
+      IFK::None,                       // ?__7 <unused>
+      IFK::None,                       // ?__8 <unused>
+      IFK::None,                       // ?__9 <unused>
+      IFK::ManVectorCtorIter,          // ?__A managed vector ctor iterator
+      IFK::ManVectorDtorIter,          // ?__B managed vector dtor iterator
+      IFK::EHVectorCopyCtorIter,       // ?__C EH vector copy ctor iterator
+      IFK::EHVectorVbaseCopyCtorIter,  // ?__D EH vector vbase copy ctor iter
+      IFK::None,                       // ?__E dynamic initializer for `T'
+      IFK::None,                       // ?__F dynamic atexit destructor for `T'
+      IFK::VectorCopyCtorIter,         // ?__G vector copy constructor iter
+      IFK::VectorVbaseCopyCtorIter,    // ?__H vector vbase copy ctor iter
+      IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor
+                                       // iter
+      IFK::None,                       // ?__J local static thread guard
+      IFK::None,                       // ?__K operator ""_name
+      IFK::CoAwait,                    // ?__L co_await
+      IFK::None,                       // ?__M <unused>
+      IFK::None,                       // ?__N <unused>
+      IFK::None,                       // ?__O <unused>
+      IFK::None,                       // ?__P <unused>
+      IFK::None,                       // ?__Q <unused>
+      IFK::None,                       // ?__R <unused>
+      IFK::None,                       // ?__S <unused>
+      IFK::None,                       // ?__T <unused>
+      IFK::None,                       // ?__U <unused>
+      IFK::None,                       // ?__V <unused>
+      IFK::None,                       // ?__W <unused>
+      IFK::None,                       // ?__X <unused>
+      IFK::None,                       // ?__Y <unused>
+      IFK::None,                       // ?__Z <unused>
+  };
+
+  int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10);
+  switch (Group) {
+  case FunctionIdentifierCodeGroup::Basic:
+    return Basic[Index];
+  case FunctionIdentifierCodeGroup::Under:
+    return Under[Index];
+  case FunctionIdentifierCodeGroup::DoubleUnder:
+    return DoubleUnder[Index];
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+IdentifierNode *
+Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
+                                          FunctionIdentifierCodeGroup Group) {
+  switch (Group) {
+  case FunctionIdentifierCodeGroup::Basic:
+    switch (char CH = MangledName.popFront()) {
+    case '0':
+    case '1':
+      return demangleStructorIdentifier(MangledName, CH == '1');
+    case 'B':
+      return demangleConversionOperatorIdentifier(MangledName);
+    default:
+      return Arena.alloc<IntrinsicFunctionIdentifierNode>(
+          translateIntrinsicFunctionCode(CH, Group));
+    }
+    break;
+  case FunctionIdentifierCodeGroup::Under:
+    return Arena.alloc<IntrinsicFunctionIdentifierNode>(
+        translateIntrinsicFunctionCode(MangledName.popFront(), Group));
+  case FunctionIdentifierCodeGroup::DoubleUnder:
+    switch (char CH = MangledName.popFront()) {
+    case 'K':
+      return demangleLiteralOperatorIdentifier(MangledName);
+    default:
+      return Arena.alloc<IntrinsicFunctionIdentifierNode>(
+          translateIntrinsicFunctionCode(CH, Group));
+    }
+  }
+  // No Mangling Yet:      Spaceship,                    // operator<=>
+
+  return nullptr;
+}
+
+SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
+                                             QualifiedNameNode *Name) {
+  // Read a variable.
+  switch (MangledName.front()) {
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4': {
+    StorageClass SC = demangleVariableStorageClass(MangledName);
+    return demangleVariableEncoding(MangledName, SC);
+  }
+  case '8':
+    return nullptr;
+  }
+  FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);
+
+  IdentifierNode *UQN = Name->getUnqualifiedIdentifier();
+  if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
+    ConversionOperatorIdentifierNode *COIN =
+        static_cast<ConversionOperatorIdentifierNode *>(UQN);
+    COIN->TargetType = FSN->Signature->ReturnType;
+  }
+  return FSN;
+}
+
+// Parser entry point.
+SymbolNode *Demangler::parse(StringView &MangledName) {
+  // We can't demangle MD5 names, just output them as-is.
+  // Also, MSVC-style mangled symbols must start with '?'.
+  if (MangledName.startsWith("??@")) {
+    // This is an MD5 mangled name.  We can't demangle it, just return the
+    // mangled name.
+    SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);
+    S->Name = synthesizeQualifiedName(Arena, MangledName);
+    return S;
+  }
+
+  if (!MangledName.startsWith('?')) {
+    Error = true;
+    return nullptr;
+  }
+
+  MangledName.consumeFront('?');
+
+  // ?$ is a template instantiation, but all other names that start with ? are
+  // operators / special names.
+  if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName))
+    return SI;
+
+  // What follows is a main symbol name. This may include namespaces or class
+  // back references.
+  QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
+  if (Error)
+    return nullptr;
+
+  SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
+  if (Symbol) {
+    Symbol->Name = QN;
+  }
+
+  if (Error)
+    return nullptr;
+
+  return Symbol;
+}
+
+TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
+  if (!MangledName.consumeFront(".?A"))
+    return nullptr;
+  MangledName.consumeFront(".?A");
+  if (MangledName.empty())
+    return nullptr;
+
+  return demangleClassType(MangledName);
+}
+
+// <type-encoding> ::= <storage-class> <variable-type>
+// <storage-class> ::= 0  # private static member
+//                 ::= 1  # protected static member
+//                 ::= 2  # public static member
+//                 ::= 3  # global
+//                 ::= 4  # static local
+
+VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
+                                                        StorageClass SC) {
+  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+
+  VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
+  VSN->SC = SC;
+
+  // <variable-type> ::= <type> <cvr-qualifiers>
+  //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references
+  switch (VSN->Type->kind()) {
+  case NodeKind::PointerType: {
+    PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type);
+
+    Qualifiers ExtraChildQuals = Q_None;
+    PTN->Quals = Qualifiers(VSN->Type->Quals |
+                            demanglePointerExtQualifiers(MangledName));
+
+    bool IsMember = false;
+    std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);
+
+    if (PTN->ClassParent) {
+      QualifiedNameNode *BackRefName =
+          demangleFullyQualifiedTypeName(MangledName);
+      (void)BackRefName;
+    }
+    PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals);
+
+    break;
+  }
+  default:
+    VSN->Type->Quals = demangleQualifiers(MangledName).first;
+    break;
+  }
+
+  return VSN;
+}
+
+// Sometimes numbers are encoded in mangled symbols. For example,
+// "int (*x)[20]" is a valid C type (x is a pointer to an array of
+// length 20), so we need some way to embed numbers as part of symbols.
+// This function parses it.
+//
+// <number>               ::= [?] <non-negative integer>
+//
+// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10
+//                        ::= <hex digit>+ @  # when Numbrer == 0 or >= 10
+//
+// <hex-digit>            ::= [A-P]           # A = 0, B = 1, ...
+std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
+  bool IsNegative = MangledName.consumeFront('?');
+
+  if (startsWithDigit(MangledName)) {
+    uint64_t Ret = MangledName[0] - '0' + 1;
+    MangledName = MangledName.dropFront(1);
+    return {Ret, IsNegative};
+  }
+
+  uint64_t Ret = 0;
+  for (size_t i = 0; i < MangledName.size(); ++i) {
+    char C = MangledName[i];
+    if (C == '@') {
+      MangledName = MangledName.dropFront(i + 1);
+      return {Ret, IsNegative};
+    }
+    if ('A' <= C && C <= 'P') {
+      Ret = (Ret << 4) + (C - 'A');
+      continue;
+    }
+    break;
+  }
+
+  Error = true;
+  return {0ULL, false};
+}
+
+uint64_t Demangler::demangleUnsigned(StringView &MangledName) {
+  bool IsNegative = false;
+  uint64_t Number = 0;
+  std::tie(Number, IsNegative) = demangleNumber(MangledName);
+  if (IsNegative)
+    Error = true;
+  return Number;
+}
+
+int64_t Demangler::demangleSigned(StringView &MangledName) {
+  bool IsNegative = false;
+  uint64_t Number = 0;
+  std::tie(Number, IsNegative) = demangleNumber(MangledName);
+  if (Number > INT64_MAX)
+    Error = true;
+  int64_t I = static_cast<int64_t>(Number);
+  return IsNegative ? -I : I;
+}
+
+// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
+// Memorize it.
+void Demangler::memorizeString(StringView S) {
+  if (Backrefs.NamesCount >= BackrefContext::Max)
+    return;
+  for (size_t i = 0; i < Backrefs.NamesCount; ++i)
+    if (S == Backrefs.Names[i]->Name)
+      return;
+  NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>();
+  N->Name = S;
+  Backrefs.Names[Backrefs.NamesCount++] = N;
+}
+
+NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {
+  assert(startsWithDigit(MangledName));
+
+  size_t I = MangledName[0] - '0';
+  if (I >= Backrefs.NamesCount) {
+    Error = true;
+    return nullptr;
+  }
+
+  MangledName = MangledName.dropFront();
+  return Backrefs.Names[I];
+}
+
+void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
+  // Render this class template name into a string buffer so that we can
+  // memorize it for the purpose of back-referencing.
+  OutputStream OS;
+  if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+    // FIXME: Propagate out-of-memory as an error?
+    std::terminate();
+  Identifier->output(OS, OF_Default);
+  OS << '\0';
+  char *Name = OS.getBuffer();
+
+  StringView Owned = copyString(Name);
+  memorizeString(Owned);
+  std::free(Name);
+}
+
+IdentifierNode *
+Demangler::demangleTemplateInstantiationName(StringView &MangledName,
+                                             NameBackrefBehavior NBB) {
+  assert(MangledName.startsWith("?$"));
+  MangledName.consumeFront("?$");
+
+  BackrefContext OuterContext;
+  std::swap(OuterContext, Backrefs);
+
+  IdentifierNode *Identifier =
+      demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
+  if (!Error)
+    Identifier->TemplateParams = demangleTemplateParameterList(MangledName);
+
+  std::swap(OuterContext, Backrefs);
+  if (Error)
+    return nullptr;
+
+  if (NBB & NBB_Template)
+    memorizeIdentifier(Identifier);
+
+  return Identifier;
+}
+
+NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName,
+                                                   bool Memorize) {
+  StringView S = demangleSimpleString(MangledName, Memorize);
+  if (Error)
+    return nullptr;
+
+  NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>();
+  Name->Name = S;
+  return Name;
+}
+
+static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); }
+
+static uint8_t rebasedHexDigitToNumber(char C) {
+  assert(isRebasedHexDigit(C));
+  return (C <= 'J') ? (C - 'A') : (10 + C - 'K');
+}
+
+uint8_t Demangler::demangleCharLiteral(StringView &MangledName) {
+  if (!MangledName.startsWith('?'))
+    return MangledName.popFront();
+
+  MangledName = MangledName.dropFront();
+  if (MangledName.empty())
+    goto CharLiteralError;
+
+  if (MangledName.consumeFront('$')) {
+    // Two hex digits
+    if (MangledName.size() < 2)
+      goto CharLiteralError;
+    StringView Nibbles = MangledName.substr(0, 2);
+    if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1]))
+      goto CharLiteralError;
+    // Don't append the null terminator.
+    uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]);
+    uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]);
+    MangledName = MangledName.dropFront(2);
+    return (C1 << 4) | C2;
+  }
+
+  if (startsWithDigit(MangledName)) {
+    const char *Lookup = ",/\\:. \n\t'-";
+    char C = Lookup[MangledName[0] - '0'];
+    MangledName = MangledName.dropFront();
+    return C;
+  }
+
+  if (MangledName[0] >= 'a' && MangledName[0] <= 'z') {
+    char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7',
+                       '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE',
+                       '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5',
+                       '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'};
+    char C = Lookup[MangledName[0] - 'a'];
+    MangledName = MangledName.dropFront();
+    return C;
+  }
+
+  if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') {
+    char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7',
+                       '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE',
+                       '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5',
+                       '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'};
+    char C = Lookup[MangledName[0] - 'A'];
+    MangledName = MangledName.dropFront();
+    return C;
+  }
+
+CharLiteralError:
+  Error = true;
+  return '\0';
+}
+
+wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) {
+  uint8_t C1, C2;
+
+  C1 = demangleCharLiteral(MangledName);
+  if (Error)
+    goto WCharLiteralError;
+  C2 = demangleCharLiteral(MangledName);
+  if (Error)
+    goto WCharLiteralError;
+
+  return ((wchar_t)C1 << 8) | (wchar_t)C2;
+
+WCharLiteralError:
+  Error = true;
+  return L'\0';
+}
+
+static void writeHexDigit(char *Buffer, uint8_t Digit) {
+  assert(Digit <= 15);
+  *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);
+}
+
+static void outputHex(OutputStream &OS, unsigned C) {
+  if (C == 0) {
+    OS << "\\x00";
+    return;
+  }
+  // It's easier to do the math if we can work from right to left, but we need
+  // to print the numbers from left to right.  So render this into a temporary
+  // buffer first, then output the temporary buffer.  Each byte is of the form
+  // \xAB, which means that each byte needs 4 characters.  Since there are at
+  // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer.
+  char TempBuffer[17];
+
+  ::memset(TempBuffer, 0, sizeof(TempBuffer));
+  constexpr int MaxPos = 15;
+
+  int Pos = MaxPos - 1;
+  while (C != 0) {
+    for (int I = 0; I < 2; ++I) {
+      writeHexDigit(&TempBuffer[Pos--], C % 16);
+      C /= 16;
+    }
+    TempBuffer[Pos--] = 'x';
+    TempBuffer[Pos--] = '\\';
+    assert(Pos >= 0);
+  }
+  OS << StringView(&TempBuffer[Pos + 1]);
+}
+
+static void outputEscapedChar(OutputStream &OS, unsigned C) {
+  switch (C) {
+  case '\'': // single quote
+    OS << "\\\'";
+    return;
+  case '\"': // double quote
+    OS << "\\\"";
+    return;
+  case '\\': // backslash
+    OS << "\\\\";
+    return;
+  case '\a': // bell
+    OS << "\\a";
+    return;
+  case '\b': // backspace
+    OS << "\\b";
+    return;
+  case '\f': // form feed
+    OS << "\\f";
+    return;
+  case '\n': // new line
+    OS << "\\n";
+    return;
+  case '\r': // carriage return
+    OS << "\\r";
+    return;
+  case '\t': // tab
+    OS << "\\t";
+    return;
+  case '\v': // vertical tab
+    OS << "\\v";
+    return;
+  default:
+    break;
+  }
+
+  if (C > 0x1F && C < 0x7F) {
+    // Standard ascii char.
+    OS << (char)C;
+    return;
+  }
+
+  outputHex(OS, C);
+}
+
+static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
+  const uint8_t *End = StringBytes + Length - 1;
+  unsigned Count = 0;
+  while (Length > 0 && *End == 0) {
+    --Length;
+    --End;
+    ++Count;
+  }
+  return Count;
+}
+
+static unsigned countEmbeddedNulls(const uint8_t *StringBytes,
+                                   unsigned Length) {
+  unsigned Result = 0;
+  for (unsigned I = 0; I < Length; ++I) {
+    if (*StringBytes++ == 0)
+      ++Result;
+  }
+  return Result;
+}
+
+static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
+                                  unsigned NumBytes) {
+  assert(NumBytes > 0);
+
+  // If the number of bytes is odd, this is guaranteed to be a char string.
+  if (NumBytes % 2 == 1)
+    return 1;
+
+  // All strings can encode at most 32 bytes of data.  If it's less than that,
+  // then we encoded the entire string.  In this case we check for a 1-byte,
+  // 2-byte, or 4-byte null terminator.
+  if (NumBytes < 32) {
+    unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars);
+    if (TrailingNulls >= 4)
+      return 4;
+    if (TrailingNulls >= 2)
+      return 2;
+    return 1;
+  }
+
+  // The whole string was not able to be encoded.  Try to look at embedded null
+  // terminators to guess.  The heuristic is that we count all embedded null
+  // terminators.  If more than 2/3 are null, it's a char32.  If more than 1/3
+  // are null, it's a char16.  Otherwise it's a char8.  This obviously isn't
+  // perfect and is biased towards languages that have ascii alphabets, but this
+  // was always going to be best effort since the encoding is lossy.
+  unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars);
+  if (Nulls >= 2 * NumChars / 3)
+    return 4;
+  if (Nulls >= NumChars / 3)
+    return 2;
+  return 1;
+}
+
+static unsigned decodeMultiByteChar(const uint8_t *StringBytes,
+                                    unsigned CharIndex, unsigned CharBytes) {
+  assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4);
+  unsigned Offset = CharIndex * CharBytes;
+  unsigned Result = 0;
+  StringBytes = StringBytes + Offset;
+  for (unsigned I = 0; I < CharBytes; ++I) {
+    unsigned C = static_cast<unsigned>(StringBytes[I]);
+    Result |= C << (8 * I);
+  }
+  return Result;
+}
+
+FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {
+  FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>();
+  VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>();
+  FSN->Signature = Arena.alloc<ThunkSignatureNode>();
+  FSN->Signature->FunctionClass = FC_NoParameterList;
+
+  FSN->Name = demangleNameScopeChain(MangledName, VTIN);
+  if (!Error)
+    Error = !MangledName.consumeFront("$B");
+  if (!Error)
+    VTIN->OffsetInVTable = demangleUnsigned(MangledName);
+  if (!Error)
+    Error = !MangledName.consumeFront('A');
+  if (!Error)
+    FSN->Signature->CallConvention = demangleCallingConvention(MangledName);
+  return (Error) ? nullptr : FSN;
+}
+
+EncodedStringLiteralNode *
+Demangler::demangleStringLiteral(StringView &MangledName) {
+  // This function uses goto, so declare all variables up front.
+  OutputStream OS;
+  StringView CRC;
+  uint64_t StringByteSize;
+  bool IsWcharT = false;
+  bool IsNegative = false;
+  size_t CrcEndPos = 0;
+  char *ResultBuffer = nullptr;
+
+  EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
+
+  // Prefix indicating the beginning of a string literal
+  if (!MangledName.consumeFront("@_"))
+    goto StringLiteralError;
+  if (MangledName.empty())
+    goto StringLiteralError;
+
+  // Char Type (regular or wchar_t)
+  switch (MangledName.popFront()) {
+  case '1':
+    IsWcharT = true;
+    LLVM_FALLTHROUGH;
+  case '0':
+    break;
+  default:
+    goto StringLiteralError;
+  }
+
+  // Encoded Length
+  std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);
+  if (Error || IsNegative)
+    goto StringLiteralError;
+
+  // CRC 32 (always 8 characters plus a terminator)
+  CrcEndPos = MangledName.find('@');
+  if (CrcEndPos == StringView::npos)
+    goto StringLiteralError;
+  CRC = MangledName.substr(0, CrcEndPos);
+  MangledName = MangledName.dropFront(CrcEndPos + 1);
+  if (MangledName.empty())
+    goto StringLiteralError;
+
+  if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+    // FIXME: Propagate out-of-memory as an error?
+    std::terminate();
+  if (IsWcharT) {
+    Result->Char = CharKind::Wchar;
+    if (StringByteSize > 64)
+      Result->IsTruncated = true;
+
+    while (!MangledName.consumeFront('@')) {
+      assert(StringByteSize >= 2);
+      wchar_t W = demangleWcharLiteral(MangledName);
+      if (StringByteSize != 2 || Result->IsTruncated)
+        outputEscapedChar(OS, W);
+      StringByteSize -= 2;
+      if (Error)
+        goto StringLiteralError;
+    }
+  } else {
+    // The max byte length is actually 32, but some compilers mangled strings
+    // incorrectly, so we have to assume it can go higher.
+    constexpr unsigned MaxStringByteLength = 32 * 4;
+    uint8_t StringBytes[MaxStringByteLength];
+
+    unsigned BytesDecoded = 0;
+    while (!MangledName.consumeFront('@')) {
+      assert(StringByteSize >= 1);
+      StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName);
+    }
+
+    if (StringByteSize > BytesDecoded)
+      Result->IsTruncated = true;
+
+    unsigned CharBytes =
+        guessCharByteSize(StringBytes, BytesDecoded, StringByteSize);
+    assert(StringByteSize % CharBytes == 0);
+    switch (CharBytes) {
+    case 1:
+      Result->Char = CharKind::Char;
+      break;
+    case 2:
+      Result->Char = CharKind::Char16;
+      break;
+    case 4:
+      Result->Char = CharKind::Char32;
+      break;
+    default:
+      LLVM_BUILTIN_UNREACHABLE;
+    }
+    const unsigned NumChars = BytesDecoded / CharBytes;
+    for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {
+      unsigned NextChar =
+          decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
+      if (CharIndex + 1 < NumChars || Result->IsTruncated)
+        outputEscapedChar(OS, NextChar);
+    }
+  }
+
+  OS << '\0';
+  ResultBuffer = OS.getBuffer();
+  Result->DecodedString = copyString(ResultBuffer);
+  std::free(ResultBuffer);
+  return Result;
+
+StringLiteralError:
+  Error = true;
+  return nullptr;
+}
+
+StringView Demangler::demangleSimpleString(StringView &MangledName,
+                                           bool Memorize) {
+  StringView S;
+  for (size_t i = 0; i < MangledName.size(); ++i) {
+    if (MangledName[i] != '@')
+      continue;
+    S = MangledName.substr(0, i);
+    MangledName = MangledName.dropFront(i + 1);
+
+    if (Memorize)
+      memorizeString(S);
+    return S;
+  }
+
+  Error = true;
+  return {};
+}
+
+NamedIdentifierNode *
+Demangler::demangleAnonymousNamespaceName(StringView &MangledName) {
+  assert(MangledName.startsWith("?A"));
+  MangledName.consumeFront("?A");
+
+  NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>();
+  Node->Name = "`anonymous namespace'";
+  size_t EndPos = MangledName.find('@');
+  if (EndPos == StringView::npos) {
+    Error = true;
+    return nullptr;
+  }
+  StringView NamespaceKey = MangledName.substr(0, EndPos);
+  memorizeString(NamespaceKey);
+  MangledName = MangledName.substr(EndPos + 1);
+  return Node;
+}
+
+NamedIdentifierNode *
+Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
+  assert(startsWithLocalScopePattern(MangledName));
+
+  NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>();
+  MangledName.consumeFront('?');
+  auto Number = demangleNumber(MangledName);
+  assert(!Number.second);
+
+  // One ? to terminate the number
+  MangledName.consumeFront('?');
+
+  assert(!Error);
+  Node *Scope = parse(MangledName);
+  if (Error)
+    return nullptr;
+
+  // Render the parent symbol's name into a buffer.
+  OutputStream OS;
+  if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+    // FIXME: Propagate out-of-memory as an error?
+    std::terminate();
+  OS << '`';
+  Scope->output(OS, OF_Default);
+  OS << '\'';
+  OS << "::`" << Number.first << "'";
+  OS << '\0';
+  char *Result = OS.getBuffer();
+  Identifier->Name = copyString(Result);
+  std::free(Result);
+  return Identifier;
+}
+
+// Parses a type name in the form of A@B@C@@ which represents C::B::A.
+QualifiedNameNode *
+Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
+  IdentifierNode *Identifier = demangleUnqualifiedTypeName(MangledName, true);
+  if (Error)
+    return nullptr;
+  assert(Identifier);
+
+  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);
+  if (Error)
+    return nullptr;
+  assert(QN);
+  return QN;
+}
+
+// Parses a symbol name in the form of A@B@C@@ which represents C::B::A.
+// Symbol names have slightly different rules regarding what can appear
+// so we separate out the implementations for flexibility.
+QualifiedNameNode *
+Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
+  // This is the final component of a symbol name (i.e. the leftmost component
+  // of a mangled name.  Since the only possible template instantiation that
+  // can appear in this context is a function template, and since those are
+  // not saved for the purposes of name backreferences, only backref simple
+  // names.
+  IdentifierNode *Identifier =
+      demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
+  if (Error)
+    return nullptr;
+
+  QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);
+  if (Error)
+    return nullptr;
+
+  if (Identifier->kind() == NodeKind::StructorIdentifier) {
+    StructorIdentifierNode *SIN =
+        static_cast<StructorIdentifierNode *>(Identifier);
+    assert(QN->Components->Count >= 2);
+    Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2];
+    SIN->Class = static_cast<IdentifierNode *>(ClassNode);
+  }
+  assert(QN);
+  return QN;
+}
+
+IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName,
+                                                       bool Memorize) {
+  // An inner-most name can be a back-reference, because a fully-qualified name
+  // (e.g. Scope + Inner) can contain other fully qualified names inside of
+  // them (for example template parameters), and these nested parameters can
+  // refer to previously mangled types.
+  if (startsWithDigit(MangledName))
+    return demangleBackRefName(MangledName);
+
+  if (MangledName.startsWith("?$"))
+    return demangleTemplateInstantiationName(MangledName, NBB_Template);
+
+  return demangleSimpleName(MangledName, Memorize);
+}
+
+IdentifierNode *
+Demangler::demangleUnqualifiedSymbolName(StringView &MangledName,
+                                         NameBackrefBehavior NBB) {
+  if (startsWithDigit(MangledName))
+    return demangleBackRefName(MangledName);
+  if (MangledName.startsWith("?$"))
+    return demangleTemplateInstantiationName(MangledName, NBB);
+  if (MangledName.startsWith('?'))
+    return demangleFunctionIdentifierCode(MangledName);
+  return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0);
+}
+
+IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) {
+  if (startsWithDigit(MangledName))
+    return demangleBackRefName(MangledName);
+
+  if (MangledName.startsWith("?$"))
+    return demangleTemplateInstantiationName(MangledName, NBB_Template);
+
+  if (MangledName.startsWith("?A"))
+    return demangleAnonymousNamespaceName(MangledName);
+
+  if (startsWithLocalScopePattern(MangledName))
+    return demangleLocallyScopedNamePiece(MangledName);
+
+  return demangleSimpleName(MangledName, true);
+}
+
+static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
+                                          size_t Count) {
+  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
+  N->Count = Count;
+  N->Nodes = Arena.allocArray<Node *>(Count);
+  for (size_t I = 0; I < Count; ++I) {
+    N->Nodes[I] = Head->N;
+    Head = Head->Next;
+  }
+  return N;
+}
+
+QualifiedNameNode *
+Demangler::demangleNameScopeChain(StringView &MangledName,
+                                  IdentifierNode *UnqualifiedName) {
+  NodeList *Head = Arena.alloc<NodeList>();
+
+  Head->N = UnqualifiedName;
+
+  size_t Count = 1;
+  while (!MangledName.consumeFront("@")) {
+    ++Count;
+    NodeList *NewHead = Arena.alloc<NodeList>();
+    NewHead->Next = Head;
+    Head = NewHead;
+
+    if (MangledName.empty()) {
+      Error = true;
+      return nullptr;
+    }
+
+    assert(!Error);
+    IdentifierNode *Elem = demangleNameScopePiece(MangledName);
+    if (Error)
+      return nullptr;
+
+    Head->N = Elem;
+  }
+
+  QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();
+  QN->Components = nodeListToNodeArray(Arena, Head, Count);
+  return QN;
+}
+
+FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
+  switch (MangledName.popFront()) {
+  case '9':
+    return FuncClass(FC_ExternC | FC_NoParameterList);
+  case 'A':
+    return FC_Private;
+  case 'B':
+    return FuncClass(FC_Private | FC_Far);
+  case 'C':
+    return FuncClass(FC_Private | FC_Static);
+  case 'D':
+    return FuncClass(FC_Private | FC_Static);
+  case 'E':
+    return FuncClass(FC_Private | FC_Virtual);
+  case 'F':
+    return FuncClass(FC_Private | FC_Virtual);
+  case 'G':
+    return FuncClass(FC_Private | FC_StaticThisAdjust);
+  case 'H':
+    return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far);
+  case 'I':
+    return FuncClass(FC_Protected);
+  case 'J':
+    return FuncClass(FC_Protected | FC_Far);
+  case 'K':
+    return FuncClass(FC_Protected | FC_Static);
+  case 'L':
+    return FuncClass(FC_Protected | FC_Static | FC_Far);
+  case 'M':
+    return FuncClass(FC_Protected | FC_Virtual);
+  case 'N':
+    return FuncClass(FC_Protected | FC_Virtual | FC_Far);
+  case 'O':
+    return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust);
+  case 'P':
+    return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far);
+  case 'Q':
+    return FuncClass(FC_Public);
+  case 'R':
+    return FuncClass(FC_Public | FC_Far);
+  case 'S':
+    return FuncClass(FC_Public | FC_Static);
+  case 'T':
+    return FuncClass(FC_Public | FC_Static | FC_Far);
+  case 'U':
+    return FuncClass(FC_Public | FC_Virtual);
+  case 'V':
+    return FuncClass(FC_Public | FC_Virtual | FC_Far);
+  case 'W':
+    return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust);
+  case 'X':
+    return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far);
+  case 'Y':
+    return FuncClass(FC_Global);
+  case 'Z':
+    return FuncClass(FC_Global | FC_Far);
+  case '$': {
+    FuncClass VFlag = FC_VirtualThisAdjust;
+    if (MangledName.consumeFront('R'))
+      VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx);
+
+    switch (MangledName.popFront()) {
+    case '0':
+      return FuncClass(FC_Private | FC_Virtual | VFlag);
+    case '1':
+      return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far);
+    case '2':
+      return FuncClass(FC_Protected | FC_Virtual | VFlag);
+    case '3':
+      return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far);
+    case '4':
+      return FuncClass(FC_Public | FC_Virtual | VFlag);
+    case '5':
+      return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far);
+    }
+  }
+  }
+
+  Error = true;
+  return FC_Public;
+}
+
+CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
+  switch (MangledName.popFront()) {
+  case 'A':
+  case 'B':
+    return CallingConv::Cdecl;
+  case 'C':
+  case 'D':
+    return CallingConv::Pascal;
+  case 'E':
+  case 'F':
+    return CallingConv::Thiscall;
+  case 'G':
+  case 'H':
+    return CallingConv::Stdcall;
+  case 'I':
+  case 'J':
+    return CallingConv::Fastcall;
+  case 'M':
+  case 'N':
+    return CallingConv::Clrcall;
+  case 'O':
+  case 'P':
+    return CallingConv::Eabi;
+  case 'Q':
+    return CallingConv::Vectorcall;
+  }
+
+  return CallingConv::None;
+}
+
+StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
+  assert(std::isdigit(MangledName.front()));
+
+  switch (MangledName.popFront()) {
+  case '0':
+    return StorageClass::PrivateStatic;
+  case '1':
+    return StorageClass::ProtectedStatic;
+  case '2':
+    return StorageClass::PublicStatic;
+  case '3':
+    return StorageClass::Global;
+  case '4':
+    return StorageClass::FunctionLocalStatic;
+  }
+  Error = true;
+  return StorageClass::None;
+}
+
+std::pair<Qualifiers, bool>
+Demangler::demangleQualifiers(StringView &MangledName) {
+
+  switch (MangledName.popFront()) {
+  // Member qualifiers
+  case 'Q':
+    return std::make_pair(Q_None, true);
+  case 'R':
+    return std::make_pair(Q_Const, true);
+  case 'S':
+    return std::make_pair(Q_Volatile, true);
+  case 'T':
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);
+  // Non-Member qualifiers
+  case 'A':
+    return std::make_pair(Q_None, false);
+  case 'B':
+    return std::make_pair(Q_Const, false);
+  case 'C':
+    return std::make_pair(Q_Volatile, false);
+  case 'D':
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);
+  }
+  Error = true;
+  return std::make_pair(Q_None, false);
+}
+
+// <variable-type> ::= <type> <cvr-qualifiers>
+//                 ::= <type> <pointee-cvr-qualifiers> # pointers, references
+TypeNode *Demangler::demangleType(StringView &MangledName,
+                                  QualifierMangleMode QMM) {
+  Qualifiers Quals = Q_None;
+  bool IsMember = false;
+  if (QMM == QualifierMangleMode::Mangle) {
+    std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
+  } else if (QMM == QualifierMangleMode::Result) {
+    if (MangledName.consumeFront('?'))
+      std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
+  }
+
+  TypeNode *Ty = nullptr;
+  if (isTagType(MangledName))
+    Ty = demangleClassType(MangledName);
+  else if (isPointerType(MangledName)) {
+    if (isMemberPointer(MangledName))
+      Ty = demangleMemberPointerType(MangledName);
+    else
+      Ty = demanglePointerType(MangledName);
+  } else if (isArrayType(MangledName))
+    Ty = demangleArrayType(MangledName);
+  else if (isFunctionType(MangledName)) {
+    if (MangledName.consumeFront("$$A8@@"))
+      Ty = demangleFunctionType(MangledName, true);
+    else {
+      assert(MangledName.startsWith("$$A6"));
+      MangledName.consumeFront("$$A6");
+      Ty = demangleFunctionType(MangledName, false);
+    }
+  } else if (isCustomType(MangledName)) {
+    Ty = demangleCustomType(MangledName);
+  } else {
+    Ty = demanglePrimitiveType(MangledName);
+    if (!Ty || Error)
+      return Ty;
+  }
+
+  Ty->Quals = Qualifiers(Ty->Quals | Quals);
+  return Ty;
+}
+
+void Demangler::demangleThrowSpecification(StringView &MangledName) {
+  if (MangledName.consumeFront('Z'))
+    return;
+
+  Error = true;
+}
+
+FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName,
+                                                       bool HasThisQuals) {
+  FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>();
+
+  if (HasThisQuals) {
+    FTy->Quals = demanglePointerExtQualifiers(MangledName);
+    FTy->RefQualifier = demangleFunctionRefQualifier(MangledName);
+    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);
+  }
+
+  // Fields that appear on both member and non-member functions.
+  FTy->CallConvention = demangleCallingConvention(MangledName);
+
+  // <return-type> ::= <type>
+  //               ::= @ # structors (they have no declared return type)
+  bool IsStructor = MangledName.consumeFront('@');
+  if (!IsStructor)
+    FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);
+
+  FTy->Params = demangleFunctionParameterList(MangledName);
+
+  demangleThrowSpecification(MangledName);
+
+  return FTy;
+}
+
+FunctionSymbolNode *
+Demangler::demangleFunctionEncoding(StringView &MangledName) {
+  FuncClass ExtraFlags = FC_None;
+  if (MangledName.consumeFront("$$J0"))
+    ExtraFlags = FC_ExternC;
+
+  FuncClass FC = demangleFunctionClass(MangledName);
+  FC = FuncClass(ExtraFlags | FC);
+
+  FunctionSignatureNode *FSN = nullptr;
+  ThunkSignatureNode *TTN = nullptr;
+  if (FC & FC_StaticThisAdjust) {
+    TTN = Arena.alloc<ThunkSignatureNode>();
+    TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);
+  } else if (FC & FC_VirtualThisAdjust) {
+    TTN = Arena.alloc<ThunkSignatureNode>();
+    if (FC & FC_VirtualThisAdjustEx) {
+      TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName);
+      TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName);
+    }
+    TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName);
+    TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);
+  }
+
+  if (FC & FC_NoParameterList) {
+    // This is an extern "C" function whose full signature hasn't been mangled.
+    // This happens when we need to mangle a local symbol inside of an extern
+    // "C" function.
+    FSN = Arena.alloc<FunctionSignatureNode>();
+  } else {
+    bool HasThisQuals = !(FC & (FC_Global | FC_Static));
+    FSN = demangleFunctionType(MangledName, HasThisQuals);
+  }
+  if (TTN) {
+    *static_cast<FunctionSignatureNode *>(TTN) = *FSN;
+    FSN = TTN;
+  }
+  FSN->FunctionClass = FC;
+
+  FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>();
+  Symbol->Signature = FSN;
+  return Symbol;
+}
+
+CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) {
+  assert(MangledName.startsWith('?'));
+  MangledName.popFront();
+
+  CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();
+  CTN->Identifier = demangleUnqualifiedTypeName(MangledName, true);
+  if (!MangledName.consumeFront('@'))
+    Error = true;
+  if (Error)
+    return nullptr;
+  return CTN;
+}
+
+// Reads a primitive type.
+PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) {
+  if (MangledName.consumeFront("$$T"))
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr);
+
+  switch (MangledName.popFront()) {
+  case 'X':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void);
+  case 'D':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char);
+  case 'C':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar);
+  case 'E':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar);
+  case 'F':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short);
+  case 'G':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort);
+  case 'H':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int);
+  case 'I':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint);
+  case 'J':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long);
+  case 'K':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong);
+  case 'M':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float);
+  case 'N':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double);
+  case 'O':
+    return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble);
+  case '_': {
+    if (MangledName.empty()) {
+      Error = true;
+      return nullptr;
+    }
+    switch (MangledName.popFront()) {
+    case 'N':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool);
+    case 'J':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64);
+    case 'K':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64);
+    case 'W':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar);
+    case 'S':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16);
+    case 'U':
+      return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32);
+    }
+    break;
+  }
+  }
+  Error = true;
+  return nullptr;
+}
+
+TagTypeNode *Demangler::demangleClassType(StringView &MangledName) {
+  TagTypeNode *TT = nullptr;
+
+  switch (MangledName.popFront()) {
+  case 'T':
+    TT = Arena.alloc<TagTypeNode>(TagKind::Union);
+    break;
+  case 'U':
+    TT = Arena.alloc<TagTypeNode>(TagKind::Struct);
+    break;
+  case 'V':
+    TT = Arena.alloc<TagTypeNode>(TagKind::Class);
+    break;
+  case 'W':
+    if (MangledName.popFront() != '4') {
+      Error = true;
+      return nullptr;
+    }
+    TT = Arena.alloc<TagTypeNode>(TagKind::Enum);
+    break;
+  default:
+    assert(false);
+  }
+
+  TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName);
+  return TT;
+}
+
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
+//                       # the E is required for 64-bit non-static pointers
+PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) {
+  PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
+
+  std::tie(Pointer->Quals, Pointer->Affinity) =
+      demanglePointerCVQualifiers(MangledName);
+
+  if (MangledName.consumeFront("6")) {
+    Pointer->Pointee = demangleFunctionType(MangledName, false);
+    return Pointer;
+  }
+
+  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
+  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+  Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);
+  return Pointer;
+}
+
+PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {
+  PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
+
+  std::tie(Pointer->Quals, Pointer->Affinity) =
+      demanglePointerCVQualifiers(MangledName);
+  assert(Pointer->Affinity == PointerAffinity::Pointer);
+
+  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
+  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+  if (MangledName.consumeFront("8")) {
+    Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
+    Pointer->Pointee = demangleFunctionType(MangledName, true);
+  } else {
+    Qualifiers PointeeQuals = Q_None;
+    bool IsMember = false;
+    std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);
+    assert(IsMember);
+    Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
+
+    Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);
+    Pointer->Pointee->Quals = PointeeQuals;
+  }
+
+  return Pointer;
+}
+
+Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) {
+  Qualifiers Quals = Q_None;
+  if (MangledName.consumeFront('E'))
+    Quals = Qualifiers(Quals | Q_Pointer64);
+  if (MangledName.consumeFront('I'))
+    Quals = Qualifiers(Quals | Q_Restrict);
+  if (MangledName.consumeFront('F'))
+    Quals = Qualifiers(Quals | Q_Unaligned);
+
+  return Quals;
+}
+
+ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) {
+  assert(MangledName.front() == 'Y');
+  MangledName.popFront();
+
+  uint64_t Rank = 0;
+  bool IsNegative = false;
+  std::tie(Rank, IsNegative) = demangleNumber(MangledName);
+  if (IsNegative || Rank == 0) {
+    Error = true;
+    return nullptr;
+  }
+
+  ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>();
+  NodeList *Head = Arena.alloc<NodeList>();
+  NodeList *Tail = Head;
+
+  for (uint64_t I = 0; I < Rank; ++I) {
+    uint64_t D = 0;
+    std::tie(D, IsNegative) = demangleNumber(MangledName);
+    if (IsNegative) {
+      Error = true;
+      return nullptr;
+    }
+    Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative);
+    if (I + 1 < Rank) {
+      Tail->Next = Arena.alloc<NodeList>();
+      Tail = Tail->Next;
+    }
+  }
+  ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank);
+
+  if (MangledName.consumeFront("$$C")) {
+    bool IsMember = false;
+    std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName);
+    if (IsMember) {
+      Error = true;
+      return nullptr;
+    }
+  }
+
+  ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);
+  return ATy;
+}
+
+// Reads a function or a template parameters.
+NodeArrayNode *
+Demangler::demangleFunctionParameterList(StringView &MangledName) {
+  // Empty parameter list.
+  if (MangledName.consumeFront('X'))
+    return {};
+
+  NodeList *Head = Arena.alloc<NodeList>();
+  NodeList **Current = &Head;
+  size_t Count = 0;
+  while (!Error && !MangledName.startsWith('@') &&
+         !MangledName.startsWith('Z')) {
+    ++Count;
+
+    if (startsWithDigit(MangledName)) {
+      size_t N = MangledName[0] - '0';
+      if (N >= Backrefs.FunctionParamCount) {
+        Error = true;
+        return {};
+      }
+      MangledName = MangledName.dropFront();
+
+      *Current = Arena.alloc<NodeList>();
+      (*Current)->N = Backrefs.FunctionParams[N];
+      Current = &(*Current)->Next;
+      continue;
+    }
+
+    size_t OldSize = MangledName.size();
+
+    *Current = Arena.alloc<NodeList>();
+    TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop);
+
+    (*Current)->N = TN;
+
+    size_t CharsConsumed = OldSize - MangledName.size();
+    assert(CharsConsumed != 0);
+
+    // Single-letter types are ignored for backreferences because memorizing
+    // them doesn't save anything.
+    if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1)
+      Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN;
+
+    Current = &(*Current)->Next;
+  }
+
+  if (Error)
+    return {};
+
+  NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count);
+  // A non-empty parameter list is terminated by either 'Z' (variadic) parameter
+  // list or '@' (non variadic).  Careful not to consume "@Z", as in that case
+  // the following Z could be a throw specifier.
+  if (MangledName.consumeFront('@'))
+    return NA;
+
+  if (MangledName.consumeFront('Z')) {
+    // This is a variadic parameter list.  We probably need a variadic node to
+    // append to the end.
+    return NA;
+  }
+
+  Error = true;
+  return {};
+}
+
+NodeArrayNode *
+Demangler::demangleTemplateParameterList(StringView &MangledName) {
+  NodeList *Head;
+  NodeList **Current = &Head;
+  size_t Count = 0;
+
+  while (!Error && !MangledName.startsWith('@')) {
+    if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
+        MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) {
+      // parameter pack separator
+      continue;
+    }
+
+    ++Count;
+
+    // Template parameter lists don't participate in back-referencing.
+    *Current = Arena.alloc<NodeList>();
+
+    NodeList &TP = **Current;
+
+    TemplateParameterReferenceNode *TPRN = nullptr;
+    if (MangledName.consumeFront("$$Y")) {
+      // Template alias
+      TP.N = demangleFullyQualifiedTypeName(MangledName);
+    } else if (MangledName.consumeFront("$$B")) {
+      // Array
+      TP.N = demangleType(MangledName, QualifierMangleMode::Drop);
+    } else if (MangledName.consumeFront("$$C")) {
+      // Type has qualifiers.
+      TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);
+    } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") ||
+               MangledName.startsWith("$I") || MangledName.startsWith("$J")) {
+      // Pointer to member
+      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
+      TPRN->IsMemberPointer = true;
+
+      MangledName = MangledName.dropFront();
+      // 1 - single inheritance       <name>
+      // H - multiple inheritance     <name> <number>
+      // I - virtual inheritance      <name> <number> <number> <number>
+      // J - unspecified inheritance  <name> <number> <number> <number>
+      char InheritanceSpecifier = MangledName.popFront();
+      SymbolNode *S = nullptr;
+      if (MangledName.startsWith('?')) {
+        S = parse(MangledName);
+        memorizeIdentifier(S->Name->getUnqualifiedIdentifier());
+      }
+
+      switch (InheritanceSpecifier) {
+      case 'J':
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'I':
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'H':
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case '1':
+        break;
+      default:
+        Error = true;
+        break;
+      }
+      TPRN->Affinity = PointerAffinity::Pointer;
+      TPRN->Symbol = S;
+    } else if (MangledName.startsWith("$E?")) {
+      MangledName.consumeFront("$E");
+      // Reference to symbol
+      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
+      TPRN->Symbol = parse(MangledName);
+      TPRN->Affinity = PointerAffinity::Reference;
+    } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) {
+      TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
+
+      // Data member pointer.
+      MangledName = MangledName.dropFront();
+      char InheritanceSpecifier = MangledName.popFront();
+
+      switch (InheritanceSpecifier) {
+      case 'G':
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'F':
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+            demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case '0':
+        break;
+      default:
+        Error = true;
+        break;
+      }
+      TPRN->IsMemberPointer = true;
+
+    } else if (MangledName.consumeFront("$0")) {
+      // Integral non-type template parameter
+      bool IsNegative = false;
+      uint64_t Value = 0;
+      std::tie(Value, IsNegative) = demangleNumber(MangledName);
+
+      TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative);
+    } else {
+      TP.N = demangleType(MangledName, QualifierMangleMode::Drop);
+    }
+    if (Error)
+      return nullptr;
+
+    Current = &TP.Next;
+  }
+
+  if (Error)
+    return nullptr;
+
+  // Template parameter lists cannot be variadic, so it can only be terminated
+  // by @.
+  if (MangledName.consumeFront('@'))
+    return nodeListToNodeArray(Arena, Head, Count);
+  Error = true;
+  return nullptr;
+}
+
+void Demangler::dumpBackReferences() {
+  std::printf("%d function parameter backreferences\n",
+              (int)Backrefs.FunctionParamCount);
+
+  // Create an output stream so we can render each type.
+  OutputStream OS;
+  if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+    std::terminate();
+  for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
+    OS.setCurrentPosition(0);
+
+    TypeNode *T = Backrefs.FunctionParams[I];
+    T->output(OS, OF_Default);
+
+    std::printf("  [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(),
+                OS.getBuffer());
+  }
+  std::free(OS.getBuffer());
+
+  if (Backrefs.FunctionParamCount > 0)
+    std::printf("\n");
+  std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);
+  for (size_t I = 0; I < Backrefs.NamesCount; ++I) {
+    std::printf("  [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),
+                Backrefs.Names[I]->Name.begin());
+  }
+  if (Backrefs.NamesCount > 0)
+    std::printf("\n");
+}
+
+char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
+                              int *Status, MSDemangleFlags Flags) {
+  int InternalStatus = demangle_success;
+  Demangler D;
+  OutputStream S;
+
+  StringView Name{MangledName};
+  SymbolNode *AST = D.parse(Name);
+
+  if (Flags & MSDF_DumpBackrefs)
+    D.dumpBackReferences();
+
+  if (D.Error)
+    InternalStatus = demangle_invalid_mangled_name;
+  else if (!initializeOutputStream(Buf, N, S, 1024))
+    InternalStatus = demangle_memory_alloc_failure;
+  else {
+    AST->output(S, OF_Default);
+    S += '\0';
+    if (N != nullptr)
+      *N = S.getCurrentPosition();
+    Buf = S.getBuffer();
+  }
+
+  if (Status)
+    *Status = InternalStatus;
+  return InternalStatus == demangle_success ? Buf : nullptr;
+}
diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
new file mode 100644
index 0000000..c57f0cf
--- /dev/null
+++ b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -0,0 +1,621 @@
+//===- MicrosoftDemangle.cpp ----------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a demangler for MSVC-style mangled symbols.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/MicrosoftDemangleNodes.h"
+#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/Utility.h"
+#include <cctype>
+
+using namespace llvm;
+using namespace ms_demangle;
+
+#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)                             \
+  case Enum::Value:                                                            \
+    OS << Desc;                                                                \
+    break;
+
+// Writes a space if the last token does not end with a punctuation.
+static void outputSpaceIfNecessary(OutputStream &OS) {
+  if (OS.empty())
+    return;
+
+  char C = OS.back();
+  if (std::isalnum(C) || C == '>')
+    OS << " ";
+}
+
+static bool outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
+  switch (Q) {
+  case Q_Const:
+    OS << "const";
+    return true;
+  case Q_Volatile:
+    OS << "volatile";
+    return true;
+  case Q_Restrict:
+    OS << "__restrict";
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+
+static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
+                                     Qualifiers Mask, bool NeedSpace) {
+  if (!(Q & Mask))
+    return NeedSpace;
+
+  if (NeedSpace)
+    OS << " ";
+
+  outputSingleQualifier(OS, Mask);
+  return true;
+}
+
+static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
+                             bool SpaceAfter) {
+  if (Q == Q_None)
+    return;
+
+  size_t Pos1 = OS.getCurrentPosition();
+  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
+  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
+  SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
+  size_t Pos2 = OS.getCurrentPosition();
+  if (SpaceAfter && Pos2 > Pos1)
+    OS << " ";
+}
+
+static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
+  outputSpaceIfNecessary(OS);
+
+  switch (CC) {
+  case CallingConv::Cdecl:
+    OS << "__cdecl";
+    break;
+  case CallingConv::Fastcall:
+    OS << "__fastcall";
+    break;
+  case CallingConv::Pascal:
+    OS << "__pascal";
+    break;
+  case CallingConv::Regcall:
+    OS << "__regcall";
+    break;
+  case CallingConv::Stdcall:
+    OS << "__stdcall";
+    break;
+  case CallingConv::Thiscall:
+    OS << "__thiscall";
+    break;
+  case CallingConv::Eabi:
+    OS << "__eabi";
+    break;
+  case CallingConv::Vectorcall:
+    OS << "__vectorcall";
+    break;
+  case CallingConv::Clrcall:
+    OS << "__clrcall";
+    break;
+  default:
+    break;
+  }
+}
+
+void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}
+
+void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+  switch (PrimKind) {
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
+    OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
+  }
+  outputQualifiers(OS, Quals, true, false);
+}
+
+void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
+  output(OS, Flags, ", ");
+}
+
+void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
+                           StringView Separator) const {
+  if (Count == 0)
+    return;
+  if (Nodes[0])
+    Nodes[0]->output(OS, Flags);
+  for (size_t I = 1; I < Count; ++I) {
+    OS << Separator;
+    Nodes[I]->output(OS, Flags);
+  }
+}
+
+void EncodedStringLiteralNode::output(OutputStream &OS,
+                                      OutputFlags Flags) const {
+  switch (Char) {
+  case CharKind::Wchar:
+    OS << "L\"";
+    break;
+  case CharKind::Char:
+    OS << "\"";
+    break;
+  case CharKind::Char16:
+    OS << "u\"";
+    break;
+  case CharKind::Char32:
+    OS << "U\"";
+    break;
+  }
+  OS << DecodedString << "\"";
+  if (IsTruncated)
+    OS << "...";
+}
+
+void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
+  if (IsNegative)
+    OS << '-';
+  OS << Value;
+}
+
+void TemplateParameterReferenceNode::output(OutputStream &OS,
+                                            OutputFlags Flags) const {
+  if (ThunkOffsetCount > 0)
+    OS << "{";
+  else if (Affinity == PointerAffinity::Pointer)
+    OS << "&";
+
+  if (Symbol) {
+    Symbol->output(OS, Flags);
+    if (ThunkOffsetCount > 0)
+      OS << ", ";
+  }
+
+  if (ThunkOffsetCount > 0)
+    OS << ThunkOffsets[0];
+  for (int I = 1; I < ThunkOffsetCount; ++I) {
+    OS << ", " << ThunkOffsets[I];
+  }
+  if (ThunkOffsetCount > 0)
+    OS << "}";
+}
+
+void IdentifierNode::outputTemplateParameters(OutputStream &OS,
+                                              OutputFlags Flags) const {
+  if (!TemplateParams)
+    return;
+  OS << "<";
+  TemplateParams->output(OS, Flags);
+  OS << ">";
+}
+
+void DynamicStructorIdentifierNode::output(OutputStream &OS,
+                                           OutputFlags Flags) const {
+  if (IsDestructor)
+    OS << "`dynamic atexit destructor for ";
+  else
+    OS << "`dynamic initializer for ";
+
+  if (Variable) {
+    OS << "`";
+    Variable->output(OS, Flags);
+    OS << "''";
+  } else {
+    OS << "'";
+    Name->output(OS, Flags);
+    OS << "''";
+  }
+}
+
+void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
+  OS << Name;
+  outputTemplateParameters(OS, Flags);
+}
+
+void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
+                                             OutputFlags Flags) const {
+  switch (Operator) {
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
+                            "operator[]");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
+                            "operator->*");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
+                            "operator>=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
+                            "operator&=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
+                            "operator|=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
+                            "operator^=");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
+                            "`vector deleting dtor'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
+                            "`default ctor closure'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
+                            "`scalar deleting dtor'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
+                            "`vector ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
+                            "`vector dtor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
+                            "`vector vbase ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
+                            "`virtual displacement map'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
+                            "`eh vector ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
+                            "`eh vector dtor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
+                            "`eh vector vbase ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
+                            "`copy ctor closure'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
+                            "`local vftable ctor closure'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
+                            "operator delete[]");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
+                            "`managed vector ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
+                            "`managed vector dtor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
+                            "`EH vector copy ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
+                            "`EH vector vbase copy ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
+                            "`vector copy ctor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
+                            "`vector vbase copy constructor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
+                            "`managed vector vbase copy constructor iterator'");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, "co_await");
+    OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator <=>");
+  case IntrinsicFunctionKind::MaxIntrinsic:
+  case IntrinsicFunctionKind::None:
+    break;
+  }
+  outputTemplateParameters(OS, Flags);
+}
+
+void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
+                                            OutputFlags Flags) const {
+  OS << "`local static guard'";
+  if (ScopeIndex > 0)
+    OS << "{" << ScopeIndex << "}";
+}
+
+void ConversionOperatorIdentifierNode::output(OutputStream &OS,
+                                              OutputFlags Flags) const {
+  OS << "operator";
+  outputTemplateParameters(OS, Flags);
+  OS << " ";
+  TargetType->output(OS, Flags);
+}
+
+void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
+  if (IsDestructor)
+    OS << "~";
+  Class->output(OS, Flags);
+  outputTemplateParameters(OS, Flags);
+}
+
+void LiteralOperatorIdentifierNode::output(OutputStream &OS,
+                                           OutputFlags Flags) const {
+  OS << "operator \"\"" << Name;
+  outputTemplateParameters(OS, Flags);
+}
+
+void FunctionSignatureNode::outputPre(OutputStream &OS,
+                                      OutputFlags Flags) const {
+  if (FunctionClass & FC_Public)
+    OS << "public: ";
+  if (FunctionClass & FC_Protected)
+    OS << "protected: ";
+  if (FunctionClass & FC_Private)
+    OS << "private: ";
+
+  if (!(FunctionClass & FC_Global)) {
+    if (FunctionClass & FC_Static)
+      OS << "static ";
+  }
+  if (FunctionClass & FC_Virtual)
+    OS << "virtual ";
+
+  if (FunctionClass & FC_ExternC)
+    OS << "extern \"C\" ";
+
+  if (ReturnType) {
+    ReturnType->outputPre(OS, Flags);
+    OS << " ";
+  }
+
+  if (!(Flags & OF_NoCallingConvention))
+    outputCallingConvention(OS, CallConvention);
+}
+
+void FunctionSignatureNode::outputPost(OutputStream &OS,
+                                       OutputFlags Flags) const {
+  if (!(FunctionClass & FC_NoParameterList)) {
+    OS << "(";
+    if (Params)
+      Params->output(OS, Flags);
+    else
+      OS << "void";
+    OS << ")";
+  }
+
+  if (Quals & Q_Const)
+    OS << " const";
+  if (Quals & Q_Volatile)
+    OS << " volatile";
+  if (Quals & Q_Restrict)
+    OS << " __restrict";
+  if (Quals & Q_Unaligned)
+    OS << " __unaligned";
+
+  if (RefQualifier == FunctionRefQualifier::Reference)
+    OS << " &";
+  else if (RefQualifier == FunctionRefQualifier::RValueReference)
+    OS << " &&";
+
+  if (ReturnType)
+    ReturnType->outputPost(OS, Flags);
+}
+
+void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+  OS << "[thunk]: ";
+
+  FunctionSignatureNode::outputPre(OS, Flags);
+}
+
+void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
+  if (FunctionClass & FC_StaticThisAdjust) {
+    OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
+  } else if (FunctionClass & FC_VirtualThisAdjust) {
+    if (FunctionClass & FC_VirtualThisAdjustEx) {
+      OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
+         << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
+         << ", " << ThisAdjust.StaticOffset << "}'";
+    } else {
+      OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
+         << ThisAdjust.StaticOffset << "}'";
+    }
+  }
+
+  FunctionSignatureNode::outputPost(OS, Flags);
+}
+