summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-30 09:15:25 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-30 09:17:24 +0100
commitd5ce1eda907df019cd3b26fc8db0246eac804c76 (patch)
treee785841998ded00ea03686e05cf70e48dcb10014
parentadc3fba76fbf1ccfd0863d39702d57f247b5b109 (diff)
include demumble without submodule
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt2
-rw-r--r--demangle/CMakeLists.txt39
-rw-r--r--demangle/demangle.cpp15
-rw-r--r--demangle/demangle.h4
-rw-r--r--demangle/third_party/llvm/LICENSE.txt279
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/Compiler.h549
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/Demangle.h133
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h92
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h5500
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def95
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h276
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h629
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/StringView.h122
-rw-r--r--demangle/third_party/llvm/include/llvm/Demangle/Utility.h199
-rw-r--r--demangle/third_party/llvm/lib/Demangle/Demangle.cpp68
-rw-r--r--demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp608
-rw-r--r--demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp2368
-rw-r--r--demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp658
m---------demumble0
20 files changed, 11635 insertions, 4 deletions
diff --git a/.gitmodules b/.gitmodules
index 2e2520dd..fd4fc9fd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,6 +25,3 @@
[submodule "luajit"]
path = external/luajit
url = https://github.com/WohlSoft/LuaJIT.git
-[submodule "demumble"]
- path = demumble
- url = https://github.com/sthalik/demumble
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 793c6dc5..8d56aa45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -180,7 +180,7 @@ include_directories(SYSTEM
"${_fm-json-include-dirs}"
)
-add_subdirectory(demumble)
+add_subdirectory(demangle)
add_subdirectory(src)
add_subdirectory(serialize)
add_subdirectory(loader)
diff --git a/demangle/CMakeLists.txt b/demangle/CMakeLists.txt
new file mode 100644
index 00000000..ce3222a4
--- /dev/null
+++ b/demangle/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+project(demumble CXX)
+
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
+set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
+set(CMAKE_CXX_STANDARD 23)
+set(CMAKE_CXX_STANDARD_DEFAULT 23)
+set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+set(CMAKE_CXX_EXTENSIONS FALSE)
+
+if (NOT MSVC)
+ add_compile_options(-Wall -fno-exceptions -fno-rtti)
+ # 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)
+ add_compile_options(-mmacosx-version-min=10.9)
+ else()
+ add_compile_options(-fno-plt)
+ endif()
+ add_compile_options(-Wno-error -Wno-sign-conversion -Wno-unused -Wno-unused-parameter)
+ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
+ add_compile_options(-Wno-shorten-64-to-32 -Wno-implicit-int-conversion -Wno-class-varargs -Wno-extra-semi-stmt)
+ endif()
+else()
+ add_compile_options(-Zc:inline -permissive- -GR-)
+ add_compile_options(-wd4100 -wd4244 -wd4267)
+ add_definitions(-D_HAS_EXCEPTIONS=0 -DNOMINMAX -D_USE_MATH_DEFINES=1)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS) # The LLVM build sets this.
+endif()
+
+include_directories(SYSTEM third_party/llvm/include)
+add_library(demumble STATIC
+ third_party/llvm/lib/Demangle/Demangle.cpp
+ third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
+ third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
+ third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
+ demangle.cpp)
+target_link_libraries(demumble PUBLIC Corrade::Containers)
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
new file mode 100644
index 00000000..f3cfd231
--- /dev/null
+++ b/demangle/demangle.cpp
@@ -0,0 +1,15 @@
+#include "demangle.h"
+#include <cstdlib>
+#include <string>
+#include "llvm/Demangle/Demangle.h"
+
+using namespace Corrade::Containers;
+
+String demangle_symbol(const char* symbol)
+{
+ if (!symbol || !*symbol)
+ return {};
+ if (const auto str = llvm::demangle(symbol); !str.empty())
+ return String{str.data(), str.size()};
+ return {};
+}
diff --git a/demangle/demangle.h b/demangle/demangle.h
new file mode 100644
index 00000000..632f9c14
--- /dev/null
+++ b/demangle/demangle.h
@@ -0,0 +1,4 @@
+#pragma once
+#include <Corrade/Containers/String.h>
+
+Corrade::Containers::String demangle_symbol(const char* symbol);
diff --git a/demangle/third_party/llvm/LICENSE.txt b/demangle/third_party/llvm/LICENSE.txt
new file mode 100644
index 00000000..fa6ac540
--- /dev/null
+++ b/demangle/third_party/llvm/LICENSE.txt
@@ -0,0 +1,279 @@
+==============================================================================
+The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
+==============================================================================
+
+ Apache License
+ Version 2.0, January 2004
+ 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.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+==============================================================================
+Software from third parties included in the LLVM Project:
+==============================================================================
+The LLVM Project contains third party software which is under different license
+terms. All such code will be identified clearly using at least one of two
+mechanisms:
+1) It will be in a separate directory tree with its own `LICENSE.txt` or
+ `LICENSE` file at the top containing the specific license and restrictions
+ which apply to that software, or
+2) It will contain specific license and restriction terms at the top of every
+ file.
+
+==============================================================================
+Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2019 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/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h b/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h
new file mode 100644
index 00000000..c17ff4ca
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h
@@ -0,0 +1,549 @@
+//===--- 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 __cplusplus
+#include <new>
+#endif
+#include <stddef.h>
+
+#if defined(_MSC_VER)
+#include <sal.h>
+#endif
+
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#ifndef __has_extension
+# define __has_extension(x) 0
+#endif
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
+// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
+#ifndef LLVM_HAS_CPP_ATTRIBUTE
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+#endif
+
+/// \macro LLVM_GNUC_PREREQ
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// available.
+#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
+
+/// \macro LLVM_MSC_PREREQ
+/// Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1910: VS2017, version 15.1 & 15.2
+/// * 1911: VS2017, version 15.3 & 15.4
+/// * 1912: VS2017, version 15.5
+/// * 1913: VS2017, version 15.6
+/// * 1914: VS2017, version 15.7
+/// * 1915: VS2017, version 15.8
+/// * 1916: VS2017, version 15.9
+/// * 1920: VS2019, version 16.0
+/// * 1921: VS2019, version 16.1
+#ifdef _MSC_VER
+#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
+
+// We require at least MSVC 2017.
+#if !LLVM_MSC_PREREQ(1910)
+#error LLVM requires at least MSVC 2017.
+#endif
+
+#else
+#define LLVM_MSC_PREREQ(version) 0
+#endif
+
+/// Does the compiler support ref-qualifiers for *this?
+///
+/// Sadly, this is separate from just rvalue reference support because GCC
+/// and MSVC implemented this later than everything else. This appears to be
+/// corrected in MSVC 2019 but not MSVC 2017.
+#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \
+ LLVM_MSC_PREREQ(1920)
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
+#else
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
+#endif
+
+/// Expands to '&' if ref-qualifiers for *this are supported.
+///
+/// This can be used to provide lvalue/rvalue overrides of member functions.
+/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+#define LLVM_LVALUE_FUNCTION &
+#else
+#define LLVM_LVALUE_FUNCTION
+#endif
+
+/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
+/// into a shared library, then the class should be private to the library and
+/// not accessible from outside it. Can also be used to mark variables and
+/// functions, making them private to any shared library they are linked into.
+/// On PE/COFF targets, library visibility is the default, so this isn't needed.
+///
+/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
+/// this attribute will be made public and visible outside of any shared library
+/// they are linked in to.
+#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
+ !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
+#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
+#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default")))
+#else
+#define LLVM_LIBRARY_VISIBILITY
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+
+#if defined(__GNUC__)
+#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
+#else
+#define LLVM_PREFETCH(addr, rw, locality)
+#endif
+
+#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
+#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define LLVM_ATTRIBUTE_USED
+#endif
+
+/// LLVM_NODISCARD - Warn if a type or return value is discarded.
+
+// Use the 'nodiscard' attribute in C++17 or newer mode.
+#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
+#define LLVM_NODISCARD [[nodiscard]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
+#define LLVM_NODISCARD [[clang::warn_unused_result]]
+// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
+// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
+// Use the 'nodiscard' attribute in C++14 mode only with GCC.
+// TODO: remove this workaround when PR33518 is resolved.
+#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
+#define LLVM_NODISCARD [[nodiscard]]
+#else
+#define LLVM_NODISCARD
+#endif
+
+// Indicate that a non-static, non-const C++ member function reinitializes
+// the entire object to a known state, independent of the previous state of
+// the object.
+//
+// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
+// marker that a moved-from object has left the indeterminate state and can be
+// reused.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
+#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define LLVM_ATTRIBUTE_REINITIALIZES
+#endif
+
+// Some compilers warn about unused functions. When a function is sometimes
+// used or not depending on build settings (e.g. a function only called from
+// within "assert"), this attribute can be used to suppress such warnings.
+//
+// However, it shouldn't be used for unused *variables*, as those have a much
+// more portable solution:
+// (void)unused_var_name;
+// Prefer cast-to-void wherever it is sufficient.
+#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
+#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define LLVM_ATTRIBUTE_UNUSED
+#endif
+
+// FIXME: Provide this for PE/COFF targets.
+#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
+ (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
+#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
+#else
+#define LLVM_ATTRIBUTE_WEAK
+#endif
+
+// Prior to clang 3.2, clang did not accept any spelling of
+// __has_attribute(const), so assume it is supported.
+#if defined(__clang__) || defined(__GNUC__)
+// aka 'CONST' but following LLVM Conventions.
+#define LLVM_READNONE __attribute__((__const__))
+#else
+#define LLVM_READNONE
+#endif
+
+#if __has_attribute(pure) || defined(__GNUC__)
+// aka 'PURE' but following LLVM Conventions.
+#define LLVM_READONLY __attribute__((__pure__))
+#else
+#define LLVM_READONLY
+#endif
+
+#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
+#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define LLVM_LIKELY(EXPR) (EXPR)
+#define LLVM_UNLIKELY(EXPR) (EXPR)
+#endif
+
+/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
+/// mark a method "not for inlining".
+#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
+
+/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
+/// so, mark a method "always inline" because it is performance sensitive. GCC
+/// 3.4 supported this but is buggy in various cases and produces unimplemented
+/// errors, just use it in GCC 4.0 and later.
+#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
+#endif
+
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define LLVM_ATTRIBUTE_NORETURN
+#endif
+
+#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
+/// pointer that does not alias any other valid pointer.
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#endif
+
+/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
+#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif __has_attribute(fallthrough)
+#define LLVM_FALLTHROUGH __attribute__((fallthrough))
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+
+/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
+/// they are constant initialized.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
+ [[clang::require_constant_initialization]]
+#else
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+
+/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
+/// lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
+#define LLVM_GSL_OWNER [[gsl::Owner]]
+#else
+#define LLVM_GSL_OWNER
+#endif
+
+/// LLVM_GSL_POINTER - Apply this to non-owning classes like
+/// StringRef to enable lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
+#define LLVM_GSL_POINTER [[gsl::Pointer]]
+#else
+#define LLVM_GSL_POINTER
+#endif
+
+/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
+/// pedantic diagnostics.
+#ifdef __GNUC__
+#define LLVM_EXTENSION __extension__
+#else
+#define LLVM_EXTENSION
+#endif
+
+// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
+// This macro will be removed.
+// Use C++14's attribute instead: [[deprecated("message")]]
+#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
+
+/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
+/// to an expression which states that it is undefined behavior for the
+/// compiler to reach this point. Otherwise is not defined.
+#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
+
+/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
+/// which causes the program to exit abnormally.
+#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
+# define LLVM_BUILTIN_TRAP __builtin_trap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC, does not require forward
+// declarations involving platform-specific typedefs (unlike RaiseException),
+// results in a call to vectored exception handlers, and encodes to a short
+// instruction that still causes the trapping behavior we want.
+# define LLVM_BUILTIN_TRAP __debugbreak()
+#else
+# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
+#endif
+
+/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
+/// an expression which causes the program to break while running
+/// under a debugger.
+#if __has_builtin(__builtin_debugtrap)
+# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC and breaks while
+// running under the debugger, and also supports invoking a debugger
+// when the OS is configured appropriately.
+# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
+#else
+// Just continue execution when built with compilers that have no
+// support. This is a debugging aid and not intended to force the
+// program to abort if encountered.
+# define LLVM_BUILTIN_DEBUGTRAP
+#endif
+
+/// \macro LLVM_ASSUME_ALIGNED
+/// Returns a pointer with an assumed alignment.
+#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
+# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+# define LLVM_ASSUME_ALIGNED(p, a) \
+ (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
+#else
+# define LLVM_ASSUME_ALIGNED(p, a) (p)
+#endif
+
+/// \macro LLVM_PACKED
+/// Used to specify a packed structure.
+/// LLVM_PACKED(
+/// struct A {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// });
+///
+/// LLVM_PACKED_START
+/// struct B {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// };
+/// LLVM_PACKED_END
+#ifdef _MSC_VER
+# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
+# define LLVM_PACKED_START __pragma(pack(push, 1))
+# define LLVM_PACKED_END __pragma(pack(pop))
+#else
+# define LLVM_PACKED(d) d __attribute__((packed))
+# define LLVM_PACKED_START _Pragma("pack(push, 1)")
+# define LLVM_PACKED_END _Pragma("pack(pop)")
+#endif
+
+/// \macro LLVM_PTR_SIZE
+/// A constant integer equivalent to the value of sizeof(void*).
+/// Generally used in combination with alignas or when doing computation in the
+/// preprocessor.
+#ifdef __SIZEOF_POINTER__
+# define LLVM_PTR_SIZE __SIZEOF_POINTER__
+#elif defined(_WIN64)
+# define LLVM_PTR_SIZE 8
+#elif defined(_WIN32)
+# define LLVM_PTR_SIZE 4
+#elif defined(_MSC_VER)
+# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
+#else
+# define LLVM_PTR_SIZE sizeof(void *)
+#endif
+
+/// \macro LLVM_MEMORY_SANITIZER_BUILD
+/// Whether LLVM itself is built with MemorySanitizer instrumentation.
+#if __has_feature(memory_sanitizer)
+# define LLVM_MEMORY_SANITIZER_BUILD 1
+# include <sanitizer/msan_interface.h>
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
+#else
+# define LLVM_MEMORY_SANITIZER_BUILD 0
+# define __msan_allocated_memory(p, size)
+# define __msan_unpoison(p, size)
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
+#endif
+
+/// \macro LLVM_ADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define LLVM_ADDRESS_SANITIZER_BUILD 1
+# include <sanitizer/asan_interface.h>
+#else
+# define LLVM_ADDRESS_SANITIZER_BUILD 0
+# define __asan_poison_memory_region(p, size)
+# define __asan_unpoison_memory_region(p, size)
+#endif
+
+/// \macro LLVM_THREAD_SANITIZER_BUILD
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
+#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define LLVM_THREAD_SANITIZER_BUILD 1
+#else
+# define LLVM_THREAD_SANITIZER_BUILD 0
+#endif
+
+#if LLVM_THREAD_SANITIZER_BUILD
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
+void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+#ifdef __cplusplus
+}
+#endif
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else
+# define TsanHappensBefore(cv)
+# define TsanHappensAfter(cv)
+# define TsanIgnoreWritesBegin()
+# define TsanIgnoreWritesEnd()
+#endif
+
+/// \macro LLVM_NO_SANITIZE
+/// Disable a particular sanitizer for a function.
+#if __has_attribute(no_sanitize)
+#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
+#else
+#define LLVM_NO_SANITIZE(KIND)
+#endif
+
+/// Mark debug helper function definitions like dump() that should not be
+/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
+// FIXME: Move this to a private config.h as it's not usable in public headers.
+#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
+
+/// \macro LLVM_PRETTY_FUNCTION
+/// Gets a user-friendly looking function signature for the current scope
+/// using the best available method on each platform. The exact format of the
+/// resulting string is implementation specific and non-portable, so this should
+/// only be used, for example, for logging or diagnostics.
+#if defined(_MSC_VER)
+#define LLVM_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__) || defined(__clang__)
+#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define LLVM_PRETTY_FUNCTION __func__
+#endif
+
+/// \macro LLVM_THREAD_LOCAL
+/// A thread-local storage specifier which can be used with globals,
+/// extern globals, and static globals.
+///
+/// This is essentially an extremely restricted analog to C++11's thread_local
+/// support. It uses thread_local if available, falling back on gcc __thread
+/// if not. __thread doesn't support many of the C++11 thread_local's
+/// features. You should only use this for PODs that you can statically
+/// initialize to some constant value. In almost all circumstances this is most
+/// appropriate for use with a pointer, integer, or small aggregation of
+/// pointers and integers.
+#if LLVM_ENABLE_THREADS
+#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
+#define LLVM_THREAD_LOCAL thread_local
+#else
+// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
+// we only need the restricted functionality that provides.
+#define LLVM_THREAD_LOCAL __thread
+#endif
+#else // !LLVM_ENABLE_THREADS
+// If threading is disabled entirely, this compiles to nothing and you get
+// a normal global variable.
+#define LLVM_THREAD_LOCAL
+#endif
+
+/// \macro LLVM_ENABLE_EXCEPTIONS
+/// Whether LLVM is built with exception support.
+#if __has_feature(cxx_exceptions)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(__GNUC__) && defined(__EXCEPTIONS)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(_MSC_VER) && defined(_CPPUNWIND)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#endif
+
+#endif
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h b/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h
new file mode 100644
index 00000000..6133d0b9
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h
@@ -0,0 +1,133 @@
+//===--- Demangle.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_DEMANGLE_H
+#define LLVM_DEMANGLE_DEMANGLE_H
+
+#include <cstddef>
+#include <string>
+
+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);
+
+enum MSDemangleFlags {
+ MSDF_None = 0,
+ MSDF_DumpBackrefs = 1 << 0,
+ MSDF_NoAccessSpecifier = 1 << 1,
+ MSDF_NoCallingConvention = 1 << 2,
+ MSDF_NoReturnType = 1 << 3,
+ MSDF_NoMemberType = 1 << 4,
+ MSDF_NoVariableType = 1 << 5,
+};
+
+/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
+/// Returns a pointer to the start of a null-terminated demangled string on
+/// success, or nullptr on error.
+/// If n_read is non-null and demangling was successful, it receives how many
+/// bytes of the input string were consumed.
+/// buf can point to a *n_buf bytes large buffer where the demangled name is
+/// stored. If the buffer is too small, it is grown with realloc(). If buf is
+/// nullptr, then this malloc()s memory for the result.
+/// *n_buf stores the size of buf on input if buf is non-nullptr, and it
+/// receives the size of the demangled string on output if n_buf is not nullptr.
+/// status receives one of the demangle_ enum entries above if it's not nullptr.
+/// Flags controls various details of the demangled representation.
+char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf,
+ size_t *n_buf, int *status,
+ MSDemangleFlags Flags = MSDF_None);
+
+// Demangles a Rust v0 mangled symbol.
+char *rustDemangle(const char *MangledName);
+
+// Demangles a D mangled symbol.
+char *dlangDemangle(const char *MangledName);
+
+/// Attempt to demangle a string using different demangling schemes.
+/// The function uses heuristics to determine which demangling scheme to use.
+/// \param MangledName - reference to string to demangle.
+/// \returns - the demangled string, or a copy of the input string if no
+/// demangling occurred.
+std::string demangle(const std::string &MangledName);
+
+bool nonMicrosoftDemangle(const char *MangledName, std::string &Result);
+
+/// "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/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h b/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h
new file mode 100644
index 00000000..2ff95dd8
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h
@@ -0,0 +1,92 @@
+//===--- DemangleConfig.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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_DEMANGLECONFIG_H
+#define LLVM_DEMANGLE_DEMANGLECONFIG_H
+
+#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 DEMANGLE_GNUC_PREREQ
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
+ ((maj) << 20) + ((min) << 10) + (patch))
+#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+#else
+#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
+#endif
+#endif
+
+#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
+#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define DEMANGLE_ATTRIBUTE_USED
+#endif
+
+#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
+#define DEMANGLE_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define DEMANGLE_UNREACHABLE __assume(false)
+#else
+#define DEMANGLE_UNREACHABLE
+#endif
+
+#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
+#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define DEMANGLE_ATTRIBUTE_NOINLINE
+#endif
+
+#if !defined(NDEBUG)
+#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
+#else
+#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
+#endif
+
+#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
+#define DEMANGLE_FALLTHROUGH [[fallthrough]]
+#elif __has_cpp_attribute(gnu::fallthrough)
+#define DEMANGLE_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 DEMANGLE_FALLTHROUGH
+#elif __has_cpp_attribute(clang::fallthrough)
+#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define DEMANGLE_FALLTHROUGH
+#endif
+
+#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
+#define DEMANGLE_NAMESPACE_END } }
+
+#endif
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
new file mode 100644
index 00000000..ea55f4a6
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -0,0 +1,5500 @@
+//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===//
+// Do not edit! See README.txt.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic itanium demangler library.
+// There are two copies of this file in the source tree. The one under
+// libcxxabi is the original and the one under llvm is the copy. Use
+// cp-to-llvm.sh to update the copy. See README.txt for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DEMANGLE_ITANIUMDEMANGLE_H
+#define DEMANGLE_ITANIUMDEMANGLE_H
+
+#include "DemangleConfig.h"
+#include "StringView.h"
+#include "Utility.h"
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <new>
+#include <utility>
+
+DEMANGLE_NAMESPACE_BEGIN
+
+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 = nullptr;
+ T *Last = nullptr;
+ T *Cap = nullptr;
+ T Inline[N] = {0};
+
+ 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;
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void push_back(const T &Elem) {
+ if (Last == Cap)
+ reserve(size() * 2);
+ *Last++ = Elem;
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ 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);
+ }
+};
+
+// 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 NODE(NodeKind) K##NodeKind,
+#include "ItaniumNodes.def"
+ };
+
+ /// 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, };
+
+ /// Operator precedence for expression nodes. Used to determine required
+ /// parens in expression emission.
+ enum class Prec {
+ Primary,
+ Postfix,
+ Unary,
+ Cast,
+ PtrMem,
+ Multiplicative,
+ Additive,
+ Shift,
+ Spaceship,
+ Relational,
+ Equality,
+ And,
+ Xor,
+ Ior,
+ AndIf,
+ OrIf,
+ Conditional,
+ Assign,
+ Comma,
+ Default,
+ };
+
+private:
+ Kind K;
+
+ Prec Precedence : 6;
+
+ // 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 : 2;
+
+ /// Track if this node is a (possibly qualified) array type. This can affect
+ /// how we format the output string.
+ Cache ArrayCache : 2;
+
+ /// Track if this node is a (possibly qualified) function type. This can
+ /// affect how we format the output string.
+ Cache FunctionCache : 2;
+
+public:
+ Node(Kind K_, Prec Precedence_ = Prec::Primary,
+ Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No,
+ Cache FunctionCache_ = Cache::No)
+ : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_),
+ ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {}
+ Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No,
+ Cache FunctionCache_ = Cache::No)
+ : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_,
+ 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(OutputBuffer &OB) const {
+ if (RHSComponentCache != Cache::Unknown)
+ return RHSComponentCache == Cache::Yes;
+ return hasRHSComponentSlow(OB);
+ }
+
+ bool hasArray(OutputBuffer &OB) const {
+ if (ArrayCache != Cache::Unknown)
+ return ArrayCache == Cache::Yes;
+ return hasArraySlow(OB);
+ }
+
+ bool hasFunction(OutputBuffer &OB) const {
+ if (FunctionCache != Cache::Unknown)
+ return FunctionCache == Cache::Yes;
+ return hasFunctionSlow(OB);
+ }
+
+ Kind getKind() const { return K; }
+
+ Prec getPrecedence() const { return Precedence; }
+
+ virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; }
+ virtual bool hasArraySlow(OutputBuffer &) const { return false; }
+ virtual bool hasFunctionSlow(OutputBuffer &) 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(OutputBuffer &) const { return this; }
+
+ // Print this node as an expression operand, surrounding it in parentheses if
+ // its precedence is [Strictly] weaker than P.
+ void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default,
+ bool StrictlyWorse = false) const {
+ bool Paren =
+ unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse);
+ if (Paren)
+ OB.printOpen();
+ print(OB);
+ if (Paren)
+ OB.printClose();
+ }
+
+ void print(OutputBuffer &OB) const {
+ printLeft(OB);
+ if (RHSComponentCache != Cache::No)
+ printRight(OB);
+ }
+
+ // Print the "left" side of this Node into OutputBuffer.
+ virtual void printLeft(OutputBuffer &) 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(OutputBuffer &) const {}
+
+ virtual StringView getBaseName() const { return StringView(); }
+
+ // Silence compiler warnings, this dtor will never be called.
+ virtual ~Node() = default;
+
+#ifndef NDEBUG
+ DEMANGLE_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(OutputBuffer &OB) const {
+ bool FirstElement = true;
+ for (size_t Idx = 0; Idx != NumElements; ++Idx) {
+ size_t BeforeComma = OB.getCurrentPosition();
+ if (!FirstElement)
+ OB += ", ";
+ size_t AfterComma = OB.getCurrentPosition();
+ Elements[Idx]->printAsOperand(OB, Node::Prec::Comma);
+
+ // Elements[Idx] is an empty parameter pack expansion, we should erase the
+ // comma we just printed.
+ if (AfterComma == OB.getCurrentPosition()) {
+ OB.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(OutputBuffer &OB) const override { Array.printWithComma(OB); }
+};
+
+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(OutputBuffer &OB) const override {
+ Prefix->print(OB);
+ OB += " (";
+ OB += Suffix;
+ OB += ")";
+ }
+};
+
+class VendorExtQualType final : public Node {
+ const Node *Ty;
+ StringView Ext;
+ const Node *TA;
+
+public:
+ VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_)
+ : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {}
+
+ const Node *getTy() const { return Ty; }
+ StringView getExt() const { return Ext; }
+ const Node *getTA() const { return TA; }
+
+ template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Ty->print(OB);
+ OB += " ";
+ OB += Ext;
+ if (TA != nullptr)
+ TA->print(OB);
+ }
+};
+
+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 final : public Node {
+protected:
+ const Qualifiers Quals;
+ const Node *Child;
+
+ void printQuals(OutputBuffer &OB) const {
+ if (Quals & QualConst)
+ OB += " const";
+ if (Quals & QualVolatile)
+ OB += " volatile";
+ if (Quals & QualRestrict)
+ OB += " restrict";
+ }
+
+public:
+ QualType(const Node *Child_, Qualifiers Quals_)
+ : Node(KQualType, Child_->RHSComponentCache,
+ Child_->ArrayCache, Child_->FunctionCache),
+ Quals(Quals_), Child(Child_) {}
+
+ Qualifiers getQuals() const { return Quals; }
+ const Node *getChild() const { return Child; }
+
+ template<typename Fn> void match(Fn F) const { F(Child, Quals); }
+
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
+ return Child->hasRHSComponent(OB);
+ }
+ bool hasArraySlow(OutputBuffer &OB) const override {
+ return Child->hasArray(OB);
+ }
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
+ return Child->hasFunction(OB);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Child->printLeft(OB);
+ printQuals(OB);
+ }
+
+ void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "operator ";
+ Ty->print(OB);
+ }
+};
+
+class PostfixQualifiedType final : public Node {
+ const Node *Ty;
+ const StringView Postfix;
+
+public:
+ PostfixQualifiedType(const Node *Ty_, StringView Postfix_)
+ : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Ty->printLeft(OB);
+ OB += 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(OutputBuffer &OB) const override { OB += Name; }
+};
+
+class BitIntType final : public Node {
+ const Node *Size;
+ bool Signed;
+
+public:
+ BitIntType(const Node *Size_, bool Signed_)
+ : Node(KBitIntType), Size(Size_), Signed(Signed_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Size, Signed); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (!Signed)
+ OB += "unsigned ";
+ OB += "_BitInt";
+ OB.printOpen();
+ Size->printAsOperand(OB);
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += Kind;
+ OB += ' ';
+ Child->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Base->printLeft(OB);
+ OB += "[abi:";
+ OB += Tag;
+ OB += "]";
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += " [enable_if:";
+ Conditions.printWithComma(OB);
+ OB += ']';
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Ty->print(OB);
+ OB += "<";
+ OB += Protocol;
+ OB += ">";
+ }
+};
+
+class PointerType final : public Node {
+ const Node *Pointee;
+
+public:
+ PointerType(const Node *Pointee_)
+ : Node(KPointerType, Pointee_->RHSComponentCache),
+ Pointee(Pointee_) {}
+
+ const Node *getPointee() const { return Pointee; }
+
+ template<typename Fn> void match(Fn F) const { F(Pointee); }
+
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
+ return Pointee->hasRHSComponent(OB);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
+ if (Pointee->getKind() != KObjCProtoName ||
+ !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+ Pointee->printLeft(OB);
+ if (Pointee->hasArray(OB))
+ OB += " ";
+ if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
+ OB += "(";
+ OB += "*";
+ } else {
+ const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
+ OB += "id<";
+ OB += objcProto->Protocol;
+ OB += ">";
+ }
+ }
+
+ void printRight(OutputBuffer &OB) const override {
+ if (Pointee->getKind() != KObjCProtoName ||
+ !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
+ if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
+ OB += ")";
+ Pointee->printRight(OB);
+ }
+ }
+};
+
+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.
+ //
+ // A combination of a TemplateForwardReference and a back-ref Substitution
+ // from an ill-formed string may have created a cycle; use cycle detection to
+ // avoid looping forever.
+ std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const {
+ auto SoFar = std::make_pair(RK, Pointee);
+ // Track the chain of nodes for the Floyd's 'tortoise and hare'
+ // cycle-detection algorithm, since getSyntaxNode(S) is impure
+ PODSmallVector<const Node *, 8> Prev;
+ for (;;) {
+ const Node *SN = SoFar.second->getSyntaxNode(OB);
+ if (SN->getKind() != KReferenceType)
+ break;
+ auto *RT = static_cast<const ReferenceType *>(SN);
+ SoFar.second = RT->Pointee;
+ SoFar.first = std::min(SoFar.first, RT->RK);
+
+ // The middle of Prev is the 'slow' pointer moving at half speed
+ Prev.push_back(SoFar.second);
+ if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) {
+ // Cycle detected
+ SoFar.second = nullptr;
+ break;
+ }
+ }
+ 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(OutputBuffer &OB) const override {
+ return Pointee->hasRHSComponent(OB);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Printing)
+ return;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
+ if (!Collapsed.second)
+ return;
+ Collapsed.second->printLeft(OB);
+ if (Collapsed.second->hasArray(OB))
+ OB += " ";
+ if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
+ OB += "(";
+
+ OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
+ }
+ void printRight(OutputBuffer &OB) const override {
+ if (Printing)
+ return;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
+ if (!Collapsed.second)
+ return;
+ if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
+ OB += ")";
+ Collapsed.second->printRight(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ return MemberType->hasRHSComponent(OB);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ MemberType->printLeft(OB);
+ if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
+ OB += "(";
+ else
+ OB += " ";
+ ClassType->print(OB);
+ OB += "::*";
+ }
+
+ void printRight(OutputBuffer &OB) const override {
+ if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
+ OB += ")";
+ MemberType->printRight(OB);
+ }
+};
+
+class ArrayType final : public Node {
+ const Node *Base;
+ Node *Dimension;
+
+public:
+ ArrayType(const Node *Base_, Node *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(OutputBuffer &) const override { return true; }
+ bool hasArraySlow(OutputBuffer &) const override { return true; }
+
+ void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+
+ void printRight(OutputBuffer &OB) const override {
+ if (OB.back() != ']')
+ OB += " ";
+ OB += "[";
+ if (Dimension)
+ Dimension->print(OB);
+ OB += "]";
+ Base->printRight(OB);
+ }
+};
+
+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(OutputBuffer &) const override { return true; }
+ bool hasFunctionSlow(OutputBuffer &) 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(OutputBuffer &OB) const override {
+ Ret->printLeft(OB);
+ OB += " ";
+ }
+
+ void printRight(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
+ Ret->printRight(OB);
+
+ if (CVQuals & QualConst)
+ OB += " const";
+ if (CVQuals & QualVolatile)
+ OB += " volatile";
+ if (CVQuals & QualRestrict)
+ OB += " restrict";
+
+ if (RefQual == FrefQualLValue)
+ OB += " &";
+ else if (RefQual == FrefQualRValue)
+ OB += " &&";
+
+ if (ExceptionSpec != nullptr) {
+ OB += ' ';
+ ExceptionSpec->print(OB);
+ }
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "noexcept";
+ OB.printOpen();
+ E->printAsOperand(OB);
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "throw";
+ OB.printOpen();
+ Types.printWithComma(OB);
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &) const override { return true; }
+ bool hasFunctionSlow(OutputBuffer &) const override { return true; }
+
+ const Node *getName() const { return Name; }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Ret) {
+ Ret->printLeft(OB);
+ if (!Ret->hasRHSComponent(OB))
+ OB += " ";
+ }
+ Name->print(OB);
+ }
+
+ void printRight(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
+ if (Ret)
+ Ret->printRight(OB);
+
+ if (CVQuals & QualConst)
+ OB += " const";
+ if (CVQuals & QualVolatile)
+ OB += " volatile";
+ if (CVQuals & QualRestrict)
+ OB += " restrict";
+
+ if (RefQual == FrefQualLValue)
+ OB += " &";
+ else if (RefQual == FrefQualRValue)
+ OB += " &&";
+
+ if (Attrs != nullptr)
+ Attrs->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "operator\"\" ";
+ OpName->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += Special;
+ Child->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "construction vtable for ";
+ FirstType->print(OB);
+ OB += "-in-";
+ SecondType->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Qual->print(OB);
+ OB += "::";
+ Name->print(OB);
+ }
+};
+
+struct ModuleName : Node {
+ ModuleName *Parent;
+ Node *Name;
+ bool IsPartition;
+
+ ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false)
+ : Node(KModuleName), Parent(Parent_), Name(Name_),
+ IsPartition(IsPartition_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Parent, Name, IsPartition);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Parent)
+ Parent->print(OB);
+ if (Parent || IsPartition)
+ OB += IsPartition ? ':' : '.';
+ Name->print(OB);
+ }
+};
+
+struct ModuleEntity : Node {
+ ModuleName *Module;
+ Node *Name;
+
+ ModuleEntity(ModuleName *Module_, Node *Name_)
+ : Node(KModuleEntity), Module(Module_), Name(Name_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Module, Name); }
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Name->print(OB);
+ OB += '@';
+ Module->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Encoding->print(OB);
+ OB += "::";
+ Entity->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Qualifier->print(OB);
+ OB += "::";
+ Name->print(OB);
+ }
+};
+
+class VectorType final : public Node {
+ const Node *BaseType;
+ const Node *Dimension;
+
+public:
+ VectorType(const Node *BaseType_, const Node *Dimension_)
+ : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {}
+
+ const Node *getBaseType() const { return BaseType; }
+ const Node *getDimension() const { return Dimension; }
+
+ template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ BaseType->print(OB);
+ OB += " vector[";
+ if (Dimension)
+ Dimension->print(OB);
+ OB += "]";
+ }
+};
+
+class PixelVectorType final : public Node {
+ const Node *Dimension;
+
+public:
+ PixelVectorType(const Node *Dimension_)
+ : Node(KPixelVectorType), Dimension(Dimension_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Dimension); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ // FIXME: This should demangle as "vector pixel".
+ OB += "pixel vector[";
+ Dimension->print(OB);
+ OB += "]";
+ }
+};
+
+class BinaryFPType final : public Node {
+ const Node *Dimension;
+
+public:
+ BinaryFPType(const Node *Dimension_)
+ : Node(KBinaryFPType), Dimension(Dimension_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Dimension); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "_Float";
+ Dimension->print(OB);
+ }
+};
+
+enum class TemplateParamKind { Type, NonType, Template };
+
+/// An invented name for a template parameter for which we don't have a
+/// corresponding template argument.
+///
+/// This node is created when parsing the <lambda-sig> for a lambda with
+/// explicit template arguments, which might be referenced in the parameter
+/// types appearing later in the <lambda-sig>.
+class SyntheticTemplateParamName final : public Node {
+ TemplateParamKind Kind;
+ unsigned Index;
+
+public:
+ SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_)
+ : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Kind, Index); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ switch (Kind) {
+ case TemplateParamKind::Type:
+ OB += "$T";
+ break;
+ case TemplateParamKind::NonType:
+ OB += "$N";
+ break;
+ case TemplateParamKind::Template:
+ OB += "$TT";
+ break;
+ }
+ if (Index > 0)
+ OB << Index - 1;
+ }
+};
+
+/// A template type parameter declaration, 'typename T'.
+class TypeTemplateParamDecl final : public Node {
+ Node *Name;
+
+public:
+ TypeTemplateParamDecl(Node *Name_)
+ : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Name); }
+
+ void printLeft(OutputBuffer &OB) const override { OB += "typename "; }
+
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+};
+
+/// A non-type template parameter declaration, 'int N'.
+class NonTypeTemplateParamDecl final : public Node {
+ Node *Name;
+ Node *Type;
+
+public:
+ NonTypeTemplateParamDecl(Node *Name_, Node *Type_)
+ : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Name, Type); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Type->printLeft(OB);
+ if (!Type->hasRHSComponent(OB))
+ OB += " ";
+ }
+
+ void printRight(OutputBuffer &OB) const override {
+ Name->print(OB);
+ Type->printRight(OB);
+ }
+};
+
+/// A template template parameter declaration,
+/// 'template<typename T> typename N'.
+class TemplateTemplateParamDecl final : public Node {
+ Node *Name;
+ NodeArray Params;
+
+public:
+ TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
+ : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
+ Params(Params_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Name, Params); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "template<";
+ Params.printWithComma(OB);
+ OB += "> typename ";
+ }
+
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+};
+
+/// A template parameter pack declaration, 'typename ...T'.
+class TemplateParamPackDecl final : public Node {
+ Node *Param;
+
+public:
+ TemplateParamPackDecl(Node *Param_)
+ : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Param); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Param->printLeft(OB);
+ OB += "...";
+ }
+
+ void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+};
+
+/// 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 OutputBuffer for a pack expansion, unless we're already expanding
+ // one.
+ void initializePackExpansion(OutputBuffer &OB) const {
+ if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
+ OB.CurrentPackMax = static_cast<unsigned>(Data.size());
+ OB.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(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB);
+ }
+ bool hasArraySlow(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasArray(OB);
+ }
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasFunction(OB);
+ }
+ const Node *getSyntaxNode(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this;
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printLeft(OB);
+ }
+ void printRight(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printRight(OB);
+ }
+};
+
+/// 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(OutputBuffer &OB) const override {
+ Elements.printWithComma(OB);
+ }
+};
+
+/// 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(OutputBuffer &OB) const override {
+ constexpr unsigned Max = std::numeric_limits<unsigned>::max();
+ ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
+ ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max);
+ size_t StreamPos = OB.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(OB);
+
+ // No ParameterPack was found in Child. This can occur if we've found a pack
+ // expansion on a <function-param>.
+ if (OB.CurrentPackMax == Max) {
+ OB += "...";
+ return;
+ }
+
+ // We found a ParameterPack, but it has no elements. Erase whatever we may
+ // of printed.
+ if (OB.CurrentPackMax == 0) {
+ OB.setCurrentPosition(StreamPos);
+ return;
+ }
+
+ // Else, iterate through the rest of the elements in the pack.
+ for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) {
+ OB += ", ";
+ OB.CurrentPackIndex = I;
+ Child->print(OB);
+ }
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ Params.printWithComma(OB);
+ OB += ">";
+ }
+};
+
+/// 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(OutputBuffer &OB) const override {
+ if (Printing)
+ return false;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasRHSComponent(OB);
+ }
+ bool hasArraySlow(OutputBuffer &OB) const override {
+ if (Printing)
+ return false;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasArray(OB);
+ }
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
+ if (Printing)
+ return false;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasFunction(OB);
+ }
+ const Node *getSyntaxNode(OutputBuffer &OB) const override {
+ if (Printing)
+ return this;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->getSyntaxNode(OB);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Printing)
+ return;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ Ref->printLeft(OB);
+ }
+ void printRight(OutputBuffer &OB) const override {
+ if (Printing)
+ return;
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ Ref->printRight(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ Name->print(OB);
+ TemplateArgs->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "::";
+ Child->print(OB);
+ }
+};
+
+enum class SpecialSubKind {
+ allocator,
+ basic_string,
+ string,
+ istream,
+ ostream,
+ iostream,
+};
+
+class SpecialSubstitution;
+class ExpandedSpecialSubstitution : public Node {
+protected:
+ SpecialSubKind SSK;
+
+ ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_)
+ : Node(K_), SSK(SSK_) {}
+public:
+ ExpandedSpecialSubstitution(SpecialSubKind SSK_)
+ : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {}
+ inline ExpandedSpecialSubstitution(SpecialSubstitution const *);
+
+ template<typename Fn> void match(Fn F) const { F(SSK); }
+
+protected:
+ bool isInstantiation() const {
+ return unsigned(SSK) >= unsigned(SpecialSubKind::string);
+ }
+
+ 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");
+ }
+ DEMANGLE_UNREACHABLE;
+ }
+
+private:
+ void printLeft(OutputBuffer &OB) const override {
+ OB << "std::" << getBaseName();
+ if (isInstantiation()) {
+ OB << "<char, std::char_traits<char>";
+ if (SSK == SpecialSubKind::string)
+ OB << ", std::allocator<char>";
+ OB << ">";
+ }
+ }
+};
+
+class SpecialSubstitution final : public ExpandedSpecialSubstitution {
+public:
+ SpecialSubstitution(SpecialSubKind SSK_)
+ : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {}
+
+ template<typename Fn> void match(Fn F) const { F(SSK); }
+
+ StringView getBaseName() const override {
+ auto SV = ExpandedSpecialSubstitution::getBaseName ();
+ if (isInstantiation()) {
+ // The instantiations are typedefs that drop the "basic_" prefix.
+ assert(SV.startsWith("basic_"));
+ SV = SV.dropFront(sizeof("basic_") - 1);
+ }
+ return SV;
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB << "std::" << getBaseName();
+ }
+};
+
+inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution(
+ SpecialSubstitution const *SS)
+ : ExpandedSpecialSubstitution(SS->SSK) {}
+
+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(OutputBuffer &OB) const override {
+ if (IsDtor)
+ OB += "~";
+ OB += 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(OutputBuffer &OB) const override {
+ OB += "~";
+ Base->printLeft(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "'unnamed";
+ OB += Count;
+ OB += "\'";
+ }
+};
+
+class ClosureTypeName : public Node {
+ NodeArray TemplateParams;
+ NodeArray Params;
+ StringView Count;
+
+public:
+ ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
+ StringView Count_)
+ : Node(KClosureTypeName), TemplateParams(TemplateParams_),
+ Params(Params_), Count(Count_) {}
+
+ template<typename Fn> void match(Fn F) const {
+ F(TemplateParams, Params, Count);
+ }
+
+ void printDeclarator(OutputBuffer &OB) const {
+ if (!TemplateParams.empty()) {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ TemplateParams.printWithComma(OB);
+ OB += ">";
+ }
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "\'lambda";
+ OB += Count;
+ OB += "\'";
+ printDeclarator(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB.printOpen('[');
+ Bindings.printWithComma(OB);
+ OB.printClose(']');
+ }
+};
+
+// -- 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_,
+ Prec Prec_)
+ : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_),
+ RHS(RHS_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(LHS, InfixOperator, RHS, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ bool ParenAll = OB.isGtInsideTemplateArgs() &&
+ (InfixOperator == ">" || InfixOperator == ">>");
+ if (ParenAll)
+ OB.printOpen();
+ // Assignment is right associative, with special LHS precedence.
+ bool IsAssign = getPrecedence() == Prec::Assign;
+ LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign);
+ // No space before comma operator
+ if (!(InfixOperator == ","))
+ OB += " ";
+ OB += InfixOperator;
+ OB += " ";
+ RHS->printAsOperand(OB, getPrecedence(), IsAssign);
+ if (ParenAll)
+ OB.printClose();
+ }
+};
+
+class ArraySubscriptExpr : public Node {
+ const Node *Op1;
+ const Node *Op2;
+
+public:
+ ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_)
+ : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Op1, Op2, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Op1->printAsOperand(OB, getPrecedence());
+ OB.printOpen('[');
+ Op2->printAsOperand(OB);
+ OB.printClose(']');
+ }
+};
+
+class PostfixExpr : public Node {
+ const Node *Child;
+ const StringView Operator;
+
+public:
+ PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_)
+ : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Child, Operator, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Child->printAsOperand(OB, getPrecedence(), true);
+ OB += 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_,
+ Prec Prec_)
+ : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Cond, Then, Else, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Cond->printAsOperand(OB, getPrecedence());
+ OB += " ? ";
+ Then->printAsOperand(OB);
+ OB += " : ";
+ Else->printAsOperand(OB, Prec::Assign, true);
+ }
+};
+
+class MemberExpr : public Node {
+ const Node *LHS;
+ const StringView Kind;
+ const Node *RHS;
+
+public:
+ MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_)
+ : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(LHS, Kind, RHS, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ LHS->printAsOperand(OB, getPrecedence(), true);
+ OB += Kind;
+ RHS->printAsOperand(OB, getPrecedence(), false);
+ }
+};
+
+class SubobjectExpr : public Node {
+ const Node *Type;
+ const Node *SubExpr;
+ StringView Offset;
+ NodeArray UnionSelectors;
+ bool OnePastTheEnd;
+
+public:
+ SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_,
+ NodeArray UnionSelectors_, bool OnePastTheEnd_)
+ : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_),
+ UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {}
+
+ template<typename Fn> void match(Fn F) const {
+ F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ SubExpr->print(OB);
+ OB += ".<";
+ Type->print(OB);
+ OB += " at offset ";
+ if (Offset.empty()) {
+ OB += "0";
+ } else if (Offset[0] == 'n') {
+ OB += "-";
+ OB += Offset.dropFront();
+ } else {
+ OB += Offset;
+ }
+ OB += ">";
+ }
+};
+
+class EnclosingExpr : public Node {
+ const StringView Prefix;
+ const Node *Infix;
+ const StringView Postfix;
+
+public:
+ EnclosingExpr(StringView Prefix_, const Node *Infix_,
+ Prec Prec_ = Prec::Primary)
+ : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Infix, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += Prefix;
+ OB.printOpen();
+ Infix->print(OB);
+ OB.printClose();
+ OB += 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_, Prec Prec_)
+ : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(CastKind, To, From, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += CastKind;
+ {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ To->printLeft(OB);
+ OB += ">";
+ }
+ OB.printOpen();
+ From->printAsOperand(OB);
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "sizeof...";
+ OB.printOpen();
+ ParameterPackExpansion PPE(Pack);
+ PPE.printLeft(OB);
+ OB.printClose();
+ }
+};
+
+class CallExpr : public Node {
+ const Node *Callee;
+ NodeArray Args;
+
+public:
+ CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_)
+ : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Callee, Args, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Callee->print(OB);
+ OB.printOpen();
+ Args.printWithComma(OB);
+ OB.printClose();
+ }
+};
+
+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_, Prec Prec_)
+ : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_),
+ InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+
+ template<typename Fn> void match(Fn F) const {
+ F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (IsGlobal)
+ OB += "::";
+ OB += "new";
+ if (IsArray)
+ OB += "[]";
+ if (!ExprList.empty()) {
+ OB.printOpen();
+ ExprList.printWithComma(OB);
+ OB.printClose();
+ }
+ OB += " ";
+ Type->print(OB);
+ if (!InitList.empty()) {
+ OB.printOpen();
+ InitList.printWithComma(OB);
+ OB.printClose();
+ }
+ }
+};
+
+class DeleteExpr : public Node {
+ Node *Op;
+ bool IsGlobal;
+ bool IsArray;
+
+public:
+ DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_)
+ : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_),
+ IsArray(IsArray_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Op, IsGlobal, IsArray, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (IsGlobal)
+ OB += "::";
+ OB += "delete";
+ if (IsArray)
+ OB += "[]";
+ OB += ' ';
+ Op->print(OB);
+ }
+};
+
+class PrefixExpr : public Node {
+ StringView Prefix;
+ Node *Child;
+
+public:
+ PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_)
+ : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Child, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += Prefix;
+ Child->printAsOperand(OB, getPrecedence());
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "fp";
+ OB += Number;
+ }
+};
+
+class ConversionExpr : public Node {
+ const Node *Type;
+ NodeArray Expressions;
+
+public:
+ ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_)
+ : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Type, Expressions, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Type->print(OB);
+ OB.printClose();
+ OB.printOpen();
+ Expressions.printWithComma(OB);
+ OB.printClose();
+ }
+};
+
+class PointerToMemberConversionExpr : public Node {
+ const Node *Type;
+ const Node *SubExpr;
+ StringView Offset;
+
+public:
+ PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
+ StringView Offset_, Prec Prec_)
+ : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_),
+ SubExpr(SubExpr_), Offset(Offset_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Type, SubExpr, Offset, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Type->print(OB);
+ OB.printClose();
+ OB.printOpen();
+ SubExpr->print(OB);
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ if (Ty)
+ Ty->print(OB);
+ OB += '{';
+ Inits.printWithComma(OB);
+ OB += '}';
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ if (IsArray) {
+ OB += '[';
+ Elem->print(OB);
+ OB += ']';
+ } else {
+ OB += '.';
+ Elem->print(OB);
+ }
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ OB += " = ";
+ Init->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += '[';
+ First->print(OB);
+ OB += " ... ";
+ Last->print(OB);
+ OB += ']';
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ OB += " = ";
+ Init->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ auto PrintPack = [&] {
+ OB.printOpen();
+ ParameterPackExpansion(Pack).print(OB);
+ OB.printClose();
+ };
+
+ OB.printOpen();
+ // Either '[init op ]... op pack' or 'pack op ...[ op init]'
+ // Refactored to '[(init|pack) op ]...[ op (pack|init)]'
+ // Fold expr operands are cast-expressions
+ if (!IsLeftFold || Init != nullptr) {
+ // '(init|pack) op '
+ if (IsLeftFold)
+ Init->printAsOperand(OB, Prec::Cast, true);
+ else
+ PrintPack();
+ OB << " " << OperatorName << " ";
+ }
+ OB << "...";
+ if (IsLeftFold || Init != nullptr) {
+ // ' op (init|pack)'
+ OB << " " << OperatorName << " ";
+ if (IsLeftFold)
+ PrintPack();
+ else
+ Init->printAsOperand(OB, Prec::Cast, true);
+ }
+ OB.printClose();
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += "throw ";
+ Op->print(OB);
+ }
+};
+
+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(OutputBuffer &OB) const override {
+ OB += Value ? StringView("true") : StringView("false");
+ }
+};
+
+class StringLiteral : public Node {
+ const Node *Type;
+
+public:
+ StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "\"<";
+ Type->print(OB);
+ OB += ">\"";
+ }
+};
+
+class LambdaExpr : public Node {
+ const Node *Type;
+
+public:
+ LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "[]";
+ if (Type->getKind() == KClosureTypeName)
+ static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB);
+ OB += "{...}";
+ }
+};
+
+class EnumLiteral : public Node {
+ // ty(integer)
+ const Node *Ty;
+ StringView Integer;
+
+public:
+ EnumLiteral(const Node *Ty_, StringView Integer_)
+ : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Ty->print(OB);
+ OB.printClose();
+
+ if (Integer[0] == 'n')
+ OB << "-" << Integer.dropFront(1);
+ else
+ OB << 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(OutputBuffer &OB) const override {
+ if (Type.size() > 3) {
+ OB.printOpen();
+ OB += Type;
+ OB.printClose();
+ }
+
+ if (Value[0] == 'n') {
+ OB += '-';
+ OB += Value.dropFront(1);
+ } else
+ OB += Value;
+
+ if (Type.size() <= 3)
+ OB += 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(OutputBuffer &OB) 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);
+ OB += 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 NODE(X) \
+ case K##X: \
+ return F(static_cast<const X *>(this));
+#include "ItaniumNodes.def"
+ }
+ assert(0 && "unknown mangling node kind");
+}
+
+/// Determine the kind of a node from its type.
+template<typename NodeT> struct NodeKind;
+#define NODE(X) \
+ template <> struct NodeKind<X> { \
+ static constexpr Node::Kind Kind = Node::K##X; \
+ static constexpr const char *name() { return #X; } \
+ };
+#include "ItaniumNodes.def"
+
+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;
+
+ using TemplateParamList = PODSmallVector<Node *, 8>;
+
+ class ScopedTemplateParamList {
+ AbstractManglingParser *Parser;
+ size_t OldNumTemplateParamLists;
+ TemplateParamList Params;
+
+ public:
+ ScopedTemplateParamList(AbstractManglingParser *TheParser)
+ : Parser(TheParser),
+ OldNumTemplateParamLists(TheParser->TemplateParams.size()) {
+ Parser->TemplateParams.push_back(&Params);
+ }
+ ~ScopedTemplateParamList() {
+ assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
+ Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
+ }
+ };
+
+ // 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.
+ TemplateParamList OuterTemplateParams;
+
+ // Lists of template parameters indexed by template parameter depth,
+ // referenced like "TL2_4_". If nonempty, element 0 is always
+ // OuterTemplateParams; inner elements are always template parameter lists of
+ // lambda expressions. For a generic lambda with no explicit template
+ // parameter list, the corresponding parameter list pointer will be null.
+ PODSmallVector<TemplateParamList *, 4> 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;
+
+ bool TryToParseTemplateArgs = true;
+ bool PermitForwardTemplateReferences = false;
+ size_t ParsingLambdaParamsAtLevel = (size_t)-1;
+
+ unsigned NumSyntheticTemplateParameters[3] = {};
+
+ 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();
+ ParsingLambdaParamsAtLevel = (size_t)-1;
+ TryToParseTemplateArgs = true;
+ PermitForwardTemplateReferences = false;
+ for (int I = 0; I != 3; ++I)
+ NumSyntheticTemplateParameters[I] = 0;
+ 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) const {
+ 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 *parseTemplateParamDecl();
+ Node *parseTemplateArgs(bool TagTemplates = false);
+ Node *parseTemplateArg();
+
+ /// Parse the <expr> production.
+ Node *parseExpr();
+ Node *parsePrefixExpr(StringView Kind, Node::Prec Prec);
+ Node *parseBinaryExpr(StringView Kind, Node::Prec Prec);
+ Node *parseIntegerLiteral(StringView Lit);
+ Node *parseExprPrimary();
+ template <class Float> Node *parseFloatingLiteral();
+ Node *parseFunctionParam();
+ Node *parseConversionExpr();
+ Node *parseBracedExpr();
+ Node *parseFoldExpr();
+ Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
+ Node *parseSubobjectExpr();
+
+ /// 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 (TemplateParams.empty() || !TemplateParams[0] ||
+ Idx >= TemplateParams[0]->size())
+ return true;
+ ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
+ }
+ ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+ return false;
+ }
+
+ /// Parse the <name> production>
+ Node *parseName(NameState *State = nullptr);
+ Node *parseLocalName(NameState *State);
+ Node *parseOperatorName(NameState *State);
+ bool parseModuleNameOpt(ModuleName *&Module);
+ Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module);
+ Node *parseUnnamedTypeName(NameState *State);
+ Node *parseSourceName(NameState *State);
+ Node *parseUnscopedName(NameState *State, bool *isSubstName);
+ Node *parseNestedName(NameState *State);
+ Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
+ Node *parseAbiTags(Node *N);
+
+ struct OperatorInfo {
+ enum OIKind : unsigned char {
+ Prefix, // Prefix unary: @ expr
+ Postfix, // Postfix unary: expr @
+ Binary, // Binary: lhs @ rhs
+ Array, // Array index: lhs [ rhs ]
+ Member, // Member access: lhs @ rhs
+ New, // New
+ Del, // Delete
+ Call, // Function call: expr (expr*)
+ CCast, // C cast: (type)expr
+ Conditional, // Conditional: expr ? expr : expr
+ NameOnly, // Overload only, not allowed in expression.
+ // Below do not have operator names
+ NamedCast, // Named cast, @<type>(expr)
+ OfIdOp, // alignof, sizeof, typeid
+
+ Unnameable = NamedCast,
+ };
+ char Enc[2]; // Encoding
+ OIKind Kind; // Kind of operator
+ bool Flag : 1; // Entry-specific flag
+ Node::Prec Prec : 7; // Precedence
+ const char *Name; // Spelling
+
+ public:
+ constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P,
+ const char *N)
+ : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {}
+
+ public:
+ bool operator<(const OperatorInfo &Other) const {
+ return *this < Other.Enc;
+ }
+ bool operator<(const char *Peek) const {
+ return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
+ }
+ bool operator==(const char *Peek) const {
+ return Enc[0] == Peek[0] && Enc[1] == Peek[1];
+ }
+ bool operator!=(const char *Peek) const { return !this->operator==(Peek); }
+
+ public:
+ StringView getSymbol() const {
+ StringView Res = Name;
+ if (Kind < Unnameable) {
+ assert(Res.startsWith("operator") &&
+ "operator name does not start with 'operator'");
+ Res = Res.dropFront(sizeof("operator") - 1);
+ Res.consumeFront(' ');
+ }
+ return Res;
+ }
+ StringView getName() const { return Name; }
+ OIKind getKind() const { return Kind; }
+ bool getFlag() const { return Flag; }
+ Node::Prec getPrecedence() const { return Prec; }
+ };
+ static const OperatorInfo Ops[];
+ static const size_t NumOps;
+ const OperatorInfo *parseOperatorEncoding();
+
+ /// Parse the <unresolved-name> production.
+ Node *parseUnresolvedName(bool Global);
+ 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) {
+ if (look() == 'N')
+ return getDerived().parseNestedName(State);
+ if (look() == 'Z')
+ return getDerived().parseLocalName(State);
+
+ Node *Result = nullptr;
+ bool IsSubst = false;
+
+ Result = getDerived().parseUnscopedName(State, &IsSubst);
+ if (!Result)
+ return nullptr;
+
+ if (look() == 'I') {
+ // ::= <unscoped-template-name> <template-args>
+ if (!IsSubst)
+ // An unscoped-template-name is substitutable.
+ Subs.push_back(Result);
+ Node *TA = getDerived().parseTemplateArgs(State != nullptr);
+ if (TA == nullptr)
+ return nullptr;
+ if (State)
+ State->EndsWithTemplateArgs = true;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else if (IsSubst) {
+ // The substitution case must be followed by <template-args>.
+ return nullptr;
+ }
+
+ return Result;
+}
+
+// <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
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
+ bool *IsSubst) {
+
+ Node *Std = nullptr;
+ if (consumeIf("St")) {
+ Std = make<NameType>("std");
+ if (Std == nullptr)
+ return nullptr;
+ }
+
+ Node *Res = nullptr;
+ ModuleName *Module = nullptr;
+ if (look() == 'S') {
+ Node *S = getDerived().parseSubstitution();
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName)
+ Module = static_cast<ModuleName *>(S);
+ else if (IsSubst && Std == nullptr) {
+ Res = S;
+ *IsSubst = true;
+ } else {
+ return nullptr;
+ }
+ }
+
+ if (Res == nullptr || Std != nullptr) {
+ Res = getDerived().parseUnqualifiedName(State, Std, Module);
+ }
+
+ return Res;
+}
+
+// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
+// ::= [<module-name>] L? <source-name> [<abi-tags>]
+// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
+// # structured binding declaration
+// ::= [<module-name>] L? DC <source-name>+ E
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
+ NameState *State, Node *Scope, ModuleName *Module) {
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+
+ consumeIf('L');
+
+ Node *Result;
+ if (look() >= '1' && look() <= '9') {
+ Result = getDerived().parseSourceName(State);
+ } else if (look() == 'U') {
+ Result = getDerived().parseUnnamedTypeName(State);
+ } else if (consumeIf("DC")) {
+ // Structured binding
+ 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 if (look() == 'C' || look() == 'D') {
+ // A <ctor-dtor-name>.
+ if (Scope == nullptr || Module != nullptr)
+ return nullptr;
+ Result = getDerived().parseCtorDtorName(Scope, State);
+ } else {
+ Result = getDerived().parseOperatorName(State);
+ }
+
+ if (Result != nullptr && Module != nullptr)
+ Result = make<ModuleEntity>(Module, Result);
+ if (Result != nullptr)
+ Result = getDerived().parseAbiTags(Result);
+ if (Result != nullptr && Scope != nullptr)
+ Result = make<NestedName>(Scope, Result);
+
+ return Result;
+}
+
+// <module-name> ::= <module-subname>
+// ::= <module-name> <module-subname>
+// ::= <substitution> # passed in by caller
+// <module-subname> ::= W <source-name>
+// ::= W P <source-name>
+template <typename Derived, typename Alloc>
+bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
+ ModuleName *&Module) {
+ while (consumeIf('W')) {
+ bool IsPartition = consumeIf('P');
+ Node *Sub = getDerived().parseSourceName(nullptr);
+ if (!Sub)
+ return true;
+ Module =
+ static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition));
+ Subs.push_back(Module);
+ }
+
+ return false;
+}
+
+// <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 *State) {
+ // <template-params> refer to the innermost <template-args>. Clear out any
+ // outer args that we may have inserted into TemplateParams.
+ if (State != nullptr)
+ TemplateParams.clear();
+
+ if (consumeIf("Ut")) {
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<UnnamedTypeName>(Count);
+ }
+ if (consumeIf("Ul")) {
+ ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel,
+ TemplateParams.size());
+ ScopedTemplateParamList LambdaTemplateParams(this);
+
+ size_t ParamsBegin = Names.size();
+ while (look() == 'T' &&
+ StringView("yptn").find(look(1)) != StringView::npos) {
+ Node *T = parseTemplateParamDecl();
+ if (!T)
+ return nullptr;
+ Names.push_back(T);
+ }
+ NodeArray TempParams = popTrailingNodeArray(ParamsBegin);
+
+ // FIXME: If TempParams is empty and none of the function parameters
+ // includes 'auto', we should remove LambdaTemplateParams from the
+ // TemplateParams list. Unfortunately, we don't find out whether there are
+ // any 'auto' parameters until too late in an example such as:
+ //
+ // template<typename T> void f(
+ // decltype([](decltype([]<typename T>(T v) {}),
+ // auto) {})) {}
+ // template<typename T> void f(
+ // decltype([](decltype([]<typename T>(T w) {}),
+ // int) {})) {}
+ //
+ // Here, the type of v is at level 2 but the type of w is at level 1. We
+ // don't find this out until we encounter the type of the next parameter.
+ //
+ // However, compilers can't actually cope with the former example in
+ // practice, and it's likely to be made ill-formed in future, so we don't
+ // need to support it here.
+ //
+ // If we encounter an 'auto' in the function parameter types, we will
+ // recreate a template parameter scope for it, but any intervening lambdas
+ // will be parsed in the 'wrong' template parameter depth.
+ if (TempParams.empty())
+ TemplateParams.pop_back();
+
+ if (!consumeIf("vE")) {
+ do {
+ Node *P = getDerived().parseType();
+ if (P == nullptr)
+ return nullptr;
+ Names.push_back(P);
+ } while (!consumeIf('E'));
+ }
+ NodeArray Params = popTrailingNodeArray(ParamsBegin);
+
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<ClosureTypeName>(TempParams, Params, Count);
+ }
+ if (consumeIf("Ub")) {
+ (void)parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<NameType>("'block-literal'");
+ }
+ 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 encodings
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<
+ Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
+ Alloc>::Ops[] = {
+ // Keep ordered by encoding
+ {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
+ {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
+ {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
+ {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
+ {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
+ {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
+ {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
+ "operator co_await"},
+ {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
+ {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
+ {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+ {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
+ {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
+ {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
+ {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
+ {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
+ "operator delete[]"},
+ {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
+ {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
+ {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
+ "operator delete"},
+ {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator.*"},
+ {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix,
+ "operator."},
+ {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"},
+ {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="},
+ {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"},
+ {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="},
+ {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="},
+ {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"},
+ {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"},
+ {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="},
+ {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="},
+ {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"},
+ {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"},
+ {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="},
+ {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="},
+ {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"},
+ {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator*"},
+ {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"},
+ {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary,
+ "operator new[]"},
+ {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
+ {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
+ {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
+ {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
+ {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
+ {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
+ {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
+ {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="},
+ {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"},
+ {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator->*"},
+ {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"},
+ {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"},
+ {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix,
+ "operator->"},
+ {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional,
+ "operator?"},
+ {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="},
+ {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="},
+ {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix,
+ "reinterpret_cast"},
+ {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator%"},
+ {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
+ {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
+ {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
+ {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
+ {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
+ {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
+ "typeid "},
+ {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
+};
+template <typename Derived, typename Alloc>
+const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
+ sizeof(Ops[0]);
+
+// If the next 2 chars are an operator encoding, consume them and return their
+// OperatorInfo. Otherwise return nullptr.
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
+AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
+ if (numLeft() < 2)
+ return nullptr;
+
+ // We can't use lower_bound as that can link to symbols in the C++ library,
+ // and this must remain independant of that.
+ size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds.
+ while (upper != lower) {
+ size_t middle = (upper + lower) / 2;
+ if (Ops[middle] < First)
+ lower = middle + 1;
+ else
+ upper = middle;
+ }
+ if (Ops[lower] != First)
+ return nullptr;
+
+ First += 2;
+ return &Ops[lower];
+}
+
+// <operator-name> ::= See parseOperatorEncoding()
+// ::= li <source-name> # operator ""
+// ::= v <digit> <source-name> # vendor extended operator
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
+ if (const auto *Op = parseOperatorEncoding()) {
+ if (Op->getKind() == OperatorInfo::CCast) {
+ // ::= cv <type> # (cast)
+ ScopedOverride<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.
+ ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences,
+ PermitForwardTemplateReferences ||
+ State != nullptr);
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ if (State) State->CtorDtorConversion = true;
+ return make<ConversionOperatorType>(Ty);
+ }
+
+ if (Op->getKind() >= OperatorInfo::Unnameable)
+ /* Not a nameable operator. */
+ return nullptr;
+ if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
+ /* Not a nameable MemberExpr */
+ return nullptr;
+
+ return make<NameType>(Op->getName());
+ }
+
+ if (consumeIf("li")) {
+ // ::= li <source-name> # operator ""
+ Node *SN = getDerived().parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<LiteralOperator>(SN);
+ }
+
+ if (consumeIf('v')) {
+ // ::= v <digit> <source-name> # vendor extended operator
+ if (look() >= '0' && look() <= '9') {
+ First++;
+ 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 ::= C4 # gcc old-style "[unified]" constructor
+// extension ::= C5 # the COMDAT used for ctors
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D4 # gcc old-style "[unified]" destructor
+// extension ::= D5 # the COMDAT used for dtors
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
+ NameState *State) {
+ if (SoFar->getKind() == Node::KSpecialSubstitution) {
+ // Expand the special substitution.
+ SoFar = make<ExpandedSpecialSubstitution>(
+ static_cast<SpecialSubstitution *>(SoFar));
+ if (!SoFar)
+ return nullptr;
+ }
+
+ if (consumeIf('C')) {
+ bool IsInherited = consumeIf('I');
+ if (look() != '1' && look() != '2' && look() != '3' && look() != '4' &&
+ 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, /*IsDtor=*/false, Variant);
+ }
+
+ if (look() == 'D' && (look(1) == '0' || look(1) == '1' || look(1) == '2' ||
+ look(1) == '4' || look(1) == '5')) {
+ int Variant = look(1) - '0';
+ First += 2;
+ if (State) State->CtorDtorConversion = true;
+ return make<CtorDtorName>(SoFar, /*IsDtor=*/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
+//
+// <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;
+ while (!consumeIf('E')) {
+ if (State)
+ // Only set end-with-template on the case that does that.
+ State->EndsWithTemplateArgs = false;
+
+ if (look() == 'T') {
+ // ::= <template-param>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseTemplateParam();
+ } else if (look() == 'I') {
+ // ::= <template-prefix> <template-args>
+ if (SoFar == nullptr)
+ return nullptr; // Must have a prefix.
+ Node *TA = getDerived().parseTemplateArgs(State != nullptr);
+ if (TA == nullptr)
+ return nullptr;
+ if (SoFar->getKind() == Node::KNameWithTemplateArgs)
+ // Semantically <template-args> <template-args> cannot be generated by a
+ // C++ entity. There will always be [something like] a name between
+ // them.
+ return nullptr;
+ if (State)
+ State->EndsWithTemplateArgs = true;
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+ // ::= <decltype>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseDecltype();
+ } else {
+ ModuleName *Module = nullptr;
+
+ if (look() == 'S') {
+ // ::= <substitution>
+ Node *S = nullptr;
+ if (look(1) == 't') {
+ First += 2;
+ S = make<NameType>("std");
+ } else {
+ S = getDerived().parseSubstitution();
+ }
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName) {
+ Module = static_cast<ModuleName *>(S);
+ } else if (SoFar != nullptr) {
+ return nullptr; // Cannot have a prefix.
+ } else {
+ SoFar = S;
+ continue; // Do not push a new substitution.
+ }
+ }
+
+ // ::= [<prefix>] <unqualified-name>
+ SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module);
+ }
+
+ if (SoFar == nullptr)
+ return nullptr;
+ Subs.push_back(SoFar);
+
+ // No longer used.
+ // <data-member-prefix> := <member source-name> [<template-args>] M
+ consumeIf('M');
+ }
+
+ 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 "::"
+// [gs] has been parsed by caller.
+// ::= 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(bool Global) {
+ 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);
+ }
+
+ // [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') {
+ Node *DimensionNumber = make<NameType>(parseNumber());
+ if (!DimensionNumber)
+ return nullptr;
+ 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, /*Dimension=*/nullptr);
+}
+
+// <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;
+
+ Node *Dimension = nullptr;
+
+ if (std::isdigit(look())) {
+ Dimension = make<NameType>(parseNumber());
+ if (!Dimension)
+ return nullptr;
+ 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;
+
+ // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
+ if (Qual.startsWith("objcproto")) {
+ StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
+ StringView Proto;
+ {
+ ScopedOverride<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 *TA = nullptr;
+ if (look() == 'I') {
+ TA = getDerived().parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ }
+
+ Node *Child = getDerived().parseQualifiedType();
+ if (Child == nullptr)
+ return nullptr;
+ return make<VendorExtQualType>(Child, Qual, TA);
+ }
+
+ 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;
+
+ 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;
+ }
+ DEMANGLE_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;
+ // Typically, <builtin-type>s are not considered substitution candidates,
+ // but the exception to that exception is vendor extended types (Itanium C++
+ // ABI 5.9.1).
+ Result = make<NameType>(Res);
+ break;
+ }
+ 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>("half");
+ // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits)
+ case 'F': {
+ First += 2;
+ Node *DimensionNumber = make<NameType>(parseNumber());
+ if (!DimensionNumber)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<BinaryFPType>(DimensionNumber);
+ }
+ // ::= DB <number> _ # C23 signed _BitInt(N)
+ // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N)
+ // ::= DU <number> _ # C23 unsigned _BitInt(N)
+ // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N)
+ case 'B':
+ case 'U': {
+ bool Signed = look(1) == 'B';
+ First += 2;
+ Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber())
+ : getDerived().parseExpr();
+ if (!Size)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<BitIntType>(Size, Signed);
+ }
+ // ::= Di # char32_t
+ case 'i':
+ First += 2;
+ return make<NameType>("char32_t");
+ // ::= Ds # char16_t
+ case 's':
+ First += 2;
+ return make<NameType>("char16_t");
+ // ::= Du # char8_t (C++2a, not yet in the Itanium spec)
+ case 'u':
+ First += 2;
+ return make<NameType>("char8_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) != 't') {
+ bool IsSubst = false;
+ Result = getDerived().parseUnscopedName(nullptr, &IsSubst);
+ if (!Result)
+ 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 (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) {
+ if (!IsSubst)
+ Subs.push_back(Result);
+ Node *TA = getDerived().parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else if (IsSubst) {
+ // If all we parsed was a substitution, don't re-insert into the
+ // substitution table.
+ return Result;
+ }
+ break;
+ }
+ DEMANGLE_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::Prec Prec) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ return make<PrefixExpr>(Kind, E, Prec);
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind,
+ Node::Prec Prec) {
+ Node *LHS = getDerived().parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = getDerived().parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<BinaryExpr>(LHS, Kind, RHS, Prec);
+}
+
+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
+// ::= fpT # 'this' expression (not part of standard?)
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
+ if (consumeIf("fpT"))
+ return make<NameType>("this");
+ 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;
+}
+
+// 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;
+ {
+ ScopedOverride<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")
+// ::= L <lambda type> E # lambda expression
+// 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;
+#if defined(__powerpc__) || defined(__s390__)
+ // Handle cases where long doubles encoded with e have the same size
+ // and representation as doubles.
+ return getDerived().template parseFloatingLiteral<double>();
+#else
+ return getDerived().template parseFloatingLiteral<long double>();
+#endif
+ case '_':
+ if (consumeIf("_Z")) {
+ Node *R = getDerived().parseEncoding();
+ if (R != nullptr && consumeIf('E'))
+ return R;
+ }
+ return nullptr;
+ case 'A': {
+ Node *T = getDerived().parseType();
+ if (T == nullptr)
+ return nullptr;
+ // FIXME: We need to include the string contents in the mangling.
+ if (consumeIf('E'))
+ return make<StringLiteral>(T);
+ return nullptr;
+ }
+ case 'D':
+ if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E')))
+ return make<NameType>("nullptr");
+ return nullptr;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ return nullptr;
+ case 'U': {
+ // FIXME: Should we support LUb... for block literals?
+ if (look(1) != 'l')
+ return nullptr;
+ Node *T = parseUnnamedTypeName(nullptr);
+ if (!T || !consumeIf('E'))
+ return nullptr;
+ return make<LambdaExpr>(T);
+ }
+ default: {
+ // might be named type
+ Node *T = getDerived().parseType();
+ if (T == nullptr)
+ return nullptr;
+ StringView N = parseNumber(/*AllowNegative=*/true);
+ if (N.empty())
+ return nullptr;
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<EnumLiteral>(T, N);
+ }
+ }
+}
+
+// <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;
+
+ bool IsLeftFold = false, HasInitializer = false;
+ switch (look()) {
+ default:
+ return nullptr;
+ case 'L':
+ IsLeftFold = true;
+ HasInitializer = true;
+ break;
+ case 'R':
+ HasInitializer = true;
+ break;
+ case 'l':
+ IsLeftFold = true;
+ break;
+ case 'r':
+ break;
+ }
+ ++First;
+
+ const auto *Op = parseOperatorEncoding();
+ if (!Op)
+ return nullptr;
+ if (!(Op->getKind() == OperatorInfo::Binary
+ || (Op->getKind() == OperatorInfo::Member
+ && Op->getName().back() == '*')))
+ return nullptr;
+
+ Node *Pack = getDerived().parseExpr();
+ if (Pack == nullptr)
+ return nullptr;
+
+ Node *Init = nullptr;
+ if (HasInitializer) {
+ Init = getDerived().parseExpr();
+ if (Init == nullptr)
+ return nullptr;
+ }
+
+ if (IsLeftFold && Init)
+ std::swap(Pack, Init);
+
+ return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
+}
+
+// <expression> ::= mc <parameter type> <expr> [<offset number>] E
+//
+// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr(
+ Node::Prec Prec) {
+ Node *Ty = getDerived().parseType();
+ if (!Ty)
+ return nullptr;
+ Node *Expr = getDerived().parseExpr();
+ if (!Expr)
+ return nullptr;
+ StringView Offset = getDerived().parseNumber(true);
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec);
+}
+
+// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
+// <union-selector> ::= _ [<number>]
+//
+// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
+ Node *Ty = getDerived().parseType();
+ if (!Ty)
+ return nullptr;
+ Node *Expr = getDerived().parseExpr();
+ if (!Expr)
+ return nullptr;
+ StringView Offset = getDerived().parseNumber(true);
+ size_t SelectorsBegin = Names.size();
+ while (consumeIf('_')) {
+ Node *Selector = make<NameType>(parseNumber());
+ if (!Selector)
+ return nullptr;
+ Names.push_back(Selector);
+ }
+ bool OnePastTheEnd = consumeIf('p');
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<SubobjectExpr>(
+ Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
+}
+
+// <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");
+
+ const auto *Op = parseOperatorEncoding();
+ if (Op) {
+ auto Sym = Op->getSymbol();
+ switch (Op->getKind()) {
+ case OperatorInfo::Binary:
+ // Binary operator: lhs @ rhs
+ return getDerived().parseBinaryExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Prefix:
+ // Prefix unary operator: @ expr
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Postfix: {
+ // Postfix unary operator: expr @
+ if (consumeIf('_'))
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<PostfixExpr>(Ex, Sym, Op->getPrecedence());
+ }
+ case OperatorInfo::Array: {
+ // Array Index: lhs [ rhs ]
+ Node *Base = getDerived().parseExpr();
+ if (Base == nullptr)
+ return nullptr;
+ Node *Index = getDerived().parseExpr();
+ if (Index == nullptr)
+ return nullptr;
+ return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence());
+ }
+ case OperatorInfo::Member: {
+ // Member access lhs @ rhs
+ Node *LHS = getDerived().parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = getDerived().parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence());
+ }
+ case OperatorInfo::New: {
+ // New
+ // # new (expr-list) type [(init)]
+ // [gs] nw <expression>* _ <type> [pi <expression>*] E
+ // # new[] (expr-list) type [(init)]
+ // [gs] na <expression>* _ <type> [pi <expression>*] E
+ 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 nullptr;
+ bool HaveInits = consumeIf("pi");
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ if (!HaveInits)
+ return nullptr;
+ 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=*/Op->getFlag(), Op->getPrecedence());
+ }
+ case OperatorInfo::Del: {
+ // Delete
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(),
+ Op->getPrecedence());
+ }
+ case OperatorInfo::Call: {
+ // Function Call
+ Node *Callee = getDerived().parseExpr();
+ if (Callee == nullptr)
+ return nullptr;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
+ Op->getPrecedence());
+ }
+ case OperatorInfo::CCast: {
+ // C Cast: (type)expr
+ Node *Ty;
+ {
+ ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = getDerived().parseType();
+ }
+ if (Ty == nullptr)
+ return nullptr;
+
+ size_t ExprsBegin = Names.size();
+ bool IsMany = consumeIf('_');
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ if (!IsMany)
+ break;
+ }
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ if (!IsMany && Exprs.size() != 1)
+ return nullptr;
+ return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence());
+ }
+ case OperatorInfo::Conditional: {
+ // Conditional operator: expr ? expr : expr
+ 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, Op->getPrecedence());
+ }
+ case OperatorInfo::NamedCast: {
+ // Named cast operation, @<type>(expr)
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence());
+ }
+ case OperatorInfo::OfIdOp: {
+ // [sizeof/alignof/typeid] ( <type>|<expr> )
+ Node *Arg =
+ Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
+ if (!Arg)
+ return nullptr;
+ return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence());
+ }
+ case OperatorInfo::NameOnly: {
+ // Not valid as an expression operand.
+ return nullptr;
+ }
+ }
+ DEMANGLE_UNREACHABLE;
+ }
+
+ if (numLeft() < 2)
+ return nullptr;
+
+ if (look() == 'L')
+ return getDerived().parseExprPrimary();
+ if (look() == 'T')
+ return getDerived().parseTemplateParam();
+ if (look() == '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();
+ }
+ if (consumeIf("il")) {
+ 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));
+ }
+ if (consumeIf("mc"))
+ return parsePointerToMemberConversionExpr(Node::Prec::Unary);
+ if (consumeIf("nx")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
+ }
+ if (consumeIf("so"))
+ return parseSubobjectExpr();
+ if (consumeIf("sp")) {
+ Node *Child = getDerived().parseExpr();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ParameterPackExpansion>(Child);
+ }
+ if (consumeIf("sZ")) {
+ if (look() == 'T') {
+ Node *R = getDerived().parseTemplateParam();
+ if (R == nullptr)
+ return nullptr;
+ return make<SizeofParamPackExpr>(R);
+ }
+ Node *FP = getDerived().parseFunctionParam();
+ if (FP == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... ", FP);
+ }
+ if (consumeIf("sP")) {
+ 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);
+ }
+ if (consumeIf("tl")) {
+ 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));
+ }
+ if (consumeIf("tr"))
+ return make<NameType>("throw");
+ if (consumeIf("tw")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<ThrowExpr>(Ex);
+ }
+ if (consumeIf('u')) {
+ Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
+ if (!Name)
+ return nullptr;
+ // Special case legacy __uuidof mangling. The 't' and 'z' appear where the
+ // standard encoding expects a <template-arg>, and would be otherwise be
+ // interpreted as <type> node 'short' or 'ellipsis'. However, neither
+ // __uuidof(short) nor __uuidof(...) can actually appear, so there is no
+ // actual conflict here.
+ bool IsUUID = false;
+ Node *UUID = nullptr;
+ if (Name->getBaseName() == "__uuidof") {
+ if (consumeIf('t')) {
+ UUID = getDerived().parseType();
+ IsUUID = true;
+ } else if (consumeIf('z')) {
+ UUID = getDerived().parseExpr();
+ IsUUID = true;
+ }
+ }
+ size_t ExprsBegin = Names.size();
+ if (IsUUID) {
+ if (UUID == nullptr)
+ return nullptr;
+ Names.push_back(UUID);
+ } else {
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseTemplateArg();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ }
+ return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
+ Node::Prec::Postfix);
+ }
+
+ // Only unresolved names remain.
+ return getDerived().parseUnresolvedName(Global);
+}
+
+// <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
+// # Guard variable for one-time initialization
+// ::= GV <object name>
+// # 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
+// # construction vtable for second-in-first
+// extension ::= TC <first type> <number> _ <second type>
+// extension ::= GR <object name> # reference temporary for object
+// extension ::= GI <module name> # module global initializer
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
+ switch (look()) {
+ case 'T':
+ switch (look(1)) {
+ // TA <template-arg> # template parameter object
+ //
+ // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63
+ case 'A': {
+ First += 2;
+ Node *Arg = getDerived().parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ return make<SpecialName>("template parameter object for ", Arg);
+ }
+ // 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);
+ }
+ // GI <module-name> v
+ case 'I': {
+ First += 2;
+ ModuleName *Module = nullptr;
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+ if (Module == nullptr)
+ return nullptr;
+ return make<SpecialName>("initializer for module ", Module);
+ }
+ }
+ }
+ return nullptr;
+}
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+ // The template parameters of an encoding are unrelated to those of the
+ // enclosing context.
+ class SaveTemplateParams {
+ AbstractManglingParser *Parser;
+ decltype(TemplateParams) OldParams;
+ decltype(OuterTemplateParams) OldOuterParams;
+
+ public:
+ SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
+ OldParams = std::move(Parser->TemplateParams);
+ OldOuterParams = std::move(Parser->OuterTemplateParams);
+ Parser->TemplateParams.clear();
+ Parser->OuterTemplateParams.clear();
+ }
+ ~SaveTemplateParams() {
+ Parser->TemplateParams = std::move(OldParams);
+ Parser->OuterTemplateParams = std::move(OldOuterParams);
+ }
+ } SaveTemplateParams(this);
+
+ 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__) || defined(__riscv)
+ 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
+ // `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes.
+ // 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits.
+ // Negatives are one character longer than positives.
+ // `0x1.` and `p` are constant, and exponents `+16383` and `-16382` are the
+ // same length. 1 sign bit, 112 mantissa bits, and 15 exponent bits == 128.
+ static const size_t max_demangled_size = 42;
+ 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> >
+// The St case is handled specially in parseNestedName.
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
+ if (!consumeIf('S'))
+ return nullptr;
+
+ if (look() >= 'a' && look() <= 'z') {
+ SpecialSubKind Kind;
+ switch (look()) {
+ case 'a':
+ Kind = SpecialSubKind::allocator;
+ break;
+ case 'b':
+ Kind = SpecialSubKind::basic_string;
+ break;
+ case 'd':
+ Kind = SpecialSubKind::iostream;
+ break;
+ case 'i':
+ Kind = SpecialSubKind::istream;
+ break;
+ case 'o':
+ Kind = SpecialSubKind::ostream;
+ break;
+ case 's':
+ Kind = SpecialSubKind::string;
+ break;
+ default:
+ return nullptr;
+ }
+ ++First;
+ auto *SpecialSub = make<SpecialSubstitution>(Kind);
+ 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> _
+// ::= TL <level-1> __
+// ::= TL <level-1> _ <parameter-2 non-negative number> _
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
+ if (!consumeIf('T'))
+ return nullptr;
+
+ size_t Level = 0;
+ if (consumeIf('L')) {
+ if (parsePositiveInteger(&Level))
+ return nullptr;
+ ++Level;
+ if (!consumeIf('_'))
+ return nullptr;
+ }
+
+ size_t Index = 0;
+ if (!consumeIf('_')) {
+ if (parsePositiveInteger(&Index))
+ return nullptr;
+ ++Index;
+ if (!consumeIf('_'))
+ return nullptr;
+ }
+
+ // 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.
+ // This can only happen at the outermost level.
+ if (PermitForwardTemplateReferences && Level == 0) {
+ Node *ForwardRef = make<ForwardTemplateReference>(Index);
+ if (!ForwardRef)
+ return nullptr;
+ assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
+ ForwardTemplateRefs.push_back(
+ static_cast<ForwardTemplateReference *>(ForwardRef));
+ return ForwardRef;
+ }
+
+ if (Level >= TemplateParams.size() || !TemplateParams[Level] ||
+ Index >= TemplateParams[Level]->size()) {
+ // 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 (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) {
+ // This will be popped by the ScopedTemplateParamList in
+ // parseUnnamedTypeName.
+ if (Level == TemplateParams.size())
+ TemplateParams.push_back(nullptr);
+ return make<NameType>("auto");
+ }
+
+ return nullptr;
+ }
+
+ return (*TemplateParams[Level])[Index];
+}
+
+// <template-param-decl> ::= Ty # type parameter
+// ::= Tn <type> # non-type parameter
+// ::= Tt <template-param-decl>* E # template parameter
+// ::= Tp <template-param-decl> # parameter pack
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
+ auto InventTemplateParamName = [&](TemplateParamKind Kind) {
+ unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
+ Node *N = make<SyntheticTemplateParamName>(Kind, Index);
+ if (N) TemplateParams.back()->push_back(N);
+ return N;
+ };
+
+ if (consumeIf("Ty")) {
+ Node *Name = InventTemplateParamName(TemplateParamKind::Type);
+ if (!Name)
+ return nullptr;
+ return make<TypeTemplateParamDecl>(Name);
+ }
+
+ if (consumeIf("Tn")) {
+ Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
+ if (!Name)
+ return nullptr;
+ Node *Type = parseType();
+ if (!Type)
+ return nullptr;
+ return make<NonTypeTemplateParamDecl>(Name, Type);
+ }
+
+ if (consumeIf("Tt")) {
+ Node *Name = InventTemplateParamName(TemplateParamKind::Template);
+ if (!Name)
+ return nullptr;
+ size_t ParamsBegin = Names.size();
+ ScopedTemplateParamList TemplateTemplateParamParams(this);
+ while (!consumeIf("E")) {
+ Node *P = parseTemplateParamDecl();
+ if (!P)
+ return nullptr;
+ Names.push_back(P);
+ }
+ NodeArray Params = popTrailingNodeArray(ParamsBegin);
+ return make<TemplateTemplateParamDecl>(Name, Params);
+ }
+
+ if (consumeIf("Tp")) {
+ Node *P = parseTemplateParamDecl();
+ if (!P)
+ return nullptr;
+ return make<TemplateParamPackDecl>(P);
+ }
+
+ return nullptr;
+}
+
+// <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();
+ TemplateParams.push_back(&OuterTemplateParams);
+ OuterTemplateParams.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.back()->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") || 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") || 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;
+};
+
+DEMANGLE_NAMESPACE_END
+
+#endif // DEMANGLE_ITANIUMDEMANGLE_H
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def
new file mode 100644
index 00000000..c0e277d5
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def
@@ -0,0 +1,95 @@
+//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
+// Do not edit! See README.txt.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Define the demangler's node names
+
+#ifndef NODE
+#error Define NODE to handle nodes
+#endif
+
+NODE(NodeArrayNode)
+NODE(DotSuffix)
+NODE(VendorExtQualType)
+NODE(QualType)
+NODE(ConversionOperatorType)
+NODE(PostfixQualifiedType)
+NODE(ElaboratedTypeSpefType)
+NODE(NameType)
+NODE(AbiTagAttr)
+NODE(EnableIfAttr)
+NODE(ObjCProtoName)
+NODE(PointerType)
+NODE(ReferenceType)
+NODE(PointerToMemberType)
+NODE(ArrayType)
+NODE(FunctionType)
+NODE(NoexceptSpec)
+NODE(DynamicExceptionSpec)
+NODE(FunctionEncoding)
+NODE(LiteralOperator)
+NODE(SpecialName)
+NODE(CtorVtableSpecialName)
+NODE(QualifiedName)
+NODE(NestedName)
+NODE(LocalName)
+NODE(ModuleName)
+NODE(ModuleEntity)
+NODE(VectorType)
+NODE(PixelVectorType)
+NODE(BinaryFPType)
+NODE(BitIntType)
+NODE(SyntheticTemplateParamName)
+NODE(TypeTemplateParamDecl)
+NODE(NonTypeTemplateParamDecl)
+NODE(TemplateTemplateParamDecl)
+NODE(TemplateParamPackDecl)
+NODE(ParameterPack)
+NODE(TemplateArgumentPack)
+NODE(ParameterPackExpansion)
+NODE(TemplateArgs)
+NODE(ForwardTemplateReference)
+NODE(NameWithTemplateArgs)
+NODE(GlobalQualifiedName)
+NODE(ExpandedSpecialSubstitution)
+NODE(SpecialSubstitution)
+NODE(CtorDtorName)
+NODE(DtorName)
+NODE(UnnamedTypeName)
+NODE(ClosureTypeName)
+NODE(StructuredBindingName)
+NODE(BinaryExpr)
+NODE(ArraySubscriptExpr)
+NODE(PostfixExpr)
+NODE(ConditionalExpr)
+NODE(MemberExpr)
+NODE(SubobjectExpr)
+NODE(EnclosingExpr)
+NODE(CastExpr)
+NODE(SizeofParamPackExpr)
+NODE(CallExpr)
+NODE(NewExpr)
+NODE(DeleteExpr)
+NODE(PrefixExpr)
+NODE(FunctionParam)
+NODE(ConversionExpr)
+NODE(PointerToMemberConversionExpr)
+NODE(InitListExpr)
+NODE(FoldExpr)
+NODE(ThrowExpr)
+NODE(BoolExpr)
+NODE(StringLiteral)
+NODE(LambdaExpr)
+NODE(EnumLiteral)
+NODE(IntegerLiteral)
+NODE(FloatLiteral)
+NODE(DoubleLiteral)
+NODE(LongDoubleLiteral)
+NODE(BracedExpr)
+NODE(BracedRangeExpr)
+
+#undef NODE
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
new file mode 100644
index 00000000..f1a5e1b6
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
@@ -0,0 +1,276 @@
+//===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
+#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
+
+#include "llvm/Demangle/MicrosoftDemangleNodes.h"
+#include "llvm/Demangle/StringView.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 Size) {
+ assert(Head && Head->Buf);
+
+ uint8_t *P = Head->Buf + Head->Used;
+
+ Head->Used += Size;
+ if (Head->Used <= Head->Capacity)
+ return reinterpret_cast<char *>(P);
+
+ addNode(std::max(AllocUnit, Size));
+ Head->Used = Size;
+ return reinterpret_cast<char *>(Head->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(std::max(AllocUnit, Size));
+ Head->Used = Size;
+ return new (Head->Buf) T[Count]();
+ }
+
+ template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
+ constexpr 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)...);
+
+ static_assert(Size < AllocUnit);
+ 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);
+ SymbolNode *demangleDeclarator(StringView &MangledName);
+ SymbolNode *demangleMD5Name(StringView &MangledName);
+ SymbolNode *demangleTypeinfoName(StringView &MangledName);
+
+ 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 *demangleFunctionParameterList(StringView &MangledName,
+ bool &IsVariadic);
+ NodeArrayNode *demangleTemplateParameterList(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);
+ IntrinsicFunctionKind
+ translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group);
+ 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, bool IsThread);
+ 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);
+ bool 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_MICROSOFTDEMANGLE_H
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
new file mode 100644
index 00000000..8ad24723
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -0,0 +1,629 @@
+//===- MicrosoftDemangleNodes.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AST nodes used in the MSVC demangler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
+#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
+
+#include "llvm/Demangle/StringView.h"
+#include <array>
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+namespace itanium_demangle {
+class OutputBuffer;
+}
+}
+
+using llvm::itanium_demangle::OutputBuffer;
+using llvm::itanium_demangle::StringView;
+
+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,
+ Swift, // Clang-only
+ SwiftAsync, // Clang-only
+};
+
+enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
+
+enum OutputFlags {
+ OF_Default = 0,
+ OF_NoCallingConvention = 1,
+ OF_NoTagSpecifier = 2,
+ OF_NoAccessSpecifier = 4,
+ OF_NoMemberType = 8,
+ OF_NoReturnType = 16,
+ OF_NoVariableType = 32,
+};
+
+// Types
+enum class PrimitiveKind {
+ Void,
+ Bool,
+ Char,
+ Schar,
+ Uchar,
+ Char8,
+ 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 operator co_await
+ Spaceship, // ?__M 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(OutputBuffer &OB, OutputFlags Flags) const = 0;
+
+ std::string toString(OutputFlags Flags = OF_Default) const;
+
+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 TagTypeNode;
+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(OutputBuffer &OB, OutputFlags Flags) const = 0;
+ virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0;
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override {
+ outputPre(OB, Flags);
+ outputPost(OB, Flags);
+ }
+
+ Qualifiers Quals = Q_None;
+};
+
+struct PrimitiveTypeNode : public TypeNode {
+ explicit PrimitiveTypeNode(PrimitiveKind K)
+ : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}
+
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {}
+
+ PrimitiveKind PrimKind;
+};
+
+struct FunctionSignatureNode : public TypeNode {
+ explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
+ FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
+
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, 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;
+
+ // True if the function type is noexcept.
+ bool IsNoexcept = false;
+};
+
+struct IdentifierNode : public Node {
+ explicit IdentifierNode(NodeKind K) : Node(K) {}
+
+ NodeArrayNode *TemplateParams = nullptr;
+
+protected:
+ void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const;
+};
+
+struct VcallThunkIdentifierNode : public IdentifierNode {
+ VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ uint64_t OffsetInVTable = 0;
+};
+
+struct DynamicStructorIdentifierNode : public IdentifierNode {
+ DynamicStructorIdentifierNode()
+ : IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ VariableSymbolNode *Variable = nullptr;
+ QualifiedNameNode *Name = nullptr;
+ bool IsDestructor = false;
+};
+
+struct NamedIdentifierNode : public IdentifierNode {
+ NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ StringView Name;
+};
+
+struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
+ explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator)
+ : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
+ Operator(Operator) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ IntrinsicFunctionKind Operator;
+};
+
+struct LiteralOperatorIdentifierNode : public IdentifierNode {
+ LiteralOperatorIdentifierNode()
+ : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ StringView Name;
+};
+
+struct LocalStaticGuardIdentifierNode : public IdentifierNode {
+ LocalStaticGuardIdentifierNode()
+ : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ bool IsThread = false;
+ uint32_t ScopeIndex = 0;
+};
+
+struct ConversionOperatorIdentifierNode : public IdentifierNode {
+ ConversionOperatorIdentifierNode()
+ : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
+
+ void output(OutputBuffer &OB, 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(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ QualifiedNameNode *QualifiedName = nullptr;
+ TagKind Tag;
+};
+
+struct ArrayTypeNode : public TypeNode {
+ ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
+
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const;
+ void outputOneDimension(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override {}
+};
+
+struct CustomTypeNode : public TypeNode {
+ CustomTypeNode() : TypeNode(NodeKind::Custom) {}
+
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ IdentifierNode *Identifier = nullptr;
+};
+
+struct NodeArrayNode : public Node {
+ NodeArrayNode() : Node(NodeKind::NodeArray) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const;
+
+ Node **Nodes = nullptr;
+ size_t Count = 0;
+};
+
+struct QualifiedNameNode : public Node {
+ QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
+
+ void output(OutputBuffer &OB, 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(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ uint64_t Value = 0;
+ bool IsNegative = false;
+};
+
+struct RttiBaseClassDescriptorNode : public IdentifierNode {
+ RttiBaseClassDescriptorNode()
+ : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
+
+ void output(OutputBuffer &OB, 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(OutputBuffer &OB, OutputFlags Flags) const override;
+ QualifiedNameNode *Name = nullptr;
+};
+
+struct SpecialTableSymbolNode : public SymbolNode {
+ explicit SpecialTableSymbolNode()
+ : SymbolNode(NodeKind::SpecialTableSymbol) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+ QualifiedNameNode *TargetName = nullptr;
+ Qualifiers Quals = Qualifiers::Q_None;
+};
+
+struct LocalStaticGuardVariableNode : public SymbolNode {
+ LocalStaticGuardVariableNode()
+ : SymbolNode(NodeKind::LocalStaticGuardVariable) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ bool IsVisible = false;
+};
+
+struct EncodedStringLiteralNode : public SymbolNode {
+ EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ StringView DecodedString;
+ bool IsTruncated = false;
+ CharKind Char = CharKind::Char;
+};
+
+struct VariableSymbolNode : public SymbolNode {
+ VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ StorageClass SC = StorageClass::None;
+ TypeNode *Type = nullptr;
+};
+
+struct FunctionSymbolNode : public SymbolNode {
+ FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
+
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
+
+ FunctionSignatureNode *Signature = nullptr;
+};
+
+} // namespace ms_demangle
+} // namespace llvm
+
+#endif
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/StringView.h b/demangle/third_party/llvm/include/llvm/Demangle/StringView.h
new file mode 100644
index 00000000..6bbb8837
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/StringView.h
@@ -0,0 +1,122 @@
+//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
+// Do not edit! See README.txt.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: Use std::string_view instead when we support C++17.
+// There are two copies of this file in the source tree. The one under
+// libcxxabi is the original and the one under llvm is the copy. Use
+// cp-to-llvm.sh to update the copy. See README.txt for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DEMANGLE_STRINGVIEW_H
+#define DEMANGLE_STRINGVIEW_H
+
+#include "DemangleConfig.h"
+#include <cassert>
+#include <cstring>
+
+DEMANGLE_NAMESPACE_BEGIN
+
+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 Pos, size_t Len = npos) const {
+ assert(Pos <= size());
+ if (Len > size() - Pos)
+ Len = size() - Pos;
+ return StringView(begin() + Pos, Len);
+ }
+
+ size_t find(char C, size_t From = 0) const {
+ // Avoid calling memchr with nullptr.
+ if (From < size()) {
+ // Just forward to memchr, which is faster than a hand-rolled loop.
+ if (const void *P = ::memchr(First + From, C, size() - From))
+ return size_t(static_cast<const char *>(P) - First);
+ }
+ return npos;
+ }
+
+ 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::strncmp(Str.begin(), begin(), Str.size()) == 0;
+ }
+
+ 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::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
+}
+
+DEMANGLE_NAMESPACE_END
+
+#endif
diff --git a/demangle/third_party/llvm/include/llvm/Demangle/Utility.h b/demangle/third_party/llvm/include/llvm/Demangle/Utility.h
new file mode 100644
index 00000000..855c56e9
--- /dev/null
+++ b/demangle/third_party/llvm/include/llvm/Demangle/Utility.h
@@ -0,0 +1,199 @@
+//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
+// Do not edit! See README.txt.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provide some utility classes for use in the demangler.
+// There are two copies of this file in the source tree. The one in libcxxabi
+// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
+// the copy. See README.txt for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DEMANGLE_UTILITY_H
+#define DEMANGLE_UTILITY_H
+
+#include "StringView.h"
+#include <array>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <exception>
+#include <limits>
+
+DEMANGLE_NAMESPACE_BEGIN
+
+// Stream that AST nodes write their string representation into after the AST
+// has been parsed.
+class OutputBuffer {
+ char *Buffer = nullptr;
+ size_t CurrentPosition = 0;
+ size_t BufferCapacity = 0;
+
+ // Ensure there are at least N more positions in the buffer.
+ void grow(size_t N) {
+ size_t Need = N + CurrentPosition;
+ if (Need > BufferCapacity) {
+ // Reduce the number of reallocations, with a bit of hysteresis. The
+ // number here is chosen so the first allocation will more-than-likely not
+ // allocate more than 1K.
+ Need += 1024 - 32;
+ BufferCapacity *= 2;
+ if (BufferCapacity < Need)
+ BufferCapacity = Need;
+ Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
+ if (Buffer == nullptr)
+ std::terminate();
+ }
+ }
+
+ OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
+ std::array<char, 21> Temp;
+ char *TempPtr = Temp.data() + Temp.size();
+
+ // Output at least one character.
+ do {
+ *--TempPtr = char('0' + N % 10);
+ N /= 10;
+ } while (N);
+
+ // Add negative sign.
+ if (isNeg)
+ *--TempPtr = '-';
+
+ return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
+ }
+
+public:
+ OutputBuffer(char *StartBuf, size_t Size)
+ : Buffer(StartBuf), BufferCapacity(Size) {}
+ OutputBuffer(char *StartBuf, size_t *SizePtr)
+ : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
+ OutputBuffer() = default;
+ // Non-copyable
+ OutputBuffer(const OutputBuffer &) = delete;
+ OutputBuffer &operator=(const OutputBuffer &) = delete;
+
+ operator StringView() const { return StringView(Buffer, CurrentPosition); }
+
+ /// 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();
+
+ /// When zero, we're printing template args and '>' needs to be parenthesized.
+ /// Use a counter so we can simply increment inside parentheses.
+ unsigned GtIsGt = 1;
+
+ bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
+
+ void printOpen(char Open = '(') {
+ GtIsGt++;
+ *this += Open;
+ }
+ void printClose(char Close = ')') {
+ GtIsGt--;
+ *this += Close;
+ }
+
+ OutputBuffer &operator+=(StringView R) {
+ if (size_t Size = R.size()) {
+ grow(Size);
+ std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
+ CurrentPosition += Size;
+ }
+ return *this;
+ }
+
+ OutputBuffer &operator+=(char C) {
+ grow(1);
+ Buffer[CurrentPosition++] = C;
+ return *this;
+ }
+
+ OutputBuffer &prepend(StringView R) {
+ size_t Size = R.size();
+
+ grow(Size);
+ std::memmove(Buffer + Size, Buffer, CurrentPosition);
+ std::memcpy(Buffer, R.begin(), Size);
+ CurrentPosition += Size;
+
+ return *this;
+ }
+
+ OutputBuffer &operator<<(StringView R) { return (*this += R); }
+
+ OutputBuffer &operator<<(char C) { return (*this += C); }
+
+ OutputBuffer &operator<<(long long N) {
+ return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
+ }
+
+ OutputBuffer &operator<<(unsigned long long N) {
+ return writeUnsigned(N, false);
+ }
+
+ OutputBuffer &operator<<(long N) {
+ return this->operator<<(static_cast<long long>(N));
+ }
+
+ OutputBuffer &operator<<(unsigned long N) {
+ return this->operator<<(static_cast<unsigned long long>(N));
+ }
+
+ OutputBuffer &operator<<(int N) {
+ return this->operator<<(static_cast<long long>(N));
+ }
+
+ OutputBuffer &operator<<(unsigned int N) {
+ return this->operator<<(static_cast<unsigned long long>(N));
+ }
+
+ void insert(size_t Pos, const char *S, size_t N) {
+ assert(Pos <= CurrentPosition);
+ if (N == 0)
+ return;
+ grow(N);
+ std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
+ std::memcpy(Buffer + Pos, S, N);
+ CurrentPosition += N;
+ }
+
+ size_t getCurrentPosition() const { return CurrentPosition; }
+ void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
+
+ char back() const {
+ assert(CurrentPosition);
+ return Buffer[CurrentPosition - 1];
+ }
+
+ bool empty() const { return CurrentPosition == 0; }
+
+ char *getBuffer() { return Buffer; }
+ char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
+ size_t getBufferCapacity() const { return BufferCapacity; }
+};
+
+template <class T> class ScopedOverride {
+ T &Loc;
+ T Original;
+
+public:
+ ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+ ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+ Loc_ = std::move(NewVal);
+ }
+ ~ScopedOverride() { Loc = std::move(Original); }
+
+ ScopedOverride(const ScopedOverride &) = delete;
+ ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
+DEMANGLE_NAMESPACE_END
+
+#endif
diff --git a/demangle/third_party/llvm/lib/Demangle/Demangle.cpp b/demangle/third_party/llvm/lib/Demangle/Demangle.cpp
new file mode 100644
index 00000000..b5f2369d
--- /dev/null
+++ b/demangle/third_party/llvm/lib/Demangle/Demangle.cpp
@@ -0,0 +1,68 @@
+//===-- Demangle.cpp - Common demangling functions ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains definitions of common demangling functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/Demangle.h"
+#include <cstdlib>
+#include <cstring>
+
+static bool isItaniumEncoding(const char *S) {
+ // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
+ return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0;
+}
+
+#if 0
+static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; }
+
+static bool isDLangEncoding(const std::string &MangledName) {
+ return MangledName.size() >= 2 && MangledName[0] == '_' &&
+ MangledName[1] == 'D';
+}
+#endif
+
+std::string llvm::demangle(const std::string &MangledName) {
+ std::string Result;
+ const char *S = MangledName.c_str();
+
+ if (nonMicrosoftDemangle(S, Result))
+ return Result;
+
+ if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result))
+ return Result;
+
+ if (char *Demangled =
+ microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) {
+ Result = Demangled;
+ std::free(Demangled);
+ return Result;
+ }
+
+ return MangledName;
+}
+
+bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) {
+ char *Demangled = nullptr;
+ if (isItaniumEncoding(MangledName))
+ Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr);
+#if 0
+ else if (isRustEncoding(MangledName))
+ Demangled = rustDemangle(MangledName);
+ else if (isDLangEncoding(MangledName))
+ Demangled = dlangDemangle(MangledName);
+#endif
+
+ if (!Demangled)
+ return false;
+
+ Result = Demangled;
+ std::free(Demangled);
+ return true;
+}
diff --git a/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
new file mode 100644
index 00000000..9b646ea8
--- /dev/null
+++ b/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -0,0 +1,608 @@
+//===------------------------- ItaniumDemangle.cpp ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// 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 <utility>
+
+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(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> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
+ fprintf(stderr, "%llu", (unsigned long long)N);
+ }
+
+ template <class T> std::enable_if_t<std::is_signed<T>::value> 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 print(TemplateParamKind TPK) {
+ switch (TPK) {
+ case TemplateParamKind::Type:
+ return printStr("TemplateParamKind::Type");
+ case TemplateParamKind::NonType:
+ return printStr("TemplateParamKind::NonType");
+ case TemplateParamKind::Template:
+ return printStr("TemplateParamKind::Template");
+ }
+ }
+ void print(Node::Prec P) {
+ switch (P) {
+ case Node::Prec::Primary:
+ return printStr("Node::Prec::Primary");
+ case Node::Prec::Postfix:
+ return printStr("Node::Prec::Postfix");
+ case Node::Prec::Unary:
+ return printStr("Node::Prec::Unary");
+ case Node::Prec::Cast:
+ return printStr("Node::Prec::Cast");
+ case Node::Prec::PtrMem:
+ return printStr("Node::Prec::PtrMem");
+ case Node::Prec::Multiplicative:
+ return printStr("Node::Prec::Multiplicative");
+ case Node::Prec::Additive:
+ return printStr("Node::Prec::Additive");
+ case Node::Prec::Shift:
+ return printStr("Node::Prec::Shift");
+ case Node::Prec::Spaceship:
+ return printStr("Node::Prec::Spaceship");
+ case Node::Prec::Relational:
+ return printStr("Node::Prec::Relational");
+ case Node::Prec::Equality:
+ return printStr("Node::Prec::Equality");
+ case Node::Prec::And:
+ return printStr("Node::Prec::And");
+ case Node::Prec::Xor:
+ return printStr("Node::Prec::Xor");
+ case Node::Prec::Ior:
+ return printStr("Node::Prec::Ior");
+ case Node::Prec::AndIf:
+ return printStr("Node::Prec::AndIf");
+ case Node::Prec::OrIf:
+ return printStr("Node::Prec::OrIf");
+ case Node::Prec::Conditional:
+ return printStr("Node::Prec::Conditional");
+ case Node::Prec::Assign:
+ return printStr("Node::Prec::Assign");
+ case Node::Prec::Comma:
+ return printStr("Node::Prec::Comma");
+ case Node::Prec::Default:
+ return printStr("Node::Prec::Default");
+ }
+ }
+
+ 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));
+ Node *AST = Parser.parse();
+
+ if (AST == nullptr)
+ InternalStatus = demangle_invalid_mangled_name;
+ else {
+ OutputBuffer OB(Buf, N);
+ assert(Parser.ForwardTemplateRefs.empty());
+ AST->print(OB);
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ Buf = OB.getBuffer();
+ }
+
+ if (Status)
+ *Status = InternalStatus;
+ return InternalStatus == demangle_success ? Buf : 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) {
+ OutputBuffer OB(Buf, N);
+ RootNode->print(OB);
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ return OB.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::KModuleEntity:
+ Name = static_cast<const ModuleEntity *>(Name)->Name;
+ 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();
+
+ OutputBuffer OB(Buf, N);
+
+ 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;
+ }
+
+ if (Name->getKind() == Node::KModuleEntity)
+ Name = static_cast<const ModuleEntity *>(Name)->Name;
+
+ switch (Name->getKind()) {
+ case Node::KNestedName:
+ static_cast<const NestedName *>(Name)->Qual->print(OB);
+ break;
+ case Node::KLocalName: {
+ auto *LN = static_cast<const LocalName *>(Name);
+ LN->Encoding->print(OB);
+ OB += "::";
+ Name = LN->Entity;
+ goto KeepGoingLocalFunction;
+ }
+ default:
+ break;
+ }
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ return OB.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();
+
+ OutputBuffer OB(Buf, N);
+
+ OB += '(';
+ Params.printWithComma(OB);
+ OB += ')';
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ return OB.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionReturnType(
+ char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+
+ OutputBuffer OB(Buf, N);
+
+ if (const Node *Ret =
+ static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
+ Ret->print(OB);
+
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ return OB.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::KModuleEntity:
+ N = static_cast<const ModuleEntity *>(N)->Name;
+ 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/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
new file mode 100644
index 00000000..c21b0a30
--- /dev/null
+++ b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -0,0 +1,2368 @@
+//===- MicrosoftDemangle.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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/DemangleConfig.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, bool &Error) {
+ Error = false;
+ 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:
+ // isMemberPointer() is called only if isPointerType() returns true,
+ // and it rejects other prefixes.
+ DEMANGLE_UNREACHABLE;
+ }
+
+ // If it starts with a number, then 6 indicates a non-member function
+ // pointer, and 8 indicates a member function pointer.
+ if (startsWithDigit(MangledName)) {
+ if (MangledName[0] != '6' && MangledName[0] != '8') {
+ Error = true;
+ return false;
+ }
+ 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
+
+ if (MangledName.empty()) {
+ Error = true;
+ return false;
+ }
+
+ // 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:
+ Error = true;
+ 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;
+
+ 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);
+ }
+ // This function is only called if isPointerType() returns true,
+ // and it only returns true for the six cases listed above.
+ DEMANGLE_UNREACHABLE;
+}
+
+StringView Demangler::copyString(StringView Borrowed) {
+ char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
+ // This is not a micro-optimization, it avoids UB, should Borrowed be an null
+ // buffer.
+ if (Borrowed.size())
+ std::memcpy(Stable, Borrowed.begin(), Borrowed.size());
+
+ 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:
+ DEMANGLE_UNREACHABLE;
+ }
+ QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
+ SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();
+ STSN->Name = QN;
+ bool IsMember = false;
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+ 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, bool IsThread) {
+ LocalStaticGuardIdentifierNode *LSGI =
+ Arena.alloc<LocalStaticGuardIdentifierNode>();
+ LSGI->IsThread = IsThread;
+ 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;
+
+ SymbolNode *Symbol = demangleDeclarator(MangledName);
+ if (Error)
+ return nullptr;
+
+ FunctionSymbolNode *FSN = nullptr;
+
+ 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);
+ if (FSN)
+ 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);
+
+ switch (SIK) {
+ case SpecialIntrinsicKind::None:
+ return nullptr;
+ 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, /*IsThread=*/false);
+ case SpecialIntrinsicKind::LocalStaticThreadGuard:
+ return demangleLocalStaticGuard(MangledName, /*IsThread=*/true);
+ 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, /*IsDestructor=*/false);
+ case SpecialIntrinsicKind::DynamicAtexitDestructor:
+ return demangleInitFiniStub(MangledName, /*IsDestructor=*/true);
+ case SpecialIntrinsicKind::Typeof:
+ case SpecialIntrinsicKind::UdtReturning:
+ // It's unclear which tools produces these manglings, so demangling
+ // support is not (yet?) implemented.
+ break;
+ case SpecialIntrinsicKind::Unknown:
+ DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind.
+ }
+ Error = true;
+ return nullptr;
+}
+
+IdentifierNode *
+Demangler::demangleFunctionIdentifierCode(StringView &MangledName) {
+ assert(MangledName.startsWith('?'));
+ MangledName = MangledName.dropFront();
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
+ if (MangledName.consumeFront("__"))
+ return demangleFunctionIdentifierCode(
+ MangledName, FunctionIdentifierCodeGroup::DoubleUnder);
+ 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, /*Memorize=*/false);
+ return N;
+}
+
+IntrinsicFunctionKind
+Demangler::translateIntrinsicFunctionCode(char CH,
+ FunctionIdentifierCodeGroup Group) {
+ using IFK = IntrinsicFunctionKind;
+ if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) {
+ Error = true;
+ return IFK::None;
+ }
+
+ // 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.
+ 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 operator co_await
+ IFK::Spaceship, // ?__M operator<=>
+ 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];
+ }
+ DEMANGLE_UNREACHABLE;
+}
+
+IdentifierNode *
+Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
+ FunctionIdentifierCodeGroup Group) {
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+ 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));
+ }
+ 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));
+ }
+ }
+
+ DEMANGLE_UNREACHABLE;
+}
+
+SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
+ QualifiedNameNode *Name) {
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
+ // Read a variable.
+ switch (MangledName.front()) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4': {
+ StorageClass SC = demangleVariableStorageClass(MangledName);
+ return demangleVariableEncoding(MangledName, SC);
+ }
+ }
+ FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);
+
+ IdentifierNode *UQN = Name->getUnqualifiedIdentifier();
+ if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
+ ConversionOperatorIdentifierNode *COIN =
+ static_cast<ConversionOperatorIdentifierNode *>(UQN);
+ if (FSN)
+ COIN->TargetType = FSN->Signature->ReturnType;
+ }
+ return FSN;
+}
+
+SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) {
+ // 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 (Error)
+ return nullptr;
+ Symbol->Name = QN;
+
+ IdentifierNode *UQN = QN->getUnqualifiedIdentifier();
+ if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
+ ConversionOperatorIdentifierNode *COIN =
+ static_cast<ConversionOperatorIdentifierNode *>(UQN);
+ if (!COIN->TargetType) {
+ Error = true;
+ return nullptr;
+ }
+ }
+ return Symbol;
+}
+
+SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) {
+ assert(MangledName.startsWith("??@"));
+ // This is an MD5 mangled name. We can't demangle it, just return the
+ // mangled name.
+ // An MD5 mangled name is ??@ followed by 32 characters and a terminating @.
+ size_t MD5Last = MangledName.find('@', strlen("??@"));
+ if (MD5Last == StringView::npos) {
+ Error = true;
+ return nullptr;
+ }
+ const char *Start = MangledName.begin();
+ MangledName = MangledName.dropFront(MD5Last + 1);
+
+ // There are two additional special cases for MD5 names:
+ // 1. For complete object locators where the object name is long enough
+ // for the object to have an MD5 name, the complete object locator is
+ // called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual
+ // leading "??_R4". This is handled here.
+ // 2. For catchable types, in versions of MSVC before 2015 (<1900) or after
+ // 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8
+ // instead of_CT??@...@8 with just one MD5 name. Since we don't yet
+ // demangle catchable types anywhere, this isn't handled for MD5 names
+ // either.
+ MangledName.consumeFront("??_R4@");
+
+ StringView MD5(Start, MangledName.begin());
+ SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);
+ S->Name = synthesizeQualifiedName(Arena, MD5);
+
+ return S;
+}
+
+SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) {
+ assert(MangledName.startsWith('.'));
+ MangledName.consumeFront('.');
+
+ TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);
+ if (Error || !MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+ return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'");
+}
+
+// Parser entry point.
+SymbolNode *Demangler::parse(StringView &MangledName) {
+ // Typeinfo names are strings stored in RTTI data. They're not symbol names.
+ // It's still useful to demangle them. They're the only demangled entity
+ // that doesn't start with a "?" but a ".".
+ if (MangledName.startsWith('.'))
+ return demangleTypeinfoName(MangledName);
+
+ if (MangledName.startsWith("??@"))
+ return demangleMD5Name(MangledName);
+
+ // MSVC-style mangled symbols must start with '?'.
+ 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;
+
+ return demangleDeclarator(MangledName);
+}
+
+TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
+ if (!MangledName.consumeFront(".?A")) {
+ Error = true;
+ return nullptr;
+ }
+ MangledName.consumeFront(".?A");
+ if (MangledName.empty()) {
+ Error = true;
+ 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;
+
+ if (Error)
+ return nullptr;
+
+ // <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 Number == 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.
+ OutputBuffer OB;
+ Identifier->output(OB, OF_Default);
+ StringView Owned = copyString(OB);
+ memorizeString(Owned);
+ std::free(OB.getBuffer());
+}
+
+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) {
+ // NBB_Template is only set for types and non-leaf names ("a::" in "a::b").
+ // Structors and conversion operators only makes sense in a leaf name, so
+ // reject them in NBB_Template contexts.
+ if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier ||
+ Identifier->kind() == NodeKind::StructorIdentifier) {
+ Error = true;
+ return nullptr;
+ }
+
+ 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) {
+ assert(!MangledName.empty());
+ 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 || MangledName.empty())
+ 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(OutputBuffer &OB, unsigned C) {
+ assert (C != 0);
+
+ // 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 = sizeof(TempBuffer) - 1;
+
+ int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0.
+ while (C != 0) {
+ for (int I = 0; I < 2; ++I) {
+ writeHexDigit(&TempBuffer[Pos--], C % 16);
+ C /= 16;
+ }
+ }
+ TempBuffer[Pos--] = 'x';
+ assert(Pos >= 0);
+ TempBuffer[Pos--] = '\\';
+ OB << StringView(&TempBuffer[Pos + 1]);
+}
+
+static void outputEscapedChar(OutputBuffer &OB, unsigned C) {
+ switch (C) {
+ case '\0': // nul
+ OB << "\\0";
+ return;
+ case '\'': // single quote
+ OB << "\\\'";
+ return;
+ case '\"': // double quote
+ OB << "\\\"";
+ return;
+ case '\\': // backslash
+ OB << "\\\\";
+ return;
+ case '\a': // bell
+ OB << "\\a";
+ return;
+ case '\b': // backspace
+ OB << "\\b";
+ return;
+ case '\f': // form feed
+ OB << "\\f";
+ return;
+ case '\n': // new line
+ OB << "\\n";
+ return;
+ case '\r': // carriage return
+ OB << "\\r";
+ return;
+ case '\t': // tab
+ OB << "\\t";
+ return;
+ case '\v': // vertical tab
+ OB << "\\v";
+ return;
+ default:
+ break;
+ }
+
+ if (C > 0x1F && C < 0x7F) {
+ // Standard ascii char.
+ OB << (char)C;
+ return;
+ }
+
+ outputHex(OB, 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;
+}
+
+// A mangled (non-wide) string literal stores the total length of the string it
+// refers to (passed in NumBytes), and it contains up to 32 bytes of actual text
+// (passed in StringBytes, NumChars).
+static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
+ uint64_t 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 && NumBytes % 4 == 0)
+ 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 && NumBytes % 4 == 0)
+ 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.
+ OutputBuffer OB;
+ StringView CRC;
+ uint64_t StringByteSize;
+ bool IsWcharT = false;
+ bool IsNegative = false;
+ size_t CrcEndPos = 0;
+
+ 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;
+ DEMANGLE_FALLTHROUGH;
+ case '0':
+ break;
+ default:
+ goto StringLiteralError;
+ }
+
+ // Encoded Length
+ std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);
+ if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1))
+ 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 (IsWcharT) {
+ Result->Char = CharKind::Wchar;
+ if (StringByteSize > 64)
+ Result->IsTruncated = true;
+
+ while (!MangledName.consumeFront('@')) {
+ if (MangledName.size() < 2)
+ goto StringLiteralError;
+ wchar_t W = demangleWcharLiteral(MangledName);
+ if (StringByteSize != 2 || Result->IsTruncated)
+ outputEscapedChar(OB, 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('@')) {
+ if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength)
+ goto StringLiteralError;
+ 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:
+ DEMANGLE_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(OB, NextChar);
+ }
+ }
+
+ Result->DecodedString = copyString(OB);
+ std::free(OB.getBuffer());
+ return Result;
+
+StringLiteralError:
+ Error = true;
+ std::free(OB.getBuffer());
+ return nullptr;
+}
+
+// Returns MangledName's prefix before the first '@', or an error if
+// MangledName contains no '@' or the prefix has length 0.
+StringView Demangler::demangleSimpleString(StringView &MangledName,
+ bool Memorize) {
+ StringView S;
+ for (size_t i = 0; i < MangledName.size(); ++i) {
+ if (MangledName[i] != '@')
+ continue;
+ if (i == 0)
+ break;
+ 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('?');
+ uint64_t Number = 0;
+ bool IsNegative = false;
+ std::tie(Number, IsNegative) = demangleNumber(MangledName);
+ assert(!IsNegative);
+
+ // 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.
+ OutputBuffer OB;
+ OB << '`';
+ Scope->output(OB, OF_Default);
+ OB << '\'';
+ OB << "::`" << Number << "'";
+
+ Identifier->Name = copyString(OB);
+ std::free(OB.getBuffer());
+ 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, /*Memorize=*/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) {
+ if (QN->Components->Count < 2) {
+ Error = true;
+ return nullptr;
+ }
+ StructorIdentifierNode *SIN =
+ static_cast<StructorIdentifierNode *>(Identifier);
+ 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, /*Memorize=*/(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, /*Memorize=*/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 | FC_Far);
+ case 'E':
+ return FuncClass(FC_Private | FC_Virtual);
+ case 'F':
+ return FuncClass(FC_Private | FC_Virtual | FC_Far);
+ 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);
+ if (MangledName.empty())
+ break;
+ 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) {
+ if (MangledName.empty()) {
+ Error = true;
+ return CallingConv::None;
+ }
+
+ 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;
+ case 'S':
+ return CallingConv::Swift;
+ case 'W':
+ return CallingConv::SwiftAsync;
+ }
+
+ return CallingConv::None;
+}
+
+StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
+ assert(MangledName.front() >= '0' && MangledName.front() <= '4');
+
+ 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;
+ }
+ DEMANGLE_UNREACHABLE;
+}
+
+std::pair<Qualifiers, bool>
+Demangler::demangleQualifiers(StringView &MangledName) {
+ if (MangledName.empty()) {
+ Error = true;
+ return std::make_pair(Q_None, false);
+ }
+
+ 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);
+ }
+
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
+ TypeNode *Ty = nullptr;
+ if (isTagType(MangledName))
+ Ty = demangleClassType(MangledName);
+ else if (isPointerType(MangledName)) {
+ if (isMemberPointer(MangledName, Error))
+ Ty = demangleMemberPointerType(MangledName);
+ else if (!Error)
+ Ty = demanglePointerType(MangledName);
+ else
+ return nullptr;
+ } 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;
+}
+
+bool Demangler::demangleThrowSpecification(StringView &MangledName) {
+ if (MangledName.consumeFront("_E"))
+ return true;
+ if (MangledName.consumeFront('Z'))
+ return false;
+
+ Error = true;
+ return false;
+}
+
+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, FTy->IsVariadic);
+
+ FTy->IsNoexcept = demangleThrowSpecification(MangledName);
+
+ return FTy;
+}
+
+FunctionSymbolNode *
+Demangler::demangleFunctionEncoding(StringView &MangledName) {
+ FuncClass ExtraFlags = FC_None;
+ if (MangledName.consumeFront("$$J0"))
+ ExtraFlags = FC_ExternC;
+
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
+ 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 (Error)
+ return nullptr;
+
+ 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, /*Memorize=*/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 'Q':
+ return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char8);
+ 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.consumeFront('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);
+
+ // isMemberPointer() only returns true if there is at least one character
+ // after the qualifiers.
+ 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 || Error);
+ Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
+
+ Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);
+ if (Pointer->Pointee)
+ 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 (Error || 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's parameters.
+NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName,
+ bool &IsVariadic) {
+ // Empty parameter list.
+ if (MangledName.consumeFront('X'))
+ return nullptr;
+
+ 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 nullptr;
+ }
+ 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);
+ if (!TN || Error)
+ return nullptr;
+
+ (*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 nullptr;
+
+ 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')) {
+ IsVariadic = true;
+ return NA;
+ }
+
+ DEMANGLE_UNREACHABLE;
+}
+
+NodeArrayNode *
+Demangler::demangleTemplateParameterList(StringView &MangledName) {
+ NodeList *Head = nullptr;
+ NodeList **Current = &Head;
+ size_t Count = 0;
+
+ while (!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>
+ // J - unspecified inheritance <name> <number> <number> <number>
+ char InheritanceSpecifier = MangledName.popFront();
+ SymbolNode *S = nullptr;
+ if (MangledName.startsWith('?')) {
+ S = parse(MangledName);
+ if (Error || !S->Name) {
+ Error = true;
+ return nullptr;
+ }
+ memorizeIdentifier(S->Name->getUnqualifiedIdentifier());
+ }
+
+ switch (InheritanceSpecifier) {
+ case 'J':
+ TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+ demangleSigned(MangledName);
+ DEMANGLE_FALLTHROUGH;
+ case 'I':
+ TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+ demangleSigned(MangledName);
+ DEMANGLE_FALLTHROUGH;
+ case 'H':
+ TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+ demangleSigned(MangledName);
+ DEMANGLE_FALLTHROUGH;
+ case '1':
+ break;
+ default:
+ DEMANGLE_UNREACHABLE;
+ }
+ 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);
+ DEMANGLE_FALLTHROUGH;
+ case 'F':
+ TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+ demangleSigned(MangledName);
+ TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
+ demangleSigned(MangledName);
+ break;
+ default:
+ DEMANGLE_UNREACHABLE;
+ }
+ 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;
+ }
+
+ // The loop above returns nullptr on Error.
+ assert(!Error);
+
+ // Template parameter lists cannot be variadic, so it can only be terminated
+ // by @ (as opposed to 'Z' in the function parameter case).
+ assert(MangledName.startsWith('@')); // The above loop exits only on '@'.
+ MangledName.consumeFront('@');
+ return nodeListToNodeArray(Arena, Head, Count);
+}
+
+void Demangler::dumpBackReferences() {
+ std::printf("%d function parameter backreferences\n",
+ (int)Backrefs.FunctionParamCount);
+
+ // Create an output stream so we can render each type.
+ OutputBuffer OB;
+ for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
+ OB.setCurrentPosition(0);
+
+ TypeNode *T = Backrefs.FunctionParams[I];
+ T->output(OB, OF_Default);
+
+ StringView B = OB;
+ std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin());
+ }
+ std::free(OB.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, size_t *NMangled,
+ char *Buf, size_t *N,
+ int *Status, MSDemangleFlags Flags) {
+ Demangler D;
+
+ StringView Name{MangledName};
+ SymbolNode *AST = D.parse(Name);
+ if (!D.Error && NMangled)
+ *NMangled = Name.begin() - MangledName;
+
+ if (Flags & MSDF_DumpBackrefs)
+ D.dumpBackReferences();
+
+ OutputFlags OF = OF_Default;
+ if (Flags & MSDF_NoCallingConvention)
+ OF = OutputFlags(OF | OF_NoCallingConvention);
+ if (Flags & MSDF_NoAccessSpecifier)
+ OF = OutputFlags(OF | OF_NoAccessSpecifier);
+ if (Flags & MSDF_NoReturnType)
+ OF = OutputFlags(OF | OF_NoReturnType);
+ if (Flags & MSDF_NoMemberType)
+ OF = OutputFlags(OF | OF_NoMemberType);
+ if (Flags & MSDF_NoVariableType)
+ OF = OutputFlags(OF | OF_NoVariableType);
+
+ int InternalStatus = demangle_success;
+ if (D.Error)
+ InternalStatus = demangle_invalid_mangled_name;
+ else {
+ OutputBuffer OB(Buf, N);
+ AST->output(OB, OF);
+ OB += '\0';
+ if (N != nullptr)
+ *N = OB.getCurrentPosition();
+ Buf = OB.getBuffer();
+ }
+
+ if (Status)
+ *Status = InternalStatus;
+ return InternalStatus == demangle_success ? Buf : nullptr;
+}
diff --git a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
new file mode 100644
index 00000000..975649f2
--- /dev/null
+++ b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -0,0 +1,658 @@
+//===- MicrosoftDemangle.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a demangler for MSVC-style mangled symbols.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/MicrosoftDemangleNodes.h"
+#include "llvm/Demangle/Utility.h"
+#include <cctype>
+#include <string>
+
+using namespace llvm;
+using namespace ms_demangle;
+
+#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
+ case Enum::Value: \
+ OB << Desc; \
+ break;
+
+// Writes a space if the last token does not end with a punctuation.
+static void outputSpaceIfNecessary(OutputBuffer &OB) {
+ if (OB.empty())
+ return;
+
+ char C = OB.back();
+ if (std::isalnum(C) || C == '>')
+ OB << " ";
+}
+
+static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) {
+ switch (Q) {
+ case Q_Const:
+ OB << "const";
+ break;
+ case Q_Volatile:
+ OB << "volatile";
+ break;
+ case Q_Restrict:
+ OB << "__restrict";
+ break;
+ default:
+ break;
+ }
+}
+
+static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q,
+ Qualifiers Mask, bool NeedSpace) {
+ if (!(Q & Mask))
+ return NeedSpace;
+
+ if (NeedSpace)
+ OB << " ";
+
+ outputSingleQualifier(OB, Mask);
+ return true;
+}
+
+static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
+ bool SpaceAfter) {
+ if (Q == Q_None)
+ return;
+
+ size_t Pos1 = OB.getCurrentPosition();
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
+ size_t Pos2 = OB.getCurrentPosition();
+ if (SpaceAfter && Pos2 > Pos1)
+ OB << " ";
+}
+
+static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) {
+ outputSpaceIfNecessary(OB);
+
+ switch (CC) {
+ case CallingConv::Cdecl:
+ OB << "__cdecl";
+ break;
+ case CallingConv::Fastcall:
+ OB << "__fastcall";
+ break;
+ case CallingConv::Pascal:
+ OB << "__pascal";
+ break;
+ case CallingConv::Regcall:
+ OB << "__regcall";
+ break;
+ case CallingConv::Stdcall:
+ OB << "__stdcall";
+ break;
+ case CallingConv::Thiscall:
+ OB << "__thiscall";
+ break;
+ case CallingConv::Eabi:
+ OB << "__eabi";
+ break;
+ case CallingConv::Vectorcall:
+ OB << "__vectorcall";
+ break;
+ case CallingConv::Clrcall:
+ OB << "__clrcall";
+ break;
+ case CallingConv::Swift:
+ OB << "__attribute__((__swiftcall__)) ";
+ break;
+ case CallingConv::SwiftAsync:
+ OB << "__attribute__((__swiftasynccall__)) ";
+ break;
+ default:
+ break;
+ }
+}
+
+std::string Node::toString(OutputFlags Flags) const {
+ OutputBuffer OB;
+ this->output(OB, Flags);
+ StringView SV = OB;
+ std::string Owned(SV.begin(), SV.end());
+ std::free(OB.getBuffer());
+ return Owned;
+}
+
+void PrimitiveTypeNode::outputPre(OutputBuffer &OB, 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, Char8, "char8_t");
+ 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(OB, Quals, true, false);
+}
+
+void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ output(OB, Flags, ", ");
+}
+
+void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags,
+ StringView Separator) const {
+ if (Count == 0)
+ return;
+ if (Nodes[0])
+ Nodes[0]->output(OB, Flags);
+ for (size_t I = 1; I < Count; ++I) {
+ OB << Separator;
+ Nodes[I]->output(OB, Flags);
+ }
+}
+
+void EncodedStringLiteralNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ switch (Char) {
+ case CharKind::Wchar:
+ OB << "L\"";
+ break;
+ case CharKind::Char:
+ OB << "\"";
+ break;
+ case CharKind::Char16:
+ OB << "u\"";
+ break;
+ case CharKind::Char32:
+ OB << "U\"";
+ break;
+ }
+ OB << DecodedString << "\"";
+ if (IsTruncated)
+ OB << "...";
+}
+
+void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ if (IsNegative)
+ OB << '-';
+ OB << Value;
+}
+
+void TemplateParameterReferenceNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (ThunkOffsetCount > 0)
+ OB << "{";
+ else if (Affinity == PointerAffinity::Pointer)
+ OB << "&";
+
+ if (Symbol) {
+ Symbol->output(OB, Flags);
+ if (ThunkOffsetCount > 0)
+ OB << ", ";
+ }
+
+ if (ThunkOffsetCount > 0)
+ OB << ThunkOffsets[0];
+ for (int I = 1; I < ThunkOffsetCount; ++I) {
+ OB << ", " << ThunkOffsets[I];
+ }
+ if (ThunkOffsetCount > 0)
+ OB << "}";
+}
+
+void IdentifierNode::outputTemplateParameters(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (!TemplateParams)
+ return;
+ OB << "<";
+ TemplateParams->output(OB, Flags);
+ OB << ">";
+}
+
+void DynamicStructorIdentifierNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (IsDestructor)
+ OB << "`dynamic atexit destructor for ";
+ else
+ OB << "`dynamic initializer for ";
+
+ if (Variable) {
+ OB << "`";
+ Variable->output(OB, Flags);
+ OB << "''";
+ } else {
+ OB << "'";
+ Name->output(OB, Flags);
+ OB << "''";
+ }
+}
+
+void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ OB << Name;
+ outputTemplateParameters(OB, Flags);
+}
+
+void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB,
+ 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,
+ "operator co_await");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
+ case IntrinsicFunctionKind::MaxIntrinsic:
+ case IntrinsicFunctionKind::None:
+ break;
+ }
+ outputTemplateParameters(OB, Flags);
+}
+
+void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (IsThread)
+ OB << "`local static thread guard'";
+ else
+ OB << "`local static guard'";
+ if (ScopeIndex > 0)
+ OB << "{" << ScopeIndex << "}";
+}
+
+void ConversionOperatorIdentifierNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ OB << "operator";
+ outputTemplateParameters(OB, Flags);
+ OB << " ";
+ TargetType->output(OB, Flags);
+}
+
+void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ if (IsDestructor)
+ OB << "~";
+ Class->output(OB, Flags);
+ outputTemplateParameters(OB, Flags);
+}
+
+void LiteralOperatorIdentifierNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ OB << "operator \"\"" << Name;
+ outputTemplateParameters(OB, Flags);
+}
+
+void FunctionSignatureNode::outputPre(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (!(Flags & OF_NoAccessSpecifier)) {
+ if (FunctionClass & FC_Public)
+ OB << "public: ";
+ if (FunctionClass & FC_Protected)
+ OB << "protected: ";
+ if (FunctionClass & FC_Private)
+ OB << "private: ";
+ }
+
+ if (!(Flags & OF_NoMemberType)) {
+ if (!(FunctionClass & FC_Global)) {
+ if (FunctionClass & FC_Static)
+ OB << "static ";
+ }
+ if (FunctionClass & FC_Virtual)
+ OB << "virtual ";
+
+ if (FunctionClass & FC_ExternC)
+ OB << "extern \"C\" ";
+ }
+
+ if (!(Flags & OF_NoReturnType) && ReturnType) {
+ ReturnType->outputPre(OB, Flags);
+ OB << " ";
+ }
+
+ if (!(Flags & OF_NoCallingConvention))
+ outputCallingConvention(OB, CallConvention);
+}
+
+void FunctionSignatureNode::outputPost(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (!(FunctionClass & FC_NoParameterList)) {
+ OB << "(";
+ if (Params)
+ Params->output(OB, Flags);
+ else
+ OB << "void";
+
+ if (IsVariadic) {
+ if (OB.back() != '(')
+ OB << ", ";
+ OB << "...";
+ }
+ OB << ")";
+ }
+
+ if (Quals & Q_Const)
+ OB << " const";
+ if (Quals & Q_Volatile)
+ OB << " volatile";
+ if (Quals & Q_Restrict)
+ OB << " __restrict";
+ if (Quals & Q_Unaligned)
+ OB << " __unaligned";
+
+ if (IsNoexcept)
+ OB << " noexcept";
+
+ if (RefQualifier == FunctionRefQualifier::Reference)
+ OB << " &";
+ else if (RefQualifier == FunctionRefQualifier::RValueReference)
+ OB << " &&";
+
+ if (!(Flags & OF_NoReturnType) && ReturnType)
+ ReturnType->outputPost(OB, Flags);
+}
+
+void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ OB << "[thunk]: ";
+
+ FunctionSignatureNode::outputPre(OB, Flags);
+}
+
+void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
+ if (FunctionClass & FC_StaticThisAdjust) {
+ OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
+ } else if (FunctionClass & FC_VirtualThisAdjust) {
+ if (FunctionClass & FC_VirtualThisAdjustEx) {
+ OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
+ << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
+ << ", " << ThisAdjust.StaticOffset << "}'";
+ } else {
+ OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
+ << ThisAdjust.StaticOffset << "}'";
+ }
+ }
+
+ FunctionSignatureNode::outputPost(OB, Flags);
+}
+
+void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ if (Pointee->kind() == NodeKind::FunctionSignature) {
+ // If this is a pointer to a function, don't output the calling convention.
+ // It needs to go inside the parentheses.
+ const FunctionSignatureNode *Sig =
+ static_cast<const FunctionSignatureNode *>(Pointee);
+ Sig->outputPre(OB, OF_NoCallingConvention);
+ } else
+ Pointee->outputPre(OB, Flags);
+
+ outputSpaceIfNecessary(OB);
+
+ if (Quals & Q_Unaligned)
+ OB << "__unaligned ";
+
+ if (Pointee->kind() == NodeKind::ArrayType) {
+ OB << "(";
+ } else if (Pointee->kind() == NodeKind::FunctionSignature) {
+ OB << "(";
+ const FunctionSignatureNode *Sig =
+ static_cast<const FunctionSignatureNode *>(Pointee);
+ outputCallingConvention(OB, Sig->CallConvention);
+ OB << " ";
+ }
+
+ if (ClassParent) {
+ ClassParent->output(OB, Flags);
+ OB << "::";
+ }
+
+ switch (Affinity) {
+ case PointerAffinity::Pointer:
+ OB << "*";
+ break;
+ case PointerAffinity::Reference:
+ OB << "&";
+ break;
+ case PointerAffinity::RValueReference:
+ OB << "&&";
+ break;
+ default:
+ assert(false);
+ }
+ outputQualifiers(OB, Quals, false, false);
+}
+
+void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
+ if (Pointee->kind() == NodeKind::ArrayType ||
+ Pointee->kind() == NodeKind::FunctionSignature)
+ OB << ")";
+
+ Pointee->outputPost(OB, Flags);
+}
+
+void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ if (!(Flags & OF_NoTagSpecifier)) {
+ switch (Tag) {
+ OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
+ OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
+ OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
+ OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
+ }
+ OB << " ";
+ }
+ QualifiedName->output(OB, Flags);
+ outputQualifiers(OB, Quals, true, false);
+}
+
+void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
+
+void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ ElementType->outputPre(OB, Flags);
+ outputQualifiers(OB, Quals, true, false);
+}
+
+void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags,
+ Node *N) const {
+ assert(N->kind() == NodeKind::IntegerLiteral);
+ IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
+ if (ILN->Value != 0)
+ ILN->output(OB, Flags);
+}
+
+void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ if (Dimensions->Count == 0)
+ return;
+
+ outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
+ for (size_t I = 1; I < Dimensions->Count; ++I) {
+ OB << "][";
+ outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
+ }
+}
+
+void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
+ OB << "[";
+ outputDimensionsImpl(OB, Flags);
+ OB << "]";
+
+ ElementType->outputPost(OB, Flags);
+}
+
+void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Name->output(OB, Flags);
+}
+
+void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Signature->outputPre(OB, Flags);
+ outputSpaceIfNecessary(OB);
+ Name->output(OB, Flags);
+ Signature->outputPost(OB, Flags);
+}
+
+void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ const char *AccessSpec = nullptr;
+ bool IsStatic = true;
+ switch (SC) {
+ case StorageClass::PrivateStatic:
+ AccessSpec = "private";
+ break;
+ case StorageClass::PublicStatic:
+ AccessSpec = "public";
+ break;
+ case StorageClass::ProtectedStatic:
+ AccessSpec = "protected";
+ break;
+ default:
+ IsStatic = false;
+ break;
+ }
+ if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
+ OB << AccessSpec << ": ";
+ if (!(Flags & OF_NoMemberType) && IsStatic)
+ OB << "static ";
+
+ if (!(Flags & OF_NoVariableType) && Type) {
+ Type->outputPre(OB, Flags);
+ outputSpaceIfNecessary(OB);
+ }
+ Name->output(OB, Flags);
+ if (!(Flags & OF_NoVariableType) && Type)
+ Type->outputPost(OB, Flags);
+}
+
+void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ Identifier->output(OB, Flags);
+}
+void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
+
+void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Components->output(OB, Flags, "::");
+}
+
+void RttiBaseClassDescriptorNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ OB << "`RTTI Base Class Descriptor at (";
+ OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
+ << this->Flags;
+ OB << ")'";
+}
+
+void LocalStaticGuardVariableNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ Name->output(OB, Flags);
+}
+
+void VcallThunkIdentifierNode::output(OutputBuffer &OB,
+ OutputFlags Flags) const {
+ OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
+}
+
+void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ outputQualifiers(OB, Quals, false, true);
+ Name->output(OB, Flags);
+ if (TargetName) {
+ OB << "{for `";
+ TargetName->output(OB, Flags);
+ OB << "'}";
+ }
+}
diff --git a/demumble b/demumble
deleted file mode 160000
-Subproject d3e838b9f4ff995506024af51d43be161b98e23