Index: llvm/include/llvm/Demangle/Demangle.h =================================================================== --- llvm/include/llvm/Demangle/Demangle.h +++ llvm/include/llvm/Demangle/Demangle.h @@ -60,6 +60,9 @@ // Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); +// Demangles a D mangled symbol +char *dlangDemangle(const char *MangledName); + /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. Index: llvm/lib/Demangle/CMakeLists.txt =================================================================== --- llvm/lib/Demangle/CMakeLists.txt +++ llvm/lib/Demangle/CMakeLists.txt @@ -4,6 +4,7 @@ MicrosoftDemangle.cpp MicrosoftDemangleNodes.cpp RustDemangle.cpp + DLangDemangle.cpp ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle" Index: llvm/lib/Demangle/DLangDemangle.cpp =================================================================== --- /dev/null +++ llvm/lib/Demangle/DLangDemangle.cpp @@ -0,0 +1,2156 @@ +//===--- DLangDemangle.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a demangler for D programming language as specified in the +/// ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// +// +// Ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/MicrosoftDemangleNodes.h" + +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace { + +/// A mini string-handling class for output strings generated by D demangler +/// +/// \note Beware these aren't required to be '\0' terminated +struct OutputString { + + /// pointer to start of string + char *Buffer; + /// pointer after last character + char *Ptr; + /// pointer after end of allocated space + char *EndPtr; + +public: + /// Constructs a new output string + OutputString(); + + /// Free resources previously allocated to the Buffer + void free(); + + /// Get the current length of the string + int getLength(); + + /// Set a given new length to the string + /// + /// \param Size new length + void setLength(int Size); + + /// Append a given single char to the string + /// + /// \param C char to append + void append(char C); + + /// Append a given input to the string + /// + /// \param Str input string to append + void append(const char *Str); + + /// Append a given input with a specific length to the string + /// + /// \param Str input string to append + /// \param Size length to append from the given input string + void append(const char *Str, size_t Size); + + /// Prepend a given input to the string + /// + /// \param Str input string to prepend + void prepend(const char *Str); + + /// Prepend a given input with a specific length to the string + /// + /// \param Str input string to prepend + /// \param Size length to prepend from the given input string + void prepend(const char *Str, size_t Size); + +private: + /// Allocate more needed space to the Buffer + /// + /// \param Size size of the space needed + void need(size_t Size); +}; + +/// Demangle information structure +struct Demangler { + /// Initialize the information structure we use to pass around information + /// + /// \param Mangled String to demangle + Demangler(const char *Mangled); + + /// Extract and demangle the mangled symbol and append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#name_mangling + /// \see https://dlang.org/spec/abi.html#MangledName + const char *parseMangle(OutputString *Decl); + +private: + /// Extract and demangle a given mangled symbol and append it to the output + /// string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#name_mangling + /// \see https://dlang.org/spec/abi.html#MangledName + const char *parseMangle(OutputString *Decl, const char *Mangled); + + /// Extract the number from a given string + /// + /// \param Mangled string to extract the number + /// \param Ret assigned result value + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \note A result larger than UINT_MAX is considered a failure + /// + /// \see https://dlang.org/spec/abi.html#Number + const char *decodeNumber(const char *Mangled, unsigned long *Ret); + + /// Extract the hex-digit from a given string + /// + /// \param Mangled string to extract the hex-digit + /// \param Ret assigned result value + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#HexDigits + const char *decodeHexdigit(const char *Mangled, char *Ret); + + /// Extract the back reference position from a given string + /// + /// \param Mangled string to extract the back reference position + /// \param Ret assigned result value + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \note a result <= 0 is a failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref + /// \see https://dlang.org/spec/abi.html#NumberBackRef + const char *decodeBackrefPos(const char *Mangled, long *Ret); + + /// Extract the symbol pointed by the back reference form a given string + /// + /// \param Mangled string to extract the back reference position + /// \param Ret assigned result value + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref + const char *decodeBackref(const char *Mangled, const char **Ret); + + /// Extract and demangle backreferenced symbol from a given mangled symbol + /// and append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref + /// \see https://dlang.org/spec/abi.html#IdentifierBackRef + const char *parseSymbolBackref(OutputString *Decl, const char *Mangled); + + /// Extract and demangle backreferenced type from a given mangled symbol + /// and append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param IsFunction whether the backreferenced type is expected to be a + /// function + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref + /// \see https://dlang.org/spec/abi.html#TypeBackRef + const char *parseTypeBackref(OutputString *Decl, const char *Mangled, + bool IsFunction); + + /// Check whether it is a function calling convention + /// + /// \param Mangled string to extract the function calling convention + /// + /// \return true on success, false otherwise + /// + /// \see https://dlang.org/spec/abi.html#CallConvention + /// \see https://dlang.org/spec/abi.html#function_calling_conventions + bool isCallConvention(const char *Mangled); + + /// Extract and demangle calling convention from a given mangled symbol and + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#CallConvention + /// \see https://dlang.org/spec/abi.html#function_calling_conventions + const char *parseCallConvention(OutputString *Decl, const char *Mangled); + + /// Check whether it is the beginning of a symbol name + /// + /// \param Mangled string to extract the symbol name + /// + /// \return true on success, false otherwise + /// + /// \see https://dlang.org/spec/abi.html#SymbolName + bool isSymbolName(const char *Mangled); + + /// Extract and demangle an identifier from a given mangled symbol append it + /// to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#SymbolName + const char *parseIdentifier(OutputString *Decl, const char *Mangled); + + /// Extract and demangle the plain identifier from a given mangled symbol and + /// prepend/append it to the output string, with a special treatment for some + /// magic compiler generated symbols. + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Len length of the mangled symbol name + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#LName + const char *parseLName(OutputString *Decl, const char *Mangled, + unsigned long Len); + + /// Extract and demangle the qualified symbol from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param SuffixModifiers true if we are printing the modifiers after the + /// symbol, false otherwise + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#QualifiedName + const char *parseQualified(OutputString *Decl, const char *Mangled, + bool SuffixModifiers); + + /// Extract and demangle the type modifiers from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TypeModifiers + const char *parseTypeModifiers(OutputString *Decl, const char *Mangled); + + /// Extract and demangle the D function attributes from a given mangled + /// symbol append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#FuncAttr + const char *parseAttributes(OutputString *Decl, const char *Mangled); + + /// Extract and demangle the function type from a given mangled symbol + /// without the return type and append it to the arguments, calling + /// convention and attribute output strings, respectively. + /// + /// \param Args output buffer to write the demangled arguments + /// \param Call output buffer to write the demangled calling convention + /// \param Attr output buffer to write the demangled attributes + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \note Any of the output strings can be nullptr to throw the information + /// away. + /// + /// \see https://dlang.org/spec/abi.html#TypeFunctionNoReturn + const char *parseFunctionTypeNoreturn(OutputString *Args, OutputString *Call, + OutputString *Attr, + const char *Mangled); + + /// Extract and demangle the function type from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TypeFunction + const char *parseFunctionType(OutputString *Decl, const char *Mangled); + + /// Extract and demangle the function arguments list from a given mangled + /// symbol append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Parameters + const char *parseFunctionArgs(OutputString *Decl, const char *Mangled); + + /// Extract and demangle a type from a given mangled symbol append it to + /// the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Type + const char *parseType(OutputString *Decl, const char *Mangled); + + /// Extract and demangle an integer value from a given mangled symbol append + /// it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Type mangled type character in which the type should be + /// represented as + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseInteger(OutputString *Decl, const char *Mangled, char Type); + + /// Extract and demangle a floating-point value from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseReal(OutputString *Decl, const char *Mangled); + + /// Extract and demangle a string value from a given mangled symbol append it + /// to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseString(OutputString *Decl, const char *Mangled); + + /// Extract and demangle an array literal value from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseArrayLiteral(OutputString *Decl, const char *Mangled); + + /// Extract and demangle an associative array value from a given mangled + /// symbol append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseAssocArray(OutputString *Decl, const char *Mangled); + + /// Extract and demangle an struct literal value from a given mangled symbol + /// append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Name demangled symbol name of the struct literal + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseStructLiteral(OutputString *Decl, const char *Mangled, + const char *Name); + + /// Extract and demangle any value from a given mangled symbol append it to + /// the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Name demangled symbol name of the type, if needed + /// \param Type mangled type character in which the type should be + /// represented as, if needed + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#Value + const char *parseValue(OutputString *Decl, const char *Mangled, + const char *Name, char Type); + + /// Extract and demangle a tuple value from a given mangled symbol append it + /// to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TypeTuple + const char *parseTuple(OutputString *Decl, const char *Mangled); + + /// Extract and demangle the template symbol parameter from a given mangled + /// symbol append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TemplateArgX + const char *parseTemplateSymbolParameter(OutputString *Decl, + const char *Mangled); + + /// Extract and demangle the template arguments list from a given mangled + /// symbol append it to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TemplateArgs + const char *parseTemplateArgs(OutputString *Decl, const char *Mangled); + + /// Extract and demangle a template from a given mangled symbol and append it + /// to the output string + /// + /// \param Decl output buffer to write the demangled name + /// \param Mangled mangled symbol to be demangled + /// \param Len expected characters length (default to -1 if unknown length) + /// + /// \return the remaining string on success or nullptr on failure + /// + /// \see https://dlang.org/spec/abi.html#TemplateInstanceName + const char *parseTemplate(OutputString *Decl, const char *Mangled, + unsigned long Len = -1); + + /// The string we are demangling. + const char *Str; + /// The index of the last back reference. + int LastBackref; +}; + +} // namespace + +void OutputString::need(size_t Size) { + size_t Temp; + + if (Buffer == nullptr) { + if (Size < 32) { + Size = 32; + } + Ptr = Buffer = static_cast(std::malloc(Size)); + EndPtr = Buffer + Size; + } else if (static_cast(EndPtr - Ptr) < Size) { + Temp = Ptr - Buffer; + Size += Temp; + Size *= 2; + Buffer = static_cast(std::realloc(Buffer, Size)); + Ptr = Buffer + Temp; + EndPtr = Buffer + Size; + } +} + +OutputString::OutputString() : Buffer(nullptr), Ptr(nullptr), EndPtr(nullptr) {} + +void OutputString::free() { + if (Buffer != nullptr) { + std::free(Buffer); + Buffer = Ptr = EndPtr = nullptr; + } +} + +int OutputString::getLength() { + if (Ptr == Buffer) { + return 0; + } + return Ptr - Buffer; +} + +void OutputString::setLength(int Size) { + if (Size - getLength() < 0) { + Ptr = Buffer + Size; + } +} + +void OutputString::append(char C) { + need(1); + *Ptr = C; + Ptr++; +} + +void OutputString::append(const char *Str) { append(Str, strlen(Str)); } + +void OutputString::append(const char *Str, size_t Size) { + if (Size != 0) { + need(Size); + std::memcpy(Ptr, Str, Size); + Ptr += Size; + } +} + +void OutputString::prepend(const char *Str) { + if (Str != nullptr && *Str != '\0') { + prepend(Str, strlen(Str)); + } +} + +void OutputString::prepend(const char *Str, size_t Size) { + char *TempBuffer; + + if (Size != 0) { + need(Size); + for (TempBuffer = Ptr - 1; TempBuffer >= Buffer; TempBuffer--) { + TempBuffer[Size] = TempBuffer[0]; + } + std::memcpy(Buffer, Str, Size); + Ptr += Size; + } +} + +const char *Demangler::decodeNumber(const char *Mangled, unsigned long *Ret) { + // Return nullptr if trying to extract something that isn't a digit + if (Mangled == nullptr || !std::isdigit(*Mangled)) + return nullptr; + + unsigned long Val = 0; + + while (std::isdigit(*Mangled)) { + unsigned long Digit = Mangled[0] - '0'; + + // Check for overflow. + if (Val > (UINT_MAX - Digit) / 10) + return nullptr; + + Val = Val * 10 + Digit; + Mangled++; + } + + if (*Mangled == '\0') + return nullptr; + + *Ret = Val; + return Mangled; +} + +const char *Demangler::decodeHexdigit(const char *Mangled, char *Ret) { + char C; + + // Return nullptr if trying to extract something that isn't a hexdigit + if (Mangled == nullptr || !std::isxdigit(Mangled[0]) || + !std::isxdigit(Mangled[1])) + return nullptr; + + C = Mangled[0]; + if (!std::isdigit(C)) + *Ret = C - (std::isupper(C) ? 'A' : 'a') + 10; + else + *Ret = C - '0'; + + C = Mangled[1]; + if (!std::isdigit(C)) + *Ret = (*Ret << 4) | (C - (std::isupper(C) ? 'A' : 'a') + 10); + else + *Ret = (*Ret << 4) | (C - '0'); + + Mangled += 2; + + return Mangled; +} + +bool Demangler::isCallConvention(const char *Mangled) { + switch (*Mangled) { + case 'F': + case 'U': + case 'V': + case 'W': + case 'R': + case 'Y': + return true; + + default: + return false; + } +} + +const char *Demangler::decodeBackrefPos(const char *Mangled, long *Ret) { + // Return nullptr if trying to extract something that isn't a digit + if (Mangled == nullptr || !std::isalpha(*Mangled)) + return nullptr; + + /* Any identifier or non-basic type that has been emitted to the mangled + symbol before will not be emitted again, but is referenced by a special + sequence encoding the relative position of the original occurrence in the + mangled symbol name. + Numbers in back references are encoded with base 26 by upper case letters + A-Z for higher digits but lower case letters a-z for the last digit. + NumberBackRef: + [a-z] + [A-Z] NumberBackRef + ^ + */ + unsigned long Val = 0; + + while (std::isalpha(*Mangled)) { + // Check for overflow + if (Val > (ULONG_MAX - 25) / 26) + break; + + Val *= 26; + + if (Mangled[0] >= 'a' && Mangled[0] <= 'z') { + Val += Mangled[0] - 'a'; + if ((long)Val <= 0) + break; + *Ret = Val; + return Mangled + 1; + } + + Val += Mangled[0] - 'A'; + Mangled++; + } + + return nullptr; +} + +const char *Demangler::decodeBackref(const char *Mangled, const char **Ret) { + *Ret = nullptr; + + if (Mangled == nullptr || *Mangled != 'Q') + return nullptr; + + // Position of 'Q' + const char *Qpos = Mangled; + long RefPos; + Mangled++; + + Mangled = decodeBackrefPos(Mangled, &RefPos); + if (Mangled == nullptr) + return nullptr; + + if (RefPos > Qpos - Str) + return nullptr; + + /* Set the position of the back reference. */ + *Ret = Qpos - RefPos; + + return Mangled; +} + +const char *Demangler::parseSymbolBackref(OutputString *Decl, + const char *Mangled) { + /* An identifier back reference always points to a digit 0 to 9. + IdentifierBackRef: + Q NumberBackRef + ^ + */ + const char *Backref; + unsigned long Len; + + // Get position of the back reference + Mangled = decodeBackref(Mangled, &Backref); + + // Must point to a simple identifier + Backref = decodeNumber(Backref, &Len); + if (Backref == nullptr || strlen(Backref) < Len) + return nullptr; + + Backref = parseLName(Decl, Backref, Len); + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +const char *Demangler::parseTypeBackref(OutputString *Decl, const char *Mangled, + bool IsFunction) { + /* A type back reference always points to a letter. + TypeBackRef: + Q NumberBackRef + ^ + */ + const char *Backref; + + /* If we appear to be moving backwards through the mangle string, then + bail as this may be a recursive back reference */ + if (Mangled - Str >= LastBackref) + return nullptr; + + int SaveRefPos = LastBackref; + LastBackref = Mangled - Str; + + // Get position of the back reference + Mangled = decodeBackref(Mangled, &Backref); + + // Must point to a type + if (IsFunction) + Backref = parseFunctionType(Decl, Backref); + else + Backref = parseType(Decl, Backref); + + LastBackref = SaveRefPos; + + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +bool Demangler::isSymbolName(const char *Mangled) { + long Ret; + const char *Qref = Mangled; + + if (std::isdigit(*Mangled)) + return true; + + if (Mangled[0] == '_' && Mangled[1] == '_' && + (Mangled[2] == 'T' || Mangled[2] == 'U')) + return true; + + if (*Mangled != 'Q') + return false; + + Mangled = decodeBackrefPos(Mangled + 1, &Ret); + if (Mangled == nullptr || Ret > Qref - Str) + return false; + + return std::isdigit(Qref[-Ret]); +} + +const char *Demangler::parseCallConvention(OutputString *Decl, + const char *Mangled) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + switch (*Mangled) { + case 'F': /* (D) */ + Mangled++; + break; + + case 'U': /* (C) */ + Mangled++; + Decl->append("extern(C) "); + break; + + case 'W': /* (Windows) */ + Mangled++; + Decl->append("extern(Windows) "); + break; + + case 'V': /* (Pascal) */ + Mangled++; + Decl->append("extern(Pascal) "); + break; + + case 'R': /* (C++) */ + Mangled++; + Decl->append("extern(C++) "); + break; + + case 'Y': /* (Objective-C) */ + Mangled++; + Decl->append("extern(Objective-C) "); + break; + + default: + return nullptr; + } + + return Mangled; +} + +const char *Demangler::parseTypeModifiers(OutputString *Decl, + const char *Mangled) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + switch (*Mangled) { + case 'x': /* const */ + Mangled++; + Decl->append(" const"); + return Mangled; + + case 'y': /* immutable */ + Mangled++; + Decl->append(" immutable"); + return Mangled; + + case 'O': /* shared */ + Mangled++; + Decl->append(" shared"); + return parseTypeModifiers(Decl, Mangled); + + case 'N': + Mangled++; + if (*Mangled == 'g') /* wild */ + { + Mangled++; + Decl->append(" inout"); + return parseTypeModifiers(Decl, Mangled); + } + + return nullptr; + + default: + return Mangled; + } +} + +const char *Demangler::parseAttributes(OutputString *Decl, + const char *Mangled) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + while (*Mangled == 'N') { + Mangled++; + switch (*Mangled) { + case 'a': /* pure */ + Mangled++; + Decl->append("pure "); + continue; + + case 'b': /* nothrow */ + Mangled++; + Decl->append("nothrow "); + continue; + + case 'c': /* ref */ + Mangled++; + Decl->append("ref "); + continue; + + case 'd': /* @property */ + Mangled++; + Decl->append("@property "); + continue; + + case 'e': /* @trusted */ + Mangled++; + Decl->append("@trusted "); + continue; + + case 'f': /* @safe */ + Mangled++; + Decl->append("@safe "); + continue; + + case 'g': + case 'h': + case 'k': + case 'n': + /* inout parameter is represented as 'Ng'. + vector parameter is represented as 'Nh'. + return parameter is represented as 'Nk'. + typeof(*null) parameter is represented as 'Nn'. + If we see this, then we know we're really in the + parameter list. Rewind and break. */ + Mangled--; + break; + + case 'i': /* @nogc */ + Mangled++; + Decl->append("@nogc "); + continue; + + case 'j': /* return */ + Mangled++; + Decl->append("return "); + continue; + + case 'l': /* scope */ + Mangled++; + Decl->append("scope "); + continue; + + case 'm': /* @live */ + Mangled++; + Decl->append("@live "); + continue; + + default: /* unknown attribute */ + return nullptr; + } + break; + } + + return Mangled; +} + +const char *Demangler::parseFunctionTypeNoreturn(OutputString *Args, + OutputString *Call, + OutputString *Attr, + const char *Mangled) { + OutputString Dump = OutputString(); + // Skip over calling convention and attributes + Mangled = parseCallConvention(Call ? Call : &Dump, Mangled); + Mangled = parseAttributes(Attr ? Attr : &Dump, Mangled); + + if (Args) + Args->append("("); + + Mangled = parseFunctionArgs(Args ? Args : &Dump, Mangled); + if (Args) + Args->append(")"); + + Dump.free(); + return Mangled; +} + +const char *Demangler::parseFunctionType(OutputString *Decl, + const char *Mangled) { + OutputString Attr, Args, Type; + + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + /* The order of the mangled string is: + CallConvention FuncAttrs Arguments ArgClose Type + The demangled string is re-ordered as: + CallConvention Type Arguments FuncAttrs + */ + Attr = OutputString(); + Args = OutputString(); + Type = OutputString(); + + Mangled = parseFunctionTypeNoreturn(&Args, Decl, &Attr, Mangled); + + // Function return type + Mangled = parseType(&Type, Mangled); + + // Append to decl in order + Decl->append(Type.Buffer, Type.getLength()); + Decl->append(Args.Buffer, Args.getLength()); + Decl->append(" "); + Decl->append(Attr.Buffer, Attr.getLength()); + + Attr.free(); + Args.free(); + Type.free(); + return Mangled; +} + +const char *Demangler::parseFunctionArgs(OutputString *Decl, + const char *Mangled) { + size_t N = 0; + + while (Mangled && *Mangled != '\0') { + switch (*Mangled) { + case 'X': /* (variadic T t...) style */ + Mangled++; + Decl->append("..."); + return Mangled; + case 'Y': /* (variadic T t, ...) style */ + Mangled++; + if (N != 0) + Decl->append(", "); + Decl->append("..."); + return Mangled; + case 'Z': /* Normal function */ + Mangled++; + return Mangled; + } + + if (N++) + Decl->append(", "); + + if (*Mangled == 'M') /* scope(T) */ + { + Mangled++; + Decl->append("scope "); + } + + if (Mangled[0] == 'N' && Mangled[1] == 'k') /* return(T) */ + { + Mangled += 2; + Decl->append("return "); + } + + switch (*Mangled) { + case 'I': /* in(T) */ + Mangled++; + Decl->append("in "); + if (*Mangled == 'K') /* in ref(T) */ + { + Mangled++; + Decl->append("ref "); + } + break; + case 'J': /* out(T) */ + Mangled++; + Decl->append("out "); + break; + case 'K': /* ref(T) */ + Mangled++; + Decl->append("ref "); + break; + case 'L': /* lazy(T) */ + Mangled++; + Decl->append("lazy "); + break; + } + Mangled = parseType(Decl, Mangled); + } + + return Mangled; +} + +const char *Demangler::parseType(OutputString *Decl, const char *Mangled) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + switch (*Mangled) { + case 'O': /* shared(T) */ + Mangled++; + Decl->append("shared("); + Mangled = parseType(Decl, Mangled); + Decl->append(")"); + return Mangled; + + case 'x': /* const(T) */ + Mangled++; + Decl->append("const("); + Mangled = parseType(Decl, Mangled); + Decl->append(")"); + return Mangled; + + case 'y': /* immutable(T) */ + Mangled++; + Decl->append("immutable("); + Mangled = parseType(Decl, Mangled); + Decl->append(")"); + return Mangled; + + case 'N': + Mangled++; + + switch (*Mangled) { + case 'g': // wild(T) + Mangled++; + Decl->append("inout("); + Mangled = parseType(Decl, Mangled); + Decl->append(")"); + return Mangled; + + case 'h': // vector(T) + Mangled++; + Decl->append("__vector("); + Mangled = parseType(Decl, Mangled); + Decl->append(")"); + return Mangled; + + case 'n': // typeof(*null) + Mangled++; + Decl->append("typeof(*null)"); + return Mangled; + } + + // invalid + return nullptr; + + case 'A': /* dynamic array (T[]) */ + Mangled++; + Mangled = parseType(Decl, Mangled); + Decl->append("[]"); + return Mangled; + + case 'G': /* static array (T[N]) */ + { + const char *NumPtr; + size_t Num = 0; + Mangled++; + + NumPtr = Mangled; + while (std::isdigit(*Mangled)) { + Num++; + Mangled++; + } + Mangled = parseType(Decl, Mangled); + Decl->append("["); + Decl->append(NumPtr, Num); + Decl->append("]"); + return Mangled; + } + + case 'H': /* associative array (T[T]) */ + { + OutputString Type = OutputString(); + size_t Sztype; + Mangled++; + + Mangled = parseType(&Type, Mangled); + Sztype = Type.getLength(); + + Mangled = parseType(Decl, Mangled); + Decl->append("["); + Decl->append(Type.Buffer, Sztype); + Decl->append("]"); + + Type.free(); + return Mangled; + } + + case 'P': /* pointer (T*) */ + Mangled++; + if (!isCallConvention(Mangled)) { + Mangled = parseType(Decl, Mangled); + Decl->append("*"); + return Mangled; + } + + [[clang::fallthrough]]; + case 'F': /* function T (D) */ + case 'U': /* function T (C) */ + case 'W': /* function T (Windows) */ + case 'V': /* function T (Pascal) */ + case 'R': /* function T (C++) */ + case 'Y': /* function T (Objective-C) */ + /* Function pointer types don't include the trailing asterisk. */ + Mangled = parseFunctionType(Decl, Mangled); + Decl->append("function"); + return Mangled; + + case 'C': /* class T */ + case 'S': /* struct T */ + case 'E': /* enum T */ + case 'T': /* typedef T */ + Mangled++; + return parseQualified(Decl, Mangled, false); + + case 'D': /* delegate T */ + { + OutputString Mods = OutputString(); + size_t Szmods; + Mangled++; + + Mangled = parseTypeModifiers(&Mods, Mangled); + Szmods = Mods.getLength(); + + // Back referenced function type + if (Mangled && *Mangled == 'Q') + Mangled = parseTypeBackref(Decl, Mangled, true); + else + Mangled = parseFunctionType(Decl, Mangled); + + Decl->append("delegate"); + Decl->append(Mods.Buffer, Szmods); + + Mods.free(); + return Mangled; + } + + case 'B': /* tuple T */ + Mangled++; + return parseTuple(Decl, Mangled); + + /* Basic types */ + case 'n': + Mangled++; + Decl->append("typeof(null)"); + return Mangled; + + case 'v': + Mangled++; + Decl->append("void"); + return Mangled; + + case 'g': + Mangled++; + Decl->append("byte"); + return Mangled; + case 'h': + Mangled++; + Decl->append("ubyte"); + return Mangled; + + case 's': + Mangled++; + Decl->append("short"); + return Mangled; + case 't': + Mangled++; + Decl->append("ushort"); + return Mangled; + + case 'i': + Mangled++; + Decl->append("int"); + return Mangled; + case 'k': + Mangled++; + Decl->append("uint"); + return Mangled; + + case 'l': + Mangled++; + Decl->append("long"); + return Mangled; + case 'm': + Mangled++; + Decl->append("ulong"); + return Mangled; + + case 'f': + Mangled++; + Decl->append("float"); + return Mangled; + case 'd': + Mangled++; + Decl->append("double"); + return Mangled; + case 'e': + Mangled++; + Decl->append("real"); + return Mangled; + + // Imaginary types + case 'o': + Mangled++; + Decl->append("ifloat"); + return Mangled; + case 'p': + Mangled++; + Decl->append("idouble"); + return Mangled; + case 'j': + Mangled++; + Decl->append("ireal"); + return Mangled; + + // Complex types + case 'q': + Mangled++; + Decl->append("cfloat"); + return Mangled; + case 'r': + Mangled++; + Decl->append("cdouble"); + return Mangled; + case 'c': + Mangled++; + Decl->append("creal"); + return Mangled; + + // Other types + case 'b': + Mangled++; + Decl->append("bool"); + return Mangled; + + case 'a': + Mangled++; + Decl->append("char"); + return Mangled; + case 'u': + Mangled++; + Decl->append("wchar"); + return Mangled; + case 'w': + Mangled++; + Decl->append("dchar"); + return Mangled; + + case 'z': + Mangled++; + + switch (*Mangled) { + case 'i': + Mangled++; + Decl->append("cent"); + return Mangled; + case 'k': + Mangled++; + Decl->append("ucent"); + return Mangled; + } + return nullptr; + + // Back referenced type + case 'Q': + return parseTypeBackref(Decl, Mangled, false); + + default: // unhandled + return nullptr; + } +} + +const char *Demangler::parseIdentifier(OutputString *Decl, + const char *Mangled) { + unsigned long Len; + + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + if (*Mangled == 'Q') + return parseSymbolBackref(Decl, Mangled); + + /* May be a template instance without a length prefix. */ + if (Mangled[0] == '_' && Mangled[1] == '_' && + (Mangled[2] == 'T' || Mangled[2] == 'U')) + return parseTemplate(Decl, Mangled); + + const char *Endptr = decodeNumber(Mangled, &Len); + + if (Endptr == nullptr || Len == 0) + return nullptr; + + if (strlen(Endptr) < Len) + return nullptr; + + Mangled = Endptr; + + /* May be a template instance with a length prefix. */ + if (Len >= 5 && Mangled[0] == '_' && Mangled[1] == '_' && + (Mangled[2] == 'T' || Mangled[2] == 'U')) + return parseTemplate(Decl, Mangled, Len); + + /* There can be multiple different declarations in the same function that have + the same mangled name. To make the mangled names unique, a fake parent in + the form `__Sddd' is added to the symbol. */ + if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { + const char *NumPtr = Mangled + 3; + while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) + NumPtr++; + + if (Mangled + Len == NumPtr) { + /* Skip over the fake parent. */ + Mangled += Len; + return parseIdentifier(Decl, Mangled); + } + + /* else demangle it as a plain identifier. */ + } + + return parseLName(Decl, Mangled, Len); +} + +const char *Demangler::parseLName(OutputString *Decl, const char *Mangled, + unsigned long Len) { + switch (Len) { + case 6: + if (strncmp(Mangled, "__ctor", Len) == 0) { + /* Constructor symbol for a class/struct. */ + Decl->append("this"); + Mangled += Len; + return Mangled; + } else if (strncmp(Mangled, "__dtor", Len) == 0) { + /* Destructor symbol for a class/struct. */ + Decl->append("~this"); + Mangled += Len; + return Mangled; + } else if (strncmp(Mangled, "__initZ", Len + 1) == 0) { + /* The static initialiser for a given symbol. */ + Decl->prepend("initializer for "); + Decl->setLength(Decl->getLength() - 1); + Mangled += Len; + return Mangled; + } else if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { + /* The vtable symbol for a given class. */ + Decl->prepend("vtable for "); + Decl->setLength(Decl->getLength() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 7: + if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { + /* The classinfo symbol for a given class. */ + Decl->prepend("ClassInfo for "); + Decl->setLength(Decl->getLength() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 10: + if (strncmp(Mangled, "__postblitMFZ", Len + 3) == 0) { + /* Postblit symbol for a struct. */ + Decl->append("this(this)"); + Mangled += Len + 3; + return Mangled; + } + break; + + case 11: + if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { + /* The interface symbol for a given class. */ + Decl->prepend("Interface for "); + Decl->setLength(Decl->getLength() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 12: + if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { + /* The ModuleInfo symbol for a given module. */ + Decl->prepend("ModuleInfo for "); + Decl->setLength(Decl->getLength() - 1); + Mangled += Len; + return Mangled; + } + break; + } + + Decl->append(Mangled, Len); + Mangled += Len; + + return Mangled; +} + +const char *Demangler::parseInteger(OutputString *Decl, const char *Mangled, + char Type) { + if (Type == 'a' || Type == 'u' || Type == 'w') { + /* Parse character value. */ + char Value[20]; + int Pos = sizeof(Value); + int Width = 0; + unsigned long Val; + + Mangled = decodeNumber(Mangled, &Val); + if (Mangled == nullptr) + return nullptr; + + Decl->append('\''); + + if (Type == 'a' && Val >= 0x20 && Val < 0x7F) { + /* Represent as a character literal. */ + Decl->append(static_cast(Val)); + } else { + /* Represent as a hexadecimal value. */ + switch (Type) { + case 'a': /* char */ + Decl->append("\\x"); + Width = 2; + break; + case 'u': /* wchar */ + Decl->append("\\u"); + Width = 4; + break; + case 'w': /* dchar */ + Decl->append("\\U"); + Width = 8; + break; + } + + while (Val > 0) { + int Digit = Val % 16; + + if (Digit < 10) + Value[--Pos] = (char)(Digit + '0'); + else + Value[--Pos] = (char)((Digit - 10) + 'a'); + + Val /= 16; + Width--; + } + + for (; Width > 0; Width--) + Value[--Pos] = '0'; + + Decl->append(&(Value[Pos]), sizeof(Value) - Pos); + } + Decl->append('\''); + } else if (Type == 'b') { + /* Parse boolean value. */ + unsigned long Val; + + Mangled = decodeNumber(Mangled, &Val); + if (Mangled == nullptr) + return nullptr; + + Decl->append(Val ? "true" : "false"); + } else { + /* Parse integer value. */ + const char *NumPtr = Mangled; + size_t Num = 0; + + if (!std::isdigit(*Mangled)) + return nullptr; + + while (std::isdigit(*Mangled)) { + Num++; + Mangled++; + } + Decl->append(NumPtr, Num); + + /* Append suffix. */ + switch (Type) { + case 'h': /* ubyte */ + case 't': /* ushort */ + case 'k': /* uint */ + Decl->append('u'); + break; + case 'l': /* long */ + Decl->append('L'); + break; + case 'm': /* ulong */ + Decl->append("uL"); + break; + } + } + + return Mangled; +} + +const char *Demangler::parseReal(OutputString *Decl, const char *Mangled) { + // Handle NAN and +-INF + if (strncmp(Mangled, "NAN", 3) == 0) { + Decl->append("NaN"); + Mangled += 3; + return Mangled; + } + + if (strncmp(Mangled, "INF", 3) == 0) { + Decl->append("Inf"); + Mangled += 3; + return Mangled; + } + + if (strncmp(Mangled, "NINF", 4) == 0) { + Decl->append("-Inf"); + Mangled += 4; + return Mangled; + } + + // Hexadecimal prefix and leading bit + if (*Mangled == 'N') { + Decl->append('-'); + Mangled++; + } + + if (!std::isxdigit(*Mangled)) + return nullptr; + + Decl->append("0x"); + Decl->append(Mangled, 1); + Decl->append('.'); + Mangled++; + + // Significand + while (std::isxdigit(*Mangled)) { + Decl->append(Mangled, 1); + Mangled++; + } + + // Exponent + if (*Mangled != 'P') + return nullptr; + + Decl->append('p'); + Mangled++; + + if (*Mangled == 'N') { + Decl->append('-'); + Mangled++; + } + + while (std::isdigit(*Mangled)) { + Decl->append(Mangled, 1); + Mangled++; + } + + return Mangled; +} + +const char *Demangler::parseString(OutputString *Decl, const char *Mangled) { + char Type = *Mangled; + unsigned long Len; + + Mangled++; + Mangled = decodeNumber(Mangled, &Len); + if (Mangled == nullptr || *Mangled != '_') + return nullptr; + + Mangled++; + Decl->append('\"'); + while (Len--) { + char Val; + const char *Endptr = decodeHexdigit(Mangled, &Val); + + if (Endptr == nullptr) + return nullptr; + + /* Sanitize white and non-printable characters. */ + switch (Val) { + case ' ': + Decl->append(' '); + break; + case '\t': + Decl->append("\\t"); + break; + case '\n': + Decl->append("\\n"); + break; + case '\r': + Decl->append("\\r"); + break; + case '\f': + Decl->append("\\f"); + break; + case '\v': + Decl->append("\\v"); + break; + + default: + if (std::isprint(Val)) + Decl->append(Val); + else { + Decl->append("\\x"); + Decl->append(Mangled, 2); + } + } + + Mangled = Endptr; + } + Decl->append('\"'); + + if (Type != 'a') + Decl->append(Type); + + return Mangled; +} + +const char *Demangler::parseArrayLiteral(OutputString *Decl, + const char *Mangled) { + unsigned long Elements; + + Mangled = decodeNumber(Mangled, &Elements); + if (Mangled == nullptr) + return nullptr; + + Decl->append('['); + while (Elements--) { + Mangled = parseValue(Decl, Mangled, nullptr, '\0'); + if (Mangled == nullptr) + return nullptr; + + if (Elements != 0) + Decl->append(", "); + } + + Decl->append(']'); + return Mangled; +} + +const char *Demangler::parseAssocArray(OutputString *Decl, + const char *Mangled) { + unsigned long Elements; + + Mangled = decodeNumber(Mangled, &Elements); + if (Mangled == nullptr) + return nullptr; + + Decl->append('['); + while (Elements--) { + Mangled = parseValue(Decl, Mangled, nullptr, '\0'); + if (Mangled == nullptr) + return nullptr; + + Decl->append(':'); + Mangled = parseValue(Decl, Mangled, nullptr, '\0'); + if (Mangled == nullptr) + return nullptr; + + if (Elements != 0) + Decl->append(", "); + } + + Decl->append(']'); + return Mangled; +} + +const char *Demangler::parseStructLiteral(OutputString *Decl, + const char *Mangled, + const char *Name) { + unsigned long Args; + + Mangled = decodeNumber(Mangled, &Args); + if (Mangled == nullptr) + return nullptr; + + if (Name != nullptr) + Decl->append(Name); + + Decl->append('('); + while (Args--) { + Mangled = parseValue(Decl, Mangled, nullptr, '\0'); + if (Mangled == nullptr) + return nullptr; + + if (Args != 0) + Decl->append(", "); + } + + Decl->append(')'); + return Mangled; +} + +const char *Demangler::parseValue(OutputString *Decl, const char *Mangled, + const char *Name, char Type) { + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + switch (*Mangled) { + /* Null value. */ + case 'n': + Mangled++; + Decl->append("null"); + break; + + /* Integral values. */ + case 'N': + Mangled++; + Decl->append('-'); + Mangled = parseInteger(Decl, Mangled, Type); + break; + + case 'i': + Mangled++; + /* Fall through */ + + /* There really should always be an `i' before encoded numbers, but there + wasn't in early versions of D2, so this case range must remain for + backwards compatibility. */ + [[clang::fallthrough]]; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + Mangled = parseInteger(Decl, Mangled, Type); + break; + + /* Real value. */ + case 'e': + Mangled++; + Mangled = parseReal(Decl, Mangled); + break; + + /* Complex value. */ + case 'c': + Mangled++; + Mangled = parseReal(Decl, Mangled); + Decl->append('+'); + if (Mangled == nullptr || *Mangled != 'c') + return nullptr; + Mangled++; + Mangled = parseReal(Decl, Mangled); + Decl->append('i'); + break; + + /* String values. */ + case 'a': /* UTF8 */ + case 'w': /* UTF16 */ + case 'd': /* UTF32 */ + Mangled = parseString(Decl, Mangled); + break; + + /* Array values. */ + case 'A': + Mangled++; + if (Type == 'H') + Mangled = parseAssocArray(Decl, Mangled); + else + Mangled = parseArrayLiteral(Decl, Mangled); + break; + + /* Struct values. */ + case 'S': + Mangled++; + Mangled = parseStructLiteral(Decl, Mangled, Name); + break; + + /* Function literal symbol. */ + case 'f': + Mangled++; + if (strncmp(Mangled, "_D", 2) != 0 || !isSymbolName(Mangled + 2)) + return nullptr; + Mangled = parseMangle(Decl, Mangled); + break; + + default: + return nullptr; + } + + return Mangled; +} + +const char *Demangler::parseMangle(OutputString *Decl, const char *Mangled) { + /* A D mangled symbol is comprised of both scope and type information. + MangleName: + _D QualifiedName Type + _D QualifiedName Z + ^ + The caller should have guaranteed that the start pointer is at the + above location. + Note that type is never a function type, but only the return type of + a function or the type of a variable. + */ + Mangled += 2; + + Mangled = parseQualified(Decl, Mangled, true); + + if (Mangled != nullptr) { + /* Artificial symbols end with 'Z' and have no type. */ + if (*Mangled == 'Z') + Mangled++; + else { + /* Discard the declaration or return type. */ + OutputString Type = OutputString(); + + Mangled = parseType(&Type, Mangled); + Type.free(); + } + } + + return Mangled; +} + +const char *Demangler::parseQualified(OutputString *Decl, const char *Mangled, + bool SuffixModifiers) { + /* Qualified names are identifiers separated by their encoded length. + Nested functions also encode their argument types without specifying + what they return. + QualifiedName: + SymbolFunctionName + SymbolFunctionName QualifiedName + ^ + SymbolFunctionName: + SymbolName + SymbolName TypeFunctionNoReturn + SymbolName M TypeFunctionNoReturn + SymbolName M TypeModifiers TypeFunctionNoReturn + The start pointer should be at the above location. + */ + size_t N = 0; + do { + if (N++) + Decl->append('.'); + + /* Skip over anonymous symbols. */ + while (*Mangled == '0') + Mangled++; + + Mangled = parseIdentifier(Decl, Mangled); + + /* Consume the encoded arguments. However if this is not followed by the + next encoded length or mangle type, then this is not a continuation of + a qualified name, in which case we backtrack and return the current + unconsumed position of the mangled decl. */ + if (Mangled && (*Mangled == 'M' || isCallConvention(Mangled))) { + const char *Start = Mangled; + int Saved = Decl->getLength(); + + /* Save the type modifiers for appending at the end if needed. */ + OutputString Mods = OutputString(); + + /* Skip over 'this' parameter and type modifiers. */ + if (*Mangled == 'M') { + Mangled++; + Mangled = parseTypeModifiers(&Mods, Mangled); + Decl->setLength(Saved); + } + + Mangled = parseFunctionTypeNoreturn(Decl, nullptr, nullptr, Mangled); + if (SuffixModifiers) + Decl->append(Mods.Buffer, Mods.getLength()); + + if (Mangled == nullptr || *Mangled == '\0') { + /* Did not match the rule we were looking for. */ + Mangled = Start; + Decl->setLength(Saved); + } + + Mods.free(); + } + } while (Mangled && isSymbolName(Mangled)); + + return Mangled; +} + +const char *Demangler::parseTuple(OutputString *Decl, const char *Mangled) { + unsigned long Elements; + + Mangled = decodeNumber(Mangled, &Elements); + if (Mangled == nullptr) + return nullptr; + + Decl->append("Tuple!("); + + while (Elements--) { + Mangled = parseType(Decl, Mangled); + if (Mangled == nullptr) + return nullptr; + + if (Elements != 0) + Decl->append(", "); + } + + Decl->append(')'); + return Mangled; +} + +const char *Demangler::parseTemplateSymbolParameter(OutputString *Decl, + const char *Mangled) { + if (strncmp(Mangled, "_D", 2) == 0 && isSymbolName(Mangled + 2)) + return parseMangle(Decl, Mangled); + + if (*Mangled == 'Q') + return parseQualified(Decl, Mangled, false); + + unsigned long Len; + const char *EndPtr = decodeNumber(Mangled, &Len); + + if (EndPtr == nullptr || Len == 0) + return nullptr; + + /* In template parameter symbols generated by the frontend up to 2.076, + the symbol length is encoded and the first character of the mangled + name can be a digit. This causes ambiguity issues because the digits + of the two numbers are adjacent. */ + long PtrSize = Len; + const char *PtrEnd; + int Saved = Decl->getLength(); + + /* Work backwards until a match is found. */ + for (PtrEnd = EndPtr; EndPtr != nullptr; PtrEnd--) { + Mangled = PtrEnd; + + /* Reached the beginning of the pointer to the name length, + try parsing the entire symbol. */ + if (PtrSize == 0) { + PtrSize = Len; + PtrEnd = EndPtr; + EndPtr = nullptr; + } + + /* Check whether template parameter is a function with a valid + return type or an untyped identifier. */ + if (isSymbolName(Mangled)) + Mangled = parseQualified(Decl, Mangled, false); + else if (strncmp(Mangled, "_D", 2) == 0 && isSymbolName(Mangled + 2)) + Mangled = parseMangle(Decl, Mangled); + + /* Check for name length mismatch. */ + if (Mangled && (EndPtr == nullptr || (Mangled - PtrEnd) == PtrSize)) + return Mangled; + + PtrSize /= 10; + Decl->setLength(Saved); + } + + /* No match on any combinations. */ + return nullptr; +} + +const char *Demangler::parseTemplateArgs(OutputString *Decl, + const char *Mangled) { + size_t N = 0; + + while (Mangled && *Mangled != '\0') { + switch (*Mangled) { + case 'Z': /* End of parameter list. */ + Mangled++; + return Mangled; + } + + if (N++) + Decl->append(", "); + + /* Skip over specialised template prefix. */ + if (*Mangled == 'H') + Mangled++; + + switch (*Mangled) { + case 'S': /* Symbol parameter. */ + Mangled++; + Mangled = parseTemplateSymbolParameter(Decl, Mangled); + break; + case 'T': /* Type parameter. */ + Mangled++; + Mangled = parseType(Decl, Mangled); + break; + case 'V': /* Value parameter. */ + { + OutputString Name; + char Type; + + /* Peek at the type. */ + Mangled++; + Type = *Mangled; + + if (Type == 'Q') { + /* Value type is a back reference, peek at the real type. */ + const char *Backref; + if (decodeBackref(Mangled, &Backref) == nullptr) + return nullptr; + + Type = *Backref; + } + + /* In the few instances where the type is actually desired in + the output, it should precede the value from dlang_value. */ + Name = OutputString(); + Mangled = parseType(&Name, Mangled); + Name.append('\0'); + Name.Ptr--; + + Mangled = parseValue(Decl, Mangled, Name.Buffer, Type); + Name.free(); + break; + } + case 'X': /* Externally mangled parameter. */ + { + unsigned long Len; + const char *EndPtr; + + Mangled++; + EndPtr = decodeNumber(Mangled, &Len); + if (EndPtr == nullptr || strlen(EndPtr) < Len) + return nullptr; + + Decl->append(EndPtr, Len); + Mangled = EndPtr + Len; + break; + } + default: + return nullptr; + } + } + + return Mangled; +} + +const char *Demangler::parseTemplate(OutputString *Decl, const char *Mangled, + unsigned long Len) { + const char *Start = Mangled; + OutputString Args; + + /* Template instance names have the types and values of its parameters + encoded into it. + TemplateInstanceName: + Number __T LName TemplateArgs Z + Number __U LName TemplateArgs Z + ^ + The start pointer should be at the above location, and LEN should be + the value of the decoded number. + */ + + /* Template symbol. */ + if (!isSymbolName(Mangled + 3) || Mangled[3] == '0') + return nullptr; + + Mangled += 3; + + /* Template identifier. */ + Mangled = parseIdentifier(Decl, Mangled); + + /* Template arguments. */ + Args = OutputString(); + Mangled = parseTemplateArgs(&Args, Mangled); + + Decl->append("!("); + Decl->append(Args.Buffer, Args.getLength()); + Decl->append(')'); + + Args.free(); + + /* Check for template name length mismatch. */ + if (Len != -1UL && Mangled && (unsigned long)(Mangled - Start) != Len) + return nullptr; + + return Mangled; +} + +Demangler::Demangler(const char *Mangled) + : Str(Mangled), LastBackref(strlen(Mangled)) {} + +const char *Demangler::parseMangle(OutputString *Decl) { + return parseMangle(Decl, this->Str); +} + +char *llvm::dlangDemangle(const char *MangledName) { + OutputString Decl; + char *Demangled = nullptr; + + if (MangledName == nullptr || *MangledName == '\0') + return nullptr; + + if (strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + Decl = OutputString(); + + if (strcmp(MangledName, "_Dmain") == 0) { + Decl.append("D main"); + } else { + + Demangler D = Demangler(MangledName); + MangledName = D.parseMangle(&Decl); + + /* Check that the entire symbol was successfully demangled. */ + if (MangledName == nullptr || *MangledName != '\0') + Decl.free(); + } + + if (Decl.getLength() > 0) { + Decl.append('\0'); + Decl.Ptr--; + Demangled = Decl.Buffer; + } + + return Demangled; +} + +/* vim: set ts=2 sw=2 expandtab */ Index: llvm/lib/Demangle/Demangle.cpp =================================================================== --- llvm/lib/Demangle/Demangle.cpp +++ llvm/lib/Demangle/Demangle.cpp @@ -24,12 +24,19 @@ MangledName[1] == 'R'; } +static bool isDLangEncoding(const std::string &MangledName) { + return MangledName.size() >= 2 && MangledName[0] == '_' && + MangledName[1] == 'D'; +} + std::string llvm::demangle(const std::string &MangledName) { char *Demangled; if (isItaniumEncoding(MangledName)) Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); else if (isRustEncoding(MangledName)) Demangled = rustDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); + else if (isDLangEncoding(MangledName)) + Demangled = dlangDemangle(MangledName.c_str()); else Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr, nullptr); Index: llvm/tools/llvm-dlang-demangle-fuzzer/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-dlang-demangle-fuzzer/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LLVM_LINK_COMPONENTS + Demangle + FuzzMutate + Support +) + +add_llvm_fuzzer(llvm-dlang-demangle-fuzzer + llvm-dlang-demangle-fuzzer.cpp + DUMMY_MAIN DummyDemanglerFuzzer.cpp + ) Index: llvm/tools/llvm-dlang-demangle-fuzzer/DummyDemanglerFuzzer.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-dlang-demangle-fuzzer/DummyDemanglerFuzzer.cpp @@ -0,0 +1,18 @@ +//===-- DummyDemanglerFuzzer.cpp - Entry point to sanity check the fuzzer -===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implementation of main so we can build and test without linking libFuzzer. +// +//===----------------------------------------------------------------------===// + +#include "llvm/FuzzMutate/FuzzerCLI.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +int main(int argc, char *argv[]) { + return llvm::runFuzzerOnInputs(argc, argv, LLVMFuzzerTestOneInput); +} Index: llvm/tools/llvm-dlang-demangle-fuzzer/llvm-dlang-demangle-fuzzer.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-dlang-demangle-fuzzer/llvm-dlang-demangle-fuzzer.cpp @@ -0,0 +1,19 @@ +//===--- llvm-dlang-demangle-fuzzer.cpp - Fuzzer for the DLang Demangler --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + std::string NullTerminatedString((const char *)Data, Size); + char *Demangled = llvm::dlangDemangle(NullTerminatedString.c_str()); + std::free(Demangled); + return 0; +} Index: llvm/unittests/Demangle/CMakeLists.txt =================================================================== --- llvm/unittests/Demangle/CMakeLists.txt +++ llvm/unittests/Demangle/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_unittest(DemangleTests DemangleTest.cpp + DLangDemangleTest.cpp ItaniumDemangleTest.cpp PartialDemangleTest.cpp RustDemangleTest.cpp Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -0,0 +1,317 @@ +//===------------------ DLangDemangleTest.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 +// +//===----------------------------------------------------------------------===// +// +// Testing input ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include + +TEST(DLangDemangle, Success) { + struct ExpectedVal { + const char *Mangled; + const char *Expected; + }; + + ExpectedVal ExpectedArray[] = { + {"_Dmain", "D main"}, + {"_D3app4mainFZ6dg_fooMFZi", "app.main().dg_foo()"}, + {"_D3app6foobarFPiAiHiieSQv3FooSQBc3BarZi", + "app.foobar(int*, int[], int[int], real, app.Foo, app.Bar)"}, + {"_D8demangle4testPFLAiYi", "demangle.test"}, + {"_D8demangle4testFZv", "demangle.test()"}, + {"_D8demangle4testMFZ2fnMFZv", "demangle.test().fn()"}, + {"_D8demangle4testFaZv", "demangle.test(char)"}, + {"_D8demangle4testFbZv", "demangle.test(bool)"}, + {"_D8demangle4testFcZv", "demangle.test(creal)"}, + {"_D8demangle4testFdZv", "demangle.test(double)"}, + {"_D8demangle4testFeZv", "demangle.test(real)"}, + {"_D8demangle4testFfZv", "demangle.test(float)"}, + {"_D8demangle4testFgZv", "demangle.test(byte)"}, + {"_D8demangle4testFhZv", "demangle.test(ubyte)"}, + {"_D8demangle4testFiZv", "demangle.test(int)"}, + {"_D8demangle4testFjZv", "demangle.test(ireal)"}, + {"_D8demangle4testFkZv", "demangle.test(uint)"}, + {"_D8demangle4testFlZv", "demangle.test(long)"}, + {"_D8demangle4testFmZv", "demangle.test(ulong)"}, + {"_D8demangle4testFnZv", "demangle.test(typeof(null))"}, + {"_D8demangle4testFNnZv", "demangle.test(typeof(*null))"}, + {"_D8demangle4testFoZv", "demangle.test(ifloat)"}, + {"_D8demangle4testFpZv", "demangle.test(idouble)"}, + {"_D8demangle4testFqZv", "demangle.test(cfloat)"}, + {"_D8demangle4testFrZv", "demangle.test(cdouble)"}, + {"_D8demangle4testFsZv", "demangle.test(short)"}, + {"_D8demangle4testFtZv", "demangle.test(ushort)"}, + {"_D8demangle4testFuZv", "demangle.test(wchar)"}, + {"_D8demangle4testFvZv", "demangle.test(void)"}, + {"_D8demangle4testFwZv", "demangle.test(dchar)"}, + {"_D8demangle4testFziZv", "demangle.test(cent)"}, + {"_D8demangle4testFzkZv", "demangle.test(ucent)"}, + {"_D8demangle4testFOaZv", "demangle.test(shared(char))"}, + {"_D8demangle4testFxaZv", "demangle.test(const(char))"}, + {"_D8demangle4testFyaZv", "demangle.test(immutable(char))"}, + {"_D8demangle4testFNgaZv", "demangle.test(inout(char))"}, + {"_D8demangle4testFOxaZv", "demangle.test(shared(const(char)))"}, + {"_D8demangle4testFONgaZv", "demangle.test(shared(inout(char)))"}, + {"_D8demangle4testFAaZv", "demangle.test(char[])"}, + {"_D8demangle4testFAAaZv", "demangle.test(char[][])"}, + {"_D8demangle4testFAAAaZv", "demangle.test(char[][][])"}, + {"_D8demangle4testFG42aZv", "demangle.test(char[42])"}, + {"_D8demangle4testFG42G42aZv", "demangle.test(char[42][42])"}, + {"_D8demangle4testFG42G42G42aZv", "demangle.test(char[42][42][42])"}, + {"_D8demangle4testFG1234567890aZv", "demangle.test(char[1234567890])"}, + {"_D8demangle4testFHaaZv", "demangle.test(char[char])"}, + {"_D8demangle4testFHHaaaZv", "demangle.test(char[char[char]])"}, + {"_D8demangle4testFPaZv", "demangle.test(char*)"}, + {"_D8demangle4testFPPaZv", "demangle.test(char**)"}, + {"_D8demangle4testFPPPaZv", "demangle.test(char***)"}, + {"_D8demangle4testFNhG8gZv", "demangle.test(__vector(byte[8]))"}, + {"_D8demangle4testFNhG16gZv", "demangle.test(__vector(byte[16]))"}, + {"_D8demangle4testFNhG32gZv", "demangle.test(__vector(byte[32]))"}, + {"_D8demangle4testFNhG4sZv", "demangle.test(__vector(short[4]))"}, + {"_D8demangle4testFNhG8sZv", "demangle.test(__vector(short[8]))"}, + {"_D8demangle4testFNhG16sZv", "demangle.test(__vector(short[16]))"}, + {"_D8demangle4testFNhG2iZv", "demangle.test(__vector(int[2]))"}, + {"_D8demangle4testFNhG4iZv", "demangle.test(__vector(int[4]))"}, + {"_D8demangle4testFNhG8iZv", "demangle.test(__vector(int[8]))"}, + {"_D8demangle4testFNhG1lZv", "demangle.test(__vector(long[1]))"}, + {"_D8demangle4testFNhG2lZv", "demangle.test(__vector(long[2]))"}, + {"_D8demangle4testFNhG4lZv", "demangle.test(__vector(long[4]))"}, + {"_D8demangle4testFNhG2fZv", "demangle.test(__vector(float[2]))"}, + {"_D8demangle4testFNhG4fZv", "demangle.test(__vector(float[4]))"}, + {"_D8demangle4testFNhG8fZv", "demangle.test(__vector(float[8]))"}, + {"_D8demangle4testFNhG1dZv", "demangle.test(__vector(double[1]))"}, + {"_D8demangle4testFNhG2dZv", "demangle.test(__vector(double[2]))"}, + {"_D8demangle4testFNhG4dZv", "demangle.test(__vector(double[4]))"}, + {"_D8demangle4testFC5classZv", "demangle.test(class)"}, + {"_D8demangle4testFC5class4testZv", "demangle.test(class.test)"}, + {"_D8demangle4testFS6structZv", "demangle.test(struct)"}, + {"_D8demangle4testFS6struct4testZv", "demangle.test(struct.test)"}, + {"_D8demangle4testFE4enumZv", "demangle.test(enum)"}, + {"_D8demangle4testFE4enum4testZv", "demangle.test(enum.test)"}, + {"_D8demangle4testFT7typedefZv", "demangle.test(typedef)"}, + {"_D8demangle4testFT7typedef4testZv", "demangle.test(typedef.test)"}, + {"_D8demangle4testFIaZv", "demangle.test(in char)"}, + {"_D8demangle4testFIKaZv", "demangle.test(in ref char)"}, + {"_D8demangle4testFJaZv", "demangle.test(out char)"}, + {"_D8demangle4testFKaZv", "demangle.test(ref char)"}, + {"_D8demangle4testFLaZv", "demangle.test(lazy char)"}, + {"_D8demangle4testFMaZv", "demangle.test(scope char)"}, + {"_D8demangle4testFNjaZv", "demangle.test(char)"}, + {"_D8demangle4testFNkaZv", "demangle.test(return char)"}, + {"_D8demangle4testFNlaZv", "demangle.test(char)"}, + {"_D8demangle4testFaXv", "demangle.test(char...)"}, + {"_D8demangle4testFaYv", "demangle.test(char, ...)"}, + {"_D8demangle4testFaaYv", "demangle.test(char, char, ...)"}, + {"_D8demangle4testFYv", "demangle.test(...)"}, + {"_D8demangle4testFaaZv", "demangle.test(char, char)"}, + {"_D8demangle4testFB0Zv", "demangle.test(Tuple!())"}, + {"_D8demangle4testFB1aZv", "demangle.test(Tuple!(char))"}, + {"_D8demangle4testFB2aaZv", "demangle.test(Tuple!(char, char))"}, + {"_D8demangle4testFB3aaaZv", "demangle.test(Tuple!(char, char, char))"}, + {"_D8demangle4testFB2OaaZv", "demangle.test(Tuple!(shared(char), char))"}, + {"_D8demangle4testFB3aDFZaaZv", + "demangle.test(Tuple!(char, char() delegate, char))"}, + {"_D8demangle4testFDFZaZv", "demangle.test(char() delegate)"}, + {"_D8demangle4testFDUZaZv", "demangle.test(extern(C) char() delegate)"}, + {"_D8demangle4testFDWZaZv", + "demangle.test(extern(Windows) char() delegate)"}, + {"_D8demangle4testFDVZaZv", + "demangle.test(extern(Pascal) char() delegate)"}, + {"_D8demangle4testFDRZaZv", "demangle.test(extern(C++) char() delegate)"}, + {"_D8demangle4testFDYZaZv", + "demangle.test(extern(Objective-C) char() delegate)"}, + {"_D8demangle4testFPFZaZv", "demangle.test(char() function)"}, + {"_D8demangle4testFPUZaZv", "demangle.test(extern(C) char() function)"}, + {"_D8demangle4testFPWZaZv", + "demangle.test(extern(Windows) char() function)"}, + {"_D8demangle4testFPVZaZv", + "demangle.test(extern(Pascal) char() function)"}, + {"_D8demangle4testFPRZaZv", "demangle.test(extern(C++) char() function)"}, + {"_D8demangle4testFPYZaZv", + "demangle.test(extern(Objective-C) char() function)"}, + {"_D8demangle4testFDFNaZaZv", "demangle.test(char() pure delegate)"}, + {"_D8demangle4testFDFNbZaZv", "demangle.test(char() nothrow delegate)"}, + {"_D8demangle4testFDFNcZaZv", "demangle.test(char() ref delegate)"}, + {"_D8demangle4testFDFNdZaZv", "demangle.test(char() @property delegate)"}, + {"_D8demangle4testFDFNeZaZv", "demangle.test(char() @trusted delegate)"}, + {"_D8demangle4testFDFNfZaZv", "demangle.test(char() @safe delegate)"}, + {"_D8demangle4testFDFNiZaZv", "demangle.test(char() @nogc delegate)"}, + {"_D8demangle4testFDFNmZaZv", "demangle.test(char() @live delegate)"}, + {"_D8demangle4testFDFNaNbZaZv", + "demangle.test(char() pure nothrow delegate)"}, + {"_D8demangle4testFDFNbNaZaZv", + "demangle.test(char() nothrow pure delegate)"}, + {"_D8demangle4testFDFNdNfNaZaZv", + "demangle.test(char() @property @safe pure delegate)"}, + {"_D8demangle4testFNjDFZaZv", "demangle.test(char() delegate)"}, + {"_D8demangle4testFNkDFZaZv", "demangle.test(return char() delegate)"}, + {"_D8demangle4testFDFNjZaZv", "demangle.test(char() return delegate)"}, + {"_D8demangle4testFNjNkDFNjZaZv", + "demangle.test(return char() return delegate)"}, + {"_D8demangle4testFNlDFZaZv", "demangle.test(char() delegate)"}, + {"_D8demangle4testFMDFZaZv", "demangle.test(scope char() delegate)"}, + {"_D8demangle4testFDFNlZaZv", "demangle.test(char() scope delegate)"}, + {"_D8demangle4testFMDFNlZaZv", + "demangle.test(scope char() scope delegate)"}, + {"_D8demangle4testFNlMDFNlZaZv", + "demangle.test(scope char() scope delegate)"}, + {"_D8demangle4testFPFNaZaZv", "demangle.test(char() pure function)"}, + {"_D8demangle4testFPFNbZaZv", "demangle.test(char() nothrow function)"}, + {"_D8demangle4testFPFNcZaZv", "demangle.test(char() ref function)"}, + {"_D8demangle4testFPFNdZaZv", "demangle.test(char() @property function)"}, + {"_D8demangle4testFPFNeZaZv", "demangle.test(char() @trusted function)"}, + {"_D8demangle4testFPFNfZaZv", "demangle.test(char() @safe function)"}, + {"_D8demangle4testFPFNiZaZv", "demangle.test(char() @nogc function)"}, + {"_D8demangle4testFPFNmZaZv", "demangle.test(char() @live function)"}, + {"_D8demangle4testFPFNaNbZaZv", + "demangle.test(char() pure nothrow function)"}, + {"_D8demangle4testFPFNbNaZaZv", + "demangle.test(char() nothrow pure function)"}, + {"_D8demangle4testFPFNdNfNaZaZv", + "demangle.test(char() @property @safe pure function)"}, + {"_D8demangle4testFNjPFZaZv", "demangle.test(char() function)"}, + {"_D8demangle4testFNkPFZaZv", "demangle.test(return char() function)"}, + {"_D8demangle4testFPFNjZaZv", "demangle.test(char() return function)"}, + {"_D8demangle4testFNjNkPFNjZaZv", + "demangle.test(return char() return function)"}, + {"_D8demangle4testFNlPFZaZv", "demangle.test(char() function)"}, + {"_D8demangle4testFMPFZaZv", "demangle.test(scope char() function)"}, + {"_D8demangle4testFPFNlZaZv", "demangle.test(char() scope function)"}, + {"_D8demangle4testFMPFNlZaZv", + "demangle.test(scope char() scope function)"}, + {"_D8demangle4testFNlMPFNlZaZv", + "demangle.test(scope char() scope function)"}, + {"_D8demangle4test6__initZ", "initializer for demangle.test"}, + {"_D8demangle4test6__vtblZ", "vtable for demangle.test"}, + {"_D8demangle4test7__ClassZ", "ClassInfo for demangle.test"}, + {"_D8demangle4test11__InterfaceZ", "Interface for demangle.test"}, + {"_D8demangle4test12__ModuleInfoZ", "ModuleInfo for demangle.test"}, + {"_D8demangle4test6__ctorMFZv", "demangle.test.this()"}, + {"_D8demangle4test6__dtorMFZv", "demangle.test.~this()"}, + {"_D8demangle4test10__postblitMFZv", "demangle.test.this(this)"}, + {"_D8demangle4testFHAbaZv", "demangle.test(char[bool[]])"}, + {"_D8demangle4testFHG42caZv", "demangle.test(char[creal[42]])"}, + {"_D8demangle4testFAiXv", "demangle.test(int[]...)"}, + {"_D8demangle4testFLAiXv", "demangle.test(lazy int[]...)"}, + {"_D8demangle4testFAiYv", "demangle.test(int[], ...)"}, + {"_D8demangle4testFLAiYv", "demangle.test(lazy int[], ...)"}, + {"_D8demangle4testFLilZv", "demangle.test(lazy int, long)"}, + {"_D8demangle4testFLliZv", "demangle.test(lazy long, int)"}, + {"_D8demangle4testFLC6ObjectLDFLiZiZi", + "demangle.test(lazy Object, lazy int(lazy int) delegate)"}, + {"_D8demangle9__T4testZv", "demangle.test!()"}, + {"_D8demangle9__U4testZv", "demangle.test!()"}, + {"_D8demangle11__T4testTaZv", "demangle.test!(char)"}, + {"_D8demangle13__T4testTaTaZv", "demangle.test!(char, char)"}, + {"_D8demangle15__T4testTaTaTaZv", "demangle.test!(char, char, char)"}, + {"_D8demangle16__T4testTaTOiTaZv", + "demangle.test!(char, shared(int), char)"}, + {"_D8demangle17__T4testS6symbolZv", "demangle.test!(symbol)"}, + {"_D8demangle23__T4testS116symbol3fooZv", "demangle.test!(symbol.foo)"}, + {"_D8demangle32__T4testS20_D6symbol3foo3barFZvZv", + "demangle.test!(symbol.foo.bar())"}, + {"_D8demangle19__T4testTaS6symbolZv", "demangle.test!(char, symbol)"}, + {"_D8demangle19__T4testS6symbolTaZv", "demangle.test!(symbol, char)"}, + {"_D8demangle12__T4testHTaZv", "demangle.test!(char)"}, + {"_D8demangle13__T4testVPinZv", "demangle.test!(null)"}, + {"_D8demangle15__T4testVgi123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVii123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVsi123Zv", "demangle.test!(123)"}, + {"_D8demangle15__T4testVhi123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVki123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVti123Zv", "demangle.test!(123u)"}, + {"_D8demangle15__T4testVli123Zv", "demangle.test!(123L)"}, + {"_D8demangle15__T4testVmi123Zv", "demangle.test!(123uL)"}, + {"_D8demangle15__T4testViN123Zv", "demangle.test!(-123)"}, + {"_D8demangle15__T4testVkN123Zv", "demangle.test!(-123u)"}, + {"_D8demangle15__T4testVlN123Zv", "demangle.test!(-123L)"}, + {"_D8demangle15__T4testVmN123Zv", "demangle.test!(-123uL)"}, + {"_D8demangle13__T4testVbi1Zv", "demangle.test!(true)"}, + {"_D8demangle13__T4testVbi0Zv", "demangle.test!(false)"}, + {"_D8demangle14__T4testVai10Zv", "demangle.test!('\\x0a')"}, + {"_D8demangle14__T4testVai32Zv", "demangle.test!(' ')"}, + {"_D8demangle14__T4testVai65Zv", "demangle.test!('A')"}, + {"_D8demangle15__T4testVai126Zv", "demangle.test!('~')"}, + {"_D8demangle16__T4testVui1000Zv", "demangle.test!('\\u03e8')"}, + {"_D8demangle18__T4testVwi100000Zv", "demangle.test!('\\U000186a0')"}, + {"_D8demangle17__T4testVde0A8P6Zv", "demangle.test!(0x0.A8p6)"}, + {"_D8demangle16__T4testVdeA8P2Zv", "demangle.test!(0xA.8p2)"}, + {"_D8demangle18__T4testVdeN0A8P6Zv", "demangle.test!(-0x0.A8p6)"}, + {"_D8demangle31__T4testVde0F6E978D4FDF3B646P7Zv", + "demangle.test!(0x0.F6E978D4FDF3B646p7)"}, + {"_D8demangle15__T4testVdeNANZv", "demangle.test!(NaN)"}, + {"_D8demangle15__T4testVdeINFZv", "demangle.test!(Inf)"}, + {"_D8demangle16__T4testVdeNINFZv", "demangle.test!(-Inf)"}, + {"_D8demangle23__T4testVfe0FFFFFFP128Zv", + "demangle.test!(0x0.FFFFFFp128)"}, + {"_D8demangle32__T4testVde0FFFFFFFFFFFFF8P1024Zv", + "demangle.test!(0x0.FFFFFFFFFFFFF8p1024)"}, + {"_D8demangle19__T4testVfe08PN125Zv", "demangle.test!(0x0.8p-125)"}, + {"_D8demangle20__T4testVde08PN1021Zv", "demangle.test!(0x0.8p-1021)"}, + {"_D8demangle51__T4testVrc0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv", + "demangle.test!(0x0.C4CCCCCCCCCCCCCDp4+0x0.B666666666666666p6i)"}, + {"_D8demangle52__T4testVrcN0C4CCCCCCCCCCCCCDP4c0B666666666666666P6Zv", + "demangle.test!(-0x0.C4CCCCCCCCCCCCCDp4+0x0.B666666666666666p6i)"}, + {"_D8demangle91__" + "T4testVde000111222333444555666777888999AAABBBCCCDDDEEEFFFP0001112223334" + "44555666777888999Zv", + "demangle.test!(0x0." + "00111222333444555666777888999AAABBBCCCDDDEEEFFFp00011122233344455566677" + "7888999)"}, + {"_D8demangle22__T4testVG3ua3_616263Zv", "demangle.test!(\"abc\")"}, + {"_D8demangle22__T4testVG3ud3_616263Zv", "demangle.test!(\"abc\"d)"}, + {"_D8demangle22__T4testVG3uw3_616263Zv", "demangle.test!(\"abc\"w)"}, + {"_D8demangle16__T4testVAyaa0_Zv", "demangle.test!(\"\")"}, + {"_D8demangle32__T4testVAyaa8_20090a0d0c0b00ffZv", + "demangle.test!(\" \\t\\n\\r\\f\\v\\x00\\xff\")"}, + {"_D8demangle22__T4testVAiA4i1i2i3i4Zv", "demangle.test!([1, 2, 3, 4])"}, + {"_D8demangle25__T4testVAdA2e08P1eN08P1Zv", + "demangle.test!([0x0.8p1, -0x0.8p1])"}, + {"_D8demangle23__T4testVHiiA2i1i2i3i4Zv", "demangle.test!([1:2, 3:4])"}, + {"_D8demangle39__T4testVHAxaiA2a3_616263i1a3_646566i2Zv", + "demangle.test!([\"abc\":1, \"def\":2])"}, + {"_D8demangle28__T4testVS8demangle1SS2i1i2Zv", + "demangle.test!(demangle.S(1, 2))"}, + {"_D8demangle35__T4testVS8demangle1SS2i1a3_616263Zv", + "demangle.test!(demangle.S(1, \"abc\"))"}, + {"_D8demangle13__T4testTFZaZ6mangleFZv", + "demangle.test!(char() function).mangle()"}, + {"_D8demangle4testMxFZv", "demangle.test() const"}, + {"_D8demangle4testMyFZv", "demangle.test() immutable"}, + {"_D8demangle4testMNgFZv", "demangle.test() inout"}, + {"_D8demangle4testMNgxFZv", "demangle.test() inout const"}, + {"_D8demangle4testMOFZv", "demangle.test() shared"}, + {"_D8demangle4testMOxFZv", "demangle.test() shared const"}, + {"_D8demangle4testMONgFZv", "demangle.test() shared inout"}, + {"_D8demangle4testMONgxFZv", "demangle.test() shared inout const"}, + {"_D8demangle4testFDxFZaZv", "demangle.test(char() delegate const)"}, + {"_D8demangle4testFDyFZaZv", "demangle.test(char() delegate immutable)"}, + {"_D8demangle4testFDNgFZaZv", "demangle.test(char() delegate inout)"}, + {"_D8demangle4testFDNgxFZaZv", + "demangle.test(char() delegate inout const)"}, + {"_D8demangle4testFDOFZaZv", "demangle.test(char() delegate shared)"}, + {"_D8demangle4testFDOxFZaZv", + "demangle.test(char() delegate shared const)"}, + {"_D8demangle4testFDONgFZaZv", + "demangle.test(char() delegate shared inout)"}, + {"_D8demangle4testFDONgxFZaZv", + "demangle.test(char() delegate shared inout const)"}, + {"_D8demangle004testFaZv", "demangle.test(char)"}, + {"_D8demangle000000004testFaZv", "demangle.test(char)"}}; + + for (ExpectedVal Val : ExpectedArray) { + char *Demangled = llvm::dlangDemangle(Val.Mangled); + EXPECT_STREQ(Demangled, Val.Expected); + std::free(Demangled); + } +}