summaryrefslogtreecommitdiffhomepage
path: root/demangle/third_party/llvm/lib/Demangle
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-08-30 07:14:22 +0200
committerStanislaw Halik <sthalik@misaki.pl>2023-08-30 18:22:56 +0200
commit5092df19372bd6957bd43649da43add30777212d (patch)
treebfc20215881a8e8699739069dab898b95dfd3ec6 /demangle/third_party/llvm/lib/Demangle
parentaf6ca21ed0f2715aad0b2ae80d200589b5e31089 (diff)
kill demangle
Diffstat (limited to 'demangle/third_party/llvm/lib/Demangle')
-rw-r--r--demangle/third_party/llvm/lib/Demangle/Demangle.cpp68
-rw-r--r--demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp608
-rw-r--r--demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp2368
-rw-r--r--demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp658
4 files changed, 0 insertions, 3702 deletions
diff --git a/demangle/third_party/llvm/lib/Demangle/Demangle.cpp b/demangle/third_party/llvm/lib/Demangle/Demangle.cpp
deleted file mode 100644
index b5f2369d..00000000
--- a/demangle/third_party/llvm/lib/Demangle/Demangle.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//===-- Demangle.cpp - Common demangling functions ------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file This file contains definitions of common demangling functions.
-///
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Demangle/Demangle.h"
-#include <cstdlib>
-#include <cstring>
-
-static bool isItaniumEncoding(const char *S) {
- // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
- return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0;
-}
-
-#if 0
-static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; }
-
-static bool isDLangEncoding(const std::string &MangledName) {
- return MangledName.size() >= 2 && MangledName[0] == '_' &&
- MangledName[1] == 'D';
-}
-#endif
-
-std::string llvm::demangle(const std::string &MangledName) {
- std::string Result;
- const char *S = MangledName.c_str();
-
- if (nonMicrosoftDemangle(S, Result))
- return Result;
-
- if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result))
- return Result;
-
- if (char *Demangled =
- microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) {
- Result = Demangled;
- std::free(Demangled);
- return Result;
- }
-
- return MangledName;
-}
-
-bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) {
- char *Demangled = nullptr;
- if (isItaniumEncoding(MangledName))
- Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr);
-#if 0
- else if (isRustEncoding(MangledName))
- Demangled = rustDemangle(MangledName);
- else if (isDLangEncoding(MangledName))
- Demangled = dlangDemangle(MangledName);
-#endif
-
- if (!Demangled)
- return false;
-
- Result = Demangled;
- std::free(Demangled);
- return true;
-}
diff --git a/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
deleted file mode 100644
index 9b646ea8..00000000
--- a/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ /dev/null
@@ -1,608 +0,0 @@
-//===------------------------- ItaniumDemangle.cpp ------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// FIXME: (possibly) incomplete list of features that clang mangles that this
-// file does not yet support:
-// - C++ modules TS
-
-#include "llvm/Demangle/Demangle.h"
-#include "llvm/Demangle/ItaniumDemangle.h"
-
-#include <cassert>
-#include <cctype>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
-#include <utility>
-
-using namespace llvm;
-using namespace llvm::itanium_demangle;
-
-constexpr const char *itanium_demangle::FloatData<float>::spec;
-constexpr const char *itanium_demangle::FloatData<double>::spec;
-constexpr const char *itanium_demangle::FloatData<long double>::spec;
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+ # at the end of string
-const char *itanium_demangle::parse_discriminator(const char *first,
- const char *last) {
- // parse but ignore discriminator
- if (first != last) {
- if (*first == '_') {
- const char *t1 = first + 1;
- if (t1 != last) {
- if (std::isdigit(*t1))
- first = t1 + 1;
- else if (*t1 == '_') {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- } else if (std::isdigit(*first)) {
- const char *t1 = first + 1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 == last)
- first = last;
- }
- }
- return first;
-}
-
-#ifndef NDEBUG
-namespace {
-struct DumpVisitor {
- unsigned Depth = 0;
- bool PendingNewline = false;
-
- template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
- return true;
- }
- static bool wantsNewline(NodeArray A) { return !A.empty(); }
- static constexpr bool wantsNewline(...) { return false; }
-
- template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
- for (bool B : {wantsNewline(Vs)...})
- if (B)
- return true;
- return false;
- }
-
- void printStr(const char *S) { fprintf(stderr, "%s", S); }
- void print(StringView SV) {
- fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
- }
- void print(const Node *N) {
- if (N)
- N->visit(std::ref(*this));
- else
- printStr("<null>");
- }
- void print(NodeArray A) {
- ++Depth;
- printStr("{");
- bool First = true;
- for (const Node *N : A) {
- if (First)
- print(N);
- else
- printWithComma(N);
- First = false;
- }
- printStr("}");
- --Depth;
- }
-
- // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
- void print(bool B) { printStr(B ? "true" : "false"); }
-
- template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
- fprintf(stderr, "%llu", (unsigned long long)N);
- }
-
- template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {
- fprintf(stderr, "%lld", (long long)N);
- }
-
- void print(ReferenceKind RK) {
- switch (RK) {
- case ReferenceKind::LValue:
- return printStr("ReferenceKind::LValue");
- case ReferenceKind::RValue:
- return printStr("ReferenceKind::RValue");
- }
- }
- void print(FunctionRefQual RQ) {
- switch (RQ) {
- case FunctionRefQual::FrefQualNone:
- return printStr("FunctionRefQual::FrefQualNone");
- case FunctionRefQual::FrefQualLValue:
- return printStr("FunctionRefQual::FrefQualLValue");
- case FunctionRefQual::FrefQualRValue:
- return printStr("FunctionRefQual::FrefQualRValue");
- }
- }
- void print(Qualifiers Qs) {
- if (!Qs) return printStr("QualNone");
- struct QualName { Qualifiers Q; const char *Name; } Names[] = {
- {QualConst, "QualConst"},
- {QualVolatile, "QualVolatile"},
- {QualRestrict, "QualRestrict"},
- };
- for (QualName Name : Names) {
- if (Qs & Name.Q) {
- printStr(Name.Name);
- Qs = Qualifiers(Qs & ~Name.Q);
- if (Qs) printStr(" | ");
- }
- }
- }
- void print(SpecialSubKind SSK) {
- switch (SSK) {
- case SpecialSubKind::allocator:
- return printStr("SpecialSubKind::allocator");
- case SpecialSubKind::basic_string:
- return printStr("SpecialSubKind::basic_string");
- case SpecialSubKind::string:
- return printStr("SpecialSubKind::string");
- case SpecialSubKind::istream:
- return printStr("SpecialSubKind::istream");
- case SpecialSubKind::ostream:
- return printStr("SpecialSubKind::ostream");
- case SpecialSubKind::iostream:
- return printStr("SpecialSubKind::iostream");
- }
- }
- void print(TemplateParamKind TPK) {
- switch (TPK) {
- case TemplateParamKind::Type:
- return printStr("TemplateParamKind::Type");
- case TemplateParamKind::NonType:
- return printStr("TemplateParamKind::NonType");
- case TemplateParamKind::Template:
- return printStr("TemplateParamKind::Template");
- }
- }
- void print(Node::Prec P) {
- switch (P) {
- case Node::Prec::Primary:
- return printStr("Node::Prec::Primary");
- case Node::Prec::Postfix:
- return printStr("Node::Prec::Postfix");
- case Node::Prec::Unary:
- return printStr("Node::Prec::Unary");
- case Node::Prec::Cast:
- return printStr("Node::Prec::Cast");
- case Node::Prec::PtrMem:
- return printStr("Node::Prec::PtrMem");
- case Node::Prec::Multiplicative:
- return printStr("Node::Prec::Multiplicative");
- case Node::Prec::Additive:
- return printStr("Node::Prec::Additive");
- case Node::Prec::Shift:
- return printStr("Node::Prec::Shift");
- case Node::Prec::Spaceship:
- return printStr("Node::Prec::Spaceship");
- case Node::Prec::Relational:
- return printStr("Node::Prec::Relational");
- case Node::Prec::Equality:
- return printStr("Node::Prec::Equality");
- case Node::Prec::And:
- return printStr("Node::Prec::And");
- case Node::Prec::Xor:
- return printStr("Node::Prec::Xor");
- case Node::Prec::Ior:
- return printStr("Node::Prec::Ior");
- case Node::Prec::AndIf:
- return printStr("Node::Prec::AndIf");
- case Node::Prec::OrIf:
- return printStr("Node::Prec::OrIf");
- case Node::Prec::Conditional:
- return printStr("Node::Prec::Conditional");
- case Node::Prec::Assign:
- return printStr("Node::Prec::Assign");
- case Node::Prec::Comma:
- return printStr("Node::Prec::Comma");
- case Node::Prec::Default:
- return printStr("Node::Prec::Default");
- }
- }
-
- void newLine() {
- printStr("\n");
- for (unsigned I = 0; I != Depth; ++I)
- printStr(" ");
- PendingNewline = false;
- }
-
- template<typename T> void printWithPendingNewline(T V) {
- print(V);
- if (wantsNewline(V))
- PendingNewline = true;
- }
-
- template<typename T> void printWithComma(T V) {
- if (PendingNewline || wantsNewline(V)) {
- printStr(",");
- newLine();
- } else {
- printStr(", ");
- }
-
- printWithPendingNewline(V);
- }
-
- struct CtorArgPrinter {
- DumpVisitor &Visitor;
-
- template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
- if (Visitor.anyWantNewline(V, Vs...))
- Visitor.newLine();
- Visitor.printWithPendingNewline(V);
- int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
- (void)PrintInOrder;
- }
- };
-
- template<typename NodeT> void operator()(const NodeT *Node) {
- Depth += 2;
- fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
- Node->match(CtorArgPrinter{*this});
- fprintf(stderr, ")");
- Depth -= 2;
- }
-
- void operator()(const ForwardTemplateReference *Node) {
- Depth += 2;
- fprintf(stderr, "ForwardTemplateReference(");
- if (Node->Ref && !Node->Printing) {
- Node->Printing = true;
- CtorArgPrinter{*this}(Node->Ref);
- Node->Printing = false;
- } else {
- CtorArgPrinter{*this}(Node->Index);
- }
- fprintf(stderr, ")");
- Depth -= 2;
- }
-};
-}
-
-void itanium_demangle::Node::dump() const {
- DumpVisitor V;
- visit(std::ref(V));
- V.newLine();
-}
-#endif
-
-namespace {
-class BumpPointerAllocator {
- struct BlockMeta {
- BlockMeta* Next;
- size_t Current;
- };
-
- static constexpr size_t AllocSize = 4096;
- static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
-
- alignas(long double) char InitialBuffer[AllocSize];
- BlockMeta* BlockList = nullptr;
-
- void grow() {
- char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
- if (NewMeta == nullptr)
- std::terminate();
- BlockList = new (NewMeta) BlockMeta{BlockList, 0};
- }
-
- void* allocateMassive(size_t NBytes) {
- NBytes += sizeof(BlockMeta);
- BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
- if (NewMeta == nullptr)
- std::terminate();
- BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
- return static_cast<void*>(NewMeta + 1);
- }
-
-public:
- BumpPointerAllocator()
- : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
-
- void* allocate(size_t N) {
- N = (N + 15u) & ~15u;
- if (N + BlockList->Current >= UsableAllocSize) {
- if (N > UsableAllocSize)
- return allocateMassive(N);
- grow();
- }
- BlockList->Current += N;
- return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
- BlockList->Current - N);
- }
-
- void reset() {
- while (BlockList) {
- BlockMeta* Tmp = BlockList;
- BlockList = BlockList->Next;
- if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
- std::free(Tmp);
- }
- BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
- }
-
- ~BumpPointerAllocator() { reset(); }
-};
-
-class DefaultAllocator {
- BumpPointerAllocator Alloc;
-
-public:
- void reset() { Alloc.reset(); }
-
- template<typename T, typename ...Args> T *makeNode(Args &&...args) {
- return new (Alloc.allocate(sizeof(T)))
- T(std::forward<Args>(args)...);
- }
-
- void *allocateNodeArray(size_t sz) {
- return Alloc.allocate(sizeof(Node *) * sz);
- }
-};
-} // unnamed namespace
-
-//===----------------------------------------------------------------------===//
-// Code beyond this point should not be synchronized with libc++abi.
-//===----------------------------------------------------------------------===//
-
-using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
-
-char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
- size_t *N, int *Status) {
- if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
- if (Status)
- *Status = demangle_invalid_args;
- return nullptr;
- }
-
- int InternalStatus = demangle_success;
- Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
- Node *AST = Parser.parse();
-
- if (AST == nullptr)
- InternalStatus = demangle_invalid_mangled_name;
- else {
- OutputBuffer OB(Buf, N);
- assert(Parser.ForwardTemplateRefs.empty());
- AST->print(OB);
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- Buf = OB.getBuffer();
- }
-
- if (Status)
- *Status = InternalStatus;
- return InternalStatus == demangle_success ? Buf : nullptr;
-}
-
-ItaniumPartialDemangler::ItaniumPartialDemangler()
- : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
-
-ItaniumPartialDemangler::~ItaniumPartialDemangler() {
- delete static_cast<Demangler *>(Context);
-}
-
-ItaniumPartialDemangler::ItaniumPartialDemangler(
- ItaniumPartialDemangler &&Other)
- : RootNode(Other.RootNode), Context(Other.Context) {
- Other.Context = Other.RootNode = nullptr;
-}
-
-ItaniumPartialDemangler &ItaniumPartialDemangler::
-operator=(ItaniumPartialDemangler &&Other) {
- std::swap(RootNode, Other.RootNode);
- std::swap(Context, Other.Context);
- return *this;
-}
-
-// Demangle MangledName into an AST, storing it into this->RootNode.
-bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
- Demangler *Parser = static_cast<Demangler *>(Context);
- size_t Len = std::strlen(MangledName);
- Parser->reset(MangledName, MangledName + Len);
- RootNode = Parser->parse();
- return RootNode == nullptr;
-}
-
-static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
- OutputBuffer OB(Buf, N);
- RootNode->print(OB);
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- return OB.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
-
- const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
-
- while (true) {
- switch (Name->getKind()) {
- case Node::KAbiTagAttr:
- Name = static_cast<const AbiTagAttr *>(Name)->Base;
- continue;
- case Node::KModuleEntity:
- Name = static_cast<const ModuleEntity *>(Name)->Name;
- continue;
- case Node::KNestedName:
- Name = static_cast<const NestedName *>(Name)->Name;
- continue;
- case Node::KLocalName:
- Name = static_cast<const LocalName *>(Name)->Entity;
- continue;
- case Node::KNameWithTemplateArgs:
- Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
- continue;
- default:
- return printNode(Name, Buf, N);
- }
- }
-}
-
-char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
- size_t *N) const {
- if (!isFunction())
- return nullptr;
- const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
-
- OutputBuffer OB(Buf, N);
-
- KeepGoingLocalFunction:
- while (true) {
- if (Name->getKind() == Node::KAbiTagAttr) {
- Name = static_cast<const AbiTagAttr *>(Name)->Base;
- continue;
- }
- if (Name->getKind() == Node::KNameWithTemplateArgs) {
- Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
- continue;
- }
- break;
- }
-
- if (Name->getKind() == Node::KModuleEntity)
- Name = static_cast<const ModuleEntity *>(Name)->Name;
-
- switch (Name->getKind()) {
- case Node::KNestedName:
- static_cast<const NestedName *>(Name)->Qual->print(OB);
- break;
- case Node::KLocalName: {
- auto *LN = static_cast<const LocalName *>(Name);
- LN->Encoding->print(OB);
- OB += "::";
- Name = LN->Entity;
- goto KeepGoingLocalFunction;
- }
- default:
- break;
- }
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- return OB.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
- auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
- return printNode(Name, Buf, N);
-}
-
-char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
- size_t *N) const {
- if (!isFunction())
- return nullptr;
- NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
-
- OutputBuffer OB(Buf, N);
-
- OB += '(';
- Params.printWithComma(OB);
- OB += ')';
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- return OB.getBuffer();
-}
-
-char *ItaniumPartialDemangler::getFunctionReturnType(
- char *Buf, size_t *N) const {
- if (!isFunction())
- return nullptr;
-
- OutputBuffer OB(Buf, N);
-
- if (const Node *Ret =
- static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
- Ret->print(OB);
-
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- return OB.getBuffer();
-}
-
-char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- return printNode(static_cast<Node *>(RootNode), Buf, N);
-}
-
-bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- if (!isFunction())
- return false;
- auto *E = static_cast<const FunctionEncoding *>(RootNode);
- return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
-}
-
-bool ItaniumPartialDemangler::isCtorOrDtor() const {
- const Node *N = static_cast<const Node *>(RootNode);
- while (N) {
- switch (N->getKind()) {
- default:
- return false;
- case Node::KCtorDtorName:
- return true;
-
- case Node::KAbiTagAttr:
- N = static_cast<const AbiTagAttr *>(N)->Base;
- break;
- case Node::KFunctionEncoding:
- N = static_cast<const FunctionEncoding *>(N)->getName();
- break;
- case Node::KLocalName:
- N = static_cast<const LocalName *>(N)->Entity;
- break;
- case Node::KNameWithTemplateArgs:
- N = static_cast<const NameWithTemplateArgs *>(N)->Name;
- break;
- case Node::KNestedName:
- N = static_cast<const NestedName *>(N)->Name;
- break;
- case Node::KModuleEntity:
- N = static_cast<const ModuleEntity *>(N)->Name;
- break;
- }
- }
- return false;
-}
-
-bool ItaniumPartialDemangler::isFunction() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- return static_cast<const Node *>(RootNode)->getKind() ==
- Node::KFunctionEncoding;
-}
-
-bool ItaniumPartialDemangler::isSpecialName() const {
- assert(RootNode != nullptr && "must call partialDemangle()");
- auto K = static_cast<const Node *>(RootNode)->getKind();
- return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
-}
-
-bool ItaniumPartialDemangler::isData() const {
- return !isFunction() && !isSpecialName();
-}
diff --git a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
deleted file mode 100644
index c21b0a30..00000000
--- a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ /dev/null
@@ -1,2368 +0,0 @@
-//===- MicrosoftDemangle.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a demangler for MSVC-style mangled symbols.
-//
-// This file has no dependencies on the rest of LLVM so that it can be
-// easily reused in other programs such as libcxxabi.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Demangle/MicrosoftDemangle.h"
-#include "llvm/Demangle/Demangle.h"
-#include "llvm/Demangle/MicrosoftDemangleNodes.h"
-
-#include "llvm/Demangle/DemangleConfig.h"
-#include "llvm/Demangle/StringView.h"
-#include "llvm/Demangle/Utility.h"
-
-#include <array>
-#include <cctype>
-#include <cstdio>
-#include <tuple>
-
-using namespace llvm;
-using namespace ms_demangle;
-
-static bool startsWithDigit(StringView S) {
- return !S.empty() && std::isdigit(S.front());
-}
-
-
-struct NodeList {
- Node *N = nullptr;
- NodeList *Next = nullptr;
-};
-
-static bool isMemberPointer(StringView MangledName, bool &Error) {
- Error = false;
- switch (MangledName.popFront()) {
- case '$':
- // This is probably an rvalue reference (e.g. $$Q), and you cannot have an
- // rvalue reference to a member.
- return false;
- case 'A':
- // 'A' indicates a reference, and you cannot have a reference to a member
- // function or member.
- return false;
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- // These 4 values indicate some kind of pointer, but we still don't know
- // what.
- break;
- default:
- // isMemberPointer() is called only if isPointerType() returns true,
- // and it rejects other prefixes.
- DEMANGLE_UNREACHABLE;
- }
-
- // If it starts with a number, then 6 indicates a non-member function
- // pointer, and 8 indicates a member function pointer.
- if (startsWithDigit(MangledName)) {
- if (MangledName[0] != '6' && MangledName[0] != '8') {
- Error = true;
- return false;
- }
- return (MangledName[0] == '8');
- }
-
- // Remove ext qualifiers since those can appear on either type and are
- // therefore not indicative.
- MangledName.consumeFront('E'); // 64-bit
- MangledName.consumeFront('I'); // restrict
- MangledName.consumeFront('F'); // unaligned
-
- if (MangledName.empty()) {
- Error = true;
- return false;
- }
-
- // The next value should be either ABCD (non-member) or QRST (member).
- switch (MangledName.front()) {
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- return false;
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- return true;
- default:
- Error = true;
- return false;
- }
-}
-
-static SpecialIntrinsicKind
-consumeSpecialIntrinsicKind(StringView &MangledName) {
- if (MangledName.consumeFront("?_7"))
- return SpecialIntrinsicKind::Vftable;
- if (MangledName.consumeFront("?_8"))
- return SpecialIntrinsicKind::Vbtable;
- if (MangledName.consumeFront("?_9"))
- return SpecialIntrinsicKind::VcallThunk;
- if (MangledName.consumeFront("?_A"))
- return SpecialIntrinsicKind::Typeof;
- if (MangledName.consumeFront("?_B"))
- return SpecialIntrinsicKind::LocalStaticGuard;
- if (MangledName.consumeFront("?_C"))
- return SpecialIntrinsicKind::StringLiteralSymbol;
- if (MangledName.consumeFront("?_P"))
- return SpecialIntrinsicKind::UdtReturning;
- if (MangledName.consumeFront("?_R0"))
- return SpecialIntrinsicKind::RttiTypeDescriptor;
- if (MangledName.consumeFront("?_R1"))
- return SpecialIntrinsicKind::RttiBaseClassDescriptor;
- if (MangledName.consumeFront("?_R2"))
- return SpecialIntrinsicKind::RttiBaseClassArray;
- if (MangledName.consumeFront("?_R3"))
- return SpecialIntrinsicKind::RttiClassHierarchyDescriptor;
- if (MangledName.consumeFront("?_R4"))
- return SpecialIntrinsicKind::RttiCompleteObjLocator;
- if (MangledName.consumeFront("?_S"))
- return SpecialIntrinsicKind::LocalVftable;
- if (MangledName.consumeFront("?__E"))
- return SpecialIntrinsicKind::DynamicInitializer;
- if (MangledName.consumeFront("?__F"))
- return SpecialIntrinsicKind::DynamicAtexitDestructor;
- if (MangledName.consumeFront("?__J"))
- return SpecialIntrinsicKind::LocalStaticThreadGuard;
- return SpecialIntrinsicKind::None;
-}
-
-static bool startsWithLocalScopePattern(StringView S) {
- if (!S.consumeFront('?'))
- return false;
-
- size_t End = S.find('?');
- if (End == StringView::npos)
- return false;
- StringView Candidate = S.substr(0, End);
- if (Candidate.empty())
- return false;
-
- // \?[0-9]\?
- // ?@? is the discriminator 0.
- if (Candidate.size() == 1)
- return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9');
-
- // If it's not 0-9, then it's an encoded number terminated with an @
- if (Candidate.back() != '@')
- return false;
- Candidate = Candidate.dropBack();
-
- // An encoded number starts with B-P and all subsequent digits are in A-P.
- // Note that the reason the first digit cannot be A is two fold. First, it
- // would create an ambiguity with ?A which delimits the beginning of an
- // anonymous namespace. Second, A represents 0, and you don't start a multi
- // digit number with a leading 0. Presumably the anonymous namespace
- // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J.
- if (Candidate[0] < 'B' || Candidate[0] > 'P')
- return false;
- Candidate = Candidate.dropFront();
- while (!Candidate.empty()) {
- if (Candidate[0] < 'A' || Candidate[0] > 'P')
- return false;
- Candidate = Candidate.dropFront();
- }
-
- return true;
-}
-
-static bool isTagType(StringView S) {
- switch (S.front()) {
- case 'T': // union
- case 'U': // struct
- case 'V': // class
- case 'W': // enum
- return true;
- }
- return false;
-}
-
-static bool isCustomType(StringView S) { return S[0] == '?'; }
-
-static bool isPointerType(StringView S) {
- if (S.startsWith("$$Q")) // foo &&
- return true;
-
- switch (S.front()) {
- case 'A': // foo &
- case 'P': // foo *
- case 'Q': // foo *const
- case 'R': // foo *volatile
- case 'S': // foo *const volatile
- return true;
- }
- return false;
-}
-
-static bool isArrayType(StringView S) { return S[0] == 'Y'; }
-
-static bool isFunctionType(StringView S) {
- return S.startsWith("$$A8@@") || S.startsWith("$$A6");
-}
-
-static FunctionRefQualifier
-demangleFunctionRefQualifier(StringView &MangledName) {
- if (MangledName.consumeFront('G'))
- return FunctionRefQualifier::Reference;
- else if (MangledName.consumeFront('H'))
- return FunctionRefQualifier::RValueReference;
- return FunctionRefQualifier::None;
-}
-
-static std::pair<Qualifiers, PointerAffinity>
-demanglePointerCVQualifiers(StringView &MangledName) {
- if (MangledName.consumeFront("$$Q"))
- return std::make_pair(Q_None, PointerAffinity::RValueReference);
-
- switch (MangledName.popFront()) {
- case 'A':
- return std::make_pair(Q_None, PointerAffinity::Reference);
- case 'P':
- return std::make_pair(Q_None, PointerAffinity::Pointer);
- case 'Q':
- return std::make_pair(Q_Const, PointerAffinity::Pointer);
- case 'R':
- return std::make_pair(Q_Volatile, PointerAffinity::Pointer);
- case 'S':
- return std::make_pair(Qualifiers(Q_Const | Q_Volatile),
- PointerAffinity::Pointer);
- }
- // This function is only called if isPointerType() returns true,
- // and it only returns true for the six cases listed above.
- DEMANGLE_UNREACHABLE;
-}
-
-StringView Demangler::copyString(StringView Borrowed) {
- char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
- // This is not a micro-optimization, it avoids UB, should Borrowed be an null
- // buffer.
- if (Borrowed.size())
- std::memcpy(Stable, Borrowed.begin(), Borrowed.size());
-
- return {Stable, Borrowed.size()};
-}
-
-SpecialTableSymbolNode *
-Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
- SpecialIntrinsicKind K) {
- NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();
- switch (K) {
- case SpecialIntrinsicKind::Vftable:
- NI->Name = "`vftable'";
- break;
- case SpecialIntrinsicKind::Vbtable:
- NI->Name = "`vbtable'";
- break;
- case SpecialIntrinsicKind::LocalVftable:
- NI->Name = "`local vftable'";
- break;
- case SpecialIntrinsicKind::RttiCompleteObjLocator:
- NI->Name = "`RTTI Complete Object Locator'";
- break;
- default:
- DEMANGLE_UNREACHABLE;
- }
- QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
- SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();
- STSN->Name = QN;
- bool IsMember = false;
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
- char Front = MangledName.popFront();
- if (Front != '6' && Front != '7') {
- Error = true;
- return nullptr;
- }
-
- std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
- if (!MangledName.consumeFront('@'))
- STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);
- return STSN;
-}
-
-LocalStaticGuardVariableNode *
-Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) {
- LocalStaticGuardIdentifierNode *LSGI =
- Arena.alloc<LocalStaticGuardIdentifierNode>();
- LSGI->IsThread = IsThread;
- QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);
- LocalStaticGuardVariableNode *LSGVN =
- Arena.alloc<LocalStaticGuardVariableNode>();
- LSGVN->Name = QN;
-
- if (MangledName.consumeFront("4IA"))
- LSGVN->IsVisible = false;
- else if (MangledName.consumeFront("5"))
- LSGVN->IsVisible = true;
- else {
- Error = true;
- return nullptr;
- }
-
- if (!MangledName.empty())
- LSGI->ScopeIndex = demangleUnsigned(MangledName);
- return LSGVN;
-}
-
-static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,
- StringView Name) {
- NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();
- Id->Name = Name;
- return Id;
-}
-
-static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,
- IdentifierNode *Identifier) {
- QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();
- QN->Components = Arena.alloc<NodeArrayNode>();
- QN->Components->Count = 1;
- QN->Components->Nodes = Arena.allocArray<Node *>(1);
- QN->Components->Nodes[0] = Identifier;
- return QN;
-}
-
-static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,
- StringView Name) {
- NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name);
- return synthesizeQualifiedName(Arena, Id);
-}
-
-static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,
- TypeNode *Type,
- StringView VariableName) {
- VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
- VSN->Type = Type;
- VSN->Name = synthesizeQualifiedName(Arena, VariableName);
- return VSN;
-}
-
-VariableSymbolNode *Demangler::demangleUntypedVariable(
- ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) {
- NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName);
- QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
- VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
- VSN->Name = QN;
- if (MangledName.consumeFront("8"))
- return VSN;
-
- Error = true;
- return nullptr;
-}
-
-VariableSymbolNode *
-Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
- StringView &MangledName) {
- RttiBaseClassDescriptorNode *RBCDN =
- Arena.alloc<RttiBaseClassDescriptorNode>();
- RBCDN->NVOffset = demangleUnsigned(MangledName);
- RBCDN->VBPtrOffset = demangleSigned(MangledName);
- RBCDN->VBTableOffset = demangleUnsigned(MangledName);
- RBCDN->Flags = demangleUnsigned(MangledName);
- if (Error)
- return nullptr;
-
- VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
- VSN->Name = demangleNameScopeChain(MangledName, RBCDN);
- MangledName.consumeFront('8');
- return VSN;
-}
-
-FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,
- bool IsDestructor) {
- DynamicStructorIdentifierNode *DSIN =
- Arena.alloc<DynamicStructorIdentifierNode>();
- DSIN->IsDestructor = IsDestructor;
-
- bool IsKnownStaticDataMember = false;
- if (MangledName.consumeFront('?'))
- IsKnownStaticDataMember = true;
-
- SymbolNode *Symbol = demangleDeclarator(MangledName);
- if (Error)
- return nullptr;
-
- FunctionSymbolNode *FSN = nullptr;
-
- if (Symbol->kind() == NodeKind::VariableSymbol) {
- DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol);
-
- // Older versions of clang mangled this type of symbol incorrectly. They
- // would omit the leading ? and they would only emit a single @ at the end.
- // The correct mangling is a leading ? and 2 trailing @ signs. Handle
- // both cases.
- int AtCount = IsKnownStaticDataMember ? 2 : 1;
- for (int I = 0; I < AtCount; ++I) {
- if (MangledName.consumeFront('@'))
- continue;
- Error = true;
- return nullptr;
- }
-
- FSN = demangleFunctionEncoding(MangledName);
- if (FSN)
- FSN->Name = synthesizeQualifiedName(Arena, DSIN);
- } else {
- if (IsKnownStaticDataMember) {
- // This was supposed to be a static data member, but we got a function.
- Error = true;
- return nullptr;
- }
-
- FSN = static_cast<FunctionSymbolNode *>(Symbol);
- DSIN->Name = Symbol->Name;
- FSN->Name = synthesizeQualifiedName(Arena, DSIN);
- }
-
- return FSN;
-}
-
-SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
- SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);
-
- switch (SIK) {
- case SpecialIntrinsicKind::None:
- return nullptr;
- case SpecialIntrinsicKind::StringLiteralSymbol:
- return demangleStringLiteral(MangledName);
- case SpecialIntrinsicKind::Vftable:
- case SpecialIntrinsicKind::Vbtable:
- case SpecialIntrinsicKind::LocalVftable:
- case SpecialIntrinsicKind::RttiCompleteObjLocator:
- return demangleSpecialTableSymbolNode(MangledName, SIK);
- case SpecialIntrinsicKind::VcallThunk:
- return demangleVcallThunkNode(MangledName);
- case SpecialIntrinsicKind::LocalStaticGuard:
- return demangleLocalStaticGuard(MangledName, /*IsThread=*/false);
- case SpecialIntrinsicKind::LocalStaticThreadGuard:
- return demangleLocalStaticGuard(MangledName, /*IsThread=*/true);
- case SpecialIntrinsicKind::RttiTypeDescriptor: {
- TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);
- if (Error)
- break;
- if (!MangledName.consumeFront("@8"))
- break;
- if (!MangledName.empty())
- break;
- return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'");
- }
- case SpecialIntrinsicKind::RttiBaseClassArray:
- return demangleUntypedVariable(Arena, MangledName,
- "`RTTI Base Class Array'");
- case SpecialIntrinsicKind::RttiClassHierarchyDescriptor:
- return demangleUntypedVariable(Arena, MangledName,
- "`RTTI Class Hierarchy Descriptor'");
- case SpecialIntrinsicKind::RttiBaseClassDescriptor:
- return demangleRttiBaseClassDescriptorNode(Arena, MangledName);
- case SpecialIntrinsicKind::DynamicInitializer:
- return demangleInitFiniStub(MangledName, /*IsDestructor=*/false);
- case SpecialIntrinsicKind::DynamicAtexitDestructor:
- return demangleInitFiniStub(MangledName, /*IsDestructor=*/true);
- case SpecialIntrinsicKind::Typeof:
- case SpecialIntrinsicKind::UdtReturning:
- // It's unclear which tools produces these manglings, so demangling
- // support is not (yet?) implemented.
- break;
- case SpecialIntrinsicKind::Unknown:
- DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind.
- }
- Error = true;
- return nullptr;
-}
-
-IdentifierNode *
-Demangler::demangleFunctionIdentifierCode(StringView &MangledName) {
- assert(MangledName.startsWith('?'));
- MangledName = MangledName.dropFront();
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- if (MangledName.consumeFront("__"))
- return demangleFunctionIdentifierCode(
- MangledName, FunctionIdentifierCodeGroup::DoubleUnder);
- if (MangledName.consumeFront("_"))
- return demangleFunctionIdentifierCode(MangledName,
- FunctionIdentifierCodeGroup::Under);
- return demangleFunctionIdentifierCode(MangledName,
- FunctionIdentifierCodeGroup::Basic);
-}
-
-StructorIdentifierNode *
-Demangler::demangleStructorIdentifier(StringView &MangledName,
- bool IsDestructor) {
- StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();
- N->IsDestructor = IsDestructor;
- return N;
-}
-
-ConversionOperatorIdentifierNode *
-Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) {
- ConversionOperatorIdentifierNode *N =
- Arena.alloc<ConversionOperatorIdentifierNode>();
- return N;
-}
-
-LiteralOperatorIdentifierNode *
-Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {
- LiteralOperatorIdentifierNode *N =
- Arena.alloc<LiteralOperatorIdentifierNode>();
- N->Name = demangleSimpleString(MangledName, /*Memorize=*/false);
- return N;
-}
-
-IntrinsicFunctionKind
-Demangler::translateIntrinsicFunctionCode(char CH,
- FunctionIdentifierCodeGroup Group) {
- using IFK = IntrinsicFunctionKind;
- if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) {
- Error = true;
- return IFK::None;
- }
-
- // Not all ? identifiers are intrinsics *functions*. This function only maps
- // operator codes for the special functions, all others are handled elsewhere,
- // hence the IFK::None entries in the table.
- static IFK Basic[36] = {
- IFK::None, // ?0 # Foo::Foo()
- IFK::None, // ?1 # Foo::~Foo()
- IFK::New, // ?2 # operator new
- IFK::Delete, // ?3 # operator delete
- IFK::Assign, // ?4 # operator=
- IFK::RightShift, // ?5 # operator>>
- IFK::LeftShift, // ?6 # operator<<
- IFK::LogicalNot, // ?7 # operator!
- IFK::Equals, // ?8 # operator==
- IFK::NotEquals, // ?9 # operator!=
- IFK::ArraySubscript, // ?A # operator[]
- IFK::None, // ?B # Foo::operator <type>()
- IFK::Pointer, // ?C # operator->
- IFK::Dereference, // ?D # operator*
- IFK::Increment, // ?E # operator++
- IFK::Decrement, // ?F # operator--
- IFK::Minus, // ?G # operator-
- IFK::Plus, // ?H # operator+
- IFK::BitwiseAnd, // ?I # operator&
- IFK::MemberPointer, // ?J # operator->*
- IFK::Divide, // ?K # operator/
- IFK::Modulus, // ?L # operator%
- IFK::LessThan, // ?M operator<
- IFK::LessThanEqual, // ?N operator<=
- IFK::GreaterThan, // ?O operator>
- IFK::GreaterThanEqual, // ?P operator>=
- IFK::Comma, // ?Q operator,
- IFK::Parens, // ?R operator()
- IFK::BitwiseNot, // ?S operator~
- IFK::BitwiseXor, // ?T operator^
- IFK::BitwiseOr, // ?U operator|
- IFK::LogicalAnd, // ?V operator&&
- IFK::LogicalOr, // ?W operator||
- IFK::TimesEqual, // ?X operator*=
- IFK::PlusEqual, // ?Y operator+=
- IFK::MinusEqual, // ?Z operator-=
- };
- static IFK Under[36] = {
- IFK::DivEqual, // ?_0 operator/=
- IFK::ModEqual, // ?_1 operator%=
- IFK::RshEqual, // ?_2 operator>>=
- IFK::LshEqual, // ?_3 operator<<=
- IFK::BitwiseAndEqual, // ?_4 operator&=
- IFK::BitwiseOrEqual, // ?_5 operator|=
- IFK::BitwiseXorEqual, // ?_6 operator^=
- IFK::None, // ?_7 # vftable
- IFK::None, // ?_8 # vbtable
- IFK::None, // ?_9 # vcall
- IFK::None, // ?_A # typeof
- IFK::None, // ?_B # local static guard
- IFK::None, // ?_C # string literal
- IFK::VbaseDtor, // ?_D # vbase destructor
- IFK::VecDelDtor, // ?_E # vector deleting destructor
- IFK::DefaultCtorClosure, // ?_F # default constructor closure
- IFK::ScalarDelDtor, // ?_G # scalar deleting destructor
- IFK::VecCtorIter, // ?_H # vector constructor iterator
- IFK::VecDtorIter, // ?_I # vector destructor iterator
- IFK::VecVbaseCtorIter, // ?_J # vector vbase constructor iterator
- IFK::VdispMap, // ?_K # virtual displacement map
- IFK::EHVecCtorIter, // ?_L # eh vector constructor iterator
- IFK::EHVecDtorIter, // ?_M # eh vector destructor iterator
- IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator
- IFK::CopyCtorClosure, // ?_O # copy constructor closure
- IFK::None, // ?_P<name> # udt returning <name>
- IFK::None, // ?_Q # <unknown>
- IFK::None, // ?_R0 - ?_R4 # RTTI Codes
- IFK::None, // ?_S # local vftable
- IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure
- IFK::ArrayNew, // ?_U operator new[]
- IFK::ArrayDelete, // ?_V operator delete[]
- IFK::None, // ?_W <unused>
- IFK::None, // ?_X <unused>
- IFK::None, // ?_Y <unused>
- IFK::None, // ?_Z <unused>
- };
- static IFK DoubleUnder[36] = {
- IFK::None, // ?__0 <unused>
- IFK::None, // ?__1 <unused>
- IFK::None, // ?__2 <unused>
- IFK::None, // ?__3 <unused>
- IFK::None, // ?__4 <unused>
- IFK::None, // ?__5 <unused>
- IFK::None, // ?__6 <unused>
- IFK::None, // ?__7 <unused>
- IFK::None, // ?__8 <unused>
- IFK::None, // ?__9 <unused>
- IFK::ManVectorCtorIter, // ?__A managed vector ctor iterator
- IFK::ManVectorDtorIter, // ?__B managed vector dtor iterator
- IFK::EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator
- IFK::EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iter
- IFK::None, // ?__E dynamic initializer for `T'
- IFK::None, // ?__F dynamic atexit destructor for `T'
- IFK::VectorCopyCtorIter, // ?__G vector copy constructor iter
- IFK::VectorVbaseCopyCtorIter, // ?__H vector vbase copy ctor iter
- IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor
- // iter
- IFK::None, // ?__J local static thread guard
- IFK::None, // ?__K operator ""_name
- IFK::CoAwait, // ?__L operator co_await
- IFK::Spaceship, // ?__M operator<=>
- IFK::None, // ?__N <unused>
- IFK::None, // ?__O <unused>
- IFK::None, // ?__P <unused>
- IFK::None, // ?__Q <unused>
- IFK::None, // ?__R <unused>
- IFK::None, // ?__S <unused>
- IFK::None, // ?__T <unused>
- IFK::None, // ?__U <unused>
- IFK::None, // ?__V <unused>
- IFK::None, // ?__W <unused>
- IFK::None, // ?__X <unused>
- IFK::None, // ?__Y <unused>
- IFK::None, // ?__Z <unused>
- };
-
- int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10);
- switch (Group) {
- case FunctionIdentifierCodeGroup::Basic:
- return Basic[Index];
- case FunctionIdentifierCodeGroup::Under:
- return Under[Index];
- case FunctionIdentifierCodeGroup::DoubleUnder:
- return DoubleUnder[Index];
- }
- DEMANGLE_UNREACHABLE;
-}
-
-IdentifierNode *
-Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
- FunctionIdentifierCodeGroup Group) {
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
- switch (Group) {
- case FunctionIdentifierCodeGroup::Basic:
- switch (char CH = MangledName.popFront()) {
- case '0':
- case '1':
- return demangleStructorIdentifier(MangledName, CH == '1');
- case 'B':
- return demangleConversionOperatorIdentifier(MangledName);
- default:
- return Arena.alloc<IntrinsicFunctionIdentifierNode>(
- translateIntrinsicFunctionCode(CH, Group));
- }
- case FunctionIdentifierCodeGroup::Under:
- return Arena.alloc<IntrinsicFunctionIdentifierNode>(
- translateIntrinsicFunctionCode(MangledName.popFront(), Group));
- case FunctionIdentifierCodeGroup::DoubleUnder:
- switch (char CH = MangledName.popFront()) {
- case 'K':
- return demangleLiteralOperatorIdentifier(MangledName);
- default:
- return Arena.alloc<IntrinsicFunctionIdentifierNode>(
- translateIntrinsicFunctionCode(CH, Group));
- }
- }
-
- DEMANGLE_UNREACHABLE;
-}
-
-SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
- QualifiedNameNode *Name) {
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- // Read a variable.
- switch (MangledName.front()) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4': {
- StorageClass SC = demangleVariableStorageClass(MangledName);
- return demangleVariableEncoding(MangledName, SC);
- }
- }
- FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);
-
- IdentifierNode *UQN = Name->getUnqualifiedIdentifier();
- if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
- ConversionOperatorIdentifierNode *COIN =
- static_cast<ConversionOperatorIdentifierNode *>(UQN);
- if (FSN)
- COIN->TargetType = FSN->Signature->ReturnType;
- }
- return FSN;
-}
-
-SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) {
- // What follows is a main symbol name. This may include namespaces or class
- // back references.
- QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
- if (Error)
- return nullptr;
-
- SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
- if (Error)
- return nullptr;
- Symbol->Name = QN;
-
- IdentifierNode *UQN = QN->getUnqualifiedIdentifier();
- if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
- ConversionOperatorIdentifierNode *COIN =
- static_cast<ConversionOperatorIdentifierNode *>(UQN);
- if (!COIN->TargetType) {
- Error = true;
- return nullptr;
- }
- }
- return Symbol;
-}
-
-SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) {
- assert(MangledName.startsWith("??@"));
- // This is an MD5 mangled name. We can't demangle it, just return the
- // mangled name.
- // An MD5 mangled name is ??@ followed by 32 characters and a terminating @.
- size_t MD5Last = MangledName.find('@', strlen("??@"));
- if (MD5Last == StringView::npos) {
- Error = true;
- return nullptr;
- }
- const char *Start = MangledName.begin();
- MangledName = MangledName.dropFront(MD5Last + 1);
-
- // There are two additional special cases for MD5 names:
- // 1. For complete object locators where the object name is long enough
- // for the object to have an MD5 name, the complete object locator is
- // called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual
- // leading "??_R4". This is handled here.
- // 2. For catchable types, in versions of MSVC before 2015 (<1900) or after
- // 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8
- // instead of_CT??@...@8 with just one MD5 name. Since we don't yet
- // demangle catchable types anywhere, this isn't handled for MD5 names
- // either.
- MangledName.consumeFront("??_R4@");
-
- StringView MD5(Start, MangledName.begin());
- SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);
- S->Name = synthesizeQualifiedName(Arena, MD5);
-
- return S;
-}
-
-SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) {
- assert(MangledName.startsWith('.'));
- MangledName.consumeFront('.');
-
- TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);
- if (Error || !MangledName.empty()) {
- Error = true;
- return nullptr;
- }
- return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'");
-}
-
-// Parser entry point.
-SymbolNode *Demangler::parse(StringView &MangledName) {
- // Typeinfo names are strings stored in RTTI data. They're not symbol names.
- // It's still useful to demangle them. They're the only demangled entity
- // that doesn't start with a "?" but a ".".
- if (MangledName.startsWith('.'))
- return demangleTypeinfoName(MangledName);
-
- if (MangledName.startsWith("??@"))
- return demangleMD5Name(MangledName);
-
- // MSVC-style mangled symbols must start with '?'.
- if (!MangledName.startsWith('?')) {
- Error = true;
- return nullptr;
- }
-
- MangledName.consumeFront('?');
-
- // ?$ is a template instantiation, but all other names that start with ? are
- // operators / special names.
- if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName))
- return SI;
-
- return demangleDeclarator(MangledName);
-}
-
-TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
- if (!MangledName.consumeFront(".?A")) {
- Error = true;
- return nullptr;
- }
- MangledName.consumeFront(".?A");
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- return demangleClassType(MangledName);
-}
-
-// <type-encoding> ::= <storage-class> <variable-type>
-// <storage-class> ::= 0 # private static member
-// ::= 1 # protected static member
-// ::= 2 # public static member
-// ::= 3 # global
-// ::= 4 # static local
-
-VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
- StorageClass SC) {
- VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
-
- VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
- VSN->SC = SC;
-
- if (Error)
- return nullptr;
-
- // <variable-type> ::= <type> <cvr-qualifiers>
- // ::= <type> <pointee-cvr-qualifiers> # pointers, references
- switch (VSN->Type->kind()) {
- case NodeKind::PointerType: {
- PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type);
-
- Qualifiers ExtraChildQuals = Q_None;
- PTN->Quals = Qualifiers(VSN->Type->Quals |
- demanglePointerExtQualifiers(MangledName));
-
- bool IsMember = false;
- std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);
-
- if (PTN->ClassParent) {
- QualifiedNameNode *BackRefName =
- demangleFullyQualifiedTypeName(MangledName);
- (void)BackRefName;
- }
- PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals);
-
- break;
- }
- default:
- VSN->Type->Quals = demangleQualifiers(MangledName).first;
- break;
- }
-
- return VSN;
-}
-
-// Sometimes numbers are encoded in mangled symbols. For example,
-// "int (*x)[20]" is a valid C type (x is a pointer to an array of
-// length 20), so we need some way to embed numbers as part of symbols.
-// This function parses it.
-//
-// <number> ::= [?] <non-negative integer>
-//
-// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10
-// ::= <hex digit>+ @ # when Number == 0 or >= 10
-//
-// <hex-digit> ::= [A-P] # A = 0, B = 1, ...
-std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
- bool IsNegative = MangledName.consumeFront('?');
-
- if (startsWithDigit(MangledName)) {
- uint64_t Ret = MangledName[0] - '0' + 1;
- MangledName = MangledName.dropFront(1);
- return {Ret, IsNegative};
- }
-
- uint64_t Ret = 0;
- for (size_t i = 0; i < MangledName.size(); ++i) {
- char C = MangledName[i];
- if (C == '@') {
- MangledName = MangledName.dropFront(i + 1);
- return {Ret, IsNegative};
- }
- if ('A' <= C && C <= 'P') {
- Ret = (Ret << 4) + (C - 'A');
- continue;
- }
- break;
- }
-
- Error = true;
- return {0ULL, false};
-}
-
-uint64_t Demangler::demangleUnsigned(StringView &MangledName) {
- bool IsNegative = false;
- uint64_t Number = 0;
- std::tie(Number, IsNegative) = demangleNumber(MangledName);
- if (IsNegative)
- Error = true;
- return Number;
-}
-
-int64_t Demangler::demangleSigned(StringView &MangledName) {
- bool IsNegative = false;
- uint64_t Number = 0;
- std::tie(Number, IsNegative) = demangleNumber(MangledName);
- if (Number > INT64_MAX)
- Error = true;
- int64_t I = static_cast<int64_t>(Number);
- return IsNegative ? -I : I;
-}
-
-// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
-// Memorize it.
-void Demangler::memorizeString(StringView S) {
- if (Backrefs.NamesCount >= BackrefContext::Max)
- return;
- for (size_t i = 0; i < Backrefs.NamesCount; ++i)
- if (S == Backrefs.Names[i]->Name)
- return;
- NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>();
- N->Name = S;
- Backrefs.Names[Backrefs.NamesCount++] = N;
-}
-
-NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {
- assert(startsWithDigit(MangledName));
-
- size_t I = MangledName[0] - '0';
- if (I >= Backrefs.NamesCount) {
- Error = true;
- return nullptr;
- }
-
- MangledName = MangledName.dropFront();
- return Backrefs.Names[I];
-}
-
-void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
- // Render this class template name into a string buffer so that we can
- // memorize it for the purpose of back-referencing.
- OutputBuffer OB;
- Identifier->output(OB, OF_Default);
- StringView Owned = copyString(OB);
- memorizeString(Owned);
- std::free(OB.getBuffer());
-}
-
-IdentifierNode *
-Demangler::demangleTemplateInstantiationName(StringView &MangledName,
- NameBackrefBehavior NBB) {
- assert(MangledName.startsWith("?$"));
- MangledName.consumeFront("?$");
-
- BackrefContext OuterContext;
- std::swap(OuterContext, Backrefs);
-
- IdentifierNode *Identifier =
- demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
- if (!Error)
- Identifier->TemplateParams = demangleTemplateParameterList(MangledName);
-
- std::swap(OuterContext, Backrefs);
- if (Error)
- return nullptr;
-
- if (NBB & NBB_Template) {
- // NBB_Template is only set for types and non-leaf names ("a::" in "a::b").
- // Structors and conversion operators only makes sense in a leaf name, so
- // reject them in NBB_Template contexts.
- if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier ||
- Identifier->kind() == NodeKind::StructorIdentifier) {
- Error = true;
- return nullptr;
- }
-
- memorizeIdentifier(Identifier);
- }
-
- return Identifier;
-}
-
-NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName,
- bool Memorize) {
- StringView S = demangleSimpleString(MangledName, Memorize);
- if (Error)
- return nullptr;
-
- NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>();
- Name->Name = S;
- return Name;
-}
-
-static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); }
-
-static uint8_t rebasedHexDigitToNumber(char C) {
- assert(isRebasedHexDigit(C));
- return (C <= 'J') ? (C - 'A') : (10 + C - 'K');
-}
-
-uint8_t Demangler::demangleCharLiteral(StringView &MangledName) {
- assert(!MangledName.empty());
- if (!MangledName.startsWith('?'))
- return MangledName.popFront();
-
- MangledName = MangledName.dropFront();
- if (MangledName.empty())
- goto CharLiteralError;
-
- if (MangledName.consumeFront('$')) {
- // Two hex digits
- if (MangledName.size() < 2)
- goto CharLiteralError;
- StringView Nibbles = MangledName.substr(0, 2);
- if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1]))
- goto CharLiteralError;
- // Don't append the null terminator.
- uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]);
- uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]);
- MangledName = MangledName.dropFront(2);
- return (C1 << 4) | C2;
- }
-
- if (startsWithDigit(MangledName)) {
- const char *Lookup = ",/\\:. \n\t'-";
- char C = Lookup[MangledName[0] - '0'];
- MangledName = MangledName.dropFront();
- return C;
- }
-
- if (MangledName[0] >= 'a' && MangledName[0] <= 'z') {
- char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7',
- '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE',
- '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5',
- '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'};
- char C = Lookup[MangledName[0] - 'a'];
- MangledName = MangledName.dropFront();
- return C;
- }
-
- if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') {
- char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7',
- '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE',
- '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5',
- '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'};
- char C = Lookup[MangledName[0] - 'A'];
- MangledName = MangledName.dropFront();
- return C;
- }
-
-CharLiteralError:
- Error = true;
- return '\0';
-}
-
-wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) {
- uint8_t C1, C2;
-
- C1 = demangleCharLiteral(MangledName);
- if (Error || MangledName.empty())
- goto WCharLiteralError;
- C2 = demangleCharLiteral(MangledName);
- if (Error)
- goto WCharLiteralError;
-
- return ((wchar_t)C1 << 8) | (wchar_t)C2;
-
-WCharLiteralError:
- Error = true;
- return L'\0';
-}
-
-static void writeHexDigit(char *Buffer, uint8_t Digit) {
- assert(Digit <= 15);
- *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);
-}
-
-static void outputHex(OutputBuffer &OB, unsigned C) {
- assert (C != 0);
-
- // It's easier to do the math if we can work from right to left, but we need
- // to print the numbers from left to right. So render this into a temporary
- // buffer first, then output the temporary buffer. Each byte is of the form
- // \xAB, which means that each byte needs 4 characters. Since there are at
- // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer.
- char TempBuffer[17];
-
- ::memset(TempBuffer, 0, sizeof(TempBuffer));
- constexpr int MaxPos = sizeof(TempBuffer) - 1;
-
- int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0.
- while (C != 0) {
- for (int I = 0; I < 2; ++I) {
- writeHexDigit(&TempBuffer[Pos--], C % 16);
- C /= 16;
- }
- }
- TempBuffer[Pos--] = 'x';
- assert(Pos >= 0);
- TempBuffer[Pos--] = '\\';
- OB << StringView(&TempBuffer[Pos + 1]);
-}
-
-static void outputEscapedChar(OutputBuffer &OB, unsigned C) {
- switch (C) {
- case '\0': // nul
- OB << "\\0";
- return;
- case '\'': // single quote
- OB << "\\\'";
- return;
- case '\"': // double quote
- OB << "\\\"";
- return;
- case '\\': // backslash
- OB << "\\\\";
- return;
- case '\a': // bell
- OB << "\\a";
- return;
- case '\b': // backspace
- OB << "\\b";
- return;
- case '\f': // form feed
- OB << "\\f";
- return;
- case '\n': // new line
- OB << "\\n";
- return;
- case '\r': // carriage return
- OB << "\\r";
- return;
- case '\t': // tab
- OB << "\\t";
- return;
- case '\v': // vertical tab
- OB << "\\v";
- return;
- default:
- break;
- }
-
- if (C > 0x1F && C < 0x7F) {
- // Standard ascii char.
- OB << (char)C;
- return;
- }
-
- outputHex(OB, C);
-}
-
-static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
- const uint8_t *End = StringBytes + Length - 1;
- unsigned Count = 0;
- while (Length > 0 && *End == 0) {
- --Length;
- --End;
- ++Count;
- }
- return Count;
-}
-
-static unsigned countEmbeddedNulls(const uint8_t *StringBytes,
- unsigned Length) {
- unsigned Result = 0;
- for (unsigned I = 0; I < Length; ++I) {
- if (*StringBytes++ == 0)
- ++Result;
- }
- return Result;
-}
-
-// A mangled (non-wide) string literal stores the total length of the string it
-// refers to (passed in NumBytes), and it contains up to 32 bytes of actual text
-// (passed in StringBytes, NumChars).
-static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
- uint64_t NumBytes) {
- assert(NumBytes > 0);
-
- // If the number of bytes is odd, this is guaranteed to be a char string.
- if (NumBytes % 2 == 1)
- return 1;
-
- // All strings can encode at most 32 bytes of data. If it's less than that,
- // then we encoded the entire string. In this case we check for a 1-byte,
- // 2-byte, or 4-byte null terminator.
- if (NumBytes < 32) {
- unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars);
- if (TrailingNulls >= 4 && NumBytes % 4 == 0)
- return 4;
- if (TrailingNulls >= 2)
- return 2;
- return 1;
- }
-
- // The whole string was not able to be encoded. Try to look at embedded null
- // terminators to guess. The heuristic is that we count all embedded null
- // terminators. If more than 2/3 are null, it's a char32. If more than 1/3
- // are null, it's a char16. Otherwise it's a char8. This obviously isn't
- // perfect and is biased towards languages that have ascii alphabets, but this
- // was always going to be best effort since the encoding is lossy.
- unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars);
- if (Nulls >= 2 * NumChars / 3 && NumBytes % 4 == 0)
- return 4;
- if (Nulls >= NumChars / 3)
- return 2;
- return 1;
-}
-
-static unsigned decodeMultiByteChar(const uint8_t *StringBytes,
- unsigned CharIndex, unsigned CharBytes) {
- assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4);
- unsigned Offset = CharIndex * CharBytes;
- unsigned Result = 0;
- StringBytes = StringBytes + Offset;
- for (unsigned I = 0; I < CharBytes; ++I) {
- unsigned C = static_cast<unsigned>(StringBytes[I]);
- Result |= C << (8 * I);
- }
- return Result;
-}
-
-FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {
- FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>();
- VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>();
- FSN->Signature = Arena.alloc<ThunkSignatureNode>();
- FSN->Signature->FunctionClass = FC_NoParameterList;
-
- FSN->Name = demangleNameScopeChain(MangledName, VTIN);
- if (!Error)
- Error = !MangledName.consumeFront("$B");
- if (!Error)
- VTIN->OffsetInVTable = demangleUnsigned(MangledName);
- if (!Error)
- Error = !MangledName.consumeFront('A');
- if (!Error)
- FSN->Signature->CallConvention = demangleCallingConvention(MangledName);
- return (Error) ? nullptr : FSN;
-}
-
-EncodedStringLiteralNode *
-Demangler::demangleStringLiteral(StringView &MangledName) {
- // This function uses goto, so declare all variables up front.
- OutputBuffer OB;
- StringView CRC;
- uint64_t StringByteSize;
- bool IsWcharT = false;
- bool IsNegative = false;
- size_t CrcEndPos = 0;
-
- EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
-
- // Prefix indicating the beginning of a string literal
- if (!MangledName.consumeFront("@_"))
- goto StringLiteralError;
- if (MangledName.empty())
- goto StringLiteralError;
-
- // Char Type (regular or wchar_t)
- switch (MangledName.popFront()) {
- case '1':
- IsWcharT = true;
- DEMANGLE_FALLTHROUGH;
- case '0':
- break;
- default:
- goto StringLiteralError;
- }
-
- // Encoded Length
- std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);
- if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1))
- goto StringLiteralError;
-
- // CRC 32 (always 8 characters plus a terminator)
- CrcEndPos = MangledName.find('@');
- if (CrcEndPos == StringView::npos)
- goto StringLiteralError;
- CRC = MangledName.substr(0, CrcEndPos);
- MangledName = MangledName.dropFront(CrcEndPos + 1);
- if (MangledName.empty())
- goto StringLiteralError;
-
- if (IsWcharT) {
- Result->Char = CharKind::Wchar;
- if (StringByteSize > 64)
- Result->IsTruncated = true;
-
- while (!MangledName.consumeFront('@')) {
- if (MangledName.size() < 2)
- goto StringLiteralError;
- wchar_t W = demangleWcharLiteral(MangledName);
- if (StringByteSize != 2 || Result->IsTruncated)
- outputEscapedChar(OB, W);
- StringByteSize -= 2;
- if (Error)
- goto StringLiteralError;
- }
- } else {
- // The max byte length is actually 32, but some compilers mangled strings
- // incorrectly, so we have to assume it can go higher.
- constexpr unsigned MaxStringByteLength = 32 * 4;
- uint8_t StringBytes[MaxStringByteLength];
-
- unsigned BytesDecoded = 0;
- while (!MangledName.consumeFront('@')) {
- if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength)
- goto StringLiteralError;
- StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName);
- }
-
- if (StringByteSize > BytesDecoded)
- Result->IsTruncated = true;
-
- unsigned CharBytes =
- guessCharByteSize(StringBytes, BytesDecoded, StringByteSize);
- assert(StringByteSize % CharBytes == 0);
- switch (CharBytes) {
- case 1:
- Result->Char = CharKind::Char;
- break;
- case 2:
- Result->Char = CharKind::Char16;
- break;
- case 4:
- Result->Char = CharKind::Char32;
- break;
- default:
- DEMANGLE_UNREACHABLE;
- }
- const unsigned NumChars = BytesDecoded / CharBytes;
- for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {
- unsigned NextChar =
- decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
- if (CharIndex + 1 < NumChars || Result->IsTruncated)
- outputEscapedChar(OB, NextChar);
- }
- }
-
- Result->DecodedString = copyString(OB);
- std::free(OB.getBuffer());
- return Result;
-
-StringLiteralError:
- Error = true;
- std::free(OB.getBuffer());
- return nullptr;
-}
-
-// Returns MangledName's prefix before the first '@', or an error if
-// MangledName contains no '@' or the prefix has length 0.
-StringView Demangler::demangleSimpleString(StringView &MangledName,
- bool Memorize) {
- StringView S;
- for (size_t i = 0; i < MangledName.size(); ++i) {
- if (MangledName[i] != '@')
- continue;
- if (i == 0)
- break;
- S = MangledName.substr(0, i);
- MangledName = MangledName.dropFront(i + 1);
-
- if (Memorize)
- memorizeString(S);
- return S;
- }
-
- Error = true;
- return {};
-}
-
-NamedIdentifierNode *
-Demangler::demangleAnonymousNamespaceName(StringView &MangledName) {
- assert(MangledName.startsWith("?A"));
- MangledName.consumeFront("?A");
-
- NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>();
- Node->Name = "`anonymous namespace'";
- size_t EndPos = MangledName.find('@');
- if (EndPos == StringView::npos) {
- Error = true;
- return nullptr;
- }
- StringView NamespaceKey = MangledName.substr(0, EndPos);
- memorizeString(NamespaceKey);
- MangledName = MangledName.substr(EndPos + 1);
- return Node;
-}
-
-NamedIdentifierNode *
-Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
- assert(startsWithLocalScopePattern(MangledName));
-
- NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>();
- MangledName.consumeFront('?');
- uint64_t Number = 0;
- bool IsNegative = false;
- std::tie(Number, IsNegative) = demangleNumber(MangledName);
- assert(!IsNegative);
-
- // One ? to terminate the number
- MangledName.consumeFront('?');
-
- assert(!Error);
- Node *Scope = parse(MangledName);
- if (Error)
- return nullptr;
-
- // Render the parent symbol's name into a buffer.
- OutputBuffer OB;
- OB << '`';
- Scope->output(OB, OF_Default);
- OB << '\'';
- OB << "::`" << Number << "'";
-
- Identifier->Name = copyString(OB);
- std::free(OB.getBuffer());
- return Identifier;
-}
-
-// Parses a type name in the form of A@B@C@@ which represents C::B::A.
-QualifiedNameNode *
-Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
- IdentifierNode *Identifier =
- demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
- if (Error)
- return nullptr;
- assert(Identifier);
-
- QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);
- if (Error)
- return nullptr;
- assert(QN);
- return QN;
-}
-
-// Parses a symbol name in the form of A@B@C@@ which represents C::B::A.
-// Symbol names have slightly different rules regarding what can appear
-// so we separate out the implementations for flexibility.
-QualifiedNameNode *
-Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
- // This is the final component of a symbol name (i.e. the leftmost component
- // of a mangled name. Since the only possible template instantiation that
- // can appear in this context is a function template, and since those are
- // not saved for the purposes of name backreferences, only backref simple
- // names.
- IdentifierNode *Identifier =
- demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
- if (Error)
- return nullptr;
-
- QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier);
- if (Error)
- return nullptr;
-
- if (Identifier->kind() == NodeKind::StructorIdentifier) {
- if (QN->Components->Count < 2) {
- Error = true;
- return nullptr;
- }
- StructorIdentifierNode *SIN =
- static_cast<StructorIdentifierNode *>(Identifier);
- Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2];
- SIN->Class = static_cast<IdentifierNode *>(ClassNode);
- }
- assert(QN);
- return QN;
-}
-
-IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName,
- bool Memorize) {
- // An inner-most name can be a back-reference, because a fully-qualified name
- // (e.g. Scope + Inner) can contain other fully qualified names inside of
- // them (for example template parameters), and these nested parameters can
- // refer to previously mangled types.
- if (startsWithDigit(MangledName))
- return demangleBackRefName(MangledName);
-
- if (MangledName.startsWith("?$"))
- return demangleTemplateInstantiationName(MangledName, NBB_Template);
-
- return demangleSimpleName(MangledName, Memorize);
-}
-
-IdentifierNode *
-Demangler::demangleUnqualifiedSymbolName(StringView &MangledName,
- NameBackrefBehavior NBB) {
- if (startsWithDigit(MangledName))
- return demangleBackRefName(MangledName);
- if (MangledName.startsWith("?$"))
- return demangleTemplateInstantiationName(MangledName, NBB);
- if (MangledName.startsWith('?'))
- return demangleFunctionIdentifierCode(MangledName);
- return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0);
-}
-
-IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) {
- if (startsWithDigit(MangledName))
- return demangleBackRefName(MangledName);
-
- if (MangledName.startsWith("?$"))
- return demangleTemplateInstantiationName(MangledName, NBB_Template);
-
- if (MangledName.startsWith("?A"))
- return demangleAnonymousNamespaceName(MangledName);
-
- if (startsWithLocalScopePattern(MangledName))
- return demangleLocallyScopedNamePiece(MangledName);
-
- return demangleSimpleName(MangledName, /*Memorize=*/true);
-}
-
-static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
- size_t Count) {
- NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
- N->Count = Count;
- N->Nodes = Arena.allocArray<Node *>(Count);
- for (size_t I = 0; I < Count; ++I) {
- N->Nodes[I] = Head->N;
- Head = Head->Next;
- }
- return N;
-}
-
-QualifiedNameNode *
-Demangler::demangleNameScopeChain(StringView &MangledName,
- IdentifierNode *UnqualifiedName) {
- NodeList *Head = Arena.alloc<NodeList>();
-
- Head->N = UnqualifiedName;
-
- size_t Count = 1;
- while (!MangledName.consumeFront("@")) {
- ++Count;
- NodeList *NewHead = Arena.alloc<NodeList>();
- NewHead->Next = Head;
- Head = NewHead;
-
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- assert(!Error);
- IdentifierNode *Elem = demangleNameScopePiece(MangledName);
- if (Error)
- return nullptr;
-
- Head->N = Elem;
- }
-
- QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();
- QN->Components = nodeListToNodeArray(Arena, Head, Count);
- return QN;
-}
-
-FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
- switch (MangledName.popFront()) {
- case '9':
- return FuncClass(FC_ExternC | FC_NoParameterList);
- case 'A':
- return FC_Private;
- case 'B':
- return FuncClass(FC_Private | FC_Far);
- case 'C':
- return FuncClass(FC_Private | FC_Static);
- case 'D':
- return FuncClass(FC_Private | FC_Static | FC_Far);
- case 'E':
- return FuncClass(FC_Private | FC_Virtual);
- case 'F':
- return FuncClass(FC_Private | FC_Virtual | FC_Far);
- case 'G':
- return FuncClass(FC_Private | FC_StaticThisAdjust);
- case 'H':
- return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far);
- case 'I':
- return FuncClass(FC_Protected);
- case 'J':
- return FuncClass(FC_Protected | FC_Far);
- case 'K':
- return FuncClass(FC_Protected | FC_Static);
- case 'L':
- return FuncClass(FC_Protected | FC_Static | FC_Far);
- case 'M':
- return FuncClass(FC_Protected | FC_Virtual);
- case 'N':
- return FuncClass(FC_Protected | FC_Virtual | FC_Far);
- case 'O':
- return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust);
- case 'P':
- return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far);
- case 'Q':
- return FuncClass(FC_Public);
- case 'R':
- return FuncClass(FC_Public | FC_Far);
- case 'S':
- return FuncClass(FC_Public | FC_Static);
- case 'T':
- return FuncClass(FC_Public | FC_Static | FC_Far);
- case 'U':
- return FuncClass(FC_Public | FC_Virtual);
- case 'V':
- return FuncClass(FC_Public | FC_Virtual | FC_Far);
- case 'W':
- return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust);
- case 'X':
- return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far);
- case 'Y':
- return FuncClass(FC_Global);
- case 'Z':
- return FuncClass(FC_Global | FC_Far);
- case '$': {
- FuncClass VFlag = FC_VirtualThisAdjust;
- if (MangledName.consumeFront('R'))
- VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx);
- if (MangledName.empty())
- break;
- switch (MangledName.popFront()) {
- case '0':
- return FuncClass(FC_Private | FC_Virtual | VFlag);
- case '1':
- return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far);
- case '2':
- return FuncClass(FC_Protected | FC_Virtual | VFlag);
- case '3':
- return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far);
- case '4':
- return FuncClass(FC_Public | FC_Virtual | VFlag);
- case '5':
- return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far);
- }
- }
- }
-
- Error = true;
- return FC_Public;
-}
-
-CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
- if (MangledName.empty()) {
- Error = true;
- return CallingConv::None;
- }
-
- switch (MangledName.popFront()) {
- case 'A':
- case 'B':
- return CallingConv::Cdecl;
- case 'C':
- case 'D':
- return CallingConv::Pascal;
- case 'E':
- case 'F':
- return CallingConv::Thiscall;
- case 'G':
- case 'H':
- return CallingConv::Stdcall;
- case 'I':
- case 'J':
- return CallingConv::Fastcall;
- case 'M':
- case 'N':
- return CallingConv::Clrcall;
- case 'O':
- case 'P':
- return CallingConv::Eabi;
- case 'Q':
- return CallingConv::Vectorcall;
- case 'S':
- return CallingConv::Swift;
- case 'W':
- return CallingConv::SwiftAsync;
- }
-
- return CallingConv::None;
-}
-
-StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
- assert(MangledName.front() >= '0' && MangledName.front() <= '4');
-
- switch (MangledName.popFront()) {
- case '0':
- return StorageClass::PrivateStatic;
- case '1':
- return StorageClass::ProtectedStatic;
- case '2':
- return StorageClass::PublicStatic;
- case '3':
- return StorageClass::Global;
- case '4':
- return StorageClass::FunctionLocalStatic;
- }
- DEMANGLE_UNREACHABLE;
-}
-
-std::pair<Qualifiers, bool>
-Demangler::demangleQualifiers(StringView &MangledName) {
- if (MangledName.empty()) {
- Error = true;
- return std::make_pair(Q_None, false);
- }
-
- switch (MangledName.popFront()) {
- // Member qualifiers
- case 'Q':
- return std::make_pair(Q_None, true);
- case 'R':
- return std::make_pair(Q_Const, true);
- case 'S':
- return std::make_pair(Q_Volatile, true);
- case 'T':
- return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);
- // Non-Member qualifiers
- case 'A':
- return std::make_pair(Q_None, false);
- case 'B':
- return std::make_pair(Q_Const, false);
- case 'C':
- return std::make_pair(Q_Volatile, false);
- case 'D':
- return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);
- }
- Error = true;
- return std::make_pair(Q_None, false);
-}
-
-// <variable-type> ::= <type> <cvr-qualifiers>
-// ::= <type> <pointee-cvr-qualifiers> # pointers, references
-TypeNode *Demangler::demangleType(StringView &MangledName,
- QualifierMangleMode QMM) {
- Qualifiers Quals = Q_None;
- bool IsMember = false;
- if (QMM == QualifierMangleMode::Mangle) {
- std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
- } else if (QMM == QualifierMangleMode::Result) {
- if (MangledName.consumeFront('?'))
- std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
- }
-
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- TypeNode *Ty = nullptr;
- if (isTagType(MangledName))
- Ty = demangleClassType(MangledName);
- else if (isPointerType(MangledName)) {
- if (isMemberPointer(MangledName, Error))
- Ty = demangleMemberPointerType(MangledName);
- else if (!Error)
- Ty = demanglePointerType(MangledName);
- else
- return nullptr;
- } else if (isArrayType(MangledName))
- Ty = demangleArrayType(MangledName);
- else if (isFunctionType(MangledName)) {
- if (MangledName.consumeFront("$$A8@@"))
- Ty = demangleFunctionType(MangledName, true);
- else {
- assert(MangledName.startsWith("$$A6"));
- MangledName.consumeFront("$$A6");
- Ty = demangleFunctionType(MangledName, false);
- }
- } else if (isCustomType(MangledName)) {
- Ty = demangleCustomType(MangledName);
- } else {
- Ty = demanglePrimitiveType(MangledName);
- }
-
- if (!Ty || Error)
- return Ty;
- Ty->Quals = Qualifiers(Ty->Quals | Quals);
- return Ty;
-}
-
-bool Demangler::demangleThrowSpecification(StringView &MangledName) {
- if (MangledName.consumeFront("_E"))
- return true;
- if (MangledName.consumeFront('Z'))
- return false;
-
- Error = true;
- return false;
-}
-
-FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName,
- bool HasThisQuals) {
- FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>();
-
- if (HasThisQuals) {
- FTy->Quals = demanglePointerExtQualifiers(MangledName);
- FTy->RefQualifier = demangleFunctionRefQualifier(MangledName);
- FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);
- }
-
- // Fields that appear on both member and non-member functions.
- FTy->CallConvention = demangleCallingConvention(MangledName);
-
- // <return-type> ::= <type>
- // ::= @ # structors (they have no declared return type)
- bool IsStructor = MangledName.consumeFront('@');
- if (!IsStructor)
- FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);
-
- FTy->Params = demangleFunctionParameterList(MangledName, FTy->IsVariadic);
-
- FTy->IsNoexcept = demangleThrowSpecification(MangledName);
-
- return FTy;
-}
-
-FunctionSymbolNode *
-Demangler::demangleFunctionEncoding(StringView &MangledName) {
- FuncClass ExtraFlags = FC_None;
- if (MangledName.consumeFront("$$J0"))
- ExtraFlags = FC_ExternC;
-
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
-
- FuncClass FC = demangleFunctionClass(MangledName);
- FC = FuncClass(ExtraFlags | FC);
-
- FunctionSignatureNode *FSN = nullptr;
- ThunkSignatureNode *TTN = nullptr;
- if (FC & FC_StaticThisAdjust) {
- TTN = Arena.alloc<ThunkSignatureNode>();
- TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);
- } else if (FC & FC_VirtualThisAdjust) {
- TTN = Arena.alloc<ThunkSignatureNode>();
- if (FC & FC_VirtualThisAdjustEx) {
- TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName);
- TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName);
- }
- TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName);
- TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName);
- }
-
- if (FC & FC_NoParameterList) {
- // This is an extern "C" function whose full signature hasn't been mangled.
- // This happens when we need to mangle a local symbol inside of an extern
- // "C" function.
- FSN = Arena.alloc<FunctionSignatureNode>();
- } else {
- bool HasThisQuals = !(FC & (FC_Global | FC_Static));
- FSN = demangleFunctionType(MangledName, HasThisQuals);
- }
-
- if (Error)
- return nullptr;
-
- if (TTN) {
- *static_cast<FunctionSignatureNode *>(TTN) = *FSN;
- FSN = TTN;
- }
- FSN->FunctionClass = FC;
-
- FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>();
- Symbol->Signature = FSN;
- return Symbol;
-}
-
-CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) {
- assert(MangledName.startsWith('?'));
- MangledName.popFront();
-
- CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();
- CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
- if (!MangledName.consumeFront('@'))
- Error = true;
- if (Error)
- return nullptr;
- return CTN;
-}
-
-// Reads a primitive type.
-PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) {
- if (MangledName.consumeFront("$$T"))
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr);
-
- switch (MangledName.popFront()) {
- case 'X':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void);
- case 'D':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char);
- case 'C':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar);
- case 'E':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar);
- case 'F':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short);
- case 'G':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort);
- case 'H':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int);
- case 'I':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint);
- case 'J':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long);
- case 'K':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong);
- case 'M':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float);
- case 'N':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double);
- case 'O':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble);
- case '_': {
- if (MangledName.empty()) {
- Error = true;
- return nullptr;
- }
- switch (MangledName.popFront()) {
- case 'N':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool);
- case 'J':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64);
- case 'K':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64);
- case 'W':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar);
- case 'Q':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char8);
- case 'S':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16);
- case 'U':
- return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32);
- }
- break;
- }
- }
- Error = true;
- return nullptr;
-}
-
-TagTypeNode *Demangler::demangleClassType(StringView &MangledName) {
- TagTypeNode *TT = nullptr;
-
- switch (MangledName.popFront()) {
- case 'T':
- TT = Arena.alloc<TagTypeNode>(TagKind::Union);
- break;
- case 'U':
- TT = Arena.alloc<TagTypeNode>(TagKind::Struct);
- break;
- case 'V':
- TT = Arena.alloc<TagTypeNode>(TagKind::Class);
- break;
- case 'W':
- if (!MangledName.consumeFront('4')) {
- Error = true;
- return nullptr;
- }
- TT = Arena.alloc<TagTypeNode>(TagKind::Enum);
- break;
- default:
- assert(false);
- }
-
- TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName);
- return TT;
-}
-
-// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
-// # the E is required for 64-bit non-static pointers
-PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) {
- PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
-
- std::tie(Pointer->Quals, Pointer->Affinity) =
- demanglePointerCVQualifiers(MangledName);
-
- if (MangledName.consumeFront("6")) {
- Pointer->Pointee = demangleFunctionType(MangledName, false);
- return Pointer;
- }
-
- Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
- Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
-
- Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);
- return Pointer;
-}
-
-PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {
- PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
-
- std::tie(Pointer->Quals, Pointer->Affinity) =
- demanglePointerCVQualifiers(MangledName);
- assert(Pointer->Affinity == PointerAffinity::Pointer);
-
- Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
- Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
-
- // isMemberPointer() only returns true if there is at least one character
- // after the qualifiers.
- if (MangledName.consumeFront("8")) {
- Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
- Pointer->Pointee = demangleFunctionType(MangledName, true);
- } else {
- Qualifiers PointeeQuals = Q_None;
- bool IsMember = false;
- std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);
- assert(IsMember || Error);
- Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
-
- Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);
- if (Pointer->Pointee)
- Pointer->Pointee->Quals = PointeeQuals;
- }
-
- return Pointer;
-}
-
-Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) {
- Qualifiers Quals = Q_None;
- if (MangledName.consumeFront('E'))
- Quals = Qualifiers(Quals | Q_Pointer64);
- if (MangledName.consumeFront('I'))
- Quals = Qualifiers(Quals | Q_Restrict);
- if (MangledName.consumeFront('F'))
- Quals = Qualifiers(Quals | Q_Unaligned);
-
- return Quals;
-}
-
-ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) {
- assert(MangledName.front() == 'Y');
- MangledName.popFront();
-
- uint64_t Rank = 0;
- bool IsNegative = false;
- std::tie(Rank, IsNegative) = demangleNumber(MangledName);
- if (IsNegative || Rank == 0) {
- Error = true;
- return nullptr;
- }
-
- ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>();
- NodeList *Head = Arena.alloc<NodeList>();
- NodeList *Tail = Head;
-
- for (uint64_t I = 0; I < Rank; ++I) {
- uint64_t D = 0;
- std::tie(D, IsNegative) = demangleNumber(MangledName);
- if (Error || IsNegative) {
- Error = true;
- return nullptr;
- }
- Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative);
- if (I + 1 < Rank) {
- Tail->Next = Arena.alloc<NodeList>();
- Tail = Tail->Next;
- }
- }
- ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank);
-
- if (MangledName.consumeFront("$$C")) {
- bool IsMember = false;
- std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName);
- if (IsMember) {
- Error = true;
- return nullptr;
- }
- }
-
- ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);
- return ATy;
-}
-
-// Reads a function's parameters.
-NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName,
- bool &IsVariadic) {
- // Empty parameter list.
- if (MangledName.consumeFront('X'))
- return nullptr;
-
- NodeList *Head = Arena.alloc<NodeList>();
- NodeList **Current = &Head;
- size_t Count = 0;
- while (!Error && !MangledName.startsWith('@') &&
- !MangledName.startsWith('Z')) {
- ++Count;
-
- if (startsWithDigit(MangledName)) {
- size_t N = MangledName[0] - '0';
- if (N >= Backrefs.FunctionParamCount) {
- Error = true;
- return nullptr;
- }
- MangledName = MangledName.dropFront();
-
- *Current = Arena.alloc<NodeList>();
- (*Current)->N = Backrefs.FunctionParams[N];
- Current = &(*Current)->Next;
- continue;
- }
-
- size_t OldSize = MangledName.size();
-
- *Current = Arena.alloc<NodeList>();
- TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop);
- if (!TN || Error)
- return nullptr;
-
- (*Current)->N = TN;
-
- size_t CharsConsumed = OldSize - MangledName.size();
- assert(CharsConsumed != 0);
-
- // Single-letter types are ignored for backreferences because memorizing
- // them doesn't save anything.
- if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1)
- Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN;
-
- Current = &(*Current)->Next;
- }
-
- if (Error)
- return nullptr;
-
- NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count);
- // A non-empty parameter list is terminated by either 'Z' (variadic) parameter
- // list or '@' (non variadic). Careful not to consume "@Z", as in that case
- // the following Z could be a throw specifier.
- if (MangledName.consumeFront('@'))
- return NA;
-
- if (MangledName.consumeFront('Z')) {
- IsVariadic = true;
- return NA;
- }
-
- DEMANGLE_UNREACHABLE;
-}
-
-NodeArrayNode *
-Demangler::demangleTemplateParameterList(StringView &MangledName) {
- NodeList *Head = nullptr;
- NodeList **Current = &Head;
- size_t Count = 0;
-
- while (!MangledName.startsWith('@')) {
- if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
- MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) {
- // parameter pack separator
- continue;
- }
-
- ++Count;
-
- // Template parameter lists don't participate in back-referencing.
- *Current = Arena.alloc<NodeList>();
-
- NodeList &TP = **Current;
-
- TemplateParameterReferenceNode *TPRN = nullptr;
- if (MangledName.consumeFront("$$Y")) {
- // Template alias
- TP.N = demangleFullyQualifiedTypeName(MangledName);
- } else if (MangledName.consumeFront("$$B")) {
- // Array
- TP.N = demangleType(MangledName, QualifierMangleMode::Drop);
- } else if (MangledName.consumeFront("$$C")) {
- // Type has qualifiers.
- TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);
- } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") ||
- MangledName.startsWith("$I") || MangledName.startsWith("$J")) {
- // Pointer to member
- TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
- TPRN->IsMemberPointer = true;
-
- MangledName = MangledName.dropFront();
- // 1 - single inheritance <name>
- // H - multiple inheritance <name> <number>
- // I - virtual inheritance <name> <number> <number>
- // J - unspecified inheritance <name> <number> <number> <number>
- char InheritanceSpecifier = MangledName.popFront();
- SymbolNode *S = nullptr;
- if (MangledName.startsWith('?')) {
- S = parse(MangledName);
- if (Error || !S->Name) {
- Error = true;
- return nullptr;
- }
- memorizeIdentifier(S->Name->getUnqualifiedIdentifier());
- }
-
- switch (InheritanceSpecifier) {
- case 'J':
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- DEMANGLE_FALLTHROUGH;
- case 'I':
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- DEMANGLE_FALLTHROUGH;
- case 'H':
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- DEMANGLE_FALLTHROUGH;
- case '1':
- break;
- default:
- DEMANGLE_UNREACHABLE;
- }
- TPRN->Affinity = PointerAffinity::Pointer;
- TPRN->Symbol = S;
- } else if (MangledName.startsWith("$E?")) {
- MangledName.consumeFront("$E");
- // Reference to symbol
- TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
- TPRN->Symbol = parse(MangledName);
- TPRN->Affinity = PointerAffinity::Reference;
- } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) {
- TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
-
- // Data member pointer.
- MangledName = MangledName.dropFront();
- char InheritanceSpecifier = MangledName.popFront();
-
- switch (InheritanceSpecifier) {
- case 'G':
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- DEMANGLE_FALLTHROUGH;
- case 'F':
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
- demangleSigned(MangledName);
- break;
- default:
- DEMANGLE_UNREACHABLE;
- }
- TPRN->IsMemberPointer = true;
-
- } else if (MangledName.consumeFront("$0")) {
- // Integral non-type template parameter
- bool IsNegative = false;
- uint64_t Value = 0;
- std::tie(Value, IsNegative) = demangleNumber(MangledName);
-
- TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative);
- } else {
- TP.N = demangleType(MangledName, QualifierMangleMode::Drop);
- }
- if (Error)
- return nullptr;
-
- Current = &TP.Next;
- }
-
- // The loop above returns nullptr on Error.
- assert(!Error);
-
- // Template parameter lists cannot be variadic, so it can only be terminated
- // by @ (as opposed to 'Z' in the function parameter case).
- assert(MangledName.startsWith('@')); // The above loop exits only on '@'.
- MangledName.consumeFront('@');
- return nodeListToNodeArray(Arena, Head, Count);
-}
-
-void Demangler::dumpBackReferences() {
- std::printf("%d function parameter backreferences\n",
- (int)Backrefs.FunctionParamCount);
-
- // Create an output stream so we can render each type.
- OutputBuffer OB;
- for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
- OB.setCurrentPosition(0);
-
- TypeNode *T = Backrefs.FunctionParams[I];
- T->output(OB, OF_Default);
-
- StringView B = OB;
- std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin());
- }
- std::free(OB.getBuffer());
-
- if (Backrefs.FunctionParamCount > 0)
- std::printf("\n");
- std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);
- for (size_t I = 0; I < Backrefs.NamesCount; ++I) {
- std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),
- Backrefs.Names[I]->Name.begin());
- }
- if (Backrefs.NamesCount > 0)
- std::printf("\n");
-}
-
-char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
- char *Buf, size_t *N,
- int *Status, MSDemangleFlags Flags) {
- Demangler D;
-
- StringView Name{MangledName};
- SymbolNode *AST = D.parse(Name);
- if (!D.Error && NMangled)
- *NMangled = Name.begin() - MangledName;
-
- if (Flags & MSDF_DumpBackrefs)
- D.dumpBackReferences();
-
- OutputFlags OF = OF_Default;
- if (Flags & MSDF_NoCallingConvention)
- OF = OutputFlags(OF | OF_NoCallingConvention);
- if (Flags & MSDF_NoAccessSpecifier)
- OF = OutputFlags(OF | OF_NoAccessSpecifier);
- if (Flags & MSDF_NoReturnType)
- OF = OutputFlags(OF | OF_NoReturnType);
- if (Flags & MSDF_NoMemberType)
- OF = OutputFlags(OF | OF_NoMemberType);
- if (Flags & MSDF_NoVariableType)
- OF = OutputFlags(OF | OF_NoVariableType);
-
- int InternalStatus = demangle_success;
- if (D.Error)
- InternalStatus = demangle_invalid_mangled_name;
- else {
- OutputBuffer OB(Buf, N);
- AST->output(OB, OF);
- OB += '\0';
- if (N != nullptr)
- *N = OB.getCurrentPosition();
- Buf = OB.getBuffer();
- }
-
- if (Status)
- *Status = InternalStatus;
- return InternalStatus == demangle_success ? Buf : nullptr;
-}
diff --git a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
deleted file mode 100644
index 975649f2..00000000
--- a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-//===- MicrosoftDemangle.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a demangler for MSVC-style mangled symbols.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Demangle/MicrosoftDemangleNodes.h"
-#include "llvm/Demangle/Utility.h"
-#include <cctype>
-#include <string>
-
-using namespace llvm;
-using namespace ms_demangle;
-
-#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
- case Enum::Value: \
- OB << Desc; \
- break;
-
-// Writes a space if the last token does not end with a punctuation.
-static void outputSpaceIfNecessary(OutputBuffer &OB) {
- if (OB.empty())
- return;
-
- char C = OB.back();
- if (std::isalnum(C) || C == '>')
- OB << " ";
-}
-
-static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) {
- switch (Q) {
- case Q_Const:
- OB << "const";
- break;
- case Q_Volatile:
- OB << "volatile";
- break;
- case Q_Restrict:
- OB << "__restrict";
- break;
- default:
- break;
- }
-}
-
-static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q,
- Qualifiers Mask, bool NeedSpace) {
- if (!(Q & Mask))
- return NeedSpace;
-
- if (NeedSpace)
- OB << " ";
-
- outputSingleQualifier(OB, Mask);
- return true;
-}
-
-static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
- bool SpaceAfter) {
- if (Q == Q_None)
- return;
-
- size_t Pos1 = OB.getCurrentPosition();
- SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
- size_t Pos2 = OB.getCurrentPosition();
- if (SpaceAfter && Pos2 > Pos1)
- OB << " ";
-}
-
-static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) {
- outputSpaceIfNecessary(OB);
-
- switch (CC) {
- case CallingConv::Cdecl:
- OB << "__cdecl";
- break;
- case CallingConv::Fastcall:
- OB << "__fastcall";
- break;
- case CallingConv::Pascal:
- OB << "__pascal";
- break;
- case CallingConv::Regcall:
- OB << "__regcall";
- break;
- case CallingConv::Stdcall:
- OB << "__stdcall";
- break;
- case CallingConv::Thiscall:
- OB << "__thiscall";
- break;
- case CallingConv::Eabi:
- OB << "__eabi";
- break;
- case CallingConv::Vectorcall:
- OB << "__vectorcall";
- break;
- case CallingConv::Clrcall:
- OB << "__clrcall";
- break;
- case CallingConv::Swift:
- OB << "__attribute__((__swiftcall__)) ";
- break;
- case CallingConv::SwiftAsync:
- OB << "__attribute__((__swiftasynccall__)) ";
- break;
- default:
- break;
- }
-}
-
-std::string Node::toString(OutputFlags Flags) const {
- OutputBuffer OB;
- this->output(OB, Flags);
- StringView SV = OB;
- std::string Owned(SV.begin(), SV.end());
- std::free(OB.getBuffer());
- return Owned;
-}
-
-void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- switch (PrimKind) {
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
- OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
- }
- outputQualifiers(OB, Quals, true, false);
-}
-
-void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- output(OB, Flags, ", ");
-}
-
-void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags,
- StringView Separator) const {
- if (Count == 0)
- return;
- if (Nodes[0])
- Nodes[0]->output(OB, Flags);
- for (size_t I = 1; I < Count; ++I) {
- OB << Separator;
- Nodes[I]->output(OB, Flags);
- }
-}
-
-void EncodedStringLiteralNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- switch (Char) {
- case CharKind::Wchar:
- OB << "L\"";
- break;
- case CharKind::Char:
- OB << "\"";
- break;
- case CharKind::Char16:
- OB << "u\"";
- break;
- case CharKind::Char32:
- OB << "U\"";
- break;
- }
- OB << DecodedString << "\"";
- if (IsTruncated)
- OB << "...";
-}
-
-void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- if (IsNegative)
- OB << '-';
- OB << Value;
-}
-
-void TemplateParameterReferenceNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (ThunkOffsetCount > 0)
- OB << "{";
- else if (Affinity == PointerAffinity::Pointer)
- OB << "&";
-
- if (Symbol) {
- Symbol->output(OB, Flags);
- if (ThunkOffsetCount > 0)
- OB << ", ";
- }
-
- if (ThunkOffsetCount > 0)
- OB << ThunkOffsets[0];
- for (int I = 1; I < ThunkOffsetCount; ++I) {
- OB << ", " << ThunkOffsets[I];
- }
- if (ThunkOffsetCount > 0)
- OB << "}";
-}
-
-void IdentifierNode::outputTemplateParameters(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (!TemplateParams)
- return;
- OB << "<";
- TemplateParams->output(OB, Flags);
- OB << ">";
-}
-
-void DynamicStructorIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (IsDestructor)
- OB << "`dynamic atexit destructor for ";
- else
- OB << "`dynamic initializer for ";
-
- if (Variable) {
- OB << "`";
- Variable->output(OB, Flags);
- OB << "''";
- } else {
- OB << "'";
- Name->output(OB, Flags);
- OB << "''";
- }
-}
-
-void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- OB << Name;
- outputTemplateParameters(OB, Flags);
-}
-
-void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- switch (Operator) {
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
- "operator[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
- "operator->*");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
- "operator>=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
- "operator&=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
- "operator|=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
- "operator^=");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
- "`vector deleting dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
- "`default ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
- "`scalar deleting dtor'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
- "`vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
- "`vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
- "`vector vbase ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
- "`virtual displacement map'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
- "`eh vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
- "`eh vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
- "`eh vector vbase ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
- "`copy ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
- "`local vftable ctor closure'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
- "operator delete[]");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
- "`managed vector ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
- "`managed vector dtor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
- "`EH vector copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
- "`EH vector vbase copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
- "`vector copy ctor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
- "`vector vbase copy constructor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
- "`managed vector vbase copy constructor iterator'");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
- "operator co_await");
- OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
- case IntrinsicFunctionKind::MaxIntrinsic:
- case IntrinsicFunctionKind::None:
- break;
- }
- outputTemplateParameters(OB, Flags);
-}
-
-void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (IsThread)
- OB << "`local static thread guard'";
- else
- OB << "`local static guard'";
- if (ScopeIndex > 0)
- OB << "{" << ScopeIndex << "}";
-}
-
-void ConversionOperatorIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- OB << "operator";
- outputTemplateParameters(OB, Flags);
- OB << " ";
- TargetType->output(OB, Flags);
-}
-
-void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- if (IsDestructor)
- OB << "~";
- Class->output(OB, Flags);
- outputTemplateParameters(OB, Flags);
-}
-
-void LiteralOperatorIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- OB << "operator \"\"" << Name;
- outputTemplateParameters(OB, Flags);
-}
-
-void FunctionSignatureNode::outputPre(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (!(Flags & OF_NoAccessSpecifier)) {
- if (FunctionClass & FC_Public)
- OB << "public: ";
- if (FunctionClass & FC_Protected)
- OB << "protected: ";
- if (FunctionClass & FC_Private)
- OB << "private: ";
- }
-
- if (!(Flags & OF_NoMemberType)) {
- if (!(FunctionClass & FC_Global)) {
- if (FunctionClass & FC_Static)
- OB << "static ";
- }
- if (FunctionClass & FC_Virtual)
- OB << "virtual ";
-
- if (FunctionClass & FC_ExternC)
- OB << "extern \"C\" ";
- }
-
- if (!(Flags & OF_NoReturnType) && ReturnType) {
- ReturnType->outputPre(OB, Flags);
- OB << " ";
- }
-
- if (!(Flags & OF_NoCallingConvention))
- outputCallingConvention(OB, CallConvention);
-}
-
-void FunctionSignatureNode::outputPost(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (!(FunctionClass & FC_NoParameterList)) {
- OB << "(";
- if (Params)
- Params->output(OB, Flags);
- else
- OB << "void";
-
- if (IsVariadic) {
- if (OB.back() != '(')
- OB << ", ";
- OB << "...";
- }
- OB << ")";
- }
-
- if (Quals & Q_Const)
- OB << " const";
- if (Quals & Q_Volatile)
- OB << " volatile";
- if (Quals & Q_Restrict)
- OB << " __restrict";
- if (Quals & Q_Unaligned)
- OB << " __unaligned";
-
- if (IsNoexcept)
- OB << " noexcept";
-
- if (RefQualifier == FunctionRefQualifier::Reference)
- OB << " &";
- else if (RefQualifier == FunctionRefQualifier::RValueReference)
- OB << " &&";
-
- if (!(Flags & OF_NoReturnType) && ReturnType)
- ReturnType->outputPost(OB, Flags);
-}
-
-void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- OB << "[thunk]: ";
-
- FunctionSignatureNode::outputPre(OB, Flags);
-}
-
-void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
- if (FunctionClass & FC_StaticThisAdjust) {
- OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
- } else if (FunctionClass & FC_VirtualThisAdjust) {
- if (FunctionClass & FC_VirtualThisAdjustEx) {
- OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
- << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
- << ", " << ThisAdjust.StaticOffset << "}'";
- } else {
- OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
- << ThisAdjust.StaticOffset << "}'";
- }
- }
-
- FunctionSignatureNode::outputPost(OB, Flags);
-}
-
-void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- if (Pointee->kind() == NodeKind::FunctionSignature) {
- // If this is a pointer to a function, don't output the calling convention.
- // It needs to go inside the parentheses.
- const FunctionSignatureNode *Sig =
- static_cast<const FunctionSignatureNode *>(Pointee);
- Sig->outputPre(OB, OF_NoCallingConvention);
- } else
- Pointee->outputPre(OB, Flags);
-
- outputSpaceIfNecessary(OB);
-
- if (Quals & Q_Unaligned)
- OB << "__unaligned ";
-
- if (Pointee->kind() == NodeKind::ArrayType) {
- OB << "(";
- } else if (Pointee->kind() == NodeKind::FunctionSignature) {
- OB << "(";
- const FunctionSignatureNode *Sig =
- static_cast<const FunctionSignatureNode *>(Pointee);
- outputCallingConvention(OB, Sig->CallConvention);
- OB << " ";
- }
-
- if (ClassParent) {
- ClassParent->output(OB, Flags);
- OB << "::";
- }
-
- switch (Affinity) {
- case PointerAffinity::Pointer:
- OB << "*";
- break;
- case PointerAffinity::Reference:
- OB << "&";
- break;
- case PointerAffinity::RValueReference:
- OB << "&&";
- break;
- default:
- assert(false);
- }
- outputQualifiers(OB, Quals, false, false);
-}
-
-void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
- if (Pointee->kind() == NodeKind::ArrayType ||
- Pointee->kind() == NodeKind::FunctionSignature)
- OB << ")";
-
- Pointee->outputPost(OB, Flags);
-}
-
-void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- if (!(Flags & OF_NoTagSpecifier)) {
- switch (Tag) {
- OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
- OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
- OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
- OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
- }
- OB << " ";
- }
- QualifiedName->output(OB, Flags);
- outputQualifiers(OB, Quals, true, false);
-}
-
-void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
-
-void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- ElementType->outputPre(OB, Flags);
- outputQualifiers(OB, Quals, true, false);
-}
-
-void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags,
- Node *N) const {
- assert(N->kind() == NodeKind::IntegerLiteral);
- IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
- if (ILN->Value != 0)
- ILN->output(OB, Flags);
-}
-
-void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB,
- OutputFlags Flags) const {
- if (Dimensions->Count == 0)
- return;
-
- outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
- for (size_t I = 1; I < Dimensions->Count; ++I) {
- OB << "][";
- outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
- }
-}
-
-void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
- OB << "[";
- outputDimensionsImpl(OB, Flags);
- OB << "]";
-
- ElementType->outputPost(OB, Flags);
-}
-
-void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- Name->output(OB, Flags);
-}
-
-void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- Signature->outputPre(OB, Flags);
- outputSpaceIfNecessary(OB);
- Name->output(OB, Flags);
- Signature->outputPost(OB, Flags);
-}
-
-void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- const char *AccessSpec = nullptr;
- bool IsStatic = true;
- switch (SC) {
- case StorageClass::PrivateStatic:
- AccessSpec = "private";
- break;
- case StorageClass::PublicStatic:
- AccessSpec = "public";
- break;
- case StorageClass::ProtectedStatic:
- AccessSpec = "protected";
- break;
- default:
- IsStatic = false;
- break;
- }
- if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
- OB << AccessSpec << ": ";
- if (!(Flags & OF_NoMemberType) && IsStatic)
- OB << "static ";
-
- if (!(Flags & OF_NoVariableType) && Type) {
- Type->outputPre(OB, Flags);
- outputSpaceIfNecessary(OB);
- }
- Name->output(OB, Flags);
- if (!(Flags & OF_NoVariableType) && Type)
- Type->outputPost(OB, Flags);
-}
-
-void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
- Identifier->output(OB, Flags);
-}
-void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
-
-void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- Components->output(OB, Flags, "::");
-}
-
-void RttiBaseClassDescriptorNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- OB << "`RTTI Base Class Descriptor at (";
- OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
- << this->Flags;
- OB << ")'";
-}
-
-void LocalStaticGuardVariableNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- Name->output(OB, Flags);
-}
-
-void VcallThunkIdentifierNode::output(OutputBuffer &OB,
- OutputFlags Flags) const {
- OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
-}
-
-void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
- outputQualifiers(OB, Quals, false, true);
- Name->output(OB, Flags);
- if (TargetName) {
- OB << "{for `";
- TargetName->output(OB, Flags);
- OB << "'}";
- }
-}