diff --git a/llvm/lib/Demangle/DLangDemangle.cpp b/llvm/lib/Demangle/DLangDemangle.cpp --- a/llvm/lib/Demangle/DLangDemangle.cpp +++ b/llvm/lib/Demangle/DLangDemangle.cpp @@ -168,6 +168,18 @@ /// \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 + /// + /// \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); + /// Check whether it is a function calling convention /// /// \param Mangled string to extract the function calling convention @@ -236,6 +248,8 @@ /// The string we are demangling. const char *Str; + /// The index of the last back reference. + int LastBackref; }; } // namespace @@ -445,6 +459,36 @@ return Mangled; } +const char *Demangler::parseTypeBackref(OutputString *Decl, const char *Mangled) { + /* 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); + + // TODO: Add support for function type back references + 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; @@ -818,7 +862,9 @@ } return nullptr; - // TODO: Parse back referenced types + // Back referenced type + case 'Q': + return parseTypeBackref(Decl, Mangled); default: // unhandled return nullptr; @@ -901,7 +947,7 @@ } Demangler::Demangler(const char *Mangled) - : Str(Mangled) {} + : Str(Mangled), LastBackref(strlen(Mangled)) {} const char *Demangler::parseMangle(OutputString *Decl) { return parseMangle(Decl, this->Str); diff --git a/llvm/unittests/Demangle/DLangDemangleTest.cpp b/llvm/unittests/Demangle/DLangDemangleTest.cpp --- a/llvm/unittests/Demangle/DLangDemangleTest.cpp +++ b/llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -40,7 +40,9 @@ {"_D8demangle1re", "demangle.r"}, {"_D8demangle1iinvalidtypeseq", nullptr}, {"_D8demangle3ABCQeQg1ai", "demangle.ABC.ABC.ABC.a"}, - {"_D8demangle3ABCQeQaaaa1ai", nullptr} + {"_D8demangle3ABCQeQaaaa1ai", nullptr}, + {"_D8demangle4ABCiQfQh1aQh", "demangle.ABCi.ABCi.ABCi.a"}, + {"_D8demangle4ABCiQfQh1aQaaa", nullptr} }; for (ExpectedVal Val : ExpectedArray) {