diff options
| author | Stanislaw Halik <sthalik@misaki.pl> | 2023-08-30 07:14:22 +0200 |
|---|---|---|
| committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-08-30 18:22:56 +0200 |
| commit | 5092df19372bd6957bd43649da43add30777212d (patch) | |
| tree | bfc20215881a8e8699739069dab898b95dfd3ec6 /demangle/third_party/llvm/lib/Demangle | |
| parent | af6ca21ed0f2715aad0b2ae80d200589b5e31089 (diff) | |
kill demangle
Diffstat (limited to 'demangle/third_party/llvm/lib/Demangle')
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 << "'}"; - } -} |
