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 @@ -62,7 +62,7 @@ size_t MaxRecursionLevel; // Current recursion level. size_t RecursionLevel; - + size_t BoundLifetimes; // Input string that is being demangled with "_R" prefix removed. StringView Input; // Position in the input string. @@ -89,6 +89,7 @@ void demangleGenericArg(); void demangleType(); void demangleFnSig(); + void demangleOptionalBinder(); void demangleConst(); void demangleConstInt(); void demangleConstBool(); @@ -122,6 +123,7 @@ } void printBasicType(BasicType); + void printLifetime(uint64_t Index); char look() const { if (Error || Position >= Input.size()) 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 @@ -103,6 +103,7 @@ Error = false; Print = true; RecursionLevel = 0; + BoundLifetimes = 0; if (!Mangled.consumeFront("_R")) { Error = true; @@ -242,11 +243,12 @@ // | "K" // = "L" void Demangler::demangleGenericArg() { - if (consumeIf('K')) + if (consumeIf('L')) + printLifetime(parseBase62Number()); + else if (consumeIf('K')) demangleConst(); else demangleType(); - // FIXME demangle lifetimes. } // = "a" // i8 @@ -455,13 +457,16 @@ break; } case 'R': - print("&"); - // FIXME demangle []. - demangleType(); - break; case 'Q': - print("&mut "); - // FIXME demangle []. + print('&'); + if (consumeIf('L')) { + if (auto Lifetime = parseBase62Number()) { + printLifetime(Lifetime); + print(' '); + } + } + if (C == 'Q') + print("mut "); demangleType(); break; case 'P': @@ -486,7 +491,8 @@ // = "C" // | void Demangler::demangleFnSig() { - // FIXME demangle binder. + SwapAndRestore SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + demangleOptionalBinder(); if (consumeIf('U')) print("unsafe "); @@ -523,6 +529,33 @@ } } +// Demangles optional binder and updates the number of bound lifetimes. +// +// = "G" +void Demangler::demangleOptionalBinder() { + uint64_t Binder = parseOptionalBase62Number('G'); + if (Error || Binder == 0) + return; + + // In valid inputs each bound lifetime is referenced later. Referencing a + // lifetime requires at least one byte of input. Reject inputs that are too + // short to reference all bound lifetimes. Otherwise demangling of invalid + // binders could generate excessive amounts of output. + if (Binder >= Input.size() - BoundLifetimes) { + Error = true; + return; + } + + print("for<"); + for (size_t I = 0; I != Binder; ++I) { + BoundLifetimes += 1; + if (I > 0) + print(", "); + printLifetime(1); + } + print("> "); +} + // = // | "p" // placeholder // | @@ -664,7 +697,12 @@ } // Parses optional base 62 number. The presence of a number is determined using -// Tag. Returns 0 when tag is absent and parsed value + 1 otherwise. +// Tag. Returns 0 when tag is absent and parsed value + 1 otherwise +// +// This function is indended for parsing disambiguators and binders which when +// not present have their value interpreted as 0, and otherwise as decoded +// value + 1. For example for binders, value for "G_" is 1, for "G0_" value is +// 2. When "G" is absent value is 0. uint64_t Demangler::parseOptionalBase62Number(char Tag) { if (!consumeIf(Tag)) return 0; @@ -788,3 +826,28 @@ HexDigits = Input.substr(Start, End - Start); return Value; } + +// Prints a lifetime. An index 0 always represents an erased lifetime. Indices +// starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes +// bound by one of the enclosing binders. +void Demangler::printLifetime(uint64_t Index) { + if (Index == 0) { + print("'_"); + return; + } + + if (Index - 1 >= BoundLifetimes) { + Error = true; + return; + } + + uint64_t Depth = BoundLifetimes - Index; + print('\''); + if (Depth < 26) { + char C = 'a' + Depth; + print(C); + } else { + print('z'); + printDecimalNumber(Depth - 26 + 1); + } +} 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 @@ -70,6 +70,16 @@ CHECK: generic_const::<_> _RIC13generic_constKpE +; Generic lifetime arguments + +CHECK: generic_lifetime::<'_> + _RIC16generic_lifetimeL_E + +; Invalid lifetime index. + +CHECK: _RIC16generic_lifetimeL0_E + _RIC16generic_lifetimeL0_E + ; Basic types CHECK: basic:: @@ -178,9 +188,15 @@ CHECK: types::<&_> _RIC5typesRpE +CHECK: types::<&_> + _RIC5typesRL_pE + CHECK: types::<&mut _> _RIC5typesQpE +CHECK: types::<&mut _> + _RIC5typesQL_pE + CHECK: types::<*const _> _RIC5typesPpE @@ -216,6 +232,28 @@ CHECK: function:: _RIC8functionFUK21C_cmse_nonsecure_callEuE +; Binders + +CHECK: binders:: fn(&'a _)> + _RIC7bindersFG_RL0_pEuE + +CHECK: binders:: fn(&'a mut _)> + _RIC7bindersFG_QL0_pEuE + +CHECK: binders:: fn(&'a _, &'b _)> + _RIC7bindersFG0_RL1_pRL0_pEuE + +CHECK: binders:: fn() -> for<'c, 'd> fn(&'a _, &'d _)> + _RIC7bindersFG0_EFG0_RL3_pRL0_pEuE + +CHECK: binders:: fn(&'a &'b &'c &'d &'e &'f &'g &'h &'i &'j &'k &'l &'m &'n &'o &'p &'q &'r &'s &'t &'u &'v &'w &'x &'y &'z &'z1 &'z2 &'z3 &'z4 ())> + _RIC7bindersFGs_RLt_RLs_RLr_RLq_RLp_RLo_RLn_RLm_RLl_RLk_RLj_RLi_RLh_RLg_RLf_RLe_RLd_RLc_RLb_RLa_RL9_RL8_RL7_RL6_RL5_RL4_RL3_RL2_RL1_RL0_uEuE + +; Invalid binder. Too many bound lifetimes. + +CHECK: _RIC7bindersFGFF_EuE + _RIC7bindersFGFF_EuE + ; Integer constants. Test value demangling. CHECK: integer::<0>