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   default:
236     // FIXME parse remaining productions.
237     Error = true;
238     break;
239   }
240 
241   return false;
242 }
243 
244 // <impl-path> = [<disambiguator>] <path>
245 // <disambiguator> = "s" <base-62-number>
246 void Demangler::demangleImplPath(InType InType) {
247   SwapAndRestore<bool> SavePrint(Print, false);
248   parseOptionalBase62Number('s');
249   demanglePath(InType);
250 }
251 
252 // <generic-arg> = <lifetime>
253 //               | <type>
254 //               | "K" <const>
255 // <lifetime> = "L" <base-62-number>
256 void Demangler::demangleGenericArg() {
257   if (consumeIf('L'))
258     printLifetime(parseBase62Number());
259   else if (consumeIf('K'))
260     demangleConst();
261   else
262     demangleType();
263 }
264 
265 // <basic-type> = "a"      // i8
266 //              | "b"      // bool
267 //              | "c"      // char
268 //              | "d"      // f64
269 //              | "e"      // str
270 //              | "f"      // f32
271 //              | "h"      // u8
272 //              | "i"      // isize
273 //              | "j"      // usize
274 //              | "l"      // i32
275 //              | "m"      // u32
276 //              | "n"      // i128
277 //              | "o"      // u128
278 //              | "s"      // i16
279 //              | "t"      // u16
280 //              | "u"      // ()
281 //              | "v"      // ...
282 //              | "x"      // i64
283 //              | "y"      // u64
284 //              | "z"      // !
285 //              | "p"      // placeholder (e.g. for generic params), shown as _
286 static bool parseBasicType(char C, BasicType &Type) {
287   switch (C) {
288   case 'a':
289     Type = BasicType::I8;
290     return true;
291   case 'b':
292     Type = BasicType::Bool;
293     return true;
294   case 'c':
295     Type = BasicType::Char;
296     return true;
297   case 'd':
298     Type = BasicType::F64;
299     return true;
300   case 'e':
301     Type = BasicType::Str;
302     return true;
303   case 'f':
304     Type = BasicType::F32;
305     return true;
306   case 'h':
307     Type = BasicType::U8;
308     return true;
309   case 'i':
310     Type = BasicType::ISize;
311     return true;
312   case 'j':
313     Type = BasicType::USize;
314     return true;
315   case 'l':
316     Type = BasicType::I32;
317     return true;
318   case 'm':
319     Type = BasicType::U32;
320     return true;
321   case 'n':
322     Type = BasicType::I128;
323     return true;
324   case 'o':
325     Type = BasicType::U128;
326     return true;
327   case 'p':
328     Type = BasicType::Placeholder;
329     return true;
330   case 's':
331     Type = BasicType::I16;
332     return true;
333   case 't':
334     Type = BasicType::U16;
335     return true;
336   case 'u':
337     Type = BasicType::Unit;
338     return true;
339   case 'v':
340     Type = BasicType::Variadic;
341     return true;
342   case 'x':
343     Type = BasicType::I64;
344     return true;
345   case 'y':
346     Type = BasicType::U64;
347     return true;
348   case 'z':
349     Type = BasicType::Never;
350     return true;
351   default:
352     return false;
353   }
354 }
355 
356 void Demangler::printBasicType(BasicType Type) {
357   switch (Type) {
358   case BasicType::Bool:
359     print("bool");
360     break;
361   case BasicType::Char:
362     print("char");
363     break;
364   case BasicType::I8:
365     print("i8");
366     break;
367   case BasicType::I16:
368     print("i16");
369     break;
370   case BasicType::I32:
371     print("i32");
372     break;
373   case BasicType::I64:
374     print("i64");
375     break;
376   case BasicType::I128:
377     print("i128");
378     break;
379   case BasicType::ISize:
380     print("isize");
381     break;
382   case BasicType::U8:
383     print("u8");
384     break;
385   case BasicType::U16:
386     print("u16");
387     break;
388   case BasicType::U32:
389     print("u32");
390     break;
391   case BasicType::U64:
392     print("u64");
393     break;
394   case BasicType::U128:
395     print("u128");
396     break;
397   case BasicType::USize:
398     print("usize");
399     break;
400   case BasicType::F32:
401     print("f32");
402     break;
403   case BasicType::F64:
404     print("f64");
405     break;
406   case BasicType::Str:
407     print("str");
408     break;
409   case BasicType::Placeholder:
410     print("_");
411     break;
412   case BasicType::Unit:
413     print("()");
414     break;
415   case BasicType::Variadic:
416     print("...");
417     break;
418   case BasicType::Never:
419     print("!");
420     break;
421   }
422 }
423 
424 // <type> = | <basic-type>
425 //          | <path>                      // named type
426 //          | "A" <type> <const>          // [T; N]
427 //          | "S" <type>                  // [T]
428 //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
429 //          | "R" [<lifetime>] <type>     // &T
430 //          | "Q" [<lifetime>] <type>     // &mut T
431 //          | "P" <type>                  // *const T
432 //          | "O" <type>                  // *mut T
433 //          | "F" <fn-sig>                // fn(...) -> ...
434 //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
435 //          | <backref>                   // backref
436 void Demangler::demangleType() {
437   size_t Start = Position;
438 
439   char C = consume();
440   BasicType Type;
441   if (parseBasicType(C, Type))
442     return printBasicType(Type);
443 
444   switch (C) {
445   case 'A':
446     print("[");
447     demangleType();
448     print("; ");
449     demangleConst();
450     print("]");
451     break;
452   case 'S':
453     print("[");
454     demangleType();
455     print("]");
456     break;
457   case 'T': {
458     print("(");
459     size_t I = 0;
460     for (; !Error && !consumeIf('E'); ++I) {
461       if (I > 0)
462         print(", ");
463       demangleType();
464     }
465     if (I == 1)
466       print(",");
467     print(")");
468     break;
469   }
470   case 'R':
471   case 'Q':
472     print('&');
473     if (consumeIf('L')) {
474       if (auto Lifetime = parseBase62Number()) {
475         printLifetime(Lifetime);
476         print(' ');
477       }
478     }
479     if (C == 'Q')
480       print("mut ");
481     demangleType();
482     break;
483   case 'P':
484     print("*const ");
485     demangleType();
486     break;
487   case 'O':
488     print("*mut ");
489     demangleType();
490     break;
491   case 'F':
492     demangleFnSig();
493     break;
494   case 'D':
495     demangleDynBounds();
496     if (consumeIf('L')) {
497       if (auto Lifetime = parseBase62Number()) {
498         print(" + ");
499         printLifetime(Lifetime);
500       }
501     } else {
502       Error = true;
503     }
504     break;
505   default:
506     Position = Start;
507     demanglePath(rust_demangle::InType::Yes);
508     break;
509   }
510 }
511 
512 // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
513 // <abi> = "C"
514 //       | <undisambiguated-identifier>
515 void Demangler::demangleFnSig() {
516   SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
517   demangleOptionalBinder();
518 
519   if (consumeIf('U'))
520     print("unsafe ");
521 
522   if (consumeIf('K')) {
523     print("extern \"");
524     if (consumeIf('C')) {
525       print("C");
526     } else {
527       Identifier Ident = parseIdentifier();
528       for (char C : Ident.Name) {
529         // When mangling ABI string, the "-" is replaced with "_".
530         if (C == '_')
531           C = '-';
532         print(C);
533       }
534     }
535     print("\" ");
536   }
537 
538   print("fn(");
539   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
540     if (I > 0)
541       print(", ");
542     demangleType();
543   }
544   print(")");
545 
546   if (consumeIf('u')) {
547     // Skip the unit type from the output.
548   } else {
549     print(" -> ");
550     demangleType();
551   }
552 }
553 
554 // <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
555 void Demangler::demangleDynBounds() {
556   SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
557   print("dyn ");
558   demangleOptionalBinder();
559   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
560     if (I > 0)
561       print(" + ");
562     demangleDynTrait();
563   }
564 }
565 
566 // <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
567 // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
568 void Demangler::demangleDynTrait() {
569   bool IsOpen = demanglePath(InType::Yes, LeaveOpen::Yes);
570   while (!Error && consumeIf('p')) {
571     if (!IsOpen) {
572       IsOpen = true;
573       print('<');
574     } else {
575       print(", ");
576     }
577     print(parseIdentifier().Name);
578     print(" = ");
579     demangleType();
580   }
581   if (IsOpen)
582     print(">");
583 }
584 
585 // Demangles optional binder and updates the number of bound lifetimes.
586 //
587 // <binder> = "G" <base-62-number>
588 void Demangler::demangleOptionalBinder() {
589   uint64_t Binder = parseOptionalBase62Number('G');
590   if (Error || Binder == 0)
591     return;
592 
593   // In valid inputs each bound lifetime is referenced later. Referencing a
594   // lifetime requires at least one byte of input. Reject inputs that are too
595   // short to reference all bound lifetimes. Otherwise demangling of invalid
596   // binders could generate excessive amounts of output.
597   if (Binder >= Input.size() - BoundLifetimes) {
598     Error = true;
599     return;
600   }
601 
602   print("for<");
603   for (size_t I = 0; I != Binder; ++I) {
604     BoundLifetimes += 1;
605     if (I > 0)
606       print(", ");
607     printLifetime(1);
608   }
609   print("> ");
610 }
611 
612 // <const> = <basic-type> <const-data>
613 //         | "p"                          // placeholder
614 //         | <backref>
615 void Demangler::demangleConst() {
616   BasicType Type;
617   if (parseBasicType(consume(), Type)) {
618     switch (Type) {
619     case BasicType::I8:
620     case BasicType::I16:
621     case BasicType::I32:
622     case BasicType::I64:
623     case BasicType::I128:
624     case BasicType::ISize:
625     case BasicType::U8:
626     case BasicType::U16:
627     case BasicType::U32:
628     case BasicType::U64:
629     case BasicType::U128:
630     case BasicType::USize:
631       demangleConstInt();
632       break;
633     case BasicType::Bool:
634       demangleConstBool();
635       break;
636     case BasicType::Char:
637       demangleConstChar();
638       break;
639     case BasicType::Placeholder:
640       print('_');
641       break;
642     default:
643       // FIXME demangle backreferences.
644       Error = true;
645       break;
646     }
647   } else {
648     Error = true;
649   }
650 }
651 
652 // <const-data> = ["n"] <hex-number>
653 void Demangler::demangleConstInt() {
654   if (consumeIf('n'))
655     print('-');
656 
657   StringView HexDigits;
658   uint64_t Value = parseHexNumber(HexDigits);
659   if (HexDigits.size() <= 16) {
660     printDecimalNumber(Value);
661   } else {
662     print("0x");
663     print(HexDigits);
664   }
665 }
666 
667 // <const-data> = "0_" // false
668 //              | "1_" // true
669 void Demangler::demangleConstBool() {
670   StringView HexDigits;
671   parseHexNumber(HexDigits);
672   if (HexDigits == "0")
673     print("false");
674   else if (HexDigits == "1")
675     print("true");
676   else
677     Error = true;
678 }
679 
680 /// Returns true if CodePoint represents a printable ASCII character.
681 static bool isAsciiPrintable(uint64_t CodePoint) {
682   return 0x20 <= CodePoint && CodePoint <= 0x7e;
683 }
684 
685 // <const-data> = <hex-number>
686 void Demangler::demangleConstChar() {
687   StringView HexDigits;
688   uint64_t CodePoint = parseHexNumber(HexDigits);
689   if (Error || HexDigits.size() > 6) {
690     Error = true;
691     return;
692   }
693 
694   print("'");
695   switch (CodePoint) {
696   case '\t':
697     print(R"(\t)");
698     break;
699   case '\r':
700     print(R"(\r)");
701     break;
702   case '\n':
703     print(R"(\n)");
704     break;
705   case '\\':
706     print(R"(\\)");
707     break;
708   case '"':
709     print(R"(")");
710     break;
711   case '\'':
712     print(R"(\')");
713     break;
714   default:
715     if (isAsciiPrintable(CodePoint)) {
716       char C = CodePoint;
717       print(C);
718     } else {
719       print(R"(\u{)");
720       print(HexDigits);
721       print('}');
722     }
723     break;
724   }
725   print('\'');
726 }
727 
728 // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
729 Identifier Demangler::parseIdentifier() {
730   bool Punycode = consumeIf('u');
731   uint64_t Bytes = parseDecimalNumber();
732 
733   // Underscore resolves the ambiguity when identifier starts with a decimal
734   // digit or another underscore.
735   consumeIf('_');
736 
737   if (Error || Bytes > Input.size() - Position) {
738     Error = true;
739     return {};
740   }
741   StringView S = Input.substr(Position, Bytes);
742   Position += Bytes;
743 
744   if (!std::all_of(S.begin(), S.end(), isValid)) {
745     Error = true;
746     return {};
747   }
748 
749   return {S, Punycode};
750 }
751 
752 // Parses optional base 62 number. The presence of a number is determined using
753 // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
754 //
755 // This function is indended for parsing disambiguators and binders which when
756 // not present have their value interpreted as 0, and otherwise as decoded
757 // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
758 // 2. When "G" is absent value is 0.
759 uint64_t Demangler::parseOptionalBase62Number(char Tag) {
760   if (!consumeIf(Tag))
761     return 0;
762 
763   uint64_t N = parseBase62Number();
764   if (Error || !addAssign(N, 1))
765     return 0;
766 
767   return N;
768 }
769 
770 // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
771 // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
772 // "1_" encodes 2, etc.
773 //
774 // <base-62-number> = {<0-9a-zA-Z>} "_"
775 uint64_t Demangler::parseBase62Number() {
776   if (consumeIf('_'))
777     return 0;
778 
779   uint64_t Value = 0;
780 
781   while (true) {
782     uint64_t Digit;
783     char C = consume();
784 
785     if (C == '_') {
786       break;
787     } else if (isDigit(C)) {
788       Digit = C - '0';
789     } else if (isLower(C)) {
790       Digit = 10 + (C - 'a');
791     } else if (isUpper(C)) {
792       Digit = 10 + 26 + (C - 'A');
793     } else {
794       Error = true;
795       return 0;
796     }
797 
798     if (!mulAssign(Value, 62))
799       return 0;
800 
801     if (!addAssign(Value, Digit))
802       return 0;
803   }
804 
805   if (!addAssign(Value, 1))
806     return 0;
807 
808   return Value;
809 }
810 
811 // Parses a decimal number that had been encoded without any leading zeros.
812 //
813 // <decimal-number> = "0"
814 //                  | <1-9> {<0-9>}
815 uint64_t Demangler::parseDecimalNumber() {
816   char C = look();
817   if (!isDigit(C)) {
818     Error = true;
819     return 0;
820   }
821 
822   if (C == '0') {
823     consume();
824     return 0;
825   }
826 
827   uint64_t Value = 0;
828 
829   while (isDigit(look())) {
830     if (!mulAssign(Value, 10)) {
831       Error = true;
832       return 0;
833     }
834 
835     uint64_t D = consume() - '0';
836     if (!addAssign(Value, D))
837       return 0;
838   }
839 
840   return Value;
841 }
842 
843 // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
844 // value and stores hex digits in HexDigits. The return value is unspecified if
845 // HexDigits.size() > 16.
846 //
847 // <hex-number> = "0_"
848 //              | <1-9a-f> {<0-9a-f>} "_"
849 uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
850   size_t Start = Position;
851   uint64_t Value = 0;
852 
853   if (!isHexDigit(look()))
854     Error = true;
855 
856   if (consumeIf('0')) {
857     if (!consumeIf('_'))
858       Error = true;
859   } else {
860     while (!Error && !consumeIf('_')) {
861       char C = consume();
862       Value *= 16;
863       if (isDigit(C))
864         Value += C - '0';
865       else if ('a' <= C && C <= 'f')
866         Value += 10 + (C - 'a');
867       else
868         Error = true;
869     }
870   }
871 
872   if (Error) {
873     HexDigits = StringView();
874     return 0;
875   }
876 
877   size_t End = Position - 1;
878   assert(Start < End);
879   HexDigits = Input.substr(Start, End - Start);
880   return Value;
881 }
882 
883 // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
884 // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
885 // bound by one of the enclosing binders.
886 void Demangler::printLifetime(uint64_t Index) {
887   if (Index == 0) {
888     print("'_");
889     return;
890   }
891 
892   if (Index - 1 >= BoundLifetimes) {
893     Error = true;
894     return;
895   }
896 
897   uint64_t Depth = BoundLifetimes - Index;
898   print('\'');
899   if (Depth < 26) {
900     char C = 'a' + Depth;
901     print(C);
902   } else {
903     print('z');
904     printDecimalNumber(Depth - 26 + 1);
905   }
906 }
907