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 if (Error || RecursionLevel >= MaxRecursionLevel) { 629 Error = true; 630 return; 631 } 632 SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 633 634 char C = consume(); 635 BasicType Type; 636 if (parseBasicType(C, Type)) { 637 switch (Type) { 638 case BasicType::I8: 639 case BasicType::I16: 640 case BasicType::I32: 641 case BasicType::I64: 642 case BasicType::I128: 643 case BasicType::ISize: 644 case BasicType::U8: 645 case BasicType::U16: 646 case BasicType::U32: 647 case BasicType::U64: 648 case BasicType::U128: 649 case BasicType::USize: 650 demangleConstInt(); 651 break; 652 case BasicType::Bool: 653 demangleConstBool(); 654 break; 655 case BasicType::Char: 656 demangleConstChar(); 657 break; 658 case BasicType::Placeholder: 659 print('_'); 660 break; 661 default: 662 Error = true; 663 break; 664 } 665 } else if (C == 'B') { 666 demangleBackref([&] { demangleConst(); }); 667 } else { 668 Error = true; 669 } 670 } 671 672 // <const-data> = ["n"] <hex-number> 673 void Demangler::demangleConstInt() { 674 if (consumeIf('n')) 675 print('-'); 676 677 StringView HexDigits; 678 uint64_t Value = parseHexNumber(HexDigits); 679 if (HexDigits.size() <= 16) { 680 printDecimalNumber(Value); 681 } else { 682 print("0x"); 683 print(HexDigits); 684 } 685 } 686 687 // <const-data> = "0_" // false 688 // | "1_" // true 689 void Demangler::demangleConstBool() { 690 StringView HexDigits; 691 parseHexNumber(HexDigits); 692 if (HexDigits == "0") 693 print("false"); 694 else if (HexDigits == "1") 695 print("true"); 696 else 697 Error = true; 698 } 699 700 /// Returns true if CodePoint represents a printable ASCII character. 701 static bool isAsciiPrintable(uint64_t CodePoint) { 702 return 0x20 <= CodePoint && CodePoint <= 0x7e; 703 } 704 705 // <const-data> = <hex-number> 706 void Demangler::demangleConstChar() { 707 StringView HexDigits; 708 uint64_t CodePoint = parseHexNumber(HexDigits); 709 if (Error || HexDigits.size() > 6) { 710 Error = true; 711 return; 712 } 713 714 print("'"); 715 switch (CodePoint) { 716 case '\t': 717 print(R"(\t)"); 718 break; 719 case '\r': 720 print(R"(\r)"); 721 break; 722 case '\n': 723 print(R"(\n)"); 724 break; 725 case '\\': 726 print(R"(\\)"); 727 break; 728 case '"': 729 print(R"(")"); 730 break; 731 case '\'': 732 print(R"(\')"); 733 break; 734 default: 735 if (isAsciiPrintable(CodePoint)) { 736 char C = CodePoint; 737 print(C); 738 } else { 739 print(R"(\u{)"); 740 print(HexDigits); 741 print('}'); 742 } 743 break; 744 } 745 print('\''); 746 } 747 748 // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> 749 Identifier Demangler::parseIdentifier() { 750 bool Punycode = consumeIf('u'); 751 uint64_t Bytes = parseDecimalNumber(); 752 753 // Underscore resolves the ambiguity when identifier starts with a decimal 754 // digit or another underscore. 755 consumeIf('_'); 756 757 if (Error || Bytes > Input.size() - Position) { 758 Error = true; 759 return {}; 760 } 761 StringView S = Input.substr(Position, Bytes); 762 Position += Bytes; 763 764 if (!std::all_of(S.begin(), S.end(), isValid)) { 765 Error = true; 766 return {}; 767 } 768 769 return {S, Punycode}; 770 } 771 772 // Parses optional base 62 number. The presence of a number is determined using 773 // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise 774 // 775 // This function is indended for parsing disambiguators and binders which when 776 // not present have their value interpreted as 0, and otherwise as decoded 777 // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is 778 // 2. When "G" is absent value is 0. 779 uint64_t Demangler::parseOptionalBase62Number(char Tag) { 780 if (!consumeIf(Tag)) 781 return 0; 782 783 uint64_t N = parseBase62Number(); 784 if (Error || !addAssign(N, 1)) 785 return 0; 786 787 return N; 788 } 789 790 // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by 791 // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, 792 // "1_" encodes 2, etc. 793 // 794 // <base-62-number> = {<0-9a-zA-Z>} "_" 795 uint64_t Demangler::parseBase62Number() { 796 if (consumeIf('_')) 797 return 0; 798 799 uint64_t Value = 0; 800 801 while (true) { 802 uint64_t Digit; 803 char C = consume(); 804 805 if (C == '_') { 806 break; 807 } else if (isDigit(C)) { 808 Digit = C - '0'; 809 } else if (isLower(C)) { 810 Digit = 10 + (C - 'a'); 811 } else if (isUpper(C)) { 812 Digit = 10 + 26 + (C - 'A'); 813 } else { 814 Error = true; 815 return 0; 816 } 817 818 if (!mulAssign(Value, 62)) 819 return 0; 820 821 if (!addAssign(Value, Digit)) 822 return 0; 823 } 824 825 if (!addAssign(Value, 1)) 826 return 0; 827 828 return Value; 829 } 830 831 // Parses a decimal number that had been encoded without any leading zeros. 832 // 833 // <decimal-number> = "0" 834 // | <1-9> {<0-9>} 835 uint64_t Demangler::parseDecimalNumber() { 836 char C = look(); 837 if (!isDigit(C)) { 838 Error = true; 839 return 0; 840 } 841 842 if (C == '0') { 843 consume(); 844 return 0; 845 } 846 847 uint64_t Value = 0; 848 849 while (isDigit(look())) { 850 if (!mulAssign(Value, 10)) { 851 Error = true; 852 return 0; 853 } 854 855 uint64_t D = consume() - '0'; 856 if (!addAssign(Value, D)) 857 return 0; 858 } 859 860 return Value; 861 } 862 863 // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed 864 // value and stores hex digits in HexDigits. The return value is unspecified if 865 // HexDigits.size() > 16. 866 // 867 // <hex-number> = "0_" 868 // | <1-9a-f> {<0-9a-f>} "_" 869 uint64_t Demangler::parseHexNumber(StringView &HexDigits) { 870 size_t Start = Position; 871 uint64_t Value = 0; 872 873 if (!isHexDigit(look())) 874 Error = true; 875 876 if (consumeIf('0')) { 877 if (!consumeIf('_')) 878 Error = true; 879 } else { 880 while (!Error && !consumeIf('_')) { 881 char C = consume(); 882 Value *= 16; 883 if (isDigit(C)) 884 Value += C - '0'; 885 else if ('a' <= C && C <= 'f') 886 Value += 10 + (C - 'a'); 887 else 888 Error = true; 889 } 890 } 891 892 if (Error) { 893 HexDigits = StringView(); 894 return 0; 895 } 896 897 size_t End = Position - 1; 898 assert(Start < End); 899 HexDigits = Input.substr(Start, End - Start); 900 return Value; 901 } 902 903 // Prints a lifetime. An index 0 always represents an erased lifetime. Indices 904 // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes 905 // bound by one of the enclosing binders. 906 void Demangler::printLifetime(uint64_t Index) { 907 if (Index == 0) { 908 print("'_"); 909 return; 910 } 911 912 if (Index - 1 >= BoundLifetimes) { 913 Error = true; 914 return; 915 } 916 917 uint64_t Depth = BoundLifetimes - Index; 918 print('\''); 919 if (Depth < 26) { 920 char C = 'a' + Depth; 921 print(C); 922 } else { 923 print('z'); 924 printDecimalNumber(Depth - 26 + 1); 925 } 926 } 927