diff --git a/llvm/include/llvm/Demangle/RustDemangle.h b/llvm/include/llvm/Demangle/RustDemangle.h --- a/llvm/include/llvm/Demangle/RustDemangle.h +++ b/llvm/include/llvm/Demangle/RustDemangle.h @@ -12,12 +12,14 @@ #include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/StringView.h" #include "llvm/Demangle/Utility.h" +#include namespace llvm { namespace rust_demangle { using llvm::itanium_demangle::OutputStream; using llvm::itanium_demangle::StringView; +using llvm::itanium_demangle::SwapAndRestore; struct Identifier { StringView Name; @@ -37,6 +39,10 @@ // Position in the input string. size_t Position; + // When true, print methods append the output to the stream. + // When false, the output is suppressed. + bool Print; + // True if an error occurred. bool Error; @@ -50,19 +56,50 @@ private: void demanglePath(); + void demangleImplPath(); + void demangleType(); + + // = "B" + template void demangleBackref(Callable Demangler) { + uint64_t Backref = parseBase62Number(); + if (Error || Backref >= Position) { + Error = true; + return; + } + + if (!Print) + return; + + SwapAndRestore SavePosition(Position, Backref); + Demangler(); + } Identifier parseIdentifier(); - void parseOptionalBase62Number(char Tag); + uint64_t parseOptionalBase62Number(char Tag); uint64_t parseBase62Number(); uint64_t parseDecimalNumber(); + void print(char C) { + if (Error || !Print) + return; + + Output += C; + } + void print(StringView S) { - if (Error) + if (Error || !Print) return; Output += S; } + void printDecimalNumber(uint64_t N) { + if (Error || !Print) + return; + + Output << N; + } + char look() const { if (Error || Position >= Input.size()) return 0; diff --git a/llvm/lib/Demangle/RustDemangle.cpp b/llvm/lib/Demangle/RustDemangle.cpp --- a/llvm/lib/Demangle/RustDemangle.cpp +++ b/llvm/lib/Demangle/RustDemangle.cpp @@ -89,12 +89,30 @@ return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; } +/// Returns true if C starts a . +static inline bool isPath(char C) { + switch (C) { + case 'C': + case 'M': + case 'X': + case 'Y': + case 'N': + case 'I': + case 'B': + return true; + default: + return false; + } +} + // Demangles Rust v0 mangled symbol. Returns true when successful, and false // otherwise. The demangled symbol is stored in Output field. It is // responsibility of the caller to free the memory behind the output stream. // // = "_R" [] +// = bool Demangler::demangle(StringView Mangled) { + Print = true; Position = 0; Error = false; RecursionLevel = 0; @@ -107,7 +125,10 @@ demanglePath(); - // FIXME parse optional . + if (isPath(look())) { + SwapAndRestore SavePrint(Print, false); + demanglePath(); + } if (Position != Input.size()) Error = true; @@ -115,6 +136,8 @@ return !Error; } +// Demangles a path. +// // = "C" // crate root // | "M" // (inherent impl) // | "X" // (trait impl) @@ -132,7 +155,7 @@ Error = true; return; } - RecursionLevel += 1; + SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); switch (consume()) { case 'C': { @@ -141,6 +164,30 @@ print(Ident.Name); break; } + case 'M': { + demangleImplPath(); + print('<'); + demangleType(); + print('>'); + break; + } + case 'X': { + demangleImplPath(); + print('<'); + demangleType(); + print(" as "); + demanglePath(); + print('>'); + break; + } + case 'Y': { + print('<'); + demangleType(); + print(" as "); + demanglePath(); + print('>'); + break; + } case 'N': { char NS = consume(); if (!isLower(NS) && !isUpper(NS)) { @@ -149,27 +196,67 @@ } demanglePath(); - parseOptionalBase62Number('s'); + uint64_t Disambiguator = parseOptionalBase62Number('s'); Identifier Ident = parseIdentifier(); - if (!Ident.empty()) { - // FIXME print special namespaces: - // * "C" closures - // * "S" shim - print("::"); - print(Ident.Name); + if (isUpper(NS)) { + // Special namespaces + print("::{"); + if (NS == 'C') + print("closure"); + else if (NS == 'S') + print("shim"); + else + print(NS); + if (!Ident.empty()) { + print(":"); + print(Ident.Name); + } + print('#'); + printDecimalNumber(Disambiguator); + print('}'); + } else { + // Implementation internal namespaces. + if (!Ident.empty()) { + print("::"); + print(Ident.Name); + } } break; } + case 'B': { + demangleBackref([&] { demanglePath(); }); + break; + } default: - // FIXME parse remaining productions. + // FIXME parse remaining production. Error = true; break; } +} - RecursionLevel -= 1; +// = [] +// = "s" +void Demangler::demangleImplPath() { + SwapAndRestore SavePrint(Print, false); + parseOptionalBase62Number('s'); + demanglePath(); } +// = | +// | // named type +// | "A" // [T; N] +// | "S" // [T] +// | "T" {} "E" // (T1, T2, T3, ...) +// | "R" [] // &T +// | "Q" [] // &mut T +// | "P" // *const T +// | "O" // *mut T +// | "F" // fn(...) -> ... +// | "D" // dyn Trait + Send + 'a +// | // backref +void Demangler::demangleType() { demanglePath(); } + // = ["u"] ["_"] Identifier Demangler::parseIdentifier() { bool Punycode = consumeIf('u'); @@ -195,11 +282,16 @@ } // Parses optional base 62 number. The presence of a number is determined using -// Tag. -void Demangler::parseOptionalBase62Number(char Tag) { - // Parsing result is currently unused. - if (consumeIf(Tag)) - parseBase62Number(); +// Tag. Returns 0 when tag is absent and parsed value + 1 otherwise. +uint64_t Demangler::parseOptionalBase62Number(char Tag) { + if (!consumeIf(Tag)) + return 0; + + uint64_t N = parseBase62Number(); + if (Error || !addAssign(N, 1)) + return 0; + + return N; } // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by diff --git a/llvm/test/Demangle/rust.test b/llvm/test/Demangle/rust.test --- a/llvm/test/Demangle/rust.test +++ b/llvm/test/Demangle/rust.test @@ -9,6 +9,54 @@ CHECK: a::b::c _RNvNvC1a1b1c +; Closure namespace + +CHECK: ns::f::{closure#0} + _RNCNvCs21hi0yVfW1J_2ns1f0B3_ + +CHECK: ns::f::{closure#1} + _RNCNvCs21hi0yVfW1J_2ns1fs_0B3_ + +CHECK: ns::f::{closure#1}::{closure#0} + _RNCNCNvCs21hi0yVfW1J_2ns1fs_00B5_ + +CHECK: ns::f::{closure#1}::g + _RNvNCNvCs21hi0yVfW1J_2ns1fs_01g + +; Shim namespace + +CHECK: ns::g::{shim:reify#0} + _RNSNvCshGpAVYOtgW1_2ns1g5reifyB3_ + +; Unrecognized special namespace + +CHECK: a::{B:c#10} + _RNBC1as8_1c + +; Inherent impl + +CHECK: ::new + _RNvMCshGpAVYOtgW1_1pNtB2_8SmallStr3new + +CHECK: ::len + _RNvMs_CshGpAVYOtgW1_1pNtB4_8SmallStr3len + +; Trait definition + +CHECK: ::max + _RNvYNtCshGpAVYOtgW1_1p8SmallStrNtNtCskrsM4FCwAVA_4core3cmp3Ord3maxB4_ + +CHECK: ::clone_from + _RNvYNtCshGpAVYOtgW1_1p8SmallStrNtNtCskrsM4FCwAVA_4core5clone5Clone10clone_fromB4_ + +; Trait impl + +CHECK: ::default + _RNvXs1_CshGpAVYOtgW1_1pNtB5_8SmallStrNtNtCskrsM4FCwAVA_4core7default7Default7defaultB5_ + +CHECK: ::from_str + _RNvXCshGpAVYOtgW1_1pNtB2_8SmallStrNtNtNtCskrsM4FCwAVA_4core3str6traits7FromStr8from_str + ; Invalid mangled characters CHECK: _RNvC2a.1c @@ -17,6 +65,14 @@ CHECK: _RNvC2a$1c _RNvC2a$1c +CHECK: _RNvCs._1a1b + _RNvCs._1a1b + +; Invalid namespace + +CHECK: _RNvN_NvC2ns1i01f + _RNvN_NvC2ns1i01f + ; Invalid identifier length (UINT64_MAX + 3, which happens to be ok after a wraparound). CHECK: _RNvC2ab18446744073709551618xy @@ -41,3 +97,23 @@ CHECK: _RNvC1a20abc _RNvC1a20abc + +; Invalid backreferences + +CHECK: _RB_ + _RB_ + +CHECK: _RB9_ + _RB9_ + +CHECK: _RB_1a + _RB_1a + +CHECK: _RB_RMRX + _RB_RMRX + +CHECK: _RNvNvB_1a1b1c + _RNvNvB_1a1b1c + +CHECK: _RINvCshGpAVYOtgW1_1a1fTlllEB_EB2_ + _RINvCshGpAVYOtgW1_1a1fTlllEB_EB2_