diff --git a/CMakeLists.txt b/CMakeLists.txt
index cee7209..f91ba95 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,12 +3,14 @@
cmake_minimum_required(VERSION 3.22)
+project(yuzu)
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
+
include(DownloadExternals)
include(CMakeDependentOption)
-
-project(yuzu)
+include(CTest)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
@@ -42,7 +44,7 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
-option(YUZU_TESTS "Compile tests" ON)
+option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
@@ -242,7 +244,7 @@ if (ENABLE_WEB_SERVICE)
endif()
if (YUZU_TESTS)
- find_package(Catch2 2.13.7 REQUIRED)
+ find_package(Catch2 3.0.1 REQUIRED)
endif()
find_package(Boost 1.73.0 COMPONENTS context)
@@ -606,7 +608,6 @@ if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif()
endif()
-enable_testing()
add_subdirectory(externals)
add_subdirectory(src)
diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt
new file mode 100644
index 0000000..fa4b725
--- /dev/null
+++ b/LICENSES/LLVM-exception.txt
@@ -0,0 +1,15 @@
+---- 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.
diff --git a/dist/org.yuzu_emu.yuzu.metainfo.xml b/dist/org.yuzu_emu.yuzu.metainfo.xml
index fa3935c..cfd1741 100644
--- a/dist/org.yuzu_emu.yuzu.metainfo.xml
+++ b/dist/org.yuzu_emu.yuzu.metainfo.xml
@@ -53,10 +53,10 @@ SPDX-License-Identifier: CC0-1.0
yuzu Emulator Team
- https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png
- https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png
- https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png
- https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png
- https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png
+ https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png
+ https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png
+ https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png
+ https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png
+ https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index dfd40cb..94dd8bb 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -5,6 +5,9 @@
# some of its variables, which is only possible in 3.13+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
+# Disable tests in all externals supporting the standard option name
+set(BUILD_TESTING OFF)
+
# xbyak
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
add_subdirectory(xbyak EXCLUDE_FROM_ALL)
@@ -154,3 +157,7 @@ endif()
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
endif()
+
+add_library(demangle STATIC)
+target_include_directories(demangle PUBLIC ./demangle)
+target_sources(demangle PRIVATE demangle/ItaniumDemangle.cpp)
diff --git a/externals/demangle/Demangle.h b/externals/demangle/Demangle.h
new file mode 100644
index 0000000..5b673e4
--- /dev/null
+++ b/externals/demangle/Demangle.h
@@ -0,0 +1,104 @@
+//===--- 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-FileCopyrightText: Part of the LLVM Project
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEMANGLE_DEMANGLE_H
+#define LLVM_DEMANGLE_DEMANGLE_H
+
+#include
+#include
+
+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,
+};
+char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
+ int *status, MSDemangleFlags Flags = MSDF_None);
+
+/// "Partial" demangler. This supports demangling a string into an AST
+/// (typically an intermediate stage in itaniumDemangle) and querying certain
+/// properties or partially printing the demangled name.
+struct ItaniumPartialDemangler {
+ ItaniumPartialDemangler();
+
+ ItaniumPartialDemangler(ItaniumPartialDemangler &&Other);
+ ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other);
+
+ /// Demangle into an AST. Subsequent calls to the rest of the member functions
+ /// implicitly operate on the AST this produces.
+ /// \return true on error, false otherwise
+ bool partialDemangle(const char *MangledName);
+
+ /// Just print the entire mangled name into Buf. Buf and N behave like the
+ /// second and third parameters to itaniumDemangle.
+ char *finishDemangle(char *Buf, size_t *N) const;
+
+ /// Get the base name of a function. This doesn't include trailing template
+ /// arguments, ie for "a::b" 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 . 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/externals/demangle/DemangleConfig.h b/externals/demangle/DemangleConfig.h
new file mode 100644
index 0000000..a8aef9d
--- /dev/null
+++ b/externals/demangle/DemangleConfig.h
@@ -0,0 +1,93 @@
+//===--- 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-FileCopyrightText: Part of the LLVM Project
+// 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_COMPILER_H
+#define LLVM_DEMANGLE_COMPILER_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/externals/demangle/ItaniumDemangle.cpp b/externals/demangle/ItaniumDemangle.cpp
new file mode 100644
index 0000000..5e078e3
--- /dev/null
+++ b/externals/demangle/ItaniumDemangle.cpp
@@ -0,0 +1,588 @@
+//===------------------------- 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-FileCopyrightText: Part of the LLVM Project
+// 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 "Demangle.h"
+#include "ItaniumDemangle.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace llvm;
+using namespace llvm::itanium_demangle;
+
+constexpr const char *itanium_demangle::FloatData::spec;
+constexpr const char *itanium_demangle::FloatData::spec;
+constexpr const char *itanium_demangle::FloatData::spec;
+
+// := _ # when number < 10
+// := __ _ # 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 static constexpr bool wantsNewline(const NodeT *) {
+ return true;
+ }
+ static bool wantsNewline(NodeArray A) { return !A.empty(); }
+ static constexpr bool wantsNewline(...) { return false; }
+
+ template 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("");
+ }
+ void print(NodeOrString NS) {
+ if (NS.isNode())
+ print(NS.asNode());
+ else if (NS.isString())
+ print(NS.asString());
+ else
+ printStr("NodeOrString()");
+ }
+ void print(NodeArray A) {
+ ++Depth;
+ printStr("{");
+ bool First = true;
+ for (const Node *N : A) {
+ if (First)
+ print(N);
+ else
+ printWithComma(N);
+ First = false;
+ }
+ printStr("}");
+ --Depth;
+ }
+
+ // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
+ void print(bool B) { printStr(B ? "true" : "false"); }
+
+ template
+ typename std::enable_if::value>::type print(T N) {
+ fprintf(stderr, "%llu", (unsigned long long)N);
+ }
+
+ template
+ typename std::enable_if::value>::type print(T N) {
+ fprintf(stderr, "%lld", (long long)N);
+ }
+
+ void print(ReferenceKind RK) {
+ switch (RK) {
+ case ReferenceKind::LValue:
+ return printStr("ReferenceKind::LValue");
+ case ReferenceKind::RValue:
+ return printStr("ReferenceKind::RValue");
+ }
+ }
+ void print(FunctionRefQual RQ) {
+ switch (RQ) {
+ case FunctionRefQual::FrefQualNone:
+ return printStr("FunctionRefQual::FrefQualNone");
+ case FunctionRefQual::FrefQualLValue:
+ return printStr("FunctionRefQual::FrefQualLValue");
+ case FunctionRefQual::FrefQualRValue:
+ return printStr("FunctionRefQual::FrefQualRValue");
+ }
+ }
+ void print(Qualifiers Qs) {
+ if (!Qs) return printStr("QualNone");
+ struct QualName { Qualifiers Q; const char *Name; } Names[] = {
+ {QualConst, "QualConst"},
+ {QualVolatile, "QualVolatile"},
+ {QualRestrict, "QualRestrict"},
+ };
+ for (QualName Name : Names) {
+ if (Qs & Name.Q) {
+ printStr(Name.Name);
+ Qs = Qualifiers(Qs & ~Name.Q);
+ if (Qs) printStr(" | ");
+ }
+ }
+ }
+ void print(SpecialSubKind SSK) {
+ switch (SSK) {
+ case SpecialSubKind::allocator:
+ return printStr("SpecialSubKind::allocator");
+ case SpecialSubKind::basic_string:
+ return printStr("SpecialSubKind::basic_string");
+ case SpecialSubKind::string:
+ return printStr("SpecialSubKind::string");
+ case SpecialSubKind::istream:
+ return printStr("SpecialSubKind::istream");
+ case SpecialSubKind::ostream:
+ return printStr("SpecialSubKind::ostream");
+ case SpecialSubKind::iostream:
+ return printStr("SpecialSubKind::iostream");
+ }
+ }
+ void 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 newLine() {
+ printStr("\n");
+ for (unsigned I = 0; I != Depth; ++I)
+ printStr(" ");
+ PendingNewline = false;
+ }
+
+ template void printWithPendingNewline(T V) {
+ print(V);
+ if (wantsNewline(V))
+ PendingNewline = true;
+ }
+
+ template void printWithComma(T V) {
+ if (PendingNewline || wantsNewline(V)) {
+ printStr(",");
+ newLine();
+ } else {
+ printStr(", ");
+ }
+
+ printWithPendingNewline(V);
+ }
+
+ struct CtorArgPrinter {
+ DumpVisitor &Visitor;
+
+ template 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 void operator()(const NodeT *Node) {
+ Depth += 2;
+ fprintf(stderr, "%s(", itanium_demangle::NodeKind::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(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(std::malloc(NBytes));
+ if (NewMeta == nullptr)
+ std::terminate();
+ BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
+ return static_cast(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(reinterpret_cast(BlockList + 1) +
+ BlockList->Current - N);
+ }
+
+ void reset() {
+ while (BlockList) {
+ BlockMeta* Tmp = BlockList;
+ BlockList = BlockList->Next;
+ if (reinterpret_cast(Tmp) != InitialBuffer)
+ std::free(Tmp);
+ }
+ BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
+ }
+
+ ~BumpPointerAllocator() { reset(); }
+};
+
+class DefaultAllocator {
+ BumpPointerAllocator Alloc;
+
+public:
+ void reset() { Alloc.reset(); }
+
+ template T *makeNode(Args &&...args) {
+ return new (Alloc.allocate(sizeof(T)))
+ T(std::forward(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;
+
+char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
+ size_t *N, int *Status) {
+ if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
+ if (Status)
+ *Status = demangle_invalid_args;
+ return nullptr;
+ }
+
+ int InternalStatus = demangle_success;
+ Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
+ OutputStream S;
+
+ Node *AST = Parser.parse();
+
+ if (AST == nullptr)
+ InternalStatus = demangle_invalid_mangled_name;
+ else if (!initializeOutputStream(Buf, N, S, 1024))
+ InternalStatus = demangle_memory_alloc_failure;
+ else {
+ assert(Parser.ForwardTemplateRefs.empty());
+ AST->print(S);
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ Buf = S.getBuffer();
+ }
+
+ if (Status)
+ *Status = InternalStatus;
+ return InternalStatus == demangle_success ? Buf : nullptr;
+}
+
+ItaniumPartialDemangler::ItaniumPartialDemangler()
+ : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
+
+ItaniumPartialDemangler::~ItaniumPartialDemangler() {
+ delete static_cast(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(Context);
+ size_t Len = std::strlen(MangledName);
+ Parser->reset(MangledName, MangledName + Len);
+ RootNode = Parser->parse();
+ return RootNode == nullptr;
+}
+
+static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+ RootNode->print(S);
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+
+ const Node *Name = static_cast(RootNode)->getName();
+
+ while (true) {
+ switch (Name->getKind()) {
+ case Node::KAbiTagAttr:
+ Name = static_cast(Name)->Base;
+ continue;
+ case Node::KStdQualifiedName:
+ Name = static_cast(Name)->Child;
+ continue;
+ case Node::KNestedName:
+ Name = static_cast(Name)->Name;
+ continue;
+ case Node::KLocalName:
+ Name = static_cast(Name)->Entity;
+ continue;
+ case Node::KNameWithTemplateArgs:
+ Name = static_cast(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(RootNode)->getName();
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ KeepGoingLocalFunction:
+ while (true) {
+ if (Name->getKind() == Node::KAbiTagAttr) {
+ Name = static_cast(Name)->Base;
+ continue;
+ }
+ if (Name->getKind() == Node::KNameWithTemplateArgs) {
+ Name = static_cast(Name)->Name;
+ continue;
+ }
+ break;
+ }
+
+ switch (Name->getKind()) {
+ case Node::KStdQualifiedName:
+ S += "std";
+ break;
+ case Node::KNestedName:
+ static_cast(Name)->Qual->print(S);
+ break;
+ case Node::KLocalName: {
+ auto *LN = static_cast(Name);
+ LN->Encoding->print(S);
+ S += "::";
+ Name = LN->Entity;
+ goto KeepGoingLocalFunction;
+ }
+ default:
+ break;
+ }
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+ auto *Name = static_cast(RootNode)->getName();
+ return printNode(Name, Buf, N);
+}
+
+char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
+ size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+ NodeArray Params = static_cast(RootNode)->getParams();
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ S += '(';
+ Params.printWithComma(S);
+ S += ')';
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionReturnType(
+ char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ if (const Node *Ret =
+ static_cast(RootNode)->getReturnType())
+ Ret->print(S);
+
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ return printNode(static_cast(RootNode), Buf, N);
+}
+
+bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ if (!isFunction())
+ return false;
+ auto *E = static_cast(RootNode);
+ return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
+}
+
+bool ItaniumPartialDemangler::isCtorOrDtor() const {
+ const Node *N = static_cast(RootNode);
+ while (N) {
+ switch (N->getKind()) {
+ default:
+ return false;
+ case Node::KCtorDtorName:
+ return true;
+
+ case Node::KAbiTagAttr:
+ N = static_cast(N)->Base;
+ break;
+ case Node::KFunctionEncoding:
+ N = static_cast(N)->getName();
+ break;
+ case Node::KLocalName:
+ N = static_cast(N)->Entity;
+ break;
+ case Node::KNameWithTemplateArgs:
+ N = static_cast(N)->Name;
+ break;
+ case Node::KNestedName:
+ N = static_cast(N)->Name;
+ break;
+ case Node::KStdQualifiedName:
+ N = static_cast(N)->Child;
+ break;
+ }
+ }
+ return false;
+}
+
+bool ItaniumPartialDemangler::isFunction() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ return static_cast(RootNode)->getKind() ==
+ Node::KFunctionEncoding;
+}
+
+bool ItaniumPartialDemangler::isSpecialName() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ auto K = static_cast(RootNode)->getKind();
+ return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
+}
+
+bool ItaniumPartialDemangler::isData() const {
+ return !isFunction() && !isSpecialName();
+}
diff --git a/externals/demangle/ItaniumDemangle.h b/externals/demangle/ItaniumDemangle.h
new file mode 100644
index 0000000..64b35c1
--- /dev/null
+++ b/externals/demangle/ItaniumDemangle.h
@@ -0,0 +1,5582 @@
+//===------------------------- ItaniumDemangle.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-FileCopyrightText: Part of the LLVM Project
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic itanium demangler library. This file has two byte-per-byte identical
+// copies in the source tree, one in libcxxabi, and the other in llvm.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DEMANGLE_ITANIUMDEMANGLE_H
+#define DEMANGLE_ITANIUMDEMANGLE_H
+
+// FIXME: (possibly) incomplete list of features that clang mangles that this
+// file does not yet support:
+// - C++ modules TS
+
+#include "DemangleConfig.h"
+#include "StringView.h"
+#include "Utility.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define FOR_EACH_NODE_KIND(X) \
+ X(NodeArrayNode) \
+ X(DotSuffix) \
+ X(VendorExtQualType) \
+ X(QualType) \
+ X(ConversionOperatorType) \
+ X(PostfixQualifiedType) \
+ X(ElaboratedTypeSpefType) \
+ X(NameType) \
+ X(AbiTagAttr) \
+ X(EnableIfAttr) \
+ X(ObjCProtoName) \
+ X(PointerType) \
+ X(ReferenceType) \
+ X(PointerToMemberType) \
+ X(ArrayType) \
+ X(FunctionType) \
+ X(NoexceptSpec) \
+ X(DynamicExceptionSpec) \
+ X(FunctionEncoding) \
+ X(LiteralOperator) \
+ X(SpecialName) \
+ X(CtorVtableSpecialName) \
+ X(QualifiedName) \
+ X(NestedName) \
+ X(LocalName) \
+ X(VectorType) \
+ X(PixelVectorType) \
+ X(SyntheticTemplateParamName) \
+ X(TypeTemplateParamDecl) \
+ X(NonTypeTemplateParamDecl) \
+ X(TemplateTemplateParamDecl) \
+ X(TemplateParamPackDecl) \
+ X(ParameterPack) \
+ X(TemplateArgumentPack) \
+ X(ParameterPackExpansion) \
+ X(TemplateArgs) \
+ X(ForwardTemplateReference) \
+ X(NameWithTemplateArgs) \
+ X(GlobalQualifiedName) \
+ X(StdQualifiedName) \
+ X(ExpandedSpecialSubstitution) \
+ X(SpecialSubstitution) \
+ X(CtorDtorName) \
+ X(DtorName) \
+ X(UnnamedTypeName) \
+ X(ClosureTypeName) \
+ X(StructuredBindingName) \
+ X(BinaryExpr) \
+ X(ArraySubscriptExpr) \
+ X(PostfixExpr) \
+ X(ConditionalExpr) \
+ X(MemberExpr) \
+ X(EnclosingExpr) \
+ X(CastExpr) \
+ X(SizeofParamPackExpr) \
+ X(CallExpr) \
+ X(NewExpr) \
+ X(DeleteExpr) \
+ X(PrefixExpr) \
+ X(FunctionParam) \
+ X(ConversionExpr) \
+ X(InitListExpr) \
+ X(FoldExpr) \
+ X(ThrowExpr) \
+ X(UUIDOfExpr) \
+ X(BoolExpr) \
+ X(StringLiteral) \
+ X(LambdaExpr) \
+ X(IntegerCastExpr) \
+ X(IntegerLiteral) \
+ X(FloatLiteral) \
+ X(DoubleLiteral) \
+ X(LongDoubleLiteral) \
+ X(BracedExpr) \
+ X(BracedRangeExpr)
+
+DEMANGLE_NAMESPACE_BEGIN
+
+// Base class of all AST nodes. The AST is built by the parser, then is
+// traversed by the printLeft/Right functions to produce a demangled string.
+class Node {
+public:
+ enum Kind : unsigned char {
+#define ENUMERATOR(NodeKind) K ## NodeKind,
+ FOR_EACH_NODE_KIND(ENUMERATOR)
+#undef ENUMERATOR
+ };
+
+ /// Three-way bool to track a cached value. Unknown is possible if this node
+ /// has an unexpanded parameter pack below it that may affect this cache.
+ enum class Cache : unsigned char { Yes, No, Unknown, };
+
+private:
+ Kind K;
+
+ // FIXME: Make these protected.
+public:
+ /// Tracks if this node has a component on its right side, in which case we
+ /// need to call printRight.
+ Cache RHSComponentCache;
+
+ /// Track if this node is a (possibly qualified) array type. This can affect
+ /// how we format the output string.
+ Cache ArrayCache;
+
+ /// Track if this node is a (possibly qualified) function type. This can
+ /// affect how we format the output string.
+ Cache FunctionCache;
+
+public:
+ Node(Kind K_, Cache RHSComponentCache_ = Cache::No,
+ Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)
+ : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
+ FunctionCache(FunctionCache_) {}
+
+ /// Visit the most-derived object corresponding to this object.
+ template 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 void match(Fn F) const;
+
+ bool hasRHSComponent(OutputStream &S) const {
+ if (RHSComponentCache != Cache::Unknown)
+ return RHSComponentCache == Cache::Yes;
+ return hasRHSComponentSlow(S);
+ }
+
+ bool hasArray(OutputStream &S) const {
+ if (ArrayCache != Cache::Unknown)
+ return ArrayCache == Cache::Yes;
+ return hasArraySlow(S);
+ }
+
+ bool hasFunction(OutputStream &S) const {
+ if (FunctionCache != Cache::Unknown)
+ return FunctionCache == Cache::Yes;
+ return hasFunctionSlow(S);
+ }
+
+ Kind getKind() const { return K; }
+
+ virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
+ virtual bool hasArraySlow(OutputStream &) const { return false; }
+ virtual bool hasFunctionSlow(OutputStream &) const { return false; }
+
+ // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
+ // get at a node that actually represents some concrete syntax.
+ virtual const Node *getSyntaxNode(OutputStream &) const {
+ return this;
+ }
+
+ void print(OutputStream &S) const {
+ printLeft(S);
+ if (RHSComponentCache != Cache::No)
+ printRight(S);
+ }
+
+ // Print the "left" side of this Node into OutputStream.
+ virtual void printLeft(OutputStream &) const = 0;
+
+ // Print the "right". This distinction is necessary to represent C++ types
+ // that appear on the RHS of their subtype, such as arrays or functions.
+ // Since most types don't have such a component, provide a default
+ // implementation.
+ virtual void printRight(OutputStream &) const {}
+
+ virtual StringView getBaseName() const { return StringView(); }
+
+ // Silence compiler warnings, this dtor will never be called.
+ virtual ~Node() = default;
+
+#ifndef NDEBUG
+ 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(OutputStream &S) const {
+ bool FirstElement = true;
+ for (size_t Idx = 0; Idx != NumElements; ++Idx) {
+ size_t BeforeComma = S.getCurrentPosition();
+ if (!FirstElement)
+ S += ", ";
+ size_t AfterComma = S.getCurrentPosition();
+ Elements[Idx]->print(S);
+
+ // Elements[Idx] is an empty parameter pack expansion, we should erase the
+ // comma we just printed.
+ if (AfterComma == S.getCurrentPosition()) {
+ S.setCurrentPosition(BeforeComma);
+ continue;
+ }
+
+ FirstElement = false;
+ }
+ }
+};
+
+struct NodeArrayNode : Node {
+ NodeArray Array;
+ NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {}
+
+ template void match(Fn F) const { F(Array); }
+
+ void printLeft(OutputStream &S) const override {
+ Array.printWithComma(S);
+ }
+};
+
+class DotSuffix final : public Node {
+ const Node *Prefix;
+ const StringView Suffix;
+
+public:
+ DotSuffix(const Node *Prefix_, StringView Suffix_)
+ : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
+
+ template void match(Fn F) const { F(Prefix, Suffix); }
+
+ void printLeft(OutputStream &s) const override {
+ Prefix->print(s);
+ s += " (";
+ s += Suffix;
+ s += ")";
+ }
+};
+
+class VendorExtQualType final : public Node {
+ const Node *Ty;
+ StringView Ext;
+
+public:
+ VendorExtQualType(const Node *Ty_, StringView Ext_)
+ : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}
+
+ template void match(Fn F) const { F(Ty, Ext); }
+
+ void printLeft(OutputStream &S) const override {
+ Ty->print(S);
+ S += " ";
+ S += Ext;
+ }
+};
+
+enum FunctionRefQual : unsigned char {
+ FrefQualNone,
+ FrefQualLValue,
+ FrefQualRValue,
+};
+
+enum Qualifiers {
+ QualNone = 0,
+ QualConst = 0x1,
+ QualVolatile = 0x2,
+ QualRestrict = 0x4,
+};
+
+inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) {
+ return Q1 = static_cast(Q1 | Q2);
+}
+
+class QualType final : public Node {
+protected:
+ const Qualifiers Quals;
+ const Node *Child;
+
+ void printQuals(OutputStream &S) const {
+ if (Quals & QualConst)
+ S += " const";
+ if (Quals & QualVolatile)
+ S += " volatile";
+ if (Quals & QualRestrict)
+ S += " restrict";
+ }
+
+public:
+ QualType(const Node *Child_, Qualifiers Quals_)
+ : Node(KQualType, Child_->RHSComponentCache,
+ Child_->ArrayCache, Child_->FunctionCache),
+ Quals(Quals_), Child(Child_) {}
+
+ template void match(Fn F) const { F(Child, Quals); }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Child->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ return Child->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ return Child->hasFunction(S);
+ }
+
+ void printLeft(OutputStream &S) const override {
+ Child->printLeft(S);
+ printQuals(S);
+ }
+
+ void printRight(OutputStream &S) const override { Child->printRight(S); }
+};
+
+class ConversionOperatorType final : public Node {
+ const Node *Ty;
+
+public:
+ ConversionOperatorType(const Node *Ty_)
+ : Node(KConversionOperatorType), Ty(Ty_) {}
+
+ template void match(Fn F) const { F(Ty); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "operator ";
+ Ty->print(S);
+ }
+};
+
+class PostfixQualifiedType final : public Node {
+ const Node *Ty;
+ const StringView Postfix;
+
+public:
+ PostfixQualifiedType(Node *Ty_, StringView Postfix_)
+ : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
+
+ template void match(Fn F) const { F(Ty, Postfix); }
+
+ void printLeft(OutputStream &s) const override {
+ Ty->printLeft(s);
+ s += Postfix;
+ }
+};
+
+class NameType final : public Node {
+ const StringView Name;
+
+public:
+ NameType(StringView Name_) : Node(KNameType), Name(Name_) {}
+
+ template void match(Fn F) const { F(Name); }
+
+ StringView getName() const { return Name; }
+ StringView getBaseName() const override { return Name; }
+
+ void printLeft(OutputStream &s) const override { s += Name; }
+};
+
+class ElaboratedTypeSpefType : public Node {
+ StringView Kind;
+ Node *Child;
+public:
+ ElaboratedTypeSpefType(StringView Kind_, Node *Child_)
+ : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}
+
+ template void match(Fn F) const { F(Kind, Child); }
+
+ void printLeft(OutputStream &S) const override {
+ S += Kind;
+ S += ' ';
+ Child->print(S);
+ }
+};
+
+struct AbiTagAttr : Node {
+ Node *Base;
+ StringView Tag;
+
+ AbiTagAttr(Node* Base_, StringView Tag_)
+ : Node(KAbiTagAttr, Base_->RHSComponentCache,
+ Base_->ArrayCache, Base_->FunctionCache),
+ Base(Base_), Tag(Tag_) {}
+
+ template void match(Fn F) const { F(Base, Tag); }
+
+ void printLeft(OutputStream &S) const override {
+ Base->printLeft(S);
+ S += "[abi:";
+ S += Tag;
+ S += "]";
+ }
+};
+
+class EnableIfAttr : public Node {
+ NodeArray Conditions;
+public:
+ EnableIfAttr(NodeArray Conditions_)
+ : Node(KEnableIfAttr), Conditions(Conditions_) {}
+
+ template void match(Fn F) const { F(Conditions); }
+
+ void printLeft(OutputStream &S) const override {
+ S += " [enable_if:";
+ Conditions.printWithComma(S);
+ S += ']';
+ }
+};
+
+class ObjCProtoName : public Node {
+ const Node *Ty;
+ StringView Protocol;
+
+ friend class PointerType;
+
+public:
+ ObjCProtoName(const Node *Ty_, StringView Protocol_)
+ : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
+
+ template void match(Fn F) const { F(Ty, Protocol); }
+
+ bool isObjCObject() const {
+ return Ty->getKind() == KNameType &&
+ static_cast(Ty)->getName() == "objc_object";
+ }
+
+ void printLeft(OutputStream &S) const override {
+ Ty->print(S);
+ S += "<";
+ S += Protocol;
+ S += ">";
+ }
+};
+
+class PointerType final : public Node {
+ const Node *Pointee;
+
+public:
+ PointerType(const Node *Pointee_)
+ : Node(KPointerType, Pointee_->RHSComponentCache),
+ Pointee(Pointee_) {}
+
+ template void match(Fn F) const { F(Pointee); }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Pointee->hasRHSComponent(S);
+ }
+
+ void printLeft(OutputStream &s) const override {
+ // We rewrite objc_object* into id.
+ if (Pointee->getKind() != KObjCProtoName ||
+ !static_cast(Pointee)->isObjCObject()) {
+ Pointee->printLeft(s);
+ if (Pointee->hasArray(s))
+ s += " ";
+ if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+ s += "(";
+ s += "*";
+ } else {
+ const auto *objcProto = static_cast(Pointee);
+ s += "id<";
+ s += objcProto->Protocol;
+ s += ">";
+ }
+ }
+
+ void printRight(OutputStream &s) const override {
+ if (Pointee->getKind() != KObjCProtoName ||
+ !static_cast(Pointee)->isObjCObject()) {
+ if (Pointee->hasArray(s) || Pointee->hasFunction(s))
+ s += ")";
+ Pointee->printRight(s);
+ }
+ }
+};
+
+enum class ReferenceKind {
+ LValue,
+ RValue,
+};
+
+// Represents either a LValue or an RValue reference type.
+class ReferenceType : public Node {
+ const Node *Pointee;
+ ReferenceKind RK;
+
+ mutable bool Printing = false;
+
+ // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
+ // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
+ // other combination collapses to a lvalue ref.
+ std::pair collapse(OutputStream &S) const {
+ auto SoFar = std::make_pair(RK, Pointee);
+ for (;;) {
+ const Node *SN = SoFar.second->getSyntaxNode(S);
+ if (SN->getKind() != KReferenceType)
+ break;
+ auto *RT = static_cast(SN);
+ SoFar.second = RT->Pointee;
+ SoFar.first = std::min(SoFar.first, RT->RK);
+ }
+ return SoFar;
+ }
+
+public:
+ ReferenceType(const Node *Pointee_, ReferenceKind RK_)
+ : Node(KReferenceType, Pointee_->RHSComponentCache),
+ Pointee(Pointee_), RK(RK_) {}
+
+ template void match(Fn F) const { F(Pointee, RK); }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Pointee->hasRHSComponent(S);
+ }
+
+ void printLeft(OutputStream &s) const override {
+ if (Printing)
+ return;
+ SwapAndRestore SavePrinting(Printing, true);
+ std::pair Collapsed = collapse(s);
+ Collapsed.second->printLeft(s);
+ if (Collapsed.second->hasArray(s))
+ s += " ";
+ if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
+ s += "(";
+
+ s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
+ }
+ void printRight(OutputStream &s) const override {
+ if (Printing)
+ return;
+ SwapAndRestore SavePrinting(Printing, true);
+ std::pair Collapsed = collapse(s);
+ if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
+ s += ")";
+ Collapsed.second->printRight(s);
+ }
+};
+
+class PointerToMemberType final : public Node {
+ const Node *ClassType;
+ const Node *MemberType;
+
+public:
+ PointerToMemberType(const Node *ClassType_, const Node *MemberType_)
+ : Node(KPointerToMemberType, MemberType_->RHSComponentCache),
+ ClassType(ClassType_), MemberType(MemberType_) {}
+
+ template void match(Fn F) const { F(ClassType, MemberType); }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return MemberType->hasRHSComponent(S);
+ }
+
+ void printLeft(OutputStream &s) const override {
+ MemberType->printLeft(s);
+ if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+ s += "(";
+ else
+ s += " ";
+ ClassType->print(s);
+ s += "::*";
+ }
+
+ void printRight(OutputStream &s) const override {
+ if (MemberType->hasArray(s) || MemberType->hasFunction(s))
+ s += ")";
+ MemberType->printRight(s);
+ }
+};
+
+class NodeOrString {
+ const void *First;
+ const void *Second;
+
+public:
+ /* implicit */ NodeOrString(StringView Str) {
+ const char *FirstChar = Str.begin();
+ const char *SecondChar = Str.end();
+ if (SecondChar == nullptr) {
+ assert(FirstChar == SecondChar);
+ ++FirstChar, ++SecondChar;
+ }
+ First = static_cast(FirstChar);
+ Second = static_cast(SecondChar);
+ }
+
+ /* implicit */ NodeOrString(Node *N)
+ : First(static_cast(N)), Second(nullptr) {}
+ NodeOrString() : First(nullptr), Second(nullptr) {}
+
+ bool isString() const { return Second && First; }
+ bool isNode() const { return First && !Second; }
+ bool isEmpty() const { return !First && !Second; }
+
+ StringView asString() const {
+ assert(isString());
+ return StringView(static_cast(First),
+ static_cast(Second));
+ }
+
+ const Node *asNode() const {
+ assert(isNode());
+ return static_cast(First);
+ }
+};
+
+class ArrayType final : public Node {
+ const Node *Base;
+ NodeOrString Dimension;
+
+public:
+ ArrayType(const Node *Base_, NodeOrString Dimension_)
+ : Node(KArrayType,
+ /*RHSComponentCache=*/Cache::Yes,
+ /*ArrayCache=*/Cache::Yes),
+ Base(Base_), Dimension(Dimension_) {}
+
+ template void match(Fn F) const { F(Base, Dimension); }
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasArraySlow(OutputStream &) const override { return true; }
+
+ void printLeft(OutputStream &S) const override { Base->printLeft(S); }
+
+ void printRight(OutputStream &S) const override {
+ if (S.back() != ']')
+ S += " ";
+ S += "[";
+ if (Dimension.isString())
+ S += Dimension.asString();
+ else if (Dimension.isNode())
+ Dimension.asNode()->print(S);
+ S += "]";
+ Base->printRight(S);
+ }
+};
+
+class FunctionType final : public Node {
+ const Node *Ret;
+ NodeArray Params;
+ Qualifiers CVQuals;
+ FunctionRefQual RefQual;
+ const Node *ExceptionSpec;
+
+public:
+ FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,
+ FunctionRefQual RefQual_, const Node *ExceptionSpec_)
+ : Node(KFunctionType,
+ /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+ /*FunctionCache=*/Cache::Yes),
+ Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),
+ ExceptionSpec(ExceptionSpec_) {}
+
+ template void match(Fn F) const {
+ F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
+ }
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+ // Handle C++'s ... quirky decl grammar by using the left & right
+ // distinction. Consider:
+ // int (*f(float))(char) {}
+ // f is a function that takes a float and returns a pointer to a function
+ // that takes a char and returns an int. If we're trying to print f, start
+ // by printing out the return types's left, then print our parameters, then
+ // finally print right of the return type.
+ void printLeft(OutputStream &S) const override {
+ Ret->printLeft(S);
+ S += " ";
+ }
+
+ void printRight(OutputStream &S) const override {
+ S += "(";
+ Params.printWithComma(S);
+ S += ")";
+ Ret->printRight(S);
+
+ if (CVQuals & QualConst)
+ S += " const";
+ if (CVQuals & QualVolatile)
+ S += " volatile";
+ if (CVQuals & QualRestrict)
+ S += " restrict";
+
+ if (RefQual == FrefQualLValue)
+ S += " &";
+ else if (RefQual == FrefQualRValue)
+ S += " &&";
+
+ if (ExceptionSpec != nullptr) {
+ S += ' ';
+ ExceptionSpec->print(S);
+ }
+ }
+};
+
+class NoexceptSpec : public Node {
+ const Node *E;
+public:
+ NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {}
+
+ template void match(Fn F) const { F(E); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "noexcept(";
+ E->print(S);
+ S += ")";
+ }
+};
+
+class DynamicExceptionSpec : public Node {
+ NodeArray Types;
+public:
+ DynamicExceptionSpec(NodeArray Types_)
+ : Node(KDynamicExceptionSpec), Types(Types_) {}
+
+ template void match(Fn F) const { F(Types); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "throw(";
+ Types.printWithComma(S);
+ S += ')';
+ }
+};
+
+class FunctionEncoding final : public Node {
+ const Node *Ret;
+ const Node *Name;
+ NodeArray Params;
+ const Node *Attrs;
+ Qualifiers CVQuals;
+ FunctionRefQual RefQual;
+
+public:
+ FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
+ const Node *Attrs_, Qualifiers CVQuals_,
+ FunctionRefQual RefQual_)
+ : Node(KFunctionEncoding,
+ /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+ /*FunctionCache=*/Cache::Yes),
+ Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
+ CVQuals(CVQuals_), RefQual(RefQual_) {}
+
+ template void match(Fn F) const {
+ F(Ret, Name, Params, Attrs, CVQuals, RefQual);
+ }
+
+ Qualifiers getCVQuals() const { return CVQuals; }
+ FunctionRefQual getRefQual() const { return RefQual; }
+ NodeArray getParams() const { return Params; }
+ const Node *getReturnType() const { return Ret; }
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+ const Node *getName() const { return Name; }
+
+ void printLeft(OutputStream &S) const override {
+ if (Ret) {
+ Ret->printLeft(S);
+ if (!Ret->hasRHSComponent(S))
+ S += " ";
+ }
+ Name->print(S);
+ }
+
+ void printRight(OutputStream &S) const override {
+ S += "(";
+ Params.printWithComma(S);
+ S += ")";
+ if (Ret)
+ Ret->printRight(S);
+
+ if (CVQuals & QualConst)
+ S += " const";
+ if (CVQuals & QualVolatile)
+ S += " volatile";
+ if (CVQuals & QualRestrict)
+ S += " restrict";
+
+ if (RefQual == FrefQualLValue)
+ S += " &";
+ else if (RefQual == FrefQualRValue)
+ S += " &&";
+
+ if (Attrs != nullptr)
+ Attrs->print(S);
+ }
+};
+
+class LiteralOperator : public Node {
+ const Node *OpName;
+
+public:
+ LiteralOperator(const Node *OpName_)
+ : Node(KLiteralOperator), OpName(OpName_) {}
+
+ template void match(Fn F) const { F(OpName); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "operator\"\" ";
+ OpName->print(S);
+ }
+};
+
+class SpecialName final : public Node {
+ const StringView Special;
+ const Node *Child;
+
+public:
+ SpecialName(StringView Special_, const Node *Child_)
+ : Node(KSpecialName), Special(Special_), Child(Child_) {}
+
+ template void match(Fn F) const { F(Special, Child); }
+
+ void printLeft(OutputStream &S) const override {
+ S += Special;
+ Child->print(S);
+ }
+};
+
+class CtorVtableSpecialName final : public Node {
+ const Node *FirstType;
+ const Node *SecondType;
+
+public:
+ CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_)
+ : Node(KCtorVtableSpecialName),
+ FirstType(FirstType_), SecondType(SecondType_) {}
+
+ template void match(Fn F) const { F(FirstType, SecondType); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "construction vtable for ";
+ FirstType->print(S);
+ S += "-in-";
+ SecondType->print(S);
+ }
+};
+
+struct NestedName : Node {
+ Node *Qual;
+ Node *Name;
+
+ NestedName(Node *Qual_, Node *Name_)
+ : Node(KNestedName), Qual(Qual_), Name(Name_) {}
+
+ template void match(Fn F) const { F(Qual, Name); }
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ Qual->print(S);
+ S += "::";
+ Name->print(S);
+ }
+};
+
+struct LocalName : Node {
+ Node *Encoding;
+ Node *Entity;
+
+ LocalName(Node *Encoding_, Node *Entity_)
+ : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {}
+
+ template void match(Fn F) const { F(Encoding, Entity); }
+
+ void printLeft(OutputStream &S) const override {
+ Encoding->print(S);
+ S += "::";
+ Entity->print(S);
+ }
+};
+
+class QualifiedName final : public Node {
+ // qualifier::name
+ const Node *Qualifier;
+ const Node *Name;
+
+public:
+ QualifiedName(const Node *Qualifier_, const Node *Name_)
+ : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
+
+ template void match(Fn F) const { F(Qualifier, Name); }
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ Qualifier->print(S);
+ S += "::";
+ Name->print(S);
+ }
+};
+
+class VectorType final : public Node {
+ const Node *BaseType;
+ const NodeOrString Dimension;
+
+public:
+ VectorType(const Node *BaseType_, NodeOrString Dimension_)
+ : Node(KVectorType), BaseType(BaseType_),
+ Dimension(Dimension_) {}
+
+ template void match(Fn F) const { F(BaseType, Dimension); }
+
+ void printLeft(OutputStream &S) const override {
+ BaseType->print(S);
+ S += " vector[";
+ if (Dimension.isNode())
+ Dimension.asNode()->print(S);
+ else if (Dimension.isString())
+ S += Dimension.asString();
+ S += "]";
+ }
+};
+
+class PixelVectorType final : public Node {
+ const NodeOrString Dimension;
+
+public:
+ PixelVectorType(NodeOrString Dimension_)
+ : Node(KPixelVectorType), Dimension(Dimension_) {}
+
+ template void match(Fn F) const { F(Dimension); }
+
+ void printLeft(OutputStream &S) const override {
+ // FIXME: This should demangle as "vector pixel".
+ S += "pixel vector[";
+ S += Dimension.asString();
+ S += "]";
+ }
+};
+
+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 for a lambda with
+/// explicit template arguments, which might be referenced in the parameter
+/// types appearing later in the .
+class SyntheticTemplateParamName final : public Node {
+ TemplateParamKind Kind;
+ unsigned Index;
+
+public:
+ SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_)
+ : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {}
+
+ template void match(Fn F) const { F(Kind, Index); }
+
+ void printLeft(OutputStream &S) const override {
+ switch (Kind) {
+ case TemplateParamKind::Type:
+ S += "$T";
+ break;
+ case TemplateParamKind::NonType:
+ S += "$N";
+ break;
+ case TemplateParamKind::Template:
+ S += "$TT";
+ break;
+ }
+ if (Index > 0)
+ S << 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 void match(Fn F) const { F(Name); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "typename ";
+ }
+
+ void printRight(OutputStream &S) const override {
+ Name->print(S);
+ }
+};
+
+/// 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 void match(Fn F) const { F(Name, Type); }
+
+ void printLeft(OutputStream &S) const override {
+ Type->printLeft(S);
+ if (!Type->hasRHSComponent(S))
+ S += " ";
+ }
+
+ void printRight(OutputStream &S) const override {
+ Name->print(S);
+ Type->printRight(S);
+ }
+};
+
+/// A template template parameter declaration,
+/// 'template 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 void match(Fn F) const { F(Name, Params); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "template<";
+ Params.printWithComma(S);
+ S += "> typename ";
+ }
+
+ void printRight(OutputStream &S) const override {
+ Name->print(S);
+ }
+};
+
+/// 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 void match(Fn F) const { F(Param); }
+
+ void printLeft(OutputStream &S) const override {
+ Param->printLeft(S);
+ S += "...";
+ }
+
+ void printRight(OutputStream &S) const override {
+ Param->printRight(S);
+ }
+};
+
+/// An unexpanded parameter pack (either in the expression or type context). If
+/// this AST is correct, this node will have a ParameterPackExpansion node above
+/// it.
+///
+/// This node is created when some are found that apply to an
+/// , and is stored in the TemplateParams table. In order for this to
+/// appear in the final AST, it has to referenced via a (ie,
+/// T_).
+class ParameterPack final : public Node {
+ NodeArray Data;
+
+ // Setup OutputStream for a pack expansion unless we're already expanding one.
+ void initializePackExpansion(OutputStream &S) const {
+ if (S.CurrentPackMax == std::numeric_limits::max()) {
+ S.CurrentPackMax = static_cast(Data.size());
+ S.CurrentPackIndex = 0;
+ }
+ }
+
+public:
+ ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {
+ ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->ArrayCache == Cache::No;
+ }))
+ ArrayCache = Cache::No;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->FunctionCache == Cache::No;
+ }))
+ FunctionCache = Cache::No;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->RHSComponentCache == Cache::No;
+ }))
+ RHSComponentCache = Cache::No;
+ }
+
+ template void match(Fn F) const { F(Data); }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasFunction(S);
+ }
+ const Node *getSyntaxNode(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
+ }
+
+ void printLeft(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printLeft(S);
+ }
+ void printRight(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printRight(S);
+ }
+};
+
+/// A variadic template argument. This node represents an occurrence of
+/// JE in some . It isn't itself unexpanded, unless
+/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// TemplateParams table if the this pack belongs to apply to an
+/// .
+class TemplateArgumentPack final : public Node {
+ NodeArray Elements;
+public:
+ TemplateArgumentPack(NodeArray Elements_)
+ : Node(KTemplateArgumentPack), Elements(Elements_) {}
+
+ template void match(Fn F) const { F(Elements); }
+
+ NodeArray getElements() const { return Elements; }
+
+ void printLeft(OutputStream &S) const override {
+ Elements.printWithComma(S);
+ }
+};
+
+/// A pack expansion. Below this node, there are some unexpanded ParameterPacks
+/// which each have Child->ParameterPackSize elements.
+class ParameterPackExpansion final : public Node {
+ const Node *Child;
+
+public:
+ ParameterPackExpansion(const Node *Child_)
+ : Node(KParameterPackExpansion), Child(Child_) {}
+
+ template void match(Fn F) const { F(Child); }
+
+ const Node *getChild() const { return Child; }
+
+ void printLeft(OutputStream &S) const override {
+ constexpr unsigned Max = std::numeric_limits::max();
+ SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max);
+ SwapAndRestore SavePackMax(S.CurrentPackMax, Max);
+ size_t StreamPos = S.getCurrentPosition();
+
+ // Print the first element in the pack. If Child contains a ParameterPack,
+ // it will set up S.CurrentPackMax and print the first element.
+ Child->print(S);
+
+ // No ParameterPack was found in Child. This can occur if we've found a pack
+ // expansion on a .
+ if (S.CurrentPackMax == Max) {
+ S += "...";
+ return;
+ }
+
+ // We found a ParameterPack, but it has no elements. Erase whatever we may
+ // of printed.
+ if (S.CurrentPackMax == 0) {
+ S.setCurrentPosition(StreamPos);
+ return;
+ }
+
+ // Else, iterate through the rest of the elements in the pack.
+ for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
+ S += ", ";
+ S.CurrentPackIndex = I;
+ Child->print(S);
+ }
+ }
+};
+
+class TemplateArgs final : public Node {
+ NodeArray Params;
+
+public:
+ TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+
+ template void match(Fn F) const { F(Params); }
+
+ NodeArray getParams() { return Params; }
+
+ void printLeft(OutputStream &S) const override {
+ S += "<";
+ Params.printWithComma(S);
+ if (S.back() == '>')
+ S += " ";
+ S += ">";
+ }
+};
+
+/// A forward-reference to a template argument that was not known at the point
+/// where the template parameter name was parsed in a mangling.
+///
+/// This is created when demangling the name of a specialization of a
+/// conversion function template:
+///
+/// \code
+/// struct A {
+/// template 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 void match(Fn F) const = delete;
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore SavePrinting(Printing, true);
+ return Ref->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore SavePrinting(Printing, true);
+ return Ref->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore SavePrinting(Printing, true);
+ return Ref->hasFunction(S);
+ }
+ const Node *getSyntaxNode(OutputStream &S) const override {
+ if (Printing)
+ return this;
+ SwapAndRestore SavePrinting(Printing, true);
+ return Ref->getSyntaxNode(S);
+ }
+
+ void printLeft(OutputStream &S) const override {
+ if (Printing)
+ return;
+ SwapAndRestore SavePrinting(Printing, true);
+ Ref->printLeft(S);
+ }
+ void printRight(OutputStream &S) const override {
+ if (Printing)
+ return;
+ SwapAndRestore SavePrinting(Printing, true);
+ Ref->printRight(S);
+ }
+};
+
+struct NameWithTemplateArgs : Node {
+ // name
+ Node *Name;
+ Node *TemplateArgs;
+
+ NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
+ : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
+
+ template void match(Fn F) const { F(Name, TemplateArgs); }
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ Name->print(S);
+ TemplateArgs->print(S);
+ }
+};
+
+class GlobalQualifiedName final : public Node {
+ Node *Child;
+
+public:
+ GlobalQualifiedName(Node* Child_)
+ : Node(KGlobalQualifiedName), Child(Child_) {}
+
+ template void match(Fn F) const { F(Child); }
+
+ StringView getBaseName() const override { return Child->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "::";
+ Child->print(S);
+ }
+};
+
+struct StdQualifiedName : Node {
+ Node *Child;
+
+ StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
+
+ template void match(Fn F) const { F(Child); }
+
+ StringView getBaseName() const override { return Child->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "std::";
+ Child->print(S);
+ }
+};
+
+enum class SpecialSubKind {
+ allocator,
+ basic_string,
+ string,
+ istream,
+ ostream,
+ iostream,
+};
+
+class ExpandedSpecialSubstitution final : public Node {
+ SpecialSubKind SSK;
+
+public:
+ ExpandedSpecialSubstitution(SpecialSubKind SSK_)
+ : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
+
+ template void match(Fn F) const { F(SSK); }
+
+ StringView getBaseName() const override {
+ switch (SSK) {
+ case SpecialSubKind::allocator:
+ return StringView("allocator");
+ case SpecialSubKind::basic_string:
+ return StringView("basic_string");
+ case SpecialSubKind::string:
+ return StringView("basic_string");
+ case SpecialSubKind::istream:
+ return StringView("basic_istream");
+ case SpecialSubKind::ostream:
+ return StringView("basic_ostream");
+ case SpecialSubKind::iostream:
+ return StringView("basic_iostream");
+ }
+ DEMANGLE_UNREACHABLE;
+ }
+
+ void printLeft(OutputStream &S) const override {
+ switch (SSK) {
+ case SpecialSubKind::allocator:
+ S += "std::allocator";
+ break;
+ case SpecialSubKind::basic_string:
+ S += "std::basic_string";
+ break;
+ case SpecialSubKind::string:
+ S += "std::basic_string, "
+ "std::allocator >";
+ break;
+ case SpecialSubKind::istream:
+ S += "std::basic_istream >";
+ break;
+ case SpecialSubKind::ostream:
+ S += "std::basic_ostream >";
+ break;
+ case SpecialSubKind::iostream:
+ S += "std::basic_iostream >";
+ break;
+ }
+ }
+};
+
+class SpecialSubstitution final : public Node {
+public:
+ SpecialSubKind SSK;
+
+ SpecialSubstitution(SpecialSubKind SSK_)
+ : Node(KSpecialSubstitution), SSK(SSK_) {}
+
+ template void match(Fn F) const { F(SSK); }
+
+ StringView getBaseName() const override {
+ switch (SSK) {
+ case SpecialSubKind::allocator:
+ return StringView("allocator");
+ case SpecialSubKind::basic_string:
+ return StringView("basic_string");
+ case SpecialSubKind::string:
+ return StringView("string");
+ case SpecialSubKind::istream:
+ return StringView("istream");
+ case SpecialSubKind::ostream:
+ return StringView("ostream");
+ case SpecialSubKind::iostream:
+ return StringView("iostream");
+ }
+ DEMANGLE_UNREACHABLE;
+ }
+
+ void printLeft(OutputStream &S) const override {
+ switch (SSK) {
+ case SpecialSubKind::allocator:
+ S += "std::allocator";
+ break;
+ case SpecialSubKind::basic_string:
+ S += "std::basic_string";
+ break;
+ case SpecialSubKind::string:
+ S += "std::string";
+ break;
+ case SpecialSubKind::istream:
+ S += "std::istream";
+ break;
+ case SpecialSubKind::ostream:
+ S += "std::ostream";
+ break;
+ case SpecialSubKind::iostream:
+ S += "std::iostream";
+ break;
+ }
+ }
+};
+
+class CtorDtorName final : public Node {
+ const Node *Basename;
+ const bool IsDtor;
+ const int Variant;
+
+public:
+ CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_)
+ : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_),
+ Variant(Variant_) {}
+
+ template void match(Fn F) const { F(Basename, IsDtor, Variant); }
+
+ void printLeft(OutputStream &S) const override {
+ if (IsDtor)
+ S += "~";
+ S += Basename->getBaseName();
+ }
+};
+
+class DtorName : public Node {
+ const Node *Base;
+
+public:
+ DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {}
+
+ template void match(Fn F) const { F(Base); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "~";
+ Base->printLeft(S);
+ }
+};
+
+class UnnamedTypeName : public Node {
+ const StringView Count;
+
+public:
+ UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}
+
+ template void match(Fn F) const { F(Count); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "'unnamed";
+ S += Count;
+ S += "\'";
+ }
+};
+
+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 void match(Fn F) const {
+ F(TemplateParams, Params, Count);
+ }
+
+ void printDeclarator(OutputStream &S) const {
+ if (!TemplateParams.empty()) {
+ S += "<";
+ TemplateParams.printWithComma(S);
+ S += ">";
+ }
+ S += "(";
+ Params.printWithComma(S);
+ S += ")";
+ }
+
+ void printLeft(OutputStream &S) const override {
+ S += "\'lambda";
+ S += Count;
+ S += "\'";
+ printDeclarator(S);
+ }
+};
+
+class StructuredBindingName : public Node {
+ NodeArray Bindings;
+public:
+ StructuredBindingName(NodeArray Bindings_)
+ : Node(KStructuredBindingName), Bindings(Bindings_) {}
+
+ template void match(Fn F) const { F(Bindings); }
+
+ void printLeft(OutputStream &S) const override {
+ S += '[';
+ Bindings.printWithComma(S);
+ S += ']';
+ }
+};
+
+// -- Expression Nodes --
+
+class BinaryExpr : public Node {
+ const Node *LHS;
+ const StringView InfixOperator;
+ const Node *RHS;
+
+public:
+ BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_)
+ : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {
+ }
+
+ template void match(Fn F) const { F(LHS, InfixOperator, RHS); }
+
+ void printLeft(OutputStream &S) const override {
+ // might be a template argument expression, then we need to disambiguate
+ // with parens.
+ if (InfixOperator == ">")
+ S += "(";
+
+ S += "(";
+ LHS->print(S);
+ S += ") ";
+ S += InfixOperator;
+ S += " (";
+ RHS->print(S);
+ S += ")";
+
+ if (InfixOperator == ">")
+ S += ")";
+ }
+};
+
+class ArraySubscriptExpr : public Node {
+ const Node *Op1;
+ const Node *Op2;
+
+public:
+ ArraySubscriptExpr(const Node *Op1_, const Node *Op2_)
+ : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {}
+
+ template void match(Fn F) const { F(Op1, Op2); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "(";
+ Op1->print(S);
+ S += ")[";
+ Op2->print(S);
+ S += "]";
+ }
+};
+
+class PostfixExpr : public Node {
+ const Node *Child;
+ const StringView Operator;
+
+public:
+ PostfixExpr(const Node *Child_, StringView Operator_)
+ : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {}
+
+ template void match(Fn F) const { F(Child, Operator); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "(";
+ Child->print(S);
+ S += ")";
+ S += Operator;
+ }
+};
+
+class ConditionalExpr : public Node {
+ const Node *Cond;
+ const Node *Then;
+ const Node *Else;
+
+public:
+ ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_)
+ : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {}
+
+ template void match(Fn F) const { F(Cond, Then, Else); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "(";
+ Cond->print(S);
+ S += ") ? (";
+ Then->print(S);
+ S += ") : (";
+ Else->print(S);
+ S += ")";
+ }
+};
+
+class MemberExpr : public Node {
+ const Node *LHS;
+ const StringView Kind;
+ const Node *RHS;
+
+public:
+ MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_)
+ : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
+
+ template void match(Fn F) const { F(LHS, Kind, RHS); }
+
+ void printLeft(OutputStream &S) const override {
+ LHS->print(S);
+ S += Kind;
+ RHS->print(S);
+ }
+};
+
+class EnclosingExpr : public Node {
+ const StringView Prefix;
+ const Node *Infix;
+ const StringView Postfix;
+
+public:
+ EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
+ : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_),
+ Postfix(Postfix_) {}
+
+ template void match(Fn F) const { F(Prefix, Infix, Postfix); }
+
+ void printLeft(OutputStream &S) const override {
+ S += Prefix;
+ Infix->print(S);
+ S += Postfix;
+ }
+};
+
+class CastExpr : public Node {
+ // cast_kind(from)
+ const StringView CastKind;
+ const Node *To;
+ const Node *From;
+
+public:
+ CastExpr(StringView CastKind_, const Node *To_, const Node *From_)
+ : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {}
+
+ template void match(Fn F) const { F(CastKind, To, From); }
+
+ void printLeft(OutputStream &S) const override {
+ S += CastKind;
+ S += "<";
+ To->printLeft(S);
+ S += ">(";
+ From->printLeft(S);
+ S += ")";
+ }
+};
+
+class SizeofParamPackExpr : public Node {
+ const Node *Pack;
+
+public:
+ SizeofParamPackExpr(const Node *Pack_)
+ : Node(KSizeofParamPackExpr), Pack(Pack_) {}
+
+ template void match(Fn F) const { F(Pack); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "sizeof...(";
+ ParameterPackExpansion PPE(Pack);
+ PPE.printLeft(S);
+ S += ")";
+ }
+};
+
+class CallExpr : public Node {
+ const Node *Callee;
+ NodeArray Args;
+
+public:
+ CallExpr(const Node *Callee_, NodeArray Args_)
+ : Node(KCallExpr), Callee(Callee_), Args(Args_) {}
+
+ template void match(Fn F) const { F(Callee, Args); }
+
+ void printLeft(OutputStream &S) const override {
+ Callee->print(S);
+ S += "(";
+ Args.printWithComma(S);
+ S += ")";
+ }
+};
+
+class NewExpr : public Node {
+ // new (expr_list) type(init_list)
+ NodeArray ExprList;
+ Node *Type;
+ NodeArray InitList;
+ bool IsGlobal; // ::operator new ?
+ bool IsArray; // new[] ?
+public:
+ NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
+ bool IsArray_)
+ : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_),
+ IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+
+ template void match(Fn F) const {
+ F(ExprList, Type, InitList, IsGlobal, IsArray);
+ }
+
+ void printLeft(OutputStream &S) const override {
+ if (IsGlobal)
+ S += "::operator ";
+ S += "new";
+ if (IsArray)
+ S += "[]";
+ S += ' ';
+ if (!ExprList.empty()) {
+ S += "(";
+ ExprList.printWithComma(S);
+ S += ")";
+ }
+ Type->print(S);
+ if (!InitList.empty()) {
+ S += "(";
+ InitList.printWithComma(S);
+ S += ")";
+ }
+
+ }
+};
+
+class DeleteExpr : public Node {
+ Node *Op;
+ bool IsGlobal;
+ bool IsArray;
+
+public:
+ DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
+ : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+
+ template void match(Fn F) const { F(Op, IsGlobal, IsArray); }
+
+ void printLeft(OutputStream &S) const override {
+ if (IsGlobal)
+ S += "::";
+ S += "delete";
+ if (IsArray)
+ S += "[] ";
+ Op->print(S);
+ }
+};
+
+class PrefixExpr : public Node {
+ StringView Prefix;
+ Node *Child;
+
+public:
+ PrefixExpr(StringView Prefix_, Node *Child_)
+ : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {}
+
+ template void match(Fn F) const { F(Prefix, Child); }
+
+ void printLeft(OutputStream &S) const override {
+ S += Prefix;
+ S += "(";
+ Child->print(S);
+ S += ")";
+ }
+};
+
+class FunctionParam : public Node {
+ StringView Number;
+
+public:
+ FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {}
+
+ template void match(Fn F) const { F(Number); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "fp";
+ S += Number;
+ }
+};
+
+class ConversionExpr : public Node {
+ const Node *Type;
+ NodeArray Expressions;
+
+public:
+ ConversionExpr(const Node *Type_, NodeArray Expressions_)
+ : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {}
+
+ template void match(Fn F) const { F(Type, Expressions); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "(";
+ Type->print(S);
+ S += ")(";
+ Expressions.printWithComma(S);
+ S += ")";
+ }
+};
+
+class InitListExpr : public Node {
+ const Node *Ty;
+ NodeArray Inits;
+public:
+ InitListExpr(const Node *Ty_, NodeArray Inits_)
+ : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {}
+
+ template void match(Fn F) const { F(Ty, Inits); }
+
+ void printLeft(OutputStream &S) const override {
+ if (Ty)
+ Ty->print(S);
+ S += '{';
+ Inits.printWithComma(S);
+ S += '}';
+ }
+};
+
+class BracedExpr : public Node {
+ const Node *Elem;
+ const Node *Init;
+ bool IsArray;
+public:
+ BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_)
+ : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}
+
+ template void match(Fn F) const { F(Elem, Init, IsArray); }
+
+ void printLeft(OutputStream &S) const override {
+ if (IsArray) {
+ S += '[';
+ Elem->print(S);
+ S += ']';
+ } else {
+ S += '.';
+ Elem->print(S);
+ }
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ S += " = ";
+ Init->print(S);
+ }
+};
+
+class BracedRangeExpr : public Node {
+ const Node *First;
+ const Node *Last;
+ const Node *Init;
+public:
+ BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_)
+ : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}
+
+ template void match(Fn F) const { F(First, Last, Init); }
+
+ void printLeft(OutputStream &S) const override {
+ S += '[';
+ First->print(S);
+ S += " ... ";
+ Last->print(S);
+ S += ']';
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ S += " = ";
+ Init->print(S);
+ }
+};
+
+class FoldExpr : public Node {
+ const Node *Pack, *Init;
+ StringView OperatorName;
+ bool IsLeftFold;
+
+public:
+ FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_,
+ const Node *Init_)
+ : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_),
+ IsLeftFold(IsLeftFold_) {}
+
+ template void match(Fn F) const {
+ F(IsLeftFold, OperatorName, Pack, Init);
+ }
+
+ void printLeft(OutputStream &S) const override {
+ auto PrintPack = [&] {
+ S += '(';
+ ParameterPackExpansion(Pack).print(S);
+ S += ')';
+ };
+
+ S += '(';
+
+ if (IsLeftFold) {
+ // init op ... op pack
+ if (Init != nullptr) {
+ Init->print(S);
+ S += ' ';
+ S += OperatorName;
+ S += ' ';
+ }
+ // ... op pack
+ S += "... ";
+ S += OperatorName;
+ S += ' ';
+ PrintPack();
+ } else { // !IsLeftFold
+ // pack op ...
+ PrintPack();
+ S += ' ';
+ S += OperatorName;
+ S += " ...";
+ // pack op ... op init
+ if (Init != nullptr) {
+ S += ' ';
+ S += OperatorName;
+ S += ' ';
+ Init->print(S);
+ }
+ }
+ S += ')';
+ }
+};
+
+class ThrowExpr : public Node {
+ const Node *Op;
+
+public:
+ ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {}
+
+ template void match(Fn F) const { F(Op); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "throw ";
+ Op->print(S);
+ }
+};
+
+// MSVC __uuidof extension, generated by clang in -fms-extensions mode.
+class UUIDOfExpr : public Node {
+ Node *Operand;
+public:
+ UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {}
+
+ template void match(Fn F) const { F(Operand); }
+
+ void printLeft(OutputStream &S) const override {
+ S << "__uuidof(";
+ Operand->print(S);
+ S << ")";
+ }
+};
+
+class BoolExpr : public Node {
+ bool Value;
+
+public:
+ BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {}
+
+ template void match(Fn F) const { F(Value); }
+
+ void printLeft(OutputStream &S) const override {
+ S += Value ? StringView("true") : StringView("false");
+ }
+};
+
+class StringLiteral : public Node {
+ const Node *Type;
+
+public:
+ StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {}
+
+ template void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "\"<";
+ Type->print(S);
+ S += ">\"";
+ }
+};
+
+class LambdaExpr : public Node {
+ const Node *Type;
+
+public:
+ LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {}
+
+ template void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "[]";
+ if (Type->getKind() == KClosureTypeName)
+ static_cast(Type)->printDeclarator(S);
+ S += "{...}";
+ }
+};
+
+class IntegerCastExpr : public Node {
+ // ty(integer)
+ const Node *Ty;
+ StringView Integer;
+
+public:
+ IntegerCastExpr(const Node *Ty_, StringView Integer_)
+ : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {}
+
+ template void match(Fn F) const { F(Ty, Integer); }
+
+ void printLeft(OutputStream &S) const override {
+ S += "(";
+ Ty->print(S);
+ S += ")";
+ S += Integer;
+ }
+};
+
+class IntegerLiteral : public Node {
+ StringView Type;
+ StringView Value;
+
+public:
+ IntegerLiteral(StringView Type_, StringView Value_)
+ : Node(KIntegerLiteral), Type(Type_), Value(Value_) {}
+
+ template void match(Fn F) const { F(Type, Value); }
+
+ void printLeft(OutputStream &S) const override {
+ if (Type.size() > 3) {
+ S += "(";
+ S += Type;
+ S += ")";
+ }
+
+ if (Value[0] == 'n') {
+ S += "-";
+ S += Value.dropFront(1);
+ } else
+ S += Value;
+
+ if (Type.size() <= 3)
+ S += Type;
+ }
+};
+
+template 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 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 void match(Fn F) const { F(Contents); }
+
+ void printLeft(OutputStream &s) const override {
+ const char *first = Contents.begin();
+ const char *last = Contents.end() + 1;
+
+ const size_t N = FloatData::mangled_size;
+ if (static_cast(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(*t - '0')
+ : static_cast(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast(*t - '0')
+ : static_cast(*t - 'a' + 10);
+ *e = static_cast((d1 << 4) + d0);
+ }
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[FloatData::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), FloatData::spec, value);
+ s += StringView(num, num + n);
+ }
+ }
+};
+
+using FloatLiteral = FloatLiteralImpl;
+using DoubleLiteral = FloatLiteralImpl;
+using LongDoubleLiteral = FloatLiteralImpl;
+
+/// Visit the node. Calls \c F(P), where \c P is the node cast to the
+/// appropriate derived class.
+template
+void Node::visit(Fn F) const {
+ switch (K) {
+#define CASE(X) case K ## X: return F(static_cast(this));
+ FOR_EACH_NODE_KIND(CASE)
+#undef CASE
+ }
+ assert(0 && "unknown mangling node kind");
+}
+
+/// Determine the kind of a node from its type.
+template struct NodeKind;
+#define SPECIALIZATION(X) \
+ template<> struct NodeKind { \
+ static constexpr Node::Kind Kind = Node::K##X; \
+ static constexpr const char *name() { return #X; } \
+ };
+FOR_EACH_NODE_KIND(SPECIALIZATION)
+#undef SPECIALIZATION
+
+#undef FOR_EACH_NODE_KIND
+
+template
+class PODSmallVector {
+ static_assert(std::is_pod::value,
+ "T is required to be a plain old data type");
+
+ T* First;
+ T* Last;
+ T* Cap;
+ T Inline[N];
+
+ bool isInline() const { return First == Inline; }
+
+ void clearInline() {
+ First = Inline;
+ Last = Inline;
+ Cap = Inline + N;
+ }
+
+ void reserve(size_t NewCap) {
+ size_t S = size();
+ if (isInline()) {
+ auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T)));
+ if (Tmp == nullptr)
+ std::terminate();
+ std::copy(First, Last, Tmp);
+ First = Tmp;
+ } else {
+ First = static_cast(std::realloc(First, NewCap * sizeof(T)));
+ if (First == nullptr)
+ std::terminate();
+ }
+ Last = First + S;
+ Cap = First + NewCap;
+ }
+
+public:
+ PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
+
+ PODSmallVector(const PODSmallVector&) = delete;
+ PODSmallVector& operator=(const PODSmallVector&) = delete;
+
+ PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
+ if (Other.isInline()) {
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return;
+ }
+
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ }
+
+ PODSmallVector& operator=(PODSmallVector&& Other) {
+ if (Other.isInline()) {
+ if (!isInline()) {
+ std::free(First);
+ clearInline();
+ }
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return *this;
+ }
+
+ if (isInline()) {
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ return *this;
+ }
+
+ std::swap(First, Other.First);
+ std::swap(Last, Other.Last);
+ std::swap(Cap, Other.Cap);
+ Other.clear();
+ return *this;
+ }
+
+ void push_back(const T& Elem) {
+ if (Last == Cap)
+ reserve(size() * 2);
+ *Last++ = Elem;
+ }
+
+ void pop_back() {
+ assert(Last != First && "Popping empty vector!");
+ --Last;
+ }
+
+ void dropBack(size_t Index) {
+ assert(Index <= size() && "dropBack() can't expand!");
+ Last = First + Index;
+ }
+
+ T* begin() { return First; }
+ T* end() { return Last; }
+
+ bool empty() const { return First == Last; }
+ size_t size() const { return static_cast(Last - First); }
+ T& back() {
+ assert(Last != First && "Calling back() on empty vector!");
+ return *(Last - 1);
+ }
+ T& operator[](size_t Index) {
+ assert(Index < size() && "Invalid access!");
+ return *(begin() + Index);
+ }
+ void clear() { Last = First; }
+
+ ~PODSmallVector() {
+ if (!isInline())
+ std::free(First);
+ }
+};
+
+template 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 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 Subs;
+
+ using TemplateParamList = PODSmallVector;
+
+ class ScopedTemplateParamList {
+ AbstractManglingParser *Parser;
+ size_t OldNumTemplateParamLists;
+ TemplateParamList Params;
+
+ public:
+ ScopedTemplateParamList(AbstractManglingParser *Parser)
+ : Parser(Parser),
+ OldNumTemplateParamLists(Parser->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 TemplateParams;
+
+ // Set of unresolved forward references. These can occur in a
+ // conversion operator's type, and are resolved in the enclosing .
+ PODSmallVector 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(*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 Node *make(Args &&... args) {
+ return ASTAllocator.template makeNode(std::forward(args)...);
+ }
+
+ template NodeArray makeNodeArray(It begin, It end) {
+ size_t sz = static_cast(end - begin);
+ void *mem = ASTAllocator.allocateNodeArray(sz);
+ Node **data = new (mem) Node *[sz];
+ std::copy(begin, end, data);
+ return NodeArray(data, sz);
+ }
+
+ NodeArray popTrailingNodeArray(size_t FromPosition) {
+ assert(FromPosition <= Names.size());
+ NodeArray res =
+ makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+ Names.dropBack(FromPosition);
+ return res;
+ }
+
+ bool consumeIf(StringView S) {
+ if (StringView(First, Last).startsWith(S)) {
+ First += S.size();
+ return true;
+ }
+ return false;
+ }
+
+ bool consumeIf(char C) {
+ if (First != Last && *First == C) {
+ ++First;
+ return true;
+ }
+ return false;
+ }
+
+ char consume() { return First != Last ? *First++ : '\0'; }
+
+ char look(unsigned Lookahead = 0) {
+ if (static_cast(Last - First) <= Lookahead)
+ return '\0';
+ return First[Lookahead];
+ }
+
+ size_t numLeft() const { return static_cast(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 production.
+ Node *parseExpr();
+ Node *parsePrefixExpr(StringView Kind);
+ Node *parseBinaryExpr(StringView Kind);
+ Node *parseIntegerLiteral(StringView Lit);
+ Node *parseExprPrimary();
+ template Node *parseFloatingLiteral();
+ Node *parseFunctionParam();
+ Node *parseNewExpr();
+ Node *parseConversionExpr();
+ Node *parseBracedExpr();
+ Node *parseFoldExpr();
+
+ /// Parse the 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 that is being parsed. This
+ /// information is only pertinent if the refers to an .
+ 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 production>
+ Node *parseName(NameState *State = nullptr);
+ Node *parseLocalName(NameState *State);
+ Node *parseOperatorName(NameState *State);
+ Node *parseUnqualifiedName(NameState *State);
+ Node *parseUnnamedTypeName(NameState *State);
+ Node *parseSourceName(NameState *State);
+ Node *parseUnscopedName(NameState *State);
+ Node *parseNestedName(NameState *State);
+ Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
+ Node *parseAbiTags(Node *N);
+
+ /// Parse the production.
+ Node *parseUnresolvedName();
+ Node *parseSimpleId();
+ Node *parseBaseUnresolvedName();
+ Node *parseUnresolvedType();
+ Node *parseDestructorName();
+
+ /// Top-level entry point into the parser.
+ Node *parse();
+};
+
+const char* parse_discriminator(const char* first, const char* last);
+
+// ::= // N
+// ::= # See Scope Encoding below // Z
+// ::=
+// ::=
+//
+// ::=
+// ::=