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 @@ -241,11 +241,14 @@ /// /// \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); + const char *parseQualified(OutputString *Decl, const char *Mangled, + bool SuffixModifiers); /// Extract and demangle the D function attributes from a given mangled /// symbol append it to the output string @@ -310,6 +313,17 @@ /// \see https://dlang.org/spec/abi.html#Type const char *parseType(OutputString *Decl, const char *Mangled); + /// 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); + /// The string we are demangling. const char *Str; /// The index of the last back reference. @@ -760,7 +774,7 @@ */ Mangled += 2; - Mangled = parseQualified(Decl, Mangled); + Mangled = parseQualified(Decl, Mangled, true); if (Mangled != nullptr) { // Artificial symbols end with 'Z' and have no type. @@ -778,7 +792,8 @@ return Mangled; } -const char *Demangler::parseQualified(OutputString *Decl, const char *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. @@ -810,14 +825,73 @@ Mangled = parseIdentifier(Decl, Mangled); if (Mangled && (*Mangled == 'M' || isCallConvention(Mangled))) { - // TODO: Implement type function parsing - return nullptr; + 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::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::parseIdentifier(OutputString *Decl, const char *Mangled) { unsigned long Len; @@ -874,9 +948,7 @@ return Mangled; case 'Y': /* (variadic T t, ...) style */ Mangled++; - if (N != 0) - Decl->append(", "); - Decl->append("..."); + Decl->append(", ..."); return Mangled; case 'Z': /* Normal function */ Mangled++; @@ -1042,14 +1114,12 @@ Decl->append("function"); return Mangled; - [[clang::fallthrough]]; case 'C': /* class T */ case 'S': /* struct T */ case 'E': /* enum T */ case 'T': /* typedef T */ Mangled++; - // TODO: Handle type modifiers and type functions in qualifiers - return parseQualified(Decl, Mangled); + return parseQualified(Decl, Mangled, false); // TODO: Parse delegate types // TODO: Parse tuple types 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 @@ -43,7 +43,94 @@ {"_D8demangle3ABCQeQaaaa1ai", nullptr}, {"_D8demangle4ABCiQfQh1aQh", "demangle.ABCi.ABCi.ABCi.a"}, {"_D8demangle4ABCiQfQh1aQaaa", nullptr}, - {"_D8demangle4testPFLAiYi", "demangle.test"} + {"_D8demangle4testPFLAiYi", "demangle.test"}, + {"_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)"}, + {"_D8demangle4testFZv", "demangle.test()"}, + {"_D8demangle4testMFZ2fnMFZv", "demangle.test().fn()"}, + {"_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[][][])"}, + {"_D8demangle4testFHaaZv", "demangle.test(char[char])"}, + {"_D8demangle4testFHHaaaZv", "demangle.test(char[char[char]])"}, + {"_D8demangle4testFPaZv", "demangle.test(char*)"}, + {"_D8demangle4testFPPaZv", "demangle.test(char**)"}, + {"_D8demangle4testFPPPaZv", "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])"}, + {"_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, ...)"}, + {"_D8demangle4testFXv", "demangle.test(...)"}, + {"_D8demangle4testFYv", "demangle.test(, ...)"}, + {"_D8demangle4testFaaZv", "demangle.test(char, char)"} }; for (ExpectedVal Val : ExpectedArray) {