1 //===--- RustDemangle.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a demangler for Rust v0 mangled symbols as specified in
10 // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Demangle/RustDemangle.h"
15 #include "llvm/Demangle/Demangle.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstring>
20 #include <limits>
21 
22 using namespace llvm;
23 using namespace rust_demangle;
24 
25 char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N,
26                          int *Status) {
27   if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
28     if (Status != nullptr)
29       *Status = demangle_invalid_args;
30     return nullptr;
31   }
32 
33   // Return early if mangled name doesn't look like a Rust symbol.
34   StringView Mangled(MangledName);
35   if (!Mangled.startsWith("_R")) {
36     if (Status != nullptr)
37       *Status = demangle_invalid_mangled_name;
38     return nullptr;
39   }
40 
41   Demangler D;
42   if (!initializeOutputStream(nullptr, nullptr, D.Output, 1024)) {
43     if (Status != nullptr)
44       *Status = demangle_memory_alloc_failure;
45     return nullptr;
46   }
47 
48   if (!D.demangle(Mangled)) {
49     if (Status != nullptr)
50       *Status = demangle_invalid_mangled_name;
51     std::free(D.Output.getBuffer());
52     return nullptr;
53   }
54 
55   D.Output += '\0';
56   char *Demangled = D.Output.getBuffer();
57   size_t DemangledLen = D.Output.getCurrentPosition();
58 
59   if (Buf != nullptr) {
60     if (DemangledLen <= *N) {
61       std::memcpy(Buf, Demangled, DemangledLen);
62       std::free(Demangled);
63       Demangled = Buf;
64     } else {
65       std::free(Buf);
66     }
67   }
68 
69   if (N != nullptr)
70     *N = DemangledLen;
71 
72   if (Status != nullptr)
73     *Status = demangle_success;
74 
75   return Demangled;
76 }
77 
78 Demangler::Demangler(size_t MaxRecursionLevel)
79     : MaxRecursionLevel(MaxRecursionLevel) {}
80 
81 static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
82 
83 static inline bool isHexDigit(const char C) {
84   return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
85 }
86 
87 static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
88 
89 static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
90 
91 /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
92 static inline bool isValid(const char C) {
93   return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
94 }
95 
96 // Demangles Rust v0 mangled symbol. Returns true when successful, and false
97 // otherwise. The demangled symbol is stored in Output field. It is
98 // responsibility of the caller to free the memory behind the output stream.
99 //
100 // <symbol-name> = "_R" <path> [<instantiating-crate>]
101 bool Demangler::demangle(StringView Mangled) {
102   Position = 0;
103   Error = false;
104   Print = true;
105   RecursionLevel = 0;
106   BoundLifetimes = 0;
107 
108   if (!Mangled.consumeFront("_R")) {
109     Error = true;
110     return false;
111   }
112   Input = Mangled;
113 
114   demanglePath(rust_demangle::InType::No);
115 
116   if (Position != Input.size()) {
117     SwapAndRestore<bool> SavePrint(Print, false);
118     demanglePath(InType::No);
119   }
120 
121   if (Position != Input.size())
122     Error = true;
123 
124   return !Error;
125 }
126 
127 // Demangles a path. InType indicates whether a path is inside a type. When
128 // LeaveOpen is true, a closing `>` after generic arguments is omitted from the
129 // output. Return value indicates whether generics arguments have been left
130 // open.
131 //
132 // <path> = "C" <identifier>               // crate root
133 //        | "M" <impl-path> <type>         // <T> (inherent impl)
134 //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
135 //        | "Y" <type> <path>              // <T as Trait> (trait definition)
136 //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
137 //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
138 //        | <backref>
139 // <identifier> = [<disambiguator>] <undisambiguated-identifier>
140 // <ns> = "C"      // closure
141 //      | "S"      // shim
142 //      | <A-Z>    // other special namespaces
143 //      | <a-z>    // internal namespaces
144 bool Demangler::demanglePath(InType InType, LeaveOpen LeaveOpen) {
145   if (Error || RecursionLevel >= MaxRecursionLevel) {
146     Error = true;
147     return false;
148   }
149   SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
150 
151   switch (consume()) {
152   case 'C': {
153     parseOptionalBase62Number('s');
154     Identifier Ident = parseIdentifier();
155     print(Ident.Name);
156     break;
157   }
158   case 'M': {
159     demangleImplPath(InType);
160     print("<");
161     demangleType();
162     print(">");
163     break;
164   }
165   case 'X': {
166     demangleImplPath(InType);
167     print("<");
168     demangleType();
169     print(" as ");
170     demanglePath(rust_demangle::InType::Yes);
171     print(">");
172     break;
173   }
174   case 'Y': {
175     print("<");
176     demangleType();
177     print(" as ");
178     demanglePath(rust_demangle::InType::Yes);
179     print(">");
180     break;
181   }
182   case 'N': {
183     char NS = consume();
184     if (!isLower(NS) && !isUpper(NS)) {
185       Error = true;
186       break;
187     }
188     demanglePath(InType);
189 
190     uint64_t Disambiguator = parseOptionalBase62Number('s');
191     Identifier Ident = parseIdentifier();
192 
193     if (isUpper(NS)) {
194       // Special namespaces
195       print("::{");
196       if (NS == 'C')
197         print("closure");
198       else if (NS == 'S')
199         print("shim");
200       else
201         print(NS);
202       if (!Ident.empty()) {
203         print(":");
204         print(Ident.Name);
205       }
206       print('#');
207       printDecimalNumber(Disambiguator);
208       print('}');
209     } else {
210       // Implementation internal namespaces.
211       if (!Ident.empty()) {
212         print("::");
213         print(Ident.Name);
214       }
215     }
216     break;
217   }
218   case 'I': {
219     demanglePath(InType);
220     // Omit "::" when in a type, where it is optional.
221     if (InType == rust_demangle::InType::No)
222       print("::");
223     print("<");
224     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
225       if (I > 0)
226         print(", ");
227       demangleGenericArg();
228     }
229     if (LeaveOpen == rust_demangle::LeaveOpen::Yes)
230       return true;
231     else
232       print(">");
233     break;
234   }
235   case 'B': {
236     bool IsOpen = false;
237     demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
238     return IsOpen;
239   }
240   default:
241     Error = true;
242     break;
243   }
244 
245   return false;
246 }
247 
248 // <impl-path> = [<disambiguator>] <path>
249 // <disambiguator> = "s" <base-62-number>
250 void Demangler::demangleImplPath(InType InType) {
251   SwapAndRestore<bool> SavePrint(Print, false);
252   parseOptionalBase62Number('s');
253   demanglePath(InType);
254 }
255 
256 // <generic-arg> = <lifetime>
257 //               | <type>
258 //               | "K" <const>
259 // <lifetime> = "L" <base-62-number>
260 void Demangler::demangleGenericArg() {
261   if (consumeIf('L'))
262     printLifetime(parseBase62Number());
263   else if (consumeIf('K'))
264     demangleConst();
265   else
266     demangleType();
267 }
268 
269 // <basic-type> = "a"      // i8
270 //              | "b"      // bool
271 //              | "c"      // char
272 //              | "d"      // f64
273 //              | "e"      // str
274 //              | "f"      // f32
275 //              | "h"      // u8
276 //              | "i"      // isize
277 //              | "j"      // usize
278 //              | "l"      // i32
279 //              | "m"      // u32
280 //              | "n"      // i128
281 //              | "o"      // u128
282 //              | "s"      // i16
283 //              | "t"      // u16
284 //              | "u"      // ()
285 //              | "v"      // ...
286 //              | "x"      // i64
287 //              | "y"      // u64
288 //              | "z"      // !
289 //              | "p"      // placeholder (e.g. for generic params), shown as _
290 static bool parseBasicType(char C, BasicType &Type) {
291   switch (C) {
292   case 'a':
293     Type = BasicType::I8;
294     return true;
295   case 'b':
296     Type = BasicType::Bool;
297     return true;
298   case 'c':
299     Type = BasicType::Char;
300     return true;
301   case 'd':
302     Type = BasicType::F64;
303     return true;
304   case 'e':
305     Type = BasicType::Str;
306     return true;
307   case 'f':
308     Type = BasicType::F32;
309     return true;
310   case 'h':
311     Type = BasicType::U8;
312     return true;
313   case 'i':
314     Type = BasicType::ISize;
315     return true;
316   case 'j':
317     Type = BasicType::USize;
318     return true;
319   case 'l':
320     Type = BasicType::I32;
321     return true;
322   case 'm':
323     Type = BasicType::U32;
324     return true;
325   case 'n':
326     Type = BasicType::I128;
327     return true;
328   case 'o':
329     Type = BasicType::U128;
330     return true;
331   case 'p':
332     Type = BasicType::Placeholder;
333     return true;
334   case 's':
335     Type = BasicType::I16;
336     return true;
337   case 't':
338     Type = BasicType::U16;
339     return true;
340   case 'u':
341     Type = BasicType::Unit;
342     return true;
343   case 'v':
344     Type = BasicType::Variadic;
345     return true;
346   case 'x':
347     Type = BasicType::I64;
348     return true;
349   case 'y':
350     Type = BasicType::U64;
351     return true;
352   case 'z':
353     Type = BasicType::Never;
354     return true;
355   default:
356     return false;
357   }
358 }
359 
360 void Demangler::printBasicType(BasicType Type) {
361   switch (Type) {
362   case BasicType::Bool:
363     print("bool");
364     break;
365   case BasicType::Char:
366     print("char");
367     break;
368   case BasicType::I8:
369     print("i8");
370     break;
371   case BasicType::I16:
372     print("i16");
373     break;
374   case BasicType::I32:
375     print("i32");
376     break;
377   case BasicType::I64:
378     print("i64");
379     break;
380   case BasicType::I128:
381     print("i128");
382     break;
383   case BasicType::ISize:
384     print("isize");
385     break;
386   case BasicType::U8:
387     print("u8");
388     break;
389   case BasicType::U16:
390     print("u16");
391     break;
392   case BasicType::U32:
393     print("u32");
394     break;
395   case BasicType::U64:
396     print("u64");
397     break;
398   case BasicType::U128:
399     print("u128");
400     break;
401   case BasicType::USize:
402     print("usize");
403     break;
404   case BasicType::F32:
405     print("f32");
406     break;
407   case BasicType::F64:
408     print("f64");
409     break;
410   case BasicType::Str:
411     print("str");
412     break;
413   case BasicType::Placeholder:
414     print("_");
415     break;
416   case BasicType::Unit:
417     print("()");
418     break;
419   case BasicType::Variadic:
420     print("...");
421     break;
422   case BasicType::Never:
423     print("!");
424     break;
425   }
426 }
427 
428 // <type> = | <basic-type>
429 //          | <path>                      // named type
430 //          | "A" <type> <const>          // [T; N]
431 //          | "S" <type>                  // [T]
432 //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
433 //          | "R" [<lifetime>] <type>     // &T
434 //          | "Q" [<lifetime>] <type>     // &mut T
435 //          | "P" <type>                  // *const T
436 //          | "O" <type>                  // *mut T
437 //          | "F" <fn-sig>                // fn(...) -> ...
438 //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
439 //          | <backref>                   // backref
440 void Demangler::demangleType() {
441   if (Error || RecursionLevel >= MaxRecursionLevel) {
442     Error = true;
443     return;
444   }
445   SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
446 
447   size_t Start = Position;
448   char C = consume();
449   BasicType Type;
450   if (parseBasicType(C, Type))
451     return printBasicType(Type);
452 
453   switch (C) {
454   case 'A':
455     print("[");
456     demangleType();
457     print("; ");
458     demangleConst();
459     print("]");
460     break;
461   case 'S':
462     print("[");
463     demangleType();
464     print("]");
465     break;
466   case 'T': {
467     print("(");
468     size_t I = 0;
469     for (; !Error && !consumeIf('E'); ++I) {
470       if (I > 0)
471         print(", ");
472       demangleType();
473     }
474     if (I == 1)
475       print(",");
476     print(")");
477     break;
478   }
479   case 'R':
480   case 'Q':
481     print('&');
482     if (consumeIf('L')) {
483       if (auto Lifetime = parseBase62Number()) {
484         printLifetime(Lifetime);
485         print(' ');
486       }
487     }
488     if (C == 'Q')
489       print("mut ");
490     demangleType();
491     break;
492   case 'P':
493     print("*const ");
494     demangleType();
495     break;
496   case 'O':
497     print("*mut ");
498     demangleType();
499     break;
500   case 'F':
501     demangleFnSig();
502     break;
503   case 'D':
504     demangleDynBounds();
505     if (consumeIf('L')) {
506       if (auto Lifetime = parseBase62Number()) {
507         print(" + ");
508         printLifetime(Lifetime);
509       }
510     } else {
511       Error = true;
512     }
513     break;
514   case 'B':
515     demangleBackref([&] { demangleType(); });
516     break;
517   default:
518     Position = Start;
519     demanglePath(rust_demangle::InType::Yes);
520     break;
521   }
522 }
523 
524 // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
525 // <abi> = "C"
526 //       | <undisambiguated-identifier>
527 void Demangler::demangleFnSig() {
528   SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
529   demangleOptionalBinder();
530 
531   if (consumeIf('U'))
532     print("unsafe ");
533 
534   if (consumeIf('K')) {
535     print("extern \"");
536     if (consumeIf('C')) {
537       print("C");
538     } else {
539       Identifier Ident = parseIdentifier();
540       for (char C : Ident.Name) {
541         // When mangling ABI string, the "-" is replaced with "_".
542         if (C == '_')
543           C = '-';
544         print(C);
545       }
546     }
547     print("\" ");
548   }
549 
550   print("fn(");
551   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
552     if (I > 0)
553       print(", ");
554     demangleType();
555   }
556   print(")");
557 
558   if (consumeIf('u')) {
559     // Skip the unit type from the output.
560   } else {
561     print(" -> ");
562     demangleType();
563   }
564 }
565 
566 // <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
567 void Demangler::demangleDynBounds() {
568   SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
569   print("dyn ");
570   demangleOptionalBinder();
571   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
572     if (I > 0)
573       print(" + ");
574     demangleDynTrait();
575   }
576 }
577 
578 // <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
579 // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
580 void Demangler::demangleDynTrait() {
581   bool IsOpen = demanglePath(InType::Yes, LeaveOpen::Yes);
582   while (!Error && consumeIf('p')) {
583     if (!IsOpen) {
584       IsOpen = true;
585       print('<');
586     } else {
587       print(", ");
588     }
589     print(parseIdentifier().Name);
590     print(" = ");
591     demangleType();
592   }
593   if (IsOpen)
594     print(">");
595 }
596 
597 // Demangles optional binder and updates the number of bound lifetimes.
598 //
599 // <binder> = "G" <base-62-number>
600 void Demangler::demangleOptionalBinder() {
601   uint64_t Binder = parseOptionalBase62Number('G');
602   if (Error || Binder == 0)
603     return;
604 
605   // In valid inputs each bound lifetime is referenced later. Referencing a
606   // lifetime requires at least one byte of input. Reject inputs that are too
607   // short to reference all bound lifetimes. Otherwise demangling of invalid
608   // binders could generate excessive amounts of output.
609   if (Binder >= Input.size() - BoundLifetimes) {
610     Error = true;
611     return;
612   }
613 
614   print("for<");
615   for (size_t I = 0; I != Binder; ++I) {
616     BoundLifetimes += 1;
617     if (I > 0)
618       print(", ");
619     printLifetime(1);
620   }
621   print("> ");
622 }
623 
624 // <const> = <basic-type> <const-data>
625 //         | "p"                          // placeholder
626 //         | <backref>
627 void Demangler::demangleConst() {
628   BasicType Type;
629   if (parseBasicType(consume(), Type)) {
630     switch (Type) {
631     case BasicType::I8:
632     case BasicType::I16:
633     case BasicType::I32:
634     case BasicType::I64:
635     case BasicType::I128:
636     case BasicType::ISize:
637     case BasicType::U8:
638     case BasicType::U16:
639     case BasicType::U32:
640     case BasicType::U64:
641     case BasicType::U128:
642     case BasicType::USize:
643       demangleConstInt();
644       break;
645     case BasicType::Bool:
646       demangleConstBool();
647       break;
648     case BasicType::Char:
649       demangleConstChar();
650       break;
651     case BasicType::Placeholder:
652       print('_');
653       break;
654     default:
655       // FIXME demangle backreferences.
656       Error = true;
657       break;
658     }
659   } else {
660     Error = true;
661   }
662 }
663 
664 // <const-data> = ["n"] <hex-number>
665 void Demangler::demangleConstInt() {
666   if (consumeIf('n'))
667     print('-');
668 
669   StringView HexDigits;
670   uint64_t Value = parseHexNumber(HexDigits);
671   if (HexDigits.size() <= 16) {
672     printDecimalNumber(Value);
673   } else {
674     print("0x");
675     print(HexDigits);
676   }
677 }
678 
679 // <const-data> = "0_" // false
680 //              | "1_" // true
681 void Demangler::demangleConstBool() {
682   StringView HexDigits;
683   parseHexNumber(HexDigits);
684   if (HexDigits == "0")
685     print("false");
686   else if (HexDigits == "1")
687     print("true");
688   else
689     Error = true;
690 }
691 
692 /// Returns true if CodePoint represents a printable ASCII character.
693 static bool isAsciiPrintable(uint64_t CodePoint) {
694   return 0x20 <= CodePoint && CodePoint <= 0x7e;
695 }
696 
697 // <const-data> = <hex-number>
698 void Demangler::demangleConstChar() {
699   StringView HexDigits;
700   uint64_t CodePoint = parseHexNumber(HexDigits);
701   if (Error || HexDigits.size() > 6) {
702     Error = true;
703     return;
704   }
705 
706   print("'");
707   switch (CodePoint) {
708   case '\t':
709     print(R"(\t)");
710     break;
711   case '\r':
712     print(R"(\r)");
713     break;
714   case '\n':
715     print(R"(\n)");
716     break;
717   case '\\':
718     print(R"(\\)");
719     break;
720   case '"':
721     print(R"(")");
722     break;
723   case '\'':
724     print(R"(\')");
725     break;
726   default:
727     if (isAsciiPrintable(CodePoint)) {
728       char C = CodePoint;
729       print(C);
730     } else {
731       print(R"(\u{)");
732       print(HexDigits);
733       print('}');
734     }
735     break;
736   }
737   print('\'');
738 }
739 
740 // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
741 Identifier Demangler::parseIdentifier() {
742   bool Punycode = consumeIf('u');
743   uint64_t Bytes = parseDecimalNumber();
744 
745   // Underscore resolves the ambiguity when identifier starts with a decimal
746   // digit or another underscore.
747   consumeIf('_');
748 
749   if (Error || Bytes > Input.size() - Position) {
750     Error = true;
751     return {};
752   }
753   StringView S = Input.substr(Position, Bytes);
754   Position += Bytes;
755 
756   if (!std::all_of(S.begin(), S.end(), isValid)) {
757     Error = true;
758     return {};
759   }
760 
761   return {S, Punycode};
762 }
763 
764 // Parses optional base 62 number. The presence of a number is determined using
765 // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
766 //
767 // This function is indended for parsing disambiguators and binders which when
768 // not present have their value interpreted as 0, and otherwise as decoded
769 // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
770 // 2. When "G" is absent value is 0.
771 uint64_t Demangler::parseOptionalBase62Number(char Tag) {
772   if (!consumeIf(Tag))
773     return 0;
774 
775   uint64_t N = parseBase62Number();
776   if (Error || !addAssign(N, 1))
777     return 0;
778 
779   return N;
780 }
781 
782 // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
783 // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
784 // "1_" encodes 2, etc.
785 //
786 // <base-62-number> = {<0-9a-zA-Z>} "_"
787 uint64_t Demangler::parseBase62Number() {
788   if (consumeIf('_'))
789     return 0;
790 
791   uint64_t Value = 0;
792 
793   while (true) {
794     uint64_t Digit;
795     char C = consume();
796 
797     if (C == '_') {
798       break;
799     } else if (isDigit(C)) {
800       Digit = C - '0';
801     } else if (isLower(C)) {
802       Digit = 10 + (C - 'a');
803     } else if (isUpper(C)) {
804       Digit = 10 + 26 + (C - 'A');
805     } else {
806       Error = true;
807       return 0;
808     }
809 
810     if (!mulAssign(Value, 62))
811       return 0;
812 
813     if (!addAssign(Value, Digit))
814       return 0;
815   }
816 
817   if (!addAssign(Value, 1))
818     return 0;
819 
820   return Value;
821 }
822 
823 // Parses a decimal number that had been encoded without any leading zeros.
824 //
825 // <decimal-number> = "0"
826 //                  | <1-9> {<0-9>}
827 uint64_t Demangler::parseDecimalNumber() {
828   char C = look();
829   if (!isDigit(C)) {
830     Error = true;
831     return 0;
832   }
833 
834   if (C == '0') {
835     consume();
836     return 0;
837   }
838 
839   uint64_t Value = 0;
840 
841   while (isDigit(look())) {
842     if (!mulAssign(Value, 10)) {
843       Error = true;
844       return 0;
845     }
846 
847     uint64_t D = consume() - '0';
848     if (!addAssign(Value, D))
849       return 0;
850   }
851 
852   return Value;
853 }
854 
855 // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
856 // value and stores hex digits in HexDigits. The return value is unspecified if
857 // HexDigits.size() > 16.
858 //
859 // <hex-number> = "0_"
860 //              | <1-9a-f> {<0-9a-f>} "_"
861 uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
862   size_t Start = Position;
863   uint64_t Value = 0;
864 
865   if (!isHexDigit(look()))
866     Error = true;
867 
868   if (consumeIf('0')) {
869     if (!consumeIf('_'))
870       Error = true;
871   } else {
872     while (!Error && !consumeIf('_')) {
873       char C = consume();
874       Value *= 16;
875       if (isDigit(C))
876         Value += C - '0';
877       else if ('a' <= C && C <= 'f')
878         Value += 10 + (C - 'a');
879       else
880         Error = true;
881     }
882   }
883 
884   if (Error) {
885     HexDigits = StringView();
886     return 0;
887   }
888 
889   size_t End = Position - 1;
890   assert(Start < End);
891   HexDigits = Input.substr(Start, End - Start);
892   return Value;
893 }
894 
895 // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
896 // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
897 // bound by one of the enclosing binders.
898 void Demangler::printLifetime(uint64_t Index) {
899   if (Index == 0) {
900     print("'_");
901     return;
902   }
903 
904   if (Index - 1 >= BoundLifetimes) {
905     Error = true;
906     return;
907   }
908 
909   uint64_t Depth = BoundLifetimes - Index;
910   print('\'');
911   if (Depth < 26) {
912     char C = 'a' + Depth;
913     print(C);
914   } else {
915     print('z');
916     printDecimalNumber(Depth - 26 + 1);
917   }
918 }
919