Index: llvm/lib/Demangle/DLangDemangle.cpp =================================================================== --- llvm/lib/Demangle/DLangDemangle.cpp +++ llvm/lib/Demangle/DLangDemangle.cpp @@ -338,6 +338,42 @@ /// \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. @@ -592,7 +628,9 @@ if (std::isdigit(*Mangled)) return true; - // TODO: Handle template instances + if (Mangled[0] == '_' && Mangled[1] == '_' && + (Mangled[2] == 'T' || Mangled[2] == 'U')) + return true; if (*Mangled != 'Q') return false; @@ -920,7 +958,10 @@ if (*Mangled == 'Q') return parseSymbolBackref(Decl, Mangled); - // TODO: Parse lengthless template instances + /* 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); @@ -932,7 +973,10 @@ Mangled = Endptr; - // TODO: Parse template instances with a length prefix + /* 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 @@ -1393,6 +1437,152 @@ 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; + + // TODO: Parse value literals + + 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)) {} Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- llvm/unittests/Demangle/DLangDemangleTest.cpp +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -242,7 +242,23 @@ {"_D8demangle4testFDONgxFZaZv", "demangle.test(char() delegate shared inout const)"}, {"_D8demangle004testFaZv", "demangle.test(char)"}, - {"_D8demangle000000004testFaZv", "demangle.test(char)"} + {"_D8demangle000000004testFaZv", "demangle.test(char)"}, + {"_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__T4testTFZaZ6mangleFZv", + "demangle.test!(char() function).mangle()"} }; for (ExpectedVal Val : ExpectedArray) {