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; @@ -52,10 +54,17 @@ void demanglePath(); Identifier parseIdentifier(); - void parseOptionalBase62Number(char Tag); + uint64_t parseOptionalBase62Number(char Tag); uint64_t parseBase62Number(); uint64_t parseDecimalNumber(); + void print(char C) { + if (Error) + return; + + Output += C; + } + void print(StringView S) { if (Error) return; @@ -63,6 +72,13 @@ Output += S; } + void printDecimalNumber(uint64_t N) { + if (Error) + 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 @@ -132,7 +132,7 @@ Error = true; return; } - RecursionLevel += 1; + SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); switch (consume()) { case 'C': { @@ -149,15 +149,31 @@ } 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; } @@ -166,8 +182,6 @@ Error = true; break; } - - RecursionLevel -= 1; } // = ["u"] ["_"] @@ -195,11 +209,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,30 @@ CHECK: a::b::c _RNvNvC1a1b1c +; Closure namespace + +CHECK: ns::f::{closure#0} + _RNCNvCs21hi0yVfW1J_2ns1f0 + +CHECK: ns::f::{closure#1} + _RNCNvCs21hi0yVfW1J_2ns1fs_0 + +CHECK: ns::f::{closure#1}::{closure#0} + _RNCNCNvCs21hi0yVfW1J_2ns1fs_00 + +CHECK: ns::f::{closure#1}::g + _RNvNCNvCs21hi0yVfW1J_2ns1fs_01g + +; Shim namespace + +CHECK: ns::g::{shim:reify#0} + _RNSNvCshGpAVYOtgW1_2ns1g5reify + +; Unrecognized special namespace + +CHECK: a::{B:c#10} + _RNBC1as8_1c + ; Invalid mangled characters CHECK: _RNvC2a.1c @@ -17,6 +41,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