Index: llvm/lib/Demangle/DLangDemangle.cpp =================================================================== --- llvm/lib/Demangle/DLangDemangle.cpp +++ llvm/lib/Demangle/DLangDemangle.cpp @@ -190,6 +190,18 @@ /// \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 @@ -235,6 +247,58 @@ /// \see https://dlang.org/spec/abi.html#QualifiedName const char *parseQualified(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 /// @@ -508,6 +572,181 @@ 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::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::parseMangle(OutputString *Decl, const char *Mangled) { /* A D mangled symbol is comprised of both scope and type information. MangleName: @@ -623,6 +862,71 @@ return parseLName(Decl, Mangled, Len); } +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; @@ -726,7 +1030,17 @@ return Mangled; } - // TODO: Parse function types + [[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; [[clang::fallthrough]]; case 'C': /* class T */ Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- llvm/unittests/Demangle/DLangDemangleTest.cpp +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -42,7 +42,8 @@ {"_D8demangle3ABCQeQg1ai", "demangle.ABC.ABC.ABC.a"}, {"_D8demangle3ABCQeQaaaa1ai", nullptr}, {"_D8demangle4ABCiQfQh1aQh", "demangle.ABCi.ABCi.ABCi.a"}, - {"_D8demangle4ABCiQfQh1aQaaa", nullptr} + {"_D8demangle4ABCiQfQh1aQaaa", nullptr}, + {"_D8demangle4testPFLAiYi", "demangle.test"} }; for (ExpectedVal Val : ExpectedArray) {