aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/lib/Demangle
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Demangle
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Demangle')
-rw-r--r--contrib/libs/llvm12/lib/Demangle/Demangle.cpp70
-rw-r--r--contrib/libs/llvm12/lib/Demangle/ItaniumDemangle.cpp1154
-rw-r--r--contrib/libs/llvm12/lib/Demangle/MicrosoftDemangle.cpp4754
-rw-r--r--contrib/libs/llvm12/lib/Demangle/MicrosoftDemangleNodes.cpp1304
-rw-r--r--contrib/libs/llvm12/lib/Demangle/ya.make42
5 files changed, 3662 insertions, 3662 deletions
diff --git a/contrib/libs/llvm12/lib/Demangle/Demangle.cpp b/contrib/libs/llvm12/lib/Demangle/Demangle.cpp
index 86cd3f84e2..000f75b6a9 100644
--- a/contrib/libs/llvm12/lib/Demangle/Demangle.cpp
+++ b/contrib/libs/llvm12/lib/Demangle/Demangle.cpp
@@ -1,36 +1,36 @@
-//===-- 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>
-
-static bool isItaniumEncoding(const std::string &MangledName) {
- size_t Pos = MangledName.find_first_not_of('_');
- // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'.
- return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z';
-}
-
-std::string llvm::demangle(const std::string &MangledName) {
- char *Demangled;
- if (isItaniumEncoding(MangledName))
- Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
- else
- Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr,
- nullptr, nullptr);
-
- if (!Demangled)
- return MangledName;
-
- std::string Ret = Demangled;
+//===-- 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>
+
+static bool isItaniumEncoding(const std::string &MangledName) {
+ size_t Pos = MangledName.find_first_not_of('_');
+ // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'.
+ return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z';
+}
+
+std::string llvm::demangle(const std::string &MangledName) {
+ char *Demangled;
+ if (isItaniumEncoding(MangledName))
+ Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
+ else
+ Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr,
+ nullptr, nullptr);
+
+ if (!Demangled)
+ return MangledName;
+
+ std::string Ret = Demangled;
std::free(Demangled);
- return Ret;
-}
+ return Ret;
+}
diff --git a/contrib/libs/llvm12/lib/Demangle/ItaniumDemangle.cpp b/contrib/libs/llvm12/lib/Demangle/ItaniumDemangle.cpp
index 318e70143d..6dfd931e83 100644
--- a/contrib/libs/llvm12/lib/Demangle/ItaniumDemangle.cpp
+++ b/contrib/libs/llvm12/lib/Demangle/ItaniumDemangle.cpp
@@ -1,583 +1,583 @@
-//===------------------------- 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 <numeric>
-#include <utility>
-#include <vector>
-
-using namespace llvm;
-using namespace llvm::itanium_demangle;
-
-constexpr const char *itanium_demangle::FloatData<float>::spec;
-constexpr const char *itanium_demangle::FloatData<double>::spec;
-constexpr const char *itanium_demangle::FloatData<long double>::spec;
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+ # at the end of string
-const char *itanium_demangle::parse_discriminator(const char *first,
- const char *last) {
- // parse but ignore discriminator
- if (first != last) {
- if (*first == '_') {
- const char *t1 = first + 1;
- if (t1 != last) {
- if (std::isdigit(*t1))
- first = t1 + 1;
- else if (*t1 == '_') {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- } else if (std::isdigit(*first)) {
- const char *t1 = first + 1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 == last)
- first = last;
- }
- }
- return first;
-}
-
-#ifndef NDEBUG
-namespace {
-struct DumpVisitor {
- unsigned Depth = 0;
- bool PendingNewline = false;
-
- template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
- return true;
- }
- static bool wantsNewline(NodeArray A) { return !A.empty(); }
- static constexpr bool wantsNewline(...) { return false; }
-
- template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
- for (bool B : {wantsNewline(Vs)...})
- if (B)
- return true;
- return false;
- }
-
- void printStr(const char *S) { fprintf(stderr, "%s", S); }
- void print(StringView SV) {
- fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
- }
- void print(const Node *N) {
- if (N)
- N->visit(std::ref(*this));
- else
- printStr("<null>");
- }
- void print(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 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>;
-
+//===------------------------- 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 <numeric>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::itanium_demangle;
+
+constexpr const char *itanium_demangle::FloatData<float>::spec;
+constexpr const char *itanium_demangle::FloatData<double>::spec;
+constexpr const char *itanium_demangle::FloatData<long double>::spec;
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+ # at the end of string
+const char *itanium_demangle::parse_discriminator(const char *first,
+ const char *last) {
+ // parse but ignore discriminator
+ if (first != last) {
+ if (*first == '_') {
+ const char *t1 = first + 1;
+ if (t1 != last) {
+ if (std::isdigit(*t1))
+ first = t1 + 1;
+ else if (*t1 == '_') {
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
+ }
+ }
+ } else if (std::isdigit(*first)) {
+ const char *t1 = first + 1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 == last)
+ first = last;
+ }
+ }
+ return first;
+}
+
+#ifndef NDEBUG
+namespace {
+struct DumpVisitor {
+ unsigned Depth = 0;
+ bool PendingNewline = false;
+
+ template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
+ return true;
+ }
+ static bool wantsNewline(NodeArray A) { return !A.empty(); }
+ static constexpr bool wantsNewline(...) { return false; }
+
+ template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
+ for (bool B : {wantsNewline(Vs)...})
+ if (B)
+ return true;
+ return false;
+ }
+
+ void printStr(const char *S) { fprintf(stderr, "%s", S); }
+ void print(StringView SV) {
+ fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
+ }
+ void print(const Node *N) {
+ if (N)
+ N->visit(std::ref(*this));
+ else
+ printStr("<null>");
+ }
+ void print(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 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>;
+
void llvm::itanium_demangle::demangleAST(const char *MangledName, IASTProcessor *Processor) {
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
Node* node = Parser.parse();
Processor->Process(node);
}
-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<Demangler *>(Context);
-}
-
-ItaniumPartialDemangler::ItaniumPartialDemangler(
- ItaniumPartialDemangler &&Other)
- : RootNode(Other.RootNode), Context(Other.Context) {
- Other.Context = Other.RootNode = nullptr;
-}
-
-ItaniumPartialDemangler &ItaniumPartialDemangler::
-operator=(ItaniumPartialDemangler &&Other) {
- std::swap(RootNode, Other.RootNode);
- std::swap(Context, Other.Context);
- return *this;
-}
-
-// Demangle MangledName into an AST, storing it into this->RootNode.
-bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
- Demangler *Parser = static_cast<Demangler *>(Context);
- size_t Len = std::strlen(MangledName);
- Parser->reset(MangledName, MangledName + Len);
- RootNode = Parser->parse();
- return RootNode == nullptr;
-}
-
-static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
- RootNode->print(S);
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- return S.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
-
- const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
-
- while (true) {
- switch (Name->getKind()) {
- case Node::KAbiTagAttr:
- Name = static_cast<const AbiTagAttr *>(Name)->Base;
- continue;
- case Node::KStdQualifiedName:
- Name = static_cast<const StdQualifiedName *>(Name)->Child;
- continue;
- case Node::KNestedName:
- Name = static_cast<const NestedName *>(Name)->Name;
- continue;
- case Node::KLocalName:
- Name = static_cast<const LocalName *>(Name)->Entity;
- continue;
- case Node::KNameWithTemplateArgs:
- Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
- continue;
- default:
- return printNode(Name, Buf, N);
- }
- }
-}
-
-char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
- size_t *N) const {
- if (!isFunction())
- return nullptr;
- const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
-
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
-
- KeepGoingLocalFunction:
- while (true) {
- if (Name->getKind() == Node::KAbiTagAttr) {
- Name = static_cast<const AbiTagAttr *>(Name)->Base;
- continue;
- }
- if (Name->getKind() == Node::KNameWithTemplateArgs) {
- Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
- continue;
- }
- break;
- }
-
- switch (Name->getKind()) {
- case Node::KStdQualifiedName:
- S += "std";
- break;
- case Node::KNestedName:
- static_cast<const NestedName *>(Name)->Qual->print(S);
- break;
- case Node::KLocalName: {
- auto *LN = static_cast<const LocalName *>(Name);
- LN->Encoding->print(S);
- S += "::";
- Name = LN->Entity;
- goto KeepGoingLocalFunction;
- }
- default:
- break;
- }
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- return S.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
- auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
- return printNode(Name, Buf, N);
-}
-
-char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
- size_t *N) const {
- if (!isFunction())
- return nullptr;
- NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
-
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
-
- S += '(';
- Params.printWithComma(S);
- S += ')';
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- return S.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionReturnType(
- char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
-
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
-
- if (const Node *Ret =
- static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
- Ret->print(S);
-
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- return S.getBuffer();
-}
-
-char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- return printNode(static_cast<Node *>(RootNode), Buf, N);
-}
-
-bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- if (!isFunction())
- return false;
- auto *E = static_cast<const FunctionEncoding *>(RootNode);
- return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
-}
-
-bool ItaniumPartialDemangler::isCtorOrDtor() const {
- const Node *N = static_cast<const Node *>(RootNode);
- while (N) {
- switch (N->getKind()) {
- default:
- return false;
- case Node::KCtorDtorName:
- return true;
-
- case Node::KAbiTagAttr:
- N = static_cast<const AbiTagAttr *>(N)->Base;
- break;
- case Node::KFunctionEncoding:
- N = static_cast<const FunctionEncoding *>(N)->getName();
- break;
- case Node::KLocalName:
- N = static_cast<const LocalName *>(N)->Entity;
- break;
- case Node::KNameWithTemplateArgs:
- N = static_cast<const NameWithTemplateArgs *>(N)->Name;
- break;
- case Node::KNestedName:
- N = static_cast<const NestedName *>(N)->Name;
- break;
- case Node::KStdQualifiedName:
- N = static_cast<const StdQualifiedName *>(N)->Child;
- break;
- }
- }
- return false;
-}
-
-bool ItaniumPartialDemangler::isFunction() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- return static_cast<const Node *>(RootNode)->getKind() ==
- Node::KFunctionEncoding;
-}
-
-bool ItaniumPartialDemangler::isSpecialName() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- auto K = static_cast<const Node *>(RootNode)->getKind();
- return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
-}
-
-bool ItaniumPartialDemangler::isData() const {
- return !isFunction() && !isSpecialName();
-}
+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<Demangler *>(Context);
+}
+
+ItaniumPartialDemangler::ItaniumPartialDemangler(
+ ItaniumPartialDemangler &&Other)
+ : RootNode(Other.RootNode), Context(Other.Context) {
+ Other.Context = Other.RootNode = nullptr;
+}
+
+ItaniumPartialDemangler &ItaniumPartialDemangler::
+operator=(ItaniumPartialDemangler &&Other) {
+ std::swap(RootNode, Other.RootNode);
+ std::swap(Context, Other.Context);
+ return *this;
+}
+
+// Demangle MangledName into an AST, storing it into this->RootNode.
+bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
+ Demangler *Parser = static_cast<Demangler *>(Context);
+ size_t Len = std::strlen(MangledName);
+ Parser->reset(MangledName, MangledName + Len);
+ RootNode = Parser->parse();
+ return RootNode == nullptr;
+}
+
+static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+ RootNode->print(S);
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+
+ const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
+
+ while (true) {
+ switch (Name->getKind()) {
+ case Node::KAbiTagAttr:
+ Name = static_cast<const AbiTagAttr *>(Name)->Base;
+ continue;
+ case Node::KStdQualifiedName:
+ Name = static_cast<const StdQualifiedName *>(Name)->Child;
+ continue;
+ case Node::KNestedName:
+ Name = static_cast<const NestedName *>(Name)->Name;
+ continue;
+ case Node::KLocalName:
+ Name = static_cast<const LocalName *>(Name)->Entity;
+ continue;
+ case Node::KNameWithTemplateArgs:
+ Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
+ continue;
+ default:
+ return printNode(Name, Buf, N);
+ }
+ }
+}
+
+char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
+ size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+ const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ KeepGoingLocalFunction:
+ while (true) {
+ if (Name->getKind() == Node::KAbiTagAttr) {
+ Name = static_cast<const AbiTagAttr *>(Name)->Base;
+ continue;
+ }
+ if (Name->getKind() == Node::KNameWithTemplateArgs) {
+ Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
+ continue;
+ }
+ break;
+ }
+
+ switch (Name->getKind()) {
+ case Node::KStdQualifiedName:
+ S += "std";
+ break;
+ case Node::KNestedName:
+ static_cast<const NestedName *>(Name)->Qual->print(S);
+ break;
+ case Node::KLocalName: {
+ auto *LN = static_cast<const LocalName *>(Name);
+ LN->Encoding->print(S);
+ S += "::";
+ Name = LN->Entity;
+ goto KeepGoingLocalFunction;
+ }
+ default:
+ break;
+ }
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+ auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
+ return printNode(Name, Buf, N);
+}
+
+char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
+ size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+ NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ S += '(';
+ Params.printWithComma(S);
+ S += ')';
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::getFunctionReturnType(
+ char *Buf, size_t *N) const {
+ if (!isFunction())
+ return nullptr;
+
+ OutputStream S;
+ if (!initializeOutputStream(Buf, N, S, 128))
+ return nullptr;
+
+ if (const Node *Ret =
+ static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
+ Ret->print(S);
+
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ return S.getBuffer();
+}
+
+char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ return printNode(static_cast<Node *>(RootNode), Buf, N);
+}
+
+bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ if (!isFunction())
+ return false;
+ auto *E = static_cast<const FunctionEncoding *>(RootNode);
+ return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
+}
+
+bool ItaniumPartialDemangler::isCtorOrDtor() const {
+ const Node *N = static_cast<const Node *>(RootNode);
+ while (N) {
+ switch (N->getKind()) {
+ default:
+ return false;
+ case Node::KCtorDtorName:
+ return true;
+
+ case Node::KAbiTagAttr:
+ N = static_cast<const AbiTagAttr *>(N)->Base;
+ break;
+ case Node::KFunctionEncoding:
+ N = static_cast<const FunctionEncoding *>(N)->getName();
+ break;
+ case Node::KLocalName:
+ N = static_cast<const LocalName *>(N)->Entity;
+ break;
+ case Node::KNameWithTemplateArgs:
+ N = static_cast<const NameWithTemplateArgs *>(N)->Name;
+ break;
+ case Node::KNestedName:
+ N = static_cast<const NestedName *>(N)->Name;
+ break;
+ case Node::KStdQualifiedName:
+ N = static_cast<const StdQualifiedName *>(N)->Child;
+ break;
+ }
+ }
+ return false;
+}
+
+bool ItaniumPartialDemangler::isFunction() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ return static_cast<const Node *>(RootNode)->getKind() ==
+ Node::KFunctionEncoding;
+}
+
+bool ItaniumPartialDemangler::isSpecialName() const {
+ assert(RootNode != nullptr && "must call partialDemangle()");
+ auto K = static_cast<const Node *>(RootNode)->getKind();
+ return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
+}
+
+bool ItaniumPartialDemangler::isData() const {
+ return !isFunction() && !isSpecialName();
+}
diff --git a/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangle.cpp b/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangle.cpp
index d9a7bd74e8..16074314a8 100644
--- a/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangle.cpp
+++ b/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangle.cpp
@@ -1,2377 +1,2377 @@
-//===- 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() + 1);
- std::strcpy(Stable, Borrowed.begin());
-
- return {Stable, Borrowed.size()};
-}
-
-SpecialTableSymbolNode *
-Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
- SpecialIntrinsicKind K) {
- NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();
- switch (K) {
- case SpecialIntrinsicKind::Vftable:
- NI->Name = "`vftable'";
- break;
- case SpecialIntrinsicKind::Vbtable:
- NI->Name = "`vbtable'";
- break;
- case SpecialIntrinsicKind::LocalVftable:
- NI->Name = "`local vftable'";
- break;
- case SpecialIntrinsicKind::RttiCompleteObjLocator:
- NI->Name = "`RTTI Complete Object Locator'";
- break;
- default:
- 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"))
- return nullptr;
- MangledName.consumeFront(".?A");
- if (MangledName.empty())
- return nullptr;
-
- return demangleClassType(MangledName);
-}
-
-// <type-encoding> ::= <storage-class> <variable-type>
-// <storage-class> ::= 0 # private static member
-// ::= 1 # protected static member
-// ::= 2 # public static member
-// ::= 3 # global
-// ::= 4 # static local
-
-VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
- StorageClass SC) {
- VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
-
- VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
- VSN->SC = SC;
-
- 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.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
- Identifier->output(OS, OF_Default);
- OS << '\0';
- char *Name = OS.getBuffer();
-
- StringView Owned = copyString(Name);
- memorizeString(Owned);
- std::free(Name);
-}
-
-IdentifierNode *
-Demangler::demangleTemplateInstantiationName(StringView &MangledName,
- NameBackrefBehavior NBB) {
- assert(MangledName.startsWith("?$"));
- MangledName.consumeFront("?$");
-
- BackrefContext OuterContext;
- std::swap(OuterContext, Backrefs);
-
- IdentifierNode *Identifier =
- demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
- if (!Error)
- Identifier->TemplateParams = demangleTemplateParameterList(MangledName);
-
- std::swap(OuterContext, Backrefs);
- if (Error)
- return nullptr;
-
- if (NBB & NBB_Template) {
- // 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(OutputStream &OS, 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--] = '\\';
- OS << StringView(&TempBuffer[Pos + 1]);
-}
-
-static void outputEscapedChar(OutputStream &OS, unsigned C) {
- switch (C) {
- case '\0': // nul
- OS << "\\0";
- return;
- case '\'': // single quote
- OS << "\\\'";
- return;
- case '\"': // double quote
- OS << "\\\"";
- return;
- case '\\': // backslash
- OS << "\\\\";
- return;
- case '\a': // bell
- OS << "\\a";
- return;
- case '\b': // backspace
- OS << "\\b";
- return;
- case '\f': // form feed
- OS << "\\f";
- return;
- case '\n': // new line
- OS << "\\n";
- return;
- case '\r': // carriage return
- OS << "\\r";
- return;
- case '\t': // tab
- OS << "\\t";
- return;
- case '\v': // vertical tab
- OS << "\\v";
- return;
- default:
- break;
- }
-
- if (C > 0x1F && C < 0x7F) {
- // Standard ascii char.
- OS << (char)C;
- return;
- }
-
- outputHex(OS, C);
-}
-
-static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
- const uint8_t *End = StringBytes + Length - 1;
- unsigned Count = 0;
- while (Length > 0 && *End == 0) {
- --Length;
- --End;
- ++Count;
- }
- return Count;
-}
-
-static unsigned countEmbeddedNulls(const uint8_t *StringBytes,
- unsigned Length) {
- unsigned Result = 0;
- for (unsigned I = 0; I < Length; ++I) {
- if (*StringBytes++ == 0)
- ++Result;
- }
- return Result;
-}
-
-// 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.
- OutputStream OS;
- StringView CRC;
- uint64_t StringByteSize;
- bool IsWcharT = false;
- bool IsNegative = false;
- size_t CrcEndPos = 0;
- char *ResultBuffer = nullptr;
-
- EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
-
- // Must happen before the first `goto StringLiteralError`.
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
-
- // 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(OS, W);
- StringByteSize -= 2;
- if (Error)
- goto StringLiteralError;
- }
- } else {
- // The max byte length is actually 32, but some compilers mangled strings
- // incorrectly, so we have to assume it can go higher.
- constexpr unsigned MaxStringByteLength = 32 * 4;
- uint8_t StringBytes[MaxStringByteLength];
-
- unsigned BytesDecoded = 0;
- while (!MangledName.consumeFront('@')) {
- 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(OS, NextChar);
- }
- }
-
- OS << '\0';
- ResultBuffer = OS.getBuffer();
- Result->DecodedString = copyString(ResultBuffer);
- std::free(ResultBuffer);
- return Result;
-
-StringLiteralError:
- Error = true;
- std::free(OS.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.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
- OS << '`';
- Scope->output(OS, OF_Default);
- OS << '\'';
- OS << "::`" << Number << "'";
- OS << '\0';
- char *Result = OS.getBuffer();
- Identifier->Name = copyString(Result);
- std::free(Result);
- return Identifier;
-}
-
-// Parses a type name in the form of A@B@C@@ which represents C::B::A.
-QualifiedNameNode *
-Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
- IdentifierNode *Identifier =
- demangleUnqualifiedTypeName(MangledName, /*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;
- }
-
- 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.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- std::terminate();
- for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
- OS.setCurrentPosition(0);
-
- TypeNode *T = Backrefs.FunctionParams[I];
- T->output(OS, OF_Default);
-
- std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(),
- OS.getBuffer());
- }
- std::free(OS.getBuffer());
-
- if (Backrefs.FunctionParamCount > 0)
- std::printf("\n");
- std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);
- for (size_t I = 0; I < Backrefs.NamesCount; ++I) {
- std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),
- Backrefs.Names[I]->Name.begin());
- }
- if (Backrefs.NamesCount > 0)
- std::printf("\n");
-}
-
-char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
- char *Buf, size_t *N,
- int *Status, MSDemangleFlags Flags) {
- Demangler D;
- OutputStream S;
-
- 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);
-
- int InternalStatus = demangle_success;
- if (D.Error)
- InternalStatus = demangle_invalid_mangled_name;
- else if (!initializeOutputStream(Buf, N, S, 1024))
- InternalStatus = demangle_memory_alloc_failure;
- else {
- AST->output(S, OF);
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- Buf = S.getBuffer();
- }
-
- if (Status)
- *Status = InternalStatus;
- return InternalStatus == demangle_success ? Buf : nullptr;
-}
+//===- 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() + 1);
+ std::strcpy(Stable, Borrowed.begin());
+
+ return {Stable, Borrowed.size()};
+}
+
+SpecialTableSymbolNode *
+Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
+ SpecialIntrinsicKind K) {
+ NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();
+ switch (K) {
+ case SpecialIntrinsicKind::Vftable:
+ NI->Name = "`vftable'";
+ break;
+ case SpecialIntrinsicKind::Vbtable:
+ NI->Name = "`vbtable'";
+ break;
+ case SpecialIntrinsicKind::LocalVftable:
+ NI->Name = "`local vftable'";
+ break;
+ case SpecialIntrinsicKind::RttiCompleteObjLocator:
+ NI->Name = "`RTTI Complete Object Locator'";
+ break;
+ default:
+ 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"))
+ return nullptr;
+ MangledName.consumeFront(".?A");
+ if (MangledName.empty())
+ return nullptr;
+
+ return demangleClassType(MangledName);
+}
+
+// <type-encoding> ::= <storage-class> <variable-type>
+// <storage-class> ::= 0 # private static member
+// ::= 1 # protected static member
+// ::= 2 # public static member
+// ::= 3 # global
+// ::= 4 # static local
+
+VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
+ StorageClass SC) {
+ VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+
+ VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
+ VSN->SC = SC;
+
+ 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.
+ OutputStream OS;
+ if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+ // FIXME: Propagate out-of-memory as an error?
+ std::terminate();
+ Identifier->output(OS, OF_Default);
+ OS << '\0';
+ char *Name = OS.getBuffer();
+
+ StringView Owned = copyString(Name);
+ memorizeString(Owned);
+ std::free(Name);
+}
+
+IdentifierNode *
+Demangler::demangleTemplateInstantiationName(StringView &MangledName,
+ NameBackrefBehavior NBB) {
+ assert(MangledName.startsWith("?$"));
+ MangledName.consumeFront("?$");
+
+ BackrefContext OuterContext;
+ std::swap(OuterContext, Backrefs);
+
+ IdentifierNode *Identifier =
+ demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
+ if (!Error)
+ Identifier->TemplateParams = demangleTemplateParameterList(MangledName);
+
+ std::swap(OuterContext, Backrefs);
+ if (Error)
+ return nullptr;
+
+ if (NBB & NBB_Template) {
+ // 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(OutputStream &OS, 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--] = '\\';
+ OS << StringView(&TempBuffer[Pos + 1]);
+}
+
+static void outputEscapedChar(OutputStream &OS, unsigned C) {
+ switch (C) {
+ case '\0': // nul
+ OS << "\\0";
+ return;
+ case '\'': // single quote
+ OS << "\\\'";
+ return;
+ case '\"': // double quote
+ OS << "\\\"";
+ return;
+ case '\\': // backslash
+ OS << "\\\\";
+ return;
+ case '\a': // bell
+ OS << "\\a";
+ return;
+ case '\b': // backspace
+ OS << "\\b";
+ return;
+ case '\f': // form feed
+ OS << "\\f";
+ return;
+ case '\n': // new line
+ OS << "\\n";
+ return;
+ case '\r': // carriage return
+ OS << "\\r";
+ return;
+ case '\t': // tab
+ OS << "\\t";
+ return;
+ case '\v': // vertical tab
+ OS << "\\v";
+ return;
+ default:
+ break;
+ }
+
+ if (C > 0x1F && C < 0x7F) {
+ // Standard ascii char.
+ OS << (char)C;
+ return;
+ }
+
+ outputHex(OS, C);
+}
+
+static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
+ const uint8_t *End = StringBytes + Length - 1;
+ unsigned Count = 0;
+ while (Length > 0 && *End == 0) {
+ --Length;
+ --End;
+ ++Count;
+ }
+ return Count;
+}
+
+static unsigned countEmbeddedNulls(const uint8_t *StringBytes,
+ unsigned Length) {
+ unsigned Result = 0;
+ for (unsigned I = 0; I < Length; ++I) {
+ if (*StringBytes++ == 0)
+ ++Result;
+ }
+ return Result;
+}
+
+// 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.
+ OutputStream OS;
+ StringView CRC;
+ uint64_t StringByteSize;
+ bool IsWcharT = false;
+ bool IsNegative = false;
+ size_t CrcEndPos = 0;
+ char *ResultBuffer = nullptr;
+
+ EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
+
+ // Must happen before the first `goto StringLiteralError`.
+ if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+ // FIXME: Propagate out-of-memory as an error?
+ std::terminate();
+
+ // 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(OS, W);
+ StringByteSize -= 2;
+ if (Error)
+ goto StringLiteralError;
+ }
+ } else {
+ // The max byte length is actually 32, but some compilers mangled strings
+ // incorrectly, so we have to assume it can go higher.
+ constexpr unsigned MaxStringByteLength = 32 * 4;
+ uint8_t StringBytes[MaxStringByteLength];
+
+ unsigned BytesDecoded = 0;
+ while (!MangledName.consumeFront('@')) {
+ 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(OS, NextChar);
+ }
+ }
+
+ OS << '\0';
+ ResultBuffer = OS.getBuffer();
+ Result->DecodedString = copyString(ResultBuffer);
+ std::free(ResultBuffer);
+ return Result;
+
+StringLiteralError:
+ Error = true;
+ std::free(OS.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.
+ OutputStream OS;
+ if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+ // FIXME: Propagate out-of-memory as an error?
+ std::terminate();
+ OS << '`';
+ Scope->output(OS, OF_Default);
+ OS << '\'';
+ OS << "::`" << Number << "'";
+ OS << '\0';
+ char *Result = OS.getBuffer();
+ Identifier->Name = copyString(Result);
+ std::free(Result);
+ return Identifier;
+}
+
+// Parses a type name in the form of A@B@C@@ which represents C::B::A.
+QualifiedNameNode *
+Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
+ IdentifierNode *Identifier =
+ demangleUnqualifiedTypeName(MangledName, /*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;
+ }
+
+ 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.
+ OutputStream OS;
+ if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+ std::terminate();
+ for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
+ OS.setCurrentPosition(0);
+
+ TypeNode *T = Backrefs.FunctionParams[I];
+ T->output(OS, OF_Default);
+
+ std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(),
+ OS.getBuffer());
+ }
+ std::free(OS.getBuffer());
+
+ if (Backrefs.FunctionParamCount > 0)
+ std::printf("\n");
+ std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);
+ for (size_t I = 0; I < Backrefs.NamesCount; ++I) {
+ std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),
+ Backrefs.Names[I]->Name.begin());
+ }
+ if (Backrefs.NamesCount > 0)
+ std::printf("\n");
+}
+
+char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
+ char *Buf, size_t *N,
+ int *Status, MSDemangleFlags Flags) {
+ Demangler D;
+ OutputStream S;
+
+ 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);
+
+ int InternalStatus = demangle_success;
+ if (D.Error)
+ InternalStatus = demangle_invalid_mangled_name;
+ else if (!initializeOutputStream(Buf, N, S, 1024))
+ InternalStatus = demangle_memory_alloc_failure;
+ else {
+ AST->output(S, OF);
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ Buf = S.getBuffer();
+ }
+
+ if (Status)
+ *Status = InternalStatus;
+ return InternalStatus == demangle_success ? Buf : nullptr;
+}
diff --git a/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangleNodes.cpp b/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangleNodes.cpp
index 18bc619e5b..8b15ffcee7 100644
--- a/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangleNodes.cpp
+++ b/contrib/libs/llvm12/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -1,652 +1,652 @@
-//===- 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/DemangleConfig.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: \
- OS << Desc; \
- break;
-
-// Writes a space if the last token does not end with a punctuation.
-static void outputSpaceIfNecessary(OutputStream &OS) {
- if (OS.empty())
- return;
-
- char C = OS.back();
- if (std::isalnum(C) || C == '>')
- OS << " ";
-}
-
-static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
- switch (Q) {
- case Q_Const:
- OS << "const";
- break;
- case Q_Volatile:
- OS << "volatile";
- break;
- case Q_Restrict:
- OS << "__restrict";
- break;
- default:
- break;
- }
-}
-
-static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
- Qualifiers Mask, bool NeedSpace) {
- if (!(Q & Mask))
- return NeedSpace;
-
- if (NeedSpace)
- OS << " ";
-
- outputSingleQualifier(OS, Mask);
- return true;
-}
-
-static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
- bool SpaceAfter) {
- if (Q == Q_None)
- return;
-
- size_t Pos1 = OS.getCurrentPosition();
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
- size_t Pos2 = OS.getCurrentPosition();
- if (SpaceAfter && Pos2 > Pos1)
- OS << " ";
-}
-
-static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
- outputSpaceIfNecessary(OS);
-
- switch (CC) {
- case CallingConv::Cdecl:
- OS << "__cdecl";
- break;
- case CallingConv::Fastcall:
- OS << "__fastcall";
- break;
- case CallingConv::Pascal:
- OS << "__pascal";
- break;
- case CallingConv::Regcall:
- OS << "__regcall";
- break;
- case CallingConv::Stdcall:
- OS << "__stdcall";
- break;
- case CallingConv::Thiscall:
- OS << "__thiscall";
- break;
- case CallingConv::Eabi:
- OS << "__eabi";
- break;
- case CallingConv::Vectorcall:
- OS << "__vectorcall";
- break;
- case CallingConv::Clrcall:
- OS << "__clrcall";
- break;
- default:
- break;
- }
-}
-
-std::string Node::toString(OutputFlags Flags) const {
- OutputStream OS;
- initializeOutputStream(nullptr, nullptr, OS, 1024);
- this->output(OS, Flags);
- OS << '\0';
- return {OS.getBuffer()};
-}
-
-void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
- switch (PrimKind) {
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, 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(OS, Quals, true, false);
-}
-
-void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
- output(OS, Flags, ", ");
-}
-
-void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
- StringView Separator) const {
- if (Count == 0)
- return;
- if (Nodes[0])
- Nodes[0]->output(OS, Flags);
- for (size_t I = 1; I < Count; ++I) {
- OS << Separator;
- Nodes[I]->output(OS, Flags);
- }
-}
-
-void EncodedStringLiteralNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- switch (Char) {
- case CharKind::Wchar:
- OS << "L\"";
- break;
- case CharKind::Char:
- OS << "\"";
- break;
- case CharKind::Char16:
- OS << "u\"";
- break;
- case CharKind::Char32:
- OS << "U\"";
- break;
- }
- OS << DecodedString << "\"";
- if (IsTruncated)
- OS << "...";
-}
-
-void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
- if (IsNegative)
- OS << '-';
- OS << Value;
-}
-
-void TemplateParameterReferenceNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- if (ThunkOffsetCount > 0)
- OS << "{";
- else if (Affinity == PointerAffinity::Pointer)
- OS << "&";
-
- if (Symbol) {
- Symbol->output(OS, Flags);
- if (ThunkOffsetCount > 0)
- OS << ", ";
- }
-
- if (ThunkOffsetCount > 0)
- OS << ThunkOffsets[0];
- for (int I = 1; I < ThunkOffsetCount; ++I) {
- OS << ", " << ThunkOffsets[I];
- }
- if (ThunkOffsetCount > 0)
- OS << "}";
-}
-
-void IdentifierNode::outputTemplateParameters(OutputStream &OS,
- OutputFlags Flags) const {
- if (!TemplateParams)
- return;
- OS << "<";
- TemplateParams->output(OS, Flags);
- OS << ">";
-}
-
-void DynamicStructorIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- if (IsDestructor)
- OS << "`dynamic atexit destructor for ";
- else
- OS << "`dynamic initializer for ";
-
- if (Variable) {
- OS << "`";
- Variable->output(OS, Flags);
- OS << "''";
- } else {
- OS << "'";
- Name->output(OS, Flags);
- OS << "''";
- }
-}
-
-void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
- OS << Name;
- outputTemplateParameters(OS, Flags);
-}
-
-void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- switch (Operator) {
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
- "operator[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
- "operator->*");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
- "operator>=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
- "operator&=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
- "operator|=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
- "operator^=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
- "`vector deleting dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
- "`default ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
- "`scalar deleting dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
- "`vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
- "`vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
- "`vector vbase ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
- "`virtual displacement map'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
- "`eh vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
- "`eh vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
- "`eh vector vbase ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
- "`copy ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
- "`local vftable ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
- "operator delete[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
- "`managed vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
- "`managed vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
- "`EH vector copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
- "`EH vector vbase copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
- "`vector copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
- "`vector vbase copy constructor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
- "`managed vector vbase copy constructor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
- "operator co_await");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
- case IntrinsicFunctionKind::MaxIntrinsic:
- case IntrinsicFunctionKind::None:
- break;
- }
- outputTemplateParameters(OS, Flags);
-}
-
-void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- if (IsThread)
- OS << "`local static thread guard'";
- else
- OS << "`local static guard'";
- if (ScopeIndex > 0)
- OS << "{" << ScopeIndex << "}";
-}
-
-void ConversionOperatorIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- OS << "operator";
- outputTemplateParameters(OS, Flags);
- OS << " ";
- TargetType->output(OS, Flags);
-}
-
-void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
- if (IsDestructor)
- OS << "~";
- Class->output(OS, Flags);
- outputTemplateParameters(OS, Flags);
-}
-
-void LiteralOperatorIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- OS << "operator \"\"" << Name;
- outputTemplateParameters(OS, Flags);
-}
-
-void FunctionSignatureNode::outputPre(OutputStream &OS,
- OutputFlags Flags) const {
- if (!(Flags & OF_NoAccessSpecifier)) {
- if (FunctionClass & FC_Public)
- OS << "public: ";
- if (FunctionClass & FC_Protected)
- OS << "protected: ";
- if (FunctionClass & FC_Private)
- OS << "private: ";
- }
-
- if (!(Flags & OF_NoMemberType)) {
- if (!(FunctionClass & FC_Global)) {
- if (FunctionClass & FC_Static)
- OS << "static ";
- }
- if (FunctionClass & FC_Virtual)
- OS << "virtual ";
-
- if (FunctionClass & FC_ExternC)
- OS << "extern \"C\" ";
- }
-
- if (!(Flags & OF_NoReturnType) && ReturnType) {
- ReturnType->outputPre(OS, Flags);
- OS << " ";
- }
-
- if (!(Flags & OF_NoCallingConvention))
- outputCallingConvention(OS, CallConvention);
-}
-
-void FunctionSignatureNode::outputPost(OutputStream &OS,
- OutputFlags Flags) const {
- if (!(FunctionClass & FC_NoParameterList)) {
- OS << "(";
- if (Params)
- Params->output(OS, Flags);
- else
- OS << "void";
-
- if (IsVariadic) {
- if (OS.back() != '(')
- OS << ", ";
- OS << "...";
- }
- OS << ")";
- }
-
- if (Quals & Q_Const)
- OS << " const";
- if (Quals & Q_Volatile)
- OS << " volatile";
- if (Quals & Q_Restrict)
- OS << " __restrict";
- if (Quals & Q_Unaligned)
- OS << " __unaligned";
-
- if (IsNoexcept)
- OS << " noexcept";
-
- if (RefQualifier == FunctionRefQualifier::Reference)
- OS << " &";
- else if (RefQualifier == FunctionRefQualifier::RValueReference)
- OS << " &&";
-
- if (!(Flags & OF_NoReturnType) && ReturnType)
- ReturnType->outputPost(OS, Flags);
-}
-
-void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
- OS << "[thunk]: ";
-
- FunctionSignatureNode::outputPre(OS, Flags);
-}
-
-void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
- if (FunctionClass & FC_StaticThisAdjust) {
- OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
- } else if (FunctionClass & FC_VirtualThisAdjust) {
- if (FunctionClass & FC_VirtualThisAdjustEx) {
- OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
- << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
- << ", " << ThisAdjust.StaticOffset << "}'";
- } else {
- OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
- << ThisAdjust.StaticOffset << "}'";
- }
- }
-
- FunctionSignatureNode::outputPost(OS, Flags);
-}
-
-void PointerTypeNode::outputPre(OutputStream &OS, 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(OS, OF_NoCallingConvention);
- } else
- Pointee->outputPre(OS, Flags);
-
- outputSpaceIfNecessary(OS);
-
- if (Quals & Q_Unaligned)
- OS << "__unaligned ";
-
- if (Pointee->kind() == NodeKind::ArrayType) {
- OS << "(";
- } else if (Pointee->kind() == NodeKind::FunctionSignature) {
- OS << "(";
- const FunctionSignatureNode *Sig =
- static_cast<const FunctionSignatureNode *>(Pointee);
- outputCallingConvention(OS, Sig->CallConvention);
- OS << " ";
- }
-
- if (ClassParent) {
- ClassParent->output(OS, Flags);
- OS << "::";
- }
-
- switch (Affinity) {
- case PointerAffinity::Pointer:
- OS << "*";
- break;
- case PointerAffinity::Reference:
- OS << "&";
- break;
- case PointerAffinity::RValueReference:
- OS << "&&";
- break;
- default:
- assert(false);
- }
- outputQualifiers(OS, Quals, false, false);
-}
-
-void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
- if (Pointee->kind() == NodeKind::ArrayType ||
- Pointee->kind() == NodeKind::FunctionSignature)
- OS << ")";
-
- Pointee->outputPost(OS, Flags);
-}
-
-void TagTypeNode::outputPre(OutputStream &OS, 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");
- }
- OS << " ";
- }
- QualifiedName->output(OS, Flags);
- outputQualifiers(OS, Quals, true, false);
-}
-
-void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
-
-void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
- ElementType->outputPre(OS, Flags);
- outputQualifiers(OS, Quals, true, false);
-}
-
-void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
- Node *N) const {
- assert(N->kind() == NodeKind::IntegerLiteral);
- IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
- if (ILN->Value != 0)
- ILN->output(OS, Flags);
-}
-
-void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
- OutputFlags Flags) const {
- if (Dimensions->Count == 0)
- return;
-
- outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
- for (size_t I = 1; I < Dimensions->Count; ++I) {
- OS << "][";
- outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
- }
-}
-
-void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
- OS << "[";
- outputDimensionsImpl(OS, Flags);
- OS << "]";
-
- ElementType->outputPost(OS, Flags);
-}
-
-void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- Name->output(OS, Flags);
-}
-
-void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- Signature->outputPre(OS, Flags);
- outputSpaceIfNecessary(OS);
- Name->output(OS, Flags);
- Signature->outputPost(OS, Flags);
-}
-
-void VariableSymbolNode::output(OutputStream &OS, 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)
- OS << AccessSpec << ": ";
- if (!(Flags & OF_NoMemberType) && IsStatic)
- OS << "static ";
-
- if (Type) {
- Type->outputPre(OS, Flags);
- outputSpaceIfNecessary(OS);
- }
- Name->output(OS, Flags);
- if (Type)
- Type->outputPost(OS, Flags);
-}
-
-void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
- Identifier->output(OS, Flags);
-}
-void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
-
-void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
- Components->output(OS, Flags, "::");
-}
-
-void RttiBaseClassDescriptorNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- OS << "`RTTI Base Class Descriptor at (";
- OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
- << this->Flags;
- OS << ")'";
-}
-
-void LocalStaticGuardVariableNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- Name->output(OS, Flags);
-}
-
-void VcallThunkIdentifierNode::output(OutputStream &OS,
- OutputFlags Flags) const {
- OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
-}
-
-void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- outputQualifiers(OS, Quals, false, true);
- Name->output(OS, Flags);
- if (TargetName) {
- OS << "{for `";
- TargetName->output(OS, Flags);
- OS << "'}";
- }
-}
+//===- 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/DemangleConfig.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: \
+ OS << Desc; \
+ break;
+
+// Writes a space if the last token does not end with a punctuation.
+static void outputSpaceIfNecessary(OutputStream &OS) {
+ if (OS.empty())
+ return;
+
+ char C = OS.back();
+ if (std::isalnum(C) || C == '>')
+ OS << " ";
+}
+
+static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
+ switch (Q) {
+ case Q_Const:
+ OS << "const";
+ break;
+ case Q_Volatile:
+ OS << "volatile";
+ break;
+ case Q_Restrict:
+ OS << "__restrict";
+ break;
+ default:
+ break;
+ }
+}
+
+static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
+ Qualifiers Mask, bool NeedSpace) {
+ if (!(Q & Mask))
+ return NeedSpace;
+
+ if (NeedSpace)
+ OS << " ";
+
+ outputSingleQualifier(OS, Mask);
+ return true;
+}
+
+static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
+ bool SpaceAfter) {
+ if (Q == Q_None)
+ return;
+
+ size_t Pos1 = OS.getCurrentPosition();
+ SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
+ size_t Pos2 = OS.getCurrentPosition();
+ if (SpaceAfter && Pos2 > Pos1)
+ OS << " ";
+}
+
+static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
+ outputSpaceIfNecessary(OS);
+
+ switch (CC) {
+ case CallingConv::Cdecl:
+ OS << "__cdecl";
+ break;
+ case CallingConv::Fastcall:
+ OS << "__fastcall";
+ break;
+ case CallingConv::Pascal:
+ OS << "__pascal";
+ break;
+ case CallingConv::Regcall:
+ OS << "__regcall";
+ break;
+ case CallingConv::Stdcall:
+ OS << "__stdcall";
+ break;
+ case CallingConv::Thiscall:
+ OS << "__thiscall";
+ break;
+ case CallingConv::Eabi:
+ OS << "__eabi";
+ break;
+ case CallingConv::Vectorcall:
+ OS << "__vectorcall";
+ break;
+ case CallingConv::Clrcall:
+ OS << "__clrcall";
+ break;
+ default:
+ break;
+ }
+}
+
+std::string Node::toString(OutputFlags Flags) const {
+ OutputStream OS;
+ initializeOutputStream(nullptr, nullptr, OS, 1024);
+ this->output(OS, Flags);
+ OS << '\0';
+ return {OS.getBuffer()};
+}
+
+void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+ switch (PrimKind) {
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
+ OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, 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(OS, Quals, true, false);
+}
+
+void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
+ output(OS, Flags, ", ");
+}
+
+void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
+ StringView Separator) const {
+ if (Count == 0)
+ return;
+ if (Nodes[0])
+ Nodes[0]->output(OS, Flags);
+ for (size_t I = 1; I < Count; ++I) {
+ OS << Separator;
+ Nodes[I]->output(OS, Flags);
+ }
+}
+
+void EncodedStringLiteralNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ switch (Char) {
+ case CharKind::Wchar:
+ OS << "L\"";
+ break;
+ case CharKind::Char:
+ OS << "\"";
+ break;
+ case CharKind::Char16:
+ OS << "u\"";
+ break;
+ case CharKind::Char32:
+ OS << "U\"";
+ break;
+ }
+ OS << DecodedString << "\"";
+ if (IsTruncated)
+ OS << "...";
+}
+
+void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
+ if (IsNegative)
+ OS << '-';
+ OS << Value;
+}
+
+void TemplateParameterReferenceNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (ThunkOffsetCount > 0)
+ OS << "{";
+ else if (Affinity == PointerAffinity::Pointer)
+ OS << "&";
+
+ if (Symbol) {
+ Symbol->output(OS, Flags);
+ if (ThunkOffsetCount > 0)
+ OS << ", ";
+ }
+
+ if (ThunkOffsetCount > 0)
+ OS << ThunkOffsets[0];
+ for (int I = 1; I < ThunkOffsetCount; ++I) {
+ OS << ", " << ThunkOffsets[I];
+ }
+ if (ThunkOffsetCount > 0)
+ OS << "}";
+}
+
+void IdentifierNode::outputTemplateParameters(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (!TemplateParams)
+ return;
+ OS << "<";
+ TemplateParams->output(OS, Flags);
+ OS << ">";
+}
+
+void DynamicStructorIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (IsDestructor)
+ OS << "`dynamic atexit destructor for ";
+ else
+ OS << "`dynamic initializer for ";
+
+ if (Variable) {
+ OS << "`";
+ Variable->output(OS, Flags);
+ OS << "''";
+ } else {
+ OS << "'";
+ Name->output(OS, Flags);
+ OS << "''";
+ }
+}
+
+void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
+ OS << Name;
+ outputTemplateParameters(OS, Flags);
+}
+
+void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ switch (Operator) {
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
+ "operator[]");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
+ "operator->*");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
+ "operator>=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
+ "operator&=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
+ "operator|=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
+ "operator^=");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
+ "`vector deleting dtor'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
+ "`default ctor closure'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
+ "`scalar deleting dtor'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
+ "`vector ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
+ "`vector dtor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
+ "`vector vbase ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
+ "`virtual displacement map'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
+ "`eh vector ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
+ "`eh vector dtor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
+ "`eh vector vbase ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
+ "`copy ctor closure'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
+ "`local vftable ctor closure'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
+ "operator delete[]");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
+ "`managed vector ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
+ "`managed vector dtor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
+ "`EH vector copy ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
+ "`EH vector vbase copy ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
+ "`vector copy ctor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
+ "`vector vbase copy constructor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
+ "`managed vector vbase copy constructor iterator'");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
+ "operator co_await");
+ OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
+ case IntrinsicFunctionKind::MaxIntrinsic:
+ case IntrinsicFunctionKind::None:
+ break;
+ }
+ outputTemplateParameters(OS, Flags);
+}
+
+void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (IsThread)
+ OS << "`local static thread guard'";
+ else
+ OS << "`local static guard'";
+ if (ScopeIndex > 0)
+ OS << "{" << ScopeIndex << "}";
+}
+
+void ConversionOperatorIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ OS << "operator";
+ outputTemplateParameters(OS, Flags);
+ OS << " ";
+ TargetType->output(OS, Flags);
+}
+
+void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
+ if (IsDestructor)
+ OS << "~";
+ Class->output(OS, Flags);
+ outputTemplateParameters(OS, Flags);
+}
+
+void LiteralOperatorIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ OS << "operator \"\"" << Name;
+ outputTemplateParameters(OS, Flags);
+}
+
+void FunctionSignatureNode::outputPre(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (!(Flags & OF_NoAccessSpecifier)) {
+ if (FunctionClass & FC_Public)
+ OS << "public: ";
+ if (FunctionClass & FC_Protected)
+ OS << "protected: ";
+ if (FunctionClass & FC_Private)
+ OS << "private: ";
+ }
+
+ if (!(Flags & OF_NoMemberType)) {
+ if (!(FunctionClass & FC_Global)) {
+ if (FunctionClass & FC_Static)
+ OS << "static ";
+ }
+ if (FunctionClass & FC_Virtual)
+ OS << "virtual ";
+
+ if (FunctionClass & FC_ExternC)
+ OS << "extern \"C\" ";
+ }
+
+ if (!(Flags & OF_NoReturnType) && ReturnType) {
+ ReturnType->outputPre(OS, Flags);
+ OS << " ";
+ }
+
+ if (!(Flags & OF_NoCallingConvention))
+ outputCallingConvention(OS, CallConvention);
+}
+
+void FunctionSignatureNode::outputPost(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (!(FunctionClass & FC_NoParameterList)) {
+ OS << "(";
+ if (Params)
+ Params->output(OS, Flags);
+ else
+ OS << "void";
+
+ if (IsVariadic) {
+ if (OS.back() != '(')
+ OS << ", ";
+ OS << "...";
+ }
+ OS << ")";
+ }
+
+ if (Quals & Q_Const)
+ OS << " const";
+ if (Quals & Q_Volatile)
+ OS << " volatile";
+ if (Quals & Q_Restrict)
+ OS << " __restrict";
+ if (Quals & Q_Unaligned)
+ OS << " __unaligned";
+
+ if (IsNoexcept)
+ OS << " noexcept";
+
+ if (RefQualifier == FunctionRefQualifier::Reference)
+ OS << " &";
+ else if (RefQualifier == FunctionRefQualifier::RValueReference)
+ OS << " &&";
+
+ if (!(Flags & OF_NoReturnType) && ReturnType)
+ ReturnType->outputPost(OS, Flags);
+}
+
+void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+ OS << "[thunk]: ";
+
+ FunctionSignatureNode::outputPre(OS, Flags);
+}
+
+void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
+ if (FunctionClass & FC_StaticThisAdjust) {
+ OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
+ } else if (FunctionClass & FC_VirtualThisAdjust) {
+ if (FunctionClass & FC_VirtualThisAdjustEx) {
+ OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
+ << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
+ << ", " << ThisAdjust.StaticOffset << "}'";
+ } else {
+ OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
+ << ThisAdjust.StaticOffset << "}'";
+ }
+ }
+
+ FunctionSignatureNode::outputPost(OS, Flags);
+}
+
+void PointerTypeNode::outputPre(OutputStream &OS, 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(OS, OF_NoCallingConvention);
+ } else
+ Pointee->outputPre(OS, Flags);
+
+ outputSpaceIfNecessary(OS);
+
+ if (Quals & Q_Unaligned)
+ OS << "__unaligned ";
+
+ if (Pointee->kind() == NodeKind::ArrayType) {
+ OS << "(";
+ } else if (Pointee->kind() == NodeKind::FunctionSignature) {
+ OS << "(";
+ const FunctionSignatureNode *Sig =
+ static_cast<const FunctionSignatureNode *>(Pointee);
+ outputCallingConvention(OS, Sig->CallConvention);
+ OS << " ";
+ }
+
+ if (ClassParent) {
+ ClassParent->output(OS, Flags);
+ OS << "::";
+ }
+
+ switch (Affinity) {
+ case PointerAffinity::Pointer:
+ OS << "*";
+ break;
+ case PointerAffinity::Reference:
+ OS << "&";
+ break;
+ case PointerAffinity::RValueReference:
+ OS << "&&";
+ break;
+ default:
+ assert(false);
+ }
+ outputQualifiers(OS, Quals, false, false);
+}
+
+void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
+ if (Pointee->kind() == NodeKind::ArrayType ||
+ Pointee->kind() == NodeKind::FunctionSignature)
+ OS << ")";
+
+ Pointee->outputPost(OS, Flags);
+}
+
+void TagTypeNode::outputPre(OutputStream &OS, 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");
+ }
+ OS << " ";
+ }
+ QualifiedName->output(OS, Flags);
+ outputQualifiers(OS, Quals, true, false);
+}
+
+void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
+
+void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+ ElementType->outputPre(OS, Flags);
+ outputQualifiers(OS, Quals, true, false);
+}
+
+void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
+ Node *N) const {
+ assert(N->kind() == NodeKind::IntegerLiteral);
+ IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
+ if (ILN->Value != 0)
+ ILN->output(OS, Flags);
+}
+
+void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
+ OutputFlags Flags) const {
+ if (Dimensions->Count == 0)
+ return;
+
+ outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
+ for (size_t I = 1; I < Dimensions->Count; ++I) {
+ OS << "][";
+ outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
+ }
+}
+
+void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
+ OS << "[";
+ outputDimensionsImpl(OS, Flags);
+ OS << "]";
+
+ ElementType->outputPost(OS, Flags);
+}
+
+void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
+ Name->output(OS, Flags);
+}
+
+void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
+ Signature->outputPre(OS, Flags);
+ outputSpaceIfNecessary(OS);
+ Name->output(OS, Flags);
+ Signature->outputPost(OS, Flags);
+}
+
+void VariableSymbolNode::output(OutputStream &OS, 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)
+ OS << AccessSpec << ": ";
+ if (!(Flags & OF_NoMemberType) && IsStatic)
+ OS << "static ";
+
+ if (Type) {
+ Type->outputPre(OS, Flags);
+ outputSpaceIfNecessary(OS);
+ }
+ Name->output(OS, Flags);
+ if (Type)
+ Type->outputPost(OS, Flags);
+}
+
+void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+ Identifier->output(OS, Flags);
+}
+void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
+
+void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
+ Components->output(OS, Flags, "::");
+}
+
+void RttiBaseClassDescriptorNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ OS << "`RTTI Base Class Descriptor at (";
+ OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
+ << this->Flags;
+ OS << ")'";
+}
+
+void LocalStaticGuardVariableNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ Name->output(OS, Flags);
+}
+
+void VcallThunkIdentifierNode::output(OutputStream &OS,
+ OutputFlags Flags) const {
+ OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
+}
+
+void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
+ outputQualifiers(OS, Quals, false, true);
+ Name->output(OS, Flags);
+ if (TargetName) {
+ OS << "{for `";
+ TargetName->output(OS, Flags);
+ OS << "'}";
+ }
+}
diff --git a/contrib/libs/llvm12/lib/Demangle/ya.make b/contrib/libs/llvm12/lib/Demangle/ya.make
index 354f860d30..16c0cf64f7 100644
--- a/contrib/libs/llvm12/lib/Demangle/ya.make
+++ b/contrib/libs/llvm12/lib/Demangle/ya.make
@@ -1,33 +1,33 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
-)
-
+)
+
ADDINCL(
contrib/libs/llvm12/lib/Demangle
)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- Demangle.cpp
- ItaniumDemangle.cpp
- MicrosoftDemangle.cpp
- MicrosoftDemangleNodes.cpp
-)
-
-END()
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ Demangle.cpp
+ ItaniumDemangle.cpp
+ MicrosoftDemangle.cpp
+ MicrosoftDemangleNodes.cpp
+)
+
+END()