1fe6060f1SDimitry Andric //===--- RustDemangle.cpp ---------------------------------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file defines a demangler for Rust v0 mangled symbols as specified in 10fe6060f1SDimitry Andric // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html 11fe6060f1SDimitry Andric // 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "llvm/Demangle/Demangle.h" 15fe6060f1SDimitry Andric #include "llvm/Demangle/StringView.h" 16fe6060f1SDimitry Andric #include "llvm/Demangle/Utility.h" 17fe6060f1SDimitry Andric 18fe6060f1SDimitry Andric #include <algorithm> 19fe6060f1SDimitry Andric #include <cassert> 20fe6060f1SDimitry Andric #include <cstdint> 21fe6060f1SDimitry Andric #include <cstring> 22fe6060f1SDimitry Andric #include <limits> 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric using namespace llvm; 25fe6060f1SDimitry Andric 26349cc55cSDimitry Andric using llvm::itanium_demangle::OutputBuffer; 27*81ad6265SDimitry Andric using llvm::itanium_demangle::ScopedOverride; 28fe6060f1SDimitry Andric using llvm::itanium_demangle::StringView; 29fe6060f1SDimitry Andric 30fe6060f1SDimitry Andric namespace { 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric struct Identifier { 33fe6060f1SDimitry Andric StringView Name; 34fe6060f1SDimitry Andric bool Punycode; 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric bool empty() const { return Name.empty(); } 37fe6060f1SDimitry Andric }; 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric enum class BasicType { 40fe6060f1SDimitry Andric Bool, 41fe6060f1SDimitry Andric Char, 42fe6060f1SDimitry Andric I8, 43fe6060f1SDimitry Andric I16, 44fe6060f1SDimitry Andric I32, 45fe6060f1SDimitry Andric I64, 46fe6060f1SDimitry Andric I128, 47fe6060f1SDimitry Andric ISize, 48fe6060f1SDimitry Andric U8, 49fe6060f1SDimitry Andric U16, 50fe6060f1SDimitry Andric U32, 51fe6060f1SDimitry Andric U64, 52fe6060f1SDimitry Andric U128, 53fe6060f1SDimitry Andric USize, 54fe6060f1SDimitry Andric F32, 55fe6060f1SDimitry Andric F64, 56fe6060f1SDimitry Andric Str, 57fe6060f1SDimitry Andric Placeholder, 58fe6060f1SDimitry Andric Unit, 59fe6060f1SDimitry Andric Variadic, 60fe6060f1SDimitry Andric Never, 61fe6060f1SDimitry Andric }; 62fe6060f1SDimitry Andric 63fe6060f1SDimitry Andric enum class IsInType { 64fe6060f1SDimitry Andric No, 65fe6060f1SDimitry Andric Yes, 66fe6060f1SDimitry Andric }; 67fe6060f1SDimitry Andric 68fe6060f1SDimitry Andric enum class LeaveGenericsOpen { 69fe6060f1SDimitry Andric No, 70fe6060f1SDimitry Andric Yes, 71fe6060f1SDimitry Andric }; 72fe6060f1SDimitry Andric 73fe6060f1SDimitry Andric class Demangler { 74fe6060f1SDimitry Andric // Maximum recursion level. Used to avoid stack overflow. 75fe6060f1SDimitry Andric size_t MaxRecursionLevel; 76fe6060f1SDimitry Andric // Current recursion level. 77fe6060f1SDimitry Andric size_t RecursionLevel; 78fe6060f1SDimitry Andric size_t BoundLifetimes; 79fe6060f1SDimitry Andric // Input string that is being demangled with "_R" prefix removed. 80fe6060f1SDimitry Andric StringView Input; 81fe6060f1SDimitry Andric // Position in the input string. 82fe6060f1SDimitry Andric size_t Position; 83fe6060f1SDimitry Andric // When true, print methods append the output to the stream. 84fe6060f1SDimitry Andric // When false, the output is suppressed. 85fe6060f1SDimitry Andric bool Print; 86fe6060f1SDimitry Andric // True if an error occurred. 87fe6060f1SDimitry Andric bool Error; 88fe6060f1SDimitry Andric 89fe6060f1SDimitry Andric public: 90fe6060f1SDimitry Andric // Demangled output. 91349cc55cSDimitry Andric OutputBuffer Output; 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric Demangler(size_t MaxRecursionLevel = 500); 94fe6060f1SDimitry Andric 95fe6060f1SDimitry Andric bool demangle(StringView MangledName); 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric private: 98fe6060f1SDimitry Andric bool demanglePath(IsInType Type, 99fe6060f1SDimitry Andric LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No); 100fe6060f1SDimitry Andric void demangleImplPath(IsInType InType); 101fe6060f1SDimitry Andric void demangleGenericArg(); 102fe6060f1SDimitry Andric void demangleType(); 103fe6060f1SDimitry Andric void demangleFnSig(); 104fe6060f1SDimitry Andric void demangleDynBounds(); 105fe6060f1SDimitry Andric void demangleDynTrait(); 106fe6060f1SDimitry Andric void demangleOptionalBinder(); 107fe6060f1SDimitry Andric void demangleConst(); 108fe6060f1SDimitry Andric void demangleConstInt(); 109fe6060f1SDimitry Andric void demangleConstBool(); 110fe6060f1SDimitry Andric void demangleConstChar(); 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric template <typename Callable> void demangleBackref(Callable Demangler) { 113fe6060f1SDimitry Andric uint64_t Backref = parseBase62Number(); 114fe6060f1SDimitry Andric if (Error || Backref >= Position) { 115fe6060f1SDimitry Andric Error = true; 116fe6060f1SDimitry Andric return; 117fe6060f1SDimitry Andric } 118fe6060f1SDimitry Andric 119fe6060f1SDimitry Andric if (!Print) 120fe6060f1SDimitry Andric return; 121fe6060f1SDimitry Andric 122*81ad6265SDimitry Andric ScopedOverride<size_t> SavePosition(Position, Position); 123fe6060f1SDimitry Andric Position = Backref; 124fe6060f1SDimitry Andric Demangler(); 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric Identifier parseIdentifier(); 128fe6060f1SDimitry Andric uint64_t parseOptionalBase62Number(char Tag); 129fe6060f1SDimitry Andric uint64_t parseBase62Number(); 130fe6060f1SDimitry Andric uint64_t parseDecimalNumber(); 131fe6060f1SDimitry Andric uint64_t parseHexNumber(StringView &HexDigits); 132fe6060f1SDimitry Andric 133fe6060f1SDimitry Andric void print(char C); 134fe6060f1SDimitry Andric void print(StringView S); 135fe6060f1SDimitry Andric void printDecimalNumber(uint64_t N); 136fe6060f1SDimitry Andric void printBasicType(BasicType); 137fe6060f1SDimitry Andric void printLifetime(uint64_t Index); 138349cc55cSDimitry Andric void printIdentifier(Identifier Ident); 139fe6060f1SDimitry Andric 140fe6060f1SDimitry Andric char look() const; 141fe6060f1SDimitry Andric char consume(); 142fe6060f1SDimitry Andric bool consumeIf(char Prefix); 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric bool addAssign(uint64_t &A, uint64_t B); 145fe6060f1SDimitry Andric bool mulAssign(uint64_t &A, uint64_t B); 146fe6060f1SDimitry Andric }; 147fe6060f1SDimitry Andric 148fe6060f1SDimitry Andric } // namespace 149fe6060f1SDimitry Andric 150*81ad6265SDimitry Andric char *llvm::rustDemangle(const char *MangledName) { 151*81ad6265SDimitry Andric if (MangledName == nullptr) 152fe6060f1SDimitry Andric return nullptr; 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric // Return early if mangled name doesn't look like a Rust symbol. 155fe6060f1SDimitry Andric StringView Mangled(MangledName); 156*81ad6265SDimitry Andric if (!Mangled.startsWith("_R")) 157fe6060f1SDimitry Andric return nullptr; 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric Demangler D; 160*81ad6265SDimitry Andric if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024)) 161fe6060f1SDimitry Andric return nullptr; 162fe6060f1SDimitry Andric 163fe6060f1SDimitry Andric if (!D.demangle(Mangled)) { 164fe6060f1SDimitry Andric std::free(D.Output.getBuffer()); 165fe6060f1SDimitry Andric return nullptr; 166fe6060f1SDimitry Andric } 167fe6060f1SDimitry Andric 168fe6060f1SDimitry Andric D.Output += '\0'; 169fe6060f1SDimitry Andric 170*81ad6265SDimitry Andric return D.Output.getBuffer(); 171fe6060f1SDimitry Andric } 172fe6060f1SDimitry Andric 173fe6060f1SDimitry Andric Demangler::Demangler(size_t MaxRecursionLevel) 174fe6060f1SDimitry Andric : MaxRecursionLevel(MaxRecursionLevel) {} 175fe6060f1SDimitry Andric 176fe6060f1SDimitry Andric static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; } 177fe6060f1SDimitry Andric 178fe6060f1SDimitry Andric static inline bool isHexDigit(const char C) { 179fe6060f1SDimitry Andric return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f'); 180fe6060f1SDimitry Andric } 181fe6060f1SDimitry Andric 182fe6060f1SDimitry Andric static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; } 183fe6060f1SDimitry Andric 184fe6060f1SDimitry Andric static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; } 185fe6060f1SDimitry Andric 186fe6060f1SDimitry Andric /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. 187fe6060f1SDimitry Andric static inline bool isValid(const char C) { 188fe6060f1SDimitry Andric return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; 189fe6060f1SDimitry Andric } 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric // Demangles Rust v0 mangled symbol. Returns true when successful, and false 192fe6060f1SDimitry Andric // otherwise. The demangled symbol is stored in Output field. It is 193fe6060f1SDimitry Andric // responsibility of the caller to free the memory behind the output stream. 194fe6060f1SDimitry Andric // 195fe6060f1SDimitry Andric // <symbol-name> = "_R" <path> [<instantiating-crate>] 196fe6060f1SDimitry Andric bool Demangler::demangle(StringView Mangled) { 197fe6060f1SDimitry Andric Position = 0; 198fe6060f1SDimitry Andric Error = false; 199fe6060f1SDimitry Andric Print = true; 200fe6060f1SDimitry Andric RecursionLevel = 0; 201fe6060f1SDimitry Andric BoundLifetimes = 0; 202fe6060f1SDimitry Andric 203fe6060f1SDimitry Andric if (!Mangled.consumeFront("_R")) { 204fe6060f1SDimitry Andric Error = true; 205fe6060f1SDimitry Andric return false; 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric size_t Dot = Mangled.find('.'); 208fe6060f1SDimitry Andric Input = Mangled.substr(0, Dot); 209fe6060f1SDimitry Andric StringView Suffix = Mangled.dropFront(Dot); 210fe6060f1SDimitry Andric 211fe6060f1SDimitry Andric demanglePath(IsInType::No); 212fe6060f1SDimitry Andric 213fe6060f1SDimitry Andric if (Position != Input.size()) { 214*81ad6265SDimitry Andric ScopedOverride<bool> SavePrint(Print, false); 215fe6060f1SDimitry Andric demanglePath(IsInType::No); 216fe6060f1SDimitry Andric } 217fe6060f1SDimitry Andric 218fe6060f1SDimitry Andric if (Position != Input.size()) 219fe6060f1SDimitry Andric Error = true; 220fe6060f1SDimitry Andric 221fe6060f1SDimitry Andric if (!Suffix.empty()) { 222fe6060f1SDimitry Andric print(" ("); 223fe6060f1SDimitry Andric print(Suffix); 224fe6060f1SDimitry Andric print(")"); 225fe6060f1SDimitry Andric } 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric return !Error; 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric // Demangles a path. InType indicates whether a path is inside a type. When 231fe6060f1SDimitry Andric // LeaveOpen is true, a closing `>` after generic arguments is omitted from the 232fe6060f1SDimitry Andric // output. Return value indicates whether generics arguments have been left 233fe6060f1SDimitry Andric // open. 234fe6060f1SDimitry Andric // 235fe6060f1SDimitry Andric // <path> = "C" <identifier> // crate root 236fe6060f1SDimitry Andric // | "M" <impl-path> <type> // <T> (inherent impl) 237fe6060f1SDimitry Andric // | "X" <impl-path> <type> <path> // <T as Trait> (trait impl) 238fe6060f1SDimitry Andric // | "Y" <type> <path> // <T as Trait> (trait definition) 239fe6060f1SDimitry Andric // | "N" <ns> <path> <identifier> // ...::ident (nested path) 240fe6060f1SDimitry Andric // | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args) 241fe6060f1SDimitry Andric // | <backref> 242fe6060f1SDimitry Andric // <identifier> = [<disambiguator>] <undisambiguated-identifier> 243fe6060f1SDimitry Andric // <ns> = "C" // closure 244fe6060f1SDimitry Andric // | "S" // shim 245fe6060f1SDimitry Andric // | <A-Z> // other special namespaces 246fe6060f1SDimitry Andric // | <a-z> // internal namespaces 247fe6060f1SDimitry Andric bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { 248fe6060f1SDimitry Andric if (Error || RecursionLevel >= MaxRecursionLevel) { 249fe6060f1SDimitry Andric Error = true; 250fe6060f1SDimitry Andric return false; 251fe6060f1SDimitry Andric } 252*81ad6265SDimitry Andric ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric switch (consume()) { 255fe6060f1SDimitry Andric case 'C': { 256fe6060f1SDimitry Andric parseOptionalBase62Number('s'); 257349cc55cSDimitry Andric printIdentifier(parseIdentifier()); 258fe6060f1SDimitry Andric break; 259fe6060f1SDimitry Andric } 260fe6060f1SDimitry Andric case 'M': { 261fe6060f1SDimitry Andric demangleImplPath(InType); 262fe6060f1SDimitry Andric print("<"); 263fe6060f1SDimitry Andric demangleType(); 264fe6060f1SDimitry Andric print(">"); 265fe6060f1SDimitry Andric break; 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric case 'X': { 268fe6060f1SDimitry Andric demangleImplPath(InType); 269fe6060f1SDimitry Andric print("<"); 270fe6060f1SDimitry Andric demangleType(); 271fe6060f1SDimitry Andric print(" as "); 272fe6060f1SDimitry Andric demanglePath(IsInType::Yes); 273fe6060f1SDimitry Andric print(">"); 274fe6060f1SDimitry Andric break; 275fe6060f1SDimitry Andric } 276fe6060f1SDimitry Andric case 'Y': { 277fe6060f1SDimitry Andric print("<"); 278fe6060f1SDimitry Andric demangleType(); 279fe6060f1SDimitry Andric print(" as "); 280fe6060f1SDimitry Andric demanglePath(IsInType::Yes); 281fe6060f1SDimitry Andric print(">"); 282fe6060f1SDimitry Andric break; 283fe6060f1SDimitry Andric } 284fe6060f1SDimitry Andric case 'N': { 285fe6060f1SDimitry Andric char NS = consume(); 286fe6060f1SDimitry Andric if (!isLower(NS) && !isUpper(NS)) { 287fe6060f1SDimitry Andric Error = true; 288fe6060f1SDimitry Andric break; 289fe6060f1SDimitry Andric } 290fe6060f1SDimitry Andric demanglePath(InType); 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric uint64_t Disambiguator = parseOptionalBase62Number('s'); 293fe6060f1SDimitry Andric Identifier Ident = parseIdentifier(); 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric if (isUpper(NS)) { 296fe6060f1SDimitry Andric // Special namespaces 297fe6060f1SDimitry Andric print("::{"); 298fe6060f1SDimitry Andric if (NS == 'C') 299fe6060f1SDimitry Andric print("closure"); 300fe6060f1SDimitry Andric else if (NS == 'S') 301fe6060f1SDimitry Andric print("shim"); 302fe6060f1SDimitry Andric else 303fe6060f1SDimitry Andric print(NS); 304fe6060f1SDimitry Andric if (!Ident.empty()) { 305fe6060f1SDimitry Andric print(":"); 306349cc55cSDimitry Andric printIdentifier(Ident); 307fe6060f1SDimitry Andric } 308fe6060f1SDimitry Andric print('#'); 309fe6060f1SDimitry Andric printDecimalNumber(Disambiguator); 310fe6060f1SDimitry Andric print('}'); 311fe6060f1SDimitry Andric } else { 312fe6060f1SDimitry Andric // Implementation internal namespaces. 313fe6060f1SDimitry Andric if (!Ident.empty()) { 314fe6060f1SDimitry Andric print("::"); 315349cc55cSDimitry Andric printIdentifier(Ident); 316fe6060f1SDimitry Andric } 317fe6060f1SDimitry Andric } 318fe6060f1SDimitry Andric break; 319fe6060f1SDimitry Andric } 320fe6060f1SDimitry Andric case 'I': { 321fe6060f1SDimitry Andric demanglePath(InType); 322fe6060f1SDimitry Andric // Omit "::" when in a type, where it is optional. 323fe6060f1SDimitry Andric if (InType == IsInType::No) 324fe6060f1SDimitry Andric print("::"); 325fe6060f1SDimitry Andric print("<"); 326fe6060f1SDimitry Andric for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 327fe6060f1SDimitry Andric if (I > 0) 328fe6060f1SDimitry Andric print(", "); 329fe6060f1SDimitry Andric demangleGenericArg(); 330fe6060f1SDimitry Andric } 331fe6060f1SDimitry Andric if (LeaveOpen == LeaveGenericsOpen::Yes) 332fe6060f1SDimitry Andric return true; 333fe6060f1SDimitry Andric else 334fe6060f1SDimitry Andric print(">"); 335fe6060f1SDimitry Andric break; 336fe6060f1SDimitry Andric } 337fe6060f1SDimitry Andric case 'B': { 338fe6060f1SDimitry Andric bool IsOpen = false; 339fe6060f1SDimitry Andric demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); }); 340fe6060f1SDimitry Andric return IsOpen; 341fe6060f1SDimitry Andric } 342fe6060f1SDimitry Andric default: 343fe6060f1SDimitry Andric Error = true; 344fe6060f1SDimitry Andric break; 345fe6060f1SDimitry Andric } 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric return false; 348fe6060f1SDimitry Andric } 349fe6060f1SDimitry Andric 350fe6060f1SDimitry Andric // <impl-path> = [<disambiguator>] <path> 351fe6060f1SDimitry Andric // <disambiguator> = "s" <base-62-number> 352fe6060f1SDimitry Andric void Demangler::demangleImplPath(IsInType InType) { 353*81ad6265SDimitry Andric ScopedOverride<bool> SavePrint(Print, false); 354fe6060f1SDimitry Andric parseOptionalBase62Number('s'); 355fe6060f1SDimitry Andric demanglePath(InType); 356fe6060f1SDimitry Andric } 357fe6060f1SDimitry Andric 358fe6060f1SDimitry Andric // <generic-arg> = <lifetime> 359fe6060f1SDimitry Andric // | <type> 360fe6060f1SDimitry Andric // | "K" <const> 361fe6060f1SDimitry Andric // <lifetime> = "L" <base-62-number> 362fe6060f1SDimitry Andric void Demangler::demangleGenericArg() { 363fe6060f1SDimitry Andric if (consumeIf('L')) 364fe6060f1SDimitry Andric printLifetime(parseBase62Number()); 365fe6060f1SDimitry Andric else if (consumeIf('K')) 366fe6060f1SDimitry Andric demangleConst(); 367fe6060f1SDimitry Andric else 368fe6060f1SDimitry Andric demangleType(); 369fe6060f1SDimitry Andric } 370fe6060f1SDimitry Andric 371fe6060f1SDimitry Andric // <basic-type> = "a" // i8 372fe6060f1SDimitry Andric // | "b" // bool 373fe6060f1SDimitry Andric // | "c" // char 374fe6060f1SDimitry Andric // | "d" // f64 375fe6060f1SDimitry Andric // | "e" // str 376fe6060f1SDimitry Andric // | "f" // f32 377fe6060f1SDimitry Andric // | "h" // u8 378fe6060f1SDimitry Andric // | "i" // isize 379fe6060f1SDimitry Andric // | "j" // usize 380fe6060f1SDimitry Andric // | "l" // i32 381fe6060f1SDimitry Andric // | "m" // u32 382fe6060f1SDimitry Andric // | "n" // i128 383fe6060f1SDimitry Andric // | "o" // u128 384fe6060f1SDimitry Andric // | "s" // i16 385fe6060f1SDimitry Andric // | "t" // u16 386fe6060f1SDimitry Andric // | "u" // () 387fe6060f1SDimitry Andric // | "v" // ... 388fe6060f1SDimitry Andric // | "x" // i64 389fe6060f1SDimitry Andric // | "y" // u64 390fe6060f1SDimitry Andric // | "z" // ! 391fe6060f1SDimitry Andric // | "p" // placeholder (e.g. for generic params), shown as _ 392fe6060f1SDimitry Andric static bool parseBasicType(char C, BasicType &Type) { 393fe6060f1SDimitry Andric switch (C) { 394fe6060f1SDimitry Andric case 'a': 395fe6060f1SDimitry Andric Type = BasicType::I8; 396fe6060f1SDimitry Andric return true; 397fe6060f1SDimitry Andric case 'b': 398fe6060f1SDimitry Andric Type = BasicType::Bool; 399fe6060f1SDimitry Andric return true; 400fe6060f1SDimitry Andric case 'c': 401fe6060f1SDimitry Andric Type = BasicType::Char; 402fe6060f1SDimitry Andric return true; 403fe6060f1SDimitry Andric case 'd': 404fe6060f1SDimitry Andric Type = BasicType::F64; 405fe6060f1SDimitry Andric return true; 406fe6060f1SDimitry Andric case 'e': 407fe6060f1SDimitry Andric Type = BasicType::Str; 408fe6060f1SDimitry Andric return true; 409fe6060f1SDimitry Andric case 'f': 410fe6060f1SDimitry Andric Type = BasicType::F32; 411fe6060f1SDimitry Andric return true; 412fe6060f1SDimitry Andric case 'h': 413fe6060f1SDimitry Andric Type = BasicType::U8; 414fe6060f1SDimitry Andric return true; 415fe6060f1SDimitry Andric case 'i': 416fe6060f1SDimitry Andric Type = BasicType::ISize; 417fe6060f1SDimitry Andric return true; 418fe6060f1SDimitry Andric case 'j': 419fe6060f1SDimitry Andric Type = BasicType::USize; 420fe6060f1SDimitry Andric return true; 421fe6060f1SDimitry Andric case 'l': 422fe6060f1SDimitry Andric Type = BasicType::I32; 423fe6060f1SDimitry Andric return true; 424fe6060f1SDimitry Andric case 'm': 425fe6060f1SDimitry Andric Type = BasicType::U32; 426fe6060f1SDimitry Andric return true; 427fe6060f1SDimitry Andric case 'n': 428fe6060f1SDimitry Andric Type = BasicType::I128; 429fe6060f1SDimitry Andric return true; 430fe6060f1SDimitry Andric case 'o': 431fe6060f1SDimitry Andric Type = BasicType::U128; 432fe6060f1SDimitry Andric return true; 433fe6060f1SDimitry Andric case 'p': 434fe6060f1SDimitry Andric Type = BasicType::Placeholder; 435fe6060f1SDimitry Andric return true; 436fe6060f1SDimitry Andric case 's': 437fe6060f1SDimitry Andric Type = BasicType::I16; 438fe6060f1SDimitry Andric return true; 439fe6060f1SDimitry Andric case 't': 440fe6060f1SDimitry Andric Type = BasicType::U16; 441fe6060f1SDimitry Andric return true; 442fe6060f1SDimitry Andric case 'u': 443fe6060f1SDimitry Andric Type = BasicType::Unit; 444fe6060f1SDimitry Andric return true; 445fe6060f1SDimitry Andric case 'v': 446fe6060f1SDimitry Andric Type = BasicType::Variadic; 447fe6060f1SDimitry Andric return true; 448fe6060f1SDimitry Andric case 'x': 449fe6060f1SDimitry Andric Type = BasicType::I64; 450fe6060f1SDimitry Andric return true; 451fe6060f1SDimitry Andric case 'y': 452fe6060f1SDimitry Andric Type = BasicType::U64; 453fe6060f1SDimitry Andric return true; 454fe6060f1SDimitry Andric case 'z': 455fe6060f1SDimitry Andric Type = BasicType::Never; 456fe6060f1SDimitry Andric return true; 457fe6060f1SDimitry Andric default: 458fe6060f1SDimitry Andric return false; 459fe6060f1SDimitry Andric } 460fe6060f1SDimitry Andric } 461fe6060f1SDimitry Andric 462fe6060f1SDimitry Andric void Demangler::printBasicType(BasicType Type) { 463fe6060f1SDimitry Andric switch (Type) { 464fe6060f1SDimitry Andric case BasicType::Bool: 465fe6060f1SDimitry Andric print("bool"); 466fe6060f1SDimitry Andric break; 467fe6060f1SDimitry Andric case BasicType::Char: 468fe6060f1SDimitry Andric print("char"); 469fe6060f1SDimitry Andric break; 470fe6060f1SDimitry Andric case BasicType::I8: 471fe6060f1SDimitry Andric print("i8"); 472fe6060f1SDimitry Andric break; 473fe6060f1SDimitry Andric case BasicType::I16: 474fe6060f1SDimitry Andric print("i16"); 475fe6060f1SDimitry Andric break; 476fe6060f1SDimitry Andric case BasicType::I32: 477fe6060f1SDimitry Andric print("i32"); 478fe6060f1SDimitry Andric break; 479fe6060f1SDimitry Andric case BasicType::I64: 480fe6060f1SDimitry Andric print("i64"); 481fe6060f1SDimitry Andric break; 482fe6060f1SDimitry Andric case BasicType::I128: 483fe6060f1SDimitry Andric print("i128"); 484fe6060f1SDimitry Andric break; 485fe6060f1SDimitry Andric case BasicType::ISize: 486fe6060f1SDimitry Andric print("isize"); 487fe6060f1SDimitry Andric break; 488fe6060f1SDimitry Andric case BasicType::U8: 489fe6060f1SDimitry Andric print("u8"); 490fe6060f1SDimitry Andric break; 491fe6060f1SDimitry Andric case BasicType::U16: 492fe6060f1SDimitry Andric print("u16"); 493fe6060f1SDimitry Andric break; 494fe6060f1SDimitry Andric case BasicType::U32: 495fe6060f1SDimitry Andric print("u32"); 496fe6060f1SDimitry Andric break; 497fe6060f1SDimitry Andric case BasicType::U64: 498fe6060f1SDimitry Andric print("u64"); 499fe6060f1SDimitry Andric break; 500fe6060f1SDimitry Andric case BasicType::U128: 501fe6060f1SDimitry Andric print("u128"); 502fe6060f1SDimitry Andric break; 503fe6060f1SDimitry Andric case BasicType::USize: 504fe6060f1SDimitry Andric print("usize"); 505fe6060f1SDimitry Andric break; 506fe6060f1SDimitry Andric case BasicType::F32: 507fe6060f1SDimitry Andric print("f32"); 508fe6060f1SDimitry Andric break; 509fe6060f1SDimitry Andric case BasicType::F64: 510fe6060f1SDimitry Andric print("f64"); 511fe6060f1SDimitry Andric break; 512fe6060f1SDimitry Andric case BasicType::Str: 513fe6060f1SDimitry Andric print("str"); 514fe6060f1SDimitry Andric break; 515fe6060f1SDimitry Andric case BasicType::Placeholder: 516fe6060f1SDimitry Andric print("_"); 517fe6060f1SDimitry Andric break; 518fe6060f1SDimitry Andric case BasicType::Unit: 519fe6060f1SDimitry Andric print("()"); 520fe6060f1SDimitry Andric break; 521fe6060f1SDimitry Andric case BasicType::Variadic: 522fe6060f1SDimitry Andric print("..."); 523fe6060f1SDimitry Andric break; 524fe6060f1SDimitry Andric case BasicType::Never: 525fe6060f1SDimitry Andric print("!"); 526fe6060f1SDimitry Andric break; 527fe6060f1SDimitry Andric } 528fe6060f1SDimitry Andric } 529fe6060f1SDimitry Andric 530fe6060f1SDimitry Andric // <type> = | <basic-type> 531fe6060f1SDimitry Andric // | <path> // named type 532fe6060f1SDimitry Andric // | "A" <type> <const> // [T; N] 533fe6060f1SDimitry Andric // | "S" <type> // [T] 534fe6060f1SDimitry Andric // | "T" {<type>} "E" // (T1, T2, T3, ...) 535fe6060f1SDimitry Andric // | "R" [<lifetime>] <type> // &T 536fe6060f1SDimitry Andric // | "Q" [<lifetime>] <type> // &mut T 537fe6060f1SDimitry Andric // | "P" <type> // *const T 538fe6060f1SDimitry Andric // | "O" <type> // *mut T 539fe6060f1SDimitry Andric // | "F" <fn-sig> // fn(...) -> ... 540fe6060f1SDimitry Andric // | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a 541fe6060f1SDimitry Andric // | <backref> // backref 542fe6060f1SDimitry Andric void Demangler::demangleType() { 543fe6060f1SDimitry Andric if (Error || RecursionLevel >= MaxRecursionLevel) { 544fe6060f1SDimitry Andric Error = true; 545fe6060f1SDimitry Andric return; 546fe6060f1SDimitry Andric } 547*81ad6265SDimitry Andric ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric size_t Start = Position; 550fe6060f1SDimitry Andric char C = consume(); 551fe6060f1SDimitry Andric BasicType Type; 552fe6060f1SDimitry Andric if (parseBasicType(C, Type)) 553fe6060f1SDimitry Andric return printBasicType(Type); 554fe6060f1SDimitry Andric 555fe6060f1SDimitry Andric switch (C) { 556fe6060f1SDimitry Andric case 'A': 557fe6060f1SDimitry Andric print("["); 558fe6060f1SDimitry Andric demangleType(); 559fe6060f1SDimitry Andric print("; "); 560fe6060f1SDimitry Andric demangleConst(); 561fe6060f1SDimitry Andric print("]"); 562fe6060f1SDimitry Andric break; 563fe6060f1SDimitry Andric case 'S': 564fe6060f1SDimitry Andric print("["); 565fe6060f1SDimitry Andric demangleType(); 566fe6060f1SDimitry Andric print("]"); 567fe6060f1SDimitry Andric break; 568fe6060f1SDimitry Andric case 'T': { 569fe6060f1SDimitry Andric print("("); 570fe6060f1SDimitry Andric size_t I = 0; 571fe6060f1SDimitry Andric for (; !Error && !consumeIf('E'); ++I) { 572fe6060f1SDimitry Andric if (I > 0) 573fe6060f1SDimitry Andric print(", "); 574fe6060f1SDimitry Andric demangleType(); 575fe6060f1SDimitry Andric } 576fe6060f1SDimitry Andric if (I == 1) 577fe6060f1SDimitry Andric print(","); 578fe6060f1SDimitry Andric print(")"); 579fe6060f1SDimitry Andric break; 580fe6060f1SDimitry Andric } 581fe6060f1SDimitry Andric case 'R': 582fe6060f1SDimitry Andric case 'Q': 583fe6060f1SDimitry Andric print('&'); 584fe6060f1SDimitry Andric if (consumeIf('L')) { 585fe6060f1SDimitry Andric if (auto Lifetime = parseBase62Number()) { 586fe6060f1SDimitry Andric printLifetime(Lifetime); 587fe6060f1SDimitry Andric print(' '); 588fe6060f1SDimitry Andric } 589fe6060f1SDimitry Andric } 590fe6060f1SDimitry Andric if (C == 'Q') 591fe6060f1SDimitry Andric print("mut "); 592fe6060f1SDimitry Andric demangleType(); 593fe6060f1SDimitry Andric break; 594fe6060f1SDimitry Andric case 'P': 595fe6060f1SDimitry Andric print("*const "); 596fe6060f1SDimitry Andric demangleType(); 597fe6060f1SDimitry Andric break; 598fe6060f1SDimitry Andric case 'O': 599fe6060f1SDimitry Andric print("*mut "); 600fe6060f1SDimitry Andric demangleType(); 601fe6060f1SDimitry Andric break; 602fe6060f1SDimitry Andric case 'F': 603fe6060f1SDimitry Andric demangleFnSig(); 604fe6060f1SDimitry Andric break; 605fe6060f1SDimitry Andric case 'D': 606fe6060f1SDimitry Andric demangleDynBounds(); 607fe6060f1SDimitry Andric if (consumeIf('L')) { 608fe6060f1SDimitry Andric if (auto Lifetime = parseBase62Number()) { 609fe6060f1SDimitry Andric print(" + "); 610fe6060f1SDimitry Andric printLifetime(Lifetime); 611fe6060f1SDimitry Andric } 612fe6060f1SDimitry Andric } else { 613fe6060f1SDimitry Andric Error = true; 614fe6060f1SDimitry Andric } 615fe6060f1SDimitry Andric break; 616fe6060f1SDimitry Andric case 'B': 617fe6060f1SDimitry Andric demangleBackref([&] { demangleType(); }); 618fe6060f1SDimitry Andric break; 619fe6060f1SDimitry Andric default: 620fe6060f1SDimitry Andric Position = Start; 621fe6060f1SDimitry Andric demanglePath(IsInType::Yes); 622fe6060f1SDimitry Andric break; 623fe6060f1SDimitry Andric } 624fe6060f1SDimitry Andric } 625fe6060f1SDimitry Andric 626fe6060f1SDimitry Andric // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type> 627fe6060f1SDimitry Andric // <abi> = "C" 628fe6060f1SDimitry Andric // | <undisambiguated-identifier> 629fe6060f1SDimitry Andric void Demangler::demangleFnSig() { 630*81ad6265SDimitry Andric ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 631fe6060f1SDimitry Andric demangleOptionalBinder(); 632fe6060f1SDimitry Andric 633fe6060f1SDimitry Andric if (consumeIf('U')) 634fe6060f1SDimitry Andric print("unsafe "); 635fe6060f1SDimitry Andric 636fe6060f1SDimitry Andric if (consumeIf('K')) { 637fe6060f1SDimitry Andric print("extern \""); 638fe6060f1SDimitry Andric if (consumeIf('C')) { 639fe6060f1SDimitry Andric print("C"); 640fe6060f1SDimitry Andric } else { 641fe6060f1SDimitry Andric Identifier Ident = parseIdentifier(); 642349cc55cSDimitry Andric if (Ident.Punycode) 643349cc55cSDimitry Andric Error = true; 644fe6060f1SDimitry Andric for (char C : Ident.Name) { 645fe6060f1SDimitry Andric // When mangling ABI string, the "-" is replaced with "_". 646fe6060f1SDimitry Andric if (C == '_') 647fe6060f1SDimitry Andric C = '-'; 648fe6060f1SDimitry Andric print(C); 649fe6060f1SDimitry Andric } 650fe6060f1SDimitry Andric } 651fe6060f1SDimitry Andric print("\" "); 652fe6060f1SDimitry Andric } 653fe6060f1SDimitry Andric 654fe6060f1SDimitry Andric print("fn("); 655fe6060f1SDimitry Andric for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 656fe6060f1SDimitry Andric if (I > 0) 657fe6060f1SDimitry Andric print(", "); 658fe6060f1SDimitry Andric demangleType(); 659fe6060f1SDimitry Andric } 660fe6060f1SDimitry Andric print(")"); 661fe6060f1SDimitry Andric 662fe6060f1SDimitry Andric if (consumeIf('u')) { 663fe6060f1SDimitry Andric // Skip the unit type from the output. 664fe6060f1SDimitry Andric } else { 665fe6060f1SDimitry Andric print(" -> "); 666fe6060f1SDimitry Andric demangleType(); 667fe6060f1SDimitry Andric } 668fe6060f1SDimitry Andric } 669fe6060f1SDimitry Andric 670fe6060f1SDimitry Andric // <dyn-bounds> = [<binder>] {<dyn-trait>} "E" 671fe6060f1SDimitry Andric void Demangler::demangleDynBounds() { 672*81ad6265SDimitry Andric ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 673fe6060f1SDimitry Andric print("dyn "); 674fe6060f1SDimitry Andric demangleOptionalBinder(); 675fe6060f1SDimitry Andric for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 676fe6060f1SDimitry Andric if (I > 0) 677fe6060f1SDimitry Andric print(" + "); 678fe6060f1SDimitry Andric demangleDynTrait(); 679fe6060f1SDimitry Andric } 680fe6060f1SDimitry Andric } 681fe6060f1SDimitry Andric 682fe6060f1SDimitry Andric // <dyn-trait> = <path> {<dyn-trait-assoc-binding>} 683fe6060f1SDimitry Andric // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type> 684fe6060f1SDimitry Andric void Demangler::demangleDynTrait() { 685fe6060f1SDimitry Andric bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes); 686fe6060f1SDimitry Andric while (!Error && consumeIf('p')) { 687fe6060f1SDimitry Andric if (!IsOpen) { 688fe6060f1SDimitry Andric IsOpen = true; 689fe6060f1SDimitry Andric print('<'); 690fe6060f1SDimitry Andric } else { 691fe6060f1SDimitry Andric print(", "); 692fe6060f1SDimitry Andric } 693fe6060f1SDimitry Andric print(parseIdentifier().Name); 694fe6060f1SDimitry Andric print(" = "); 695fe6060f1SDimitry Andric demangleType(); 696fe6060f1SDimitry Andric } 697fe6060f1SDimitry Andric if (IsOpen) 698fe6060f1SDimitry Andric print(">"); 699fe6060f1SDimitry Andric } 700fe6060f1SDimitry Andric 701fe6060f1SDimitry Andric // Demangles optional binder and updates the number of bound lifetimes. 702fe6060f1SDimitry Andric // 703fe6060f1SDimitry Andric // <binder> = "G" <base-62-number> 704fe6060f1SDimitry Andric void Demangler::demangleOptionalBinder() { 705fe6060f1SDimitry Andric uint64_t Binder = parseOptionalBase62Number('G'); 706fe6060f1SDimitry Andric if (Error || Binder == 0) 707fe6060f1SDimitry Andric return; 708fe6060f1SDimitry Andric 709fe6060f1SDimitry Andric // In valid inputs each bound lifetime is referenced later. Referencing a 710fe6060f1SDimitry Andric // lifetime requires at least one byte of input. Reject inputs that are too 711fe6060f1SDimitry Andric // short to reference all bound lifetimes. Otherwise demangling of invalid 712fe6060f1SDimitry Andric // binders could generate excessive amounts of output. 713fe6060f1SDimitry Andric if (Binder >= Input.size() - BoundLifetimes) { 714fe6060f1SDimitry Andric Error = true; 715fe6060f1SDimitry Andric return; 716fe6060f1SDimitry Andric } 717fe6060f1SDimitry Andric 718fe6060f1SDimitry Andric print("for<"); 719fe6060f1SDimitry Andric for (size_t I = 0; I != Binder; ++I) { 720fe6060f1SDimitry Andric BoundLifetimes += 1; 721fe6060f1SDimitry Andric if (I > 0) 722fe6060f1SDimitry Andric print(", "); 723fe6060f1SDimitry Andric printLifetime(1); 724fe6060f1SDimitry Andric } 725fe6060f1SDimitry Andric print("> "); 726fe6060f1SDimitry Andric } 727fe6060f1SDimitry Andric 728fe6060f1SDimitry Andric // <const> = <basic-type> <const-data> 729fe6060f1SDimitry Andric // | "p" // placeholder 730fe6060f1SDimitry Andric // | <backref> 731fe6060f1SDimitry Andric void Demangler::demangleConst() { 732fe6060f1SDimitry Andric if (Error || RecursionLevel >= MaxRecursionLevel) { 733fe6060f1SDimitry Andric Error = true; 734fe6060f1SDimitry Andric return; 735fe6060f1SDimitry Andric } 736*81ad6265SDimitry Andric ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 737fe6060f1SDimitry Andric 738fe6060f1SDimitry Andric char C = consume(); 739fe6060f1SDimitry Andric BasicType Type; 740fe6060f1SDimitry Andric if (parseBasicType(C, Type)) { 741fe6060f1SDimitry Andric switch (Type) { 742fe6060f1SDimitry Andric case BasicType::I8: 743fe6060f1SDimitry Andric case BasicType::I16: 744fe6060f1SDimitry Andric case BasicType::I32: 745fe6060f1SDimitry Andric case BasicType::I64: 746fe6060f1SDimitry Andric case BasicType::I128: 747fe6060f1SDimitry Andric case BasicType::ISize: 748fe6060f1SDimitry Andric case BasicType::U8: 749fe6060f1SDimitry Andric case BasicType::U16: 750fe6060f1SDimitry Andric case BasicType::U32: 751fe6060f1SDimitry Andric case BasicType::U64: 752fe6060f1SDimitry Andric case BasicType::U128: 753fe6060f1SDimitry Andric case BasicType::USize: 754fe6060f1SDimitry Andric demangleConstInt(); 755fe6060f1SDimitry Andric break; 756fe6060f1SDimitry Andric case BasicType::Bool: 757fe6060f1SDimitry Andric demangleConstBool(); 758fe6060f1SDimitry Andric break; 759fe6060f1SDimitry Andric case BasicType::Char: 760fe6060f1SDimitry Andric demangleConstChar(); 761fe6060f1SDimitry Andric break; 762fe6060f1SDimitry Andric case BasicType::Placeholder: 763fe6060f1SDimitry Andric print('_'); 764fe6060f1SDimitry Andric break; 765fe6060f1SDimitry Andric default: 766fe6060f1SDimitry Andric Error = true; 767fe6060f1SDimitry Andric break; 768fe6060f1SDimitry Andric } 769fe6060f1SDimitry Andric } else if (C == 'B') { 770fe6060f1SDimitry Andric demangleBackref([&] { demangleConst(); }); 771fe6060f1SDimitry Andric } else { 772fe6060f1SDimitry Andric Error = true; 773fe6060f1SDimitry Andric } 774fe6060f1SDimitry Andric } 775fe6060f1SDimitry Andric 776fe6060f1SDimitry Andric // <const-data> = ["n"] <hex-number> 777fe6060f1SDimitry Andric void Demangler::demangleConstInt() { 778fe6060f1SDimitry Andric if (consumeIf('n')) 779fe6060f1SDimitry Andric print('-'); 780fe6060f1SDimitry Andric 781fe6060f1SDimitry Andric StringView HexDigits; 782fe6060f1SDimitry Andric uint64_t Value = parseHexNumber(HexDigits); 783fe6060f1SDimitry Andric if (HexDigits.size() <= 16) { 784fe6060f1SDimitry Andric printDecimalNumber(Value); 785fe6060f1SDimitry Andric } else { 786fe6060f1SDimitry Andric print("0x"); 787fe6060f1SDimitry Andric print(HexDigits); 788fe6060f1SDimitry Andric } 789fe6060f1SDimitry Andric } 790fe6060f1SDimitry Andric 791fe6060f1SDimitry Andric // <const-data> = "0_" // false 792fe6060f1SDimitry Andric // | "1_" // true 793fe6060f1SDimitry Andric void Demangler::demangleConstBool() { 794fe6060f1SDimitry Andric StringView HexDigits; 795fe6060f1SDimitry Andric parseHexNumber(HexDigits); 796fe6060f1SDimitry Andric if (HexDigits == "0") 797fe6060f1SDimitry Andric print("false"); 798fe6060f1SDimitry Andric else if (HexDigits == "1") 799fe6060f1SDimitry Andric print("true"); 800fe6060f1SDimitry Andric else 801fe6060f1SDimitry Andric Error = true; 802fe6060f1SDimitry Andric } 803fe6060f1SDimitry Andric 804fe6060f1SDimitry Andric /// Returns true if CodePoint represents a printable ASCII character. 805fe6060f1SDimitry Andric static bool isAsciiPrintable(uint64_t CodePoint) { 806fe6060f1SDimitry Andric return 0x20 <= CodePoint && CodePoint <= 0x7e; 807fe6060f1SDimitry Andric } 808fe6060f1SDimitry Andric 809fe6060f1SDimitry Andric // <const-data> = <hex-number> 810fe6060f1SDimitry Andric void Demangler::demangleConstChar() { 811fe6060f1SDimitry Andric StringView HexDigits; 812fe6060f1SDimitry Andric uint64_t CodePoint = parseHexNumber(HexDigits); 813fe6060f1SDimitry Andric if (Error || HexDigits.size() > 6) { 814fe6060f1SDimitry Andric Error = true; 815fe6060f1SDimitry Andric return; 816fe6060f1SDimitry Andric } 817fe6060f1SDimitry Andric 818fe6060f1SDimitry Andric print("'"); 819fe6060f1SDimitry Andric switch (CodePoint) { 820fe6060f1SDimitry Andric case '\t': 821fe6060f1SDimitry Andric print(R"(\t)"); 822fe6060f1SDimitry Andric break; 823fe6060f1SDimitry Andric case '\r': 824fe6060f1SDimitry Andric print(R"(\r)"); 825fe6060f1SDimitry Andric break; 826fe6060f1SDimitry Andric case '\n': 827fe6060f1SDimitry Andric print(R"(\n)"); 828fe6060f1SDimitry Andric break; 829fe6060f1SDimitry Andric case '\\': 830fe6060f1SDimitry Andric print(R"(\\)"); 831fe6060f1SDimitry Andric break; 832fe6060f1SDimitry Andric case '"': 833fe6060f1SDimitry Andric print(R"(")"); 834fe6060f1SDimitry Andric break; 835fe6060f1SDimitry Andric case '\'': 836fe6060f1SDimitry Andric print(R"(\')"); 837fe6060f1SDimitry Andric break; 838fe6060f1SDimitry Andric default: 839fe6060f1SDimitry Andric if (isAsciiPrintable(CodePoint)) { 840fe6060f1SDimitry Andric char C = CodePoint; 841fe6060f1SDimitry Andric print(C); 842fe6060f1SDimitry Andric } else { 843fe6060f1SDimitry Andric print(R"(\u{)"); 844fe6060f1SDimitry Andric print(HexDigits); 845fe6060f1SDimitry Andric print('}'); 846fe6060f1SDimitry Andric } 847fe6060f1SDimitry Andric break; 848fe6060f1SDimitry Andric } 849fe6060f1SDimitry Andric print('\''); 850fe6060f1SDimitry Andric } 851fe6060f1SDimitry Andric 852fe6060f1SDimitry Andric // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> 853fe6060f1SDimitry Andric Identifier Demangler::parseIdentifier() { 854fe6060f1SDimitry Andric bool Punycode = consumeIf('u'); 855fe6060f1SDimitry Andric uint64_t Bytes = parseDecimalNumber(); 856fe6060f1SDimitry Andric 857fe6060f1SDimitry Andric // Underscore resolves the ambiguity when identifier starts with a decimal 858fe6060f1SDimitry Andric // digit or another underscore. 859fe6060f1SDimitry Andric consumeIf('_'); 860fe6060f1SDimitry Andric 861fe6060f1SDimitry Andric if (Error || Bytes > Input.size() - Position) { 862fe6060f1SDimitry Andric Error = true; 863fe6060f1SDimitry Andric return {}; 864fe6060f1SDimitry Andric } 865fe6060f1SDimitry Andric StringView S = Input.substr(Position, Bytes); 866fe6060f1SDimitry Andric Position += Bytes; 867fe6060f1SDimitry Andric 868fe6060f1SDimitry Andric if (!std::all_of(S.begin(), S.end(), isValid)) { 869fe6060f1SDimitry Andric Error = true; 870fe6060f1SDimitry Andric return {}; 871fe6060f1SDimitry Andric } 872fe6060f1SDimitry Andric 873fe6060f1SDimitry Andric return {S, Punycode}; 874fe6060f1SDimitry Andric } 875fe6060f1SDimitry Andric 876fe6060f1SDimitry Andric // Parses optional base 62 number. The presence of a number is determined using 877fe6060f1SDimitry Andric // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise 878fe6060f1SDimitry Andric // 879fe6060f1SDimitry Andric // This function is indended for parsing disambiguators and binders which when 880fe6060f1SDimitry Andric // not present have their value interpreted as 0, and otherwise as decoded 881fe6060f1SDimitry Andric // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is 882fe6060f1SDimitry Andric // 2. When "G" is absent value is 0. 883fe6060f1SDimitry Andric uint64_t Demangler::parseOptionalBase62Number(char Tag) { 884fe6060f1SDimitry Andric if (!consumeIf(Tag)) 885fe6060f1SDimitry Andric return 0; 886fe6060f1SDimitry Andric 887fe6060f1SDimitry Andric uint64_t N = parseBase62Number(); 888fe6060f1SDimitry Andric if (Error || !addAssign(N, 1)) 889fe6060f1SDimitry Andric return 0; 890fe6060f1SDimitry Andric 891fe6060f1SDimitry Andric return N; 892fe6060f1SDimitry Andric } 893fe6060f1SDimitry Andric 894fe6060f1SDimitry Andric // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by 895fe6060f1SDimitry Andric // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, 896fe6060f1SDimitry Andric // "1_" encodes 2, etc. 897fe6060f1SDimitry Andric // 898fe6060f1SDimitry Andric // <base-62-number> = {<0-9a-zA-Z>} "_" 899fe6060f1SDimitry Andric uint64_t Demangler::parseBase62Number() { 900fe6060f1SDimitry Andric if (consumeIf('_')) 901fe6060f1SDimitry Andric return 0; 902fe6060f1SDimitry Andric 903fe6060f1SDimitry Andric uint64_t Value = 0; 904fe6060f1SDimitry Andric 905fe6060f1SDimitry Andric while (true) { 906fe6060f1SDimitry Andric uint64_t Digit; 907fe6060f1SDimitry Andric char C = consume(); 908fe6060f1SDimitry Andric 909fe6060f1SDimitry Andric if (C == '_') { 910fe6060f1SDimitry Andric break; 911fe6060f1SDimitry Andric } else if (isDigit(C)) { 912fe6060f1SDimitry Andric Digit = C - '0'; 913fe6060f1SDimitry Andric } else if (isLower(C)) { 914fe6060f1SDimitry Andric Digit = 10 + (C - 'a'); 915fe6060f1SDimitry Andric } else if (isUpper(C)) { 916fe6060f1SDimitry Andric Digit = 10 + 26 + (C - 'A'); 917fe6060f1SDimitry Andric } else { 918fe6060f1SDimitry Andric Error = true; 919fe6060f1SDimitry Andric return 0; 920fe6060f1SDimitry Andric } 921fe6060f1SDimitry Andric 922fe6060f1SDimitry Andric if (!mulAssign(Value, 62)) 923fe6060f1SDimitry Andric return 0; 924fe6060f1SDimitry Andric 925fe6060f1SDimitry Andric if (!addAssign(Value, Digit)) 926fe6060f1SDimitry Andric return 0; 927fe6060f1SDimitry Andric } 928fe6060f1SDimitry Andric 929fe6060f1SDimitry Andric if (!addAssign(Value, 1)) 930fe6060f1SDimitry Andric return 0; 931fe6060f1SDimitry Andric 932fe6060f1SDimitry Andric return Value; 933fe6060f1SDimitry Andric } 934fe6060f1SDimitry Andric 935fe6060f1SDimitry Andric // Parses a decimal number that had been encoded without any leading zeros. 936fe6060f1SDimitry Andric // 937fe6060f1SDimitry Andric // <decimal-number> = "0" 938fe6060f1SDimitry Andric // | <1-9> {<0-9>} 939fe6060f1SDimitry Andric uint64_t Demangler::parseDecimalNumber() { 940fe6060f1SDimitry Andric char C = look(); 941fe6060f1SDimitry Andric if (!isDigit(C)) { 942fe6060f1SDimitry Andric Error = true; 943fe6060f1SDimitry Andric return 0; 944fe6060f1SDimitry Andric } 945fe6060f1SDimitry Andric 946fe6060f1SDimitry Andric if (C == '0') { 947fe6060f1SDimitry Andric consume(); 948fe6060f1SDimitry Andric return 0; 949fe6060f1SDimitry Andric } 950fe6060f1SDimitry Andric 951fe6060f1SDimitry Andric uint64_t Value = 0; 952fe6060f1SDimitry Andric 953fe6060f1SDimitry Andric while (isDigit(look())) { 954fe6060f1SDimitry Andric if (!mulAssign(Value, 10)) { 955fe6060f1SDimitry Andric Error = true; 956fe6060f1SDimitry Andric return 0; 957fe6060f1SDimitry Andric } 958fe6060f1SDimitry Andric 959fe6060f1SDimitry Andric uint64_t D = consume() - '0'; 960fe6060f1SDimitry Andric if (!addAssign(Value, D)) 961fe6060f1SDimitry Andric return 0; 962fe6060f1SDimitry Andric } 963fe6060f1SDimitry Andric 964fe6060f1SDimitry Andric return Value; 965fe6060f1SDimitry Andric } 966fe6060f1SDimitry Andric 967fe6060f1SDimitry Andric // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed 968fe6060f1SDimitry Andric // value and stores hex digits in HexDigits. The return value is unspecified if 969fe6060f1SDimitry Andric // HexDigits.size() > 16. 970fe6060f1SDimitry Andric // 971fe6060f1SDimitry Andric // <hex-number> = "0_" 972fe6060f1SDimitry Andric // | <1-9a-f> {<0-9a-f>} "_" 973fe6060f1SDimitry Andric uint64_t Demangler::parseHexNumber(StringView &HexDigits) { 974fe6060f1SDimitry Andric size_t Start = Position; 975fe6060f1SDimitry Andric uint64_t Value = 0; 976fe6060f1SDimitry Andric 977fe6060f1SDimitry Andric if (!isHexDigit(look())) 978fe6060f1SDimitry Andric Error = true; 979fe6060f1SDimitry Andric 980fe6060f1SDimitry Andric if (consumeIf('0')) { 981fe6060f1SDimitry Andric if (!consumeIf('_')) 982fe6060f1SDimitry Andric Error = true; 983fe6060f1SDimitry Andric } else { 984fe6060f1SDimitry Andric while (!Error && !consumeIf('_')) { 985fe6060f1SDimitry Andric char C = consume(); 986fe6060f1SDimitry Andric Value *= 16; 987fe6060f1SDimitry Andric if (isDigit(C)) 988fe6060f1SDimitry Andric Value += C - '0'; 989fe6060f1SDimitry Andric else if ('a' <= C && C <= 'f') 990fe6060f1SDimitry Andric Value += 10 + (C - 'a'); 991fe6060f1SDimitry Andric else 992fe6060f1SDimitry Andric Error = true; 993fe6060f1SDimitry Andric } 994fe6060f1SDimitry Andric } 995fe6060f1SDimitry Andric 996fe6060f1SDimitry Andric if (Error) { 997fe6060f1SDimitry Andric HexDigits = StringView(); 998fe6060f1SDimitry Andric return 0; 999fe6060f1SDimitry Andric } 1000fe6060f1SDimitry Andric 1001fe6060f1SDimitry Andric size_t End = Position - 1; 1002fe6060f1SDimitry Andric assert(Start < End); 1003fe6060f1SDimitry Andric HexDigits = Input.substr(Start, End - Start); 1004fe6060f1SDimitry Andric return Value; 1005fe6060f1SDimitry Andric } 1006fe6060f1SDimitry Andric 1007fe6060f1SDimitry Andric void Demangler::print(char C) { 1008fe6060f1SDimitry Andric if (Error || !Print) 1009fe6060f1SDimitry Andric return; 1010fe6060f1SDimitry Andric 1011fe6060f1SDimitry Andric Output += C; 1012fe6060f1SDimitry Andric } 1013fe6060f1SDimitry Andric 1014fe6060f1SDimitry Andric void Demangler::print(StringView S) { 1015fe6060f1SDimitry Andric if (Error || !Print) 1016fe6060f1SDimitry Andric return; 1017fe6060f1SDimitry Andric 1018fe6060f1SDimitry Andric Output += S; 1019fe6060f1SDimitry Andric } 1020fe6060f1SDimitry Andric 1021fe6060f1SDimitry Andric void Demangler::printDecimalNumber(uint64_t N) { 1022fe6060f1SDimitry Andric if (Error || !Print) 1023fe6060f1SDimitry Andric return; 1024fe6060f1SDimitry Andric 1025fe6060f1SDimitry Andric Output << N; 1026fe6060f1SDimitry Andric } 1027fe6060f1SDimitry Andric 1028fe6060f1SDimitry Andric // Prints a lifetime. An index 0 always represents an erased lifetime. Indices 1029fe6060f1SDimitry Andric // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes 1030fe6060f1SDimitry Andric // bound by one of the enclosing binders. 1031fe6060f1SDimitry Andric void Demangler::printLifetime(uint64_t Index) { 1032fe6060f1SDimitry Andric if (Index == 0) { 1033fe6060f1SDimitry Andric print("'_"); 1034fe6060f1SDimitry Andric return; 1035fe6060f1SDimitry Andric } 1036fe6060f1SDimitry Andric 1037fe6060f1SDimitry Andric if (Index - 1 >= BoundLifetimes) { 1038fe6060f1SDimitry Andric Error = true; 1039fe6060f1SDimitry Andric return; 1040fe6060f1SDimitry Andric } 1041fe6060f1SDimitry Andric 1042fe6060f1SDimitry Andric uint64_t Depth = BoundLifetimes - Index; 1043fe6060f1SDimitry Andric print('\''); 1044fe6060f1SDimitry Andric if (Depth < 26) { 1045fe6060f1SDimitry Andric char C = 'a' + Depth; 1046fe6060f1SDimitry Andric print(C); 1047fe6060f1SDimitry Andric } else { 1048fe6060f1SDimitry Andric print('z'); 1049fe6060f1SDimitry Andric printDecimalNumber(Depth - 26 + 1); 1050fe6060f1SDimitry Andric } 1051fe6060f1SDimitry Andric } 1052fe6060f1SDimitry Andric 1053349cc55cSDimitry Andric static inline bool decodePunycodeDigit(char C, size_t &Value) { 1054349cc55cSDimitry Andric if (isLower(C)) { 1055349cc55cSDimitry Andric Value = C - 'a'; 1056349cc55cSDimitry Andric return true; 1057349cc55cSDimitry Andric } 1058349cc55cSDimitry Andric 1059349cc55cSDimitry Andric if (isDigit(C)) { 1060349cc55cSDimitry Andric Value = 26 + (C - '0'); 1061349cc55cSDimitry Andric return true; 1062349cc55cSDimitry Andric } 1063349cc55cSDimitry Andric 1064349cc55cSDimitry Andric return false; 1065349cc55cSDimitry Andric } 1066349cc55cSDimitry Andric 1067349cc55cSDimitry Andric static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) { 1068349cc55cSDimitry Andric char *Buffer = Output.getBuffer(); 1069349cc55cSDimitry Andric char *Start = Buffer + StartIdx; 1070349cc55cSDimitry Andric char *End = Buffer + Output.getCurrentPosition(); 1071349cc55cSDimitry Andric Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer); 1072349cc55cSDimitry Andric } 1073349cc55cSDimitry Andric 1074349cc55cSDimitry Andric // Encodes code point as UTF-8 and stores results in Output. Returns false if 1075349cc55cSDimitry Andric // CodePoint is not a valid unicode scalar value. 1076349cc55cSDimitry Andric static inline bool encodeUTF8(size_t CodePoint, char *Output) { 1077349cc55cSDimitry Andric if (0xD800 <= CodePoint && CodePoint <= 0xDFFF) 1078349cc55cSDimitry Andric return false; 1079349cc55cSDimitry Andric 1080349cc55cSDimitry Andric if (CodePoint <= 0x7F) { 1081349cc55cSDimitry Andric Output[0] = CodePoint; 1082349cc55cSDimitry Andric return true; 1083349cc55cSDimitry Andric } 1084349cc55cSDimitry Andric 1085349cc55cSDimitry Andric if (CodePoint <= 0x7FF) { 1086349cc55cSDimitry Andric Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F); 1087349cc55cSDimitry Andric Output[1] = 0x80 | (CodePoint & 0x3F); 1088349cc55cSDimitry Andric return true; 1089349cc55cSDimitry Andric } 1090349cc55cSDimitry Andric 1091349cc55cSDimitry Andric if (CodePoint <= 0xFFFF) { 1092349cc55cSDimitry Andric Output[0] = 0xE0 | (CodePoint >> 12); 1093349cc55cSDimitry Andric Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F); 1094349cc55cSDimitry Andric Output[2] = 0x80 | (CodePoint & 0x3F); 1095349cc55cSDimitry Andric return true; 1096349cc55cSDimitry Andric } 1097349cc55cSDimitry Andric 1098349cc55cSDimitry Andric if (CodePoint <= 0x10FFFF) { 1099349cc55cSDimitry Andric Output[0] = 0xF0 | (CodePoint >> 18); 1100349cc55cSDimitry Andric Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F); 1101349cc55cSDimitry Andric Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F); 1102349cc55cSDimitry Andric Output[3] = 0x80 | (CodePoint & 0x3F); 1103349cc55cSDimitry Andric return true; 1104349cc55cSDimitry Andric } 1105349cc55cSDimitry Andric 1106349cc55cSDimitry Andric return false; 1107349cc55cSDimitry Andric } 1108349cc55cSDimitry Andric 1109349cc55cSDimitry Andric // Decodes string encoded using punycode and appends results to Output. 1110349cc55cSDimitry Andric // Returns true if decoding was successful. 1111349cc55cSDimitry Andric static bool decodePunycode(StringView Input, OutputBuffer &Output) { 1112349cc55cSDimitry Andric size_t OutputSize = Output.getCurrentPosition(); 1113349cc55cSDimitry Andric size_t InputIdx = 0; 1114349cc55cSDimitry Andric 1115349cc55cSDimitry Andric // Rust uses an underscore as a delimiter. 1116349cc55cSDimitry Andric size_t DelimiterPos = StringView::npos; 1117349cc55cSDimitry Andric for (size_t I = 0; I != Input.size(); ++I) 1118349cc55cSDimitry Andric if (Input[I] == '_') 1119349cc55cSDimitry Andric DelimiterPos = I; 1120349cc55cSDimitry Andric 1121349cc55cSDimitry Andric if (DelimiterPos != StringView::npos) { 1122349cc55cSDimitry Andric // Copy basic code points before the last delimiter to the output. 1123349cc55cSDimitry Andric for (; InputIdx != DelimiterPos; ++InputIdx) { 1124349cc55cSDimitry Andric char C = Input[InputIdx]; 1125349cc55cSDimitry Andric if (!isValid(C)) 1126349cc55cSDimitry Andric return false; 1127349cc55cSDimitry Andric // Code points are padded with zeros while decoding is in progress. 1128349cc55cSDimitry Andric char UTF8[4] = {C}; 1129349cc55cSDimitry Andric Output += StringView(UTF8, UTF8 + 4); 1130349cc55cSDimitry Andric } 1131349cc55cSDimitry Andric // Skip over the delimiter. 1132349cc55cSDimitry Andric ++InputIdx; 1133349cc55cSDimitry Andric } 1134349cc55cSDimitry Andric 1135349cc55cSDimitry Andric size_t Base = 36; 1136349cc55cSDimitry Andric size_t Skew = 38; 1137349cc55cSDimitry Andric size_t Bias = 72; 1138349cc55cSDimitry Andric size_t N = 0x80; 1139349cc55cSDimitry Andric size_t TMin = 1; 1140349cc55cSDimitry Andric size_t TMax = 26; 1141349cc55cSDimitry Andric size_t Damp = 700; 1142349cc55cSDimitry Andric 1143349cc55cSDimitry Andric auto Adapt = [&](size_t Delta, size_t NumPoints) { 1144349cc55cSDimitry Andric Delta /= Damp; 1145349cc55cSDimitry Andric Delta += Delta / NumPoints; 1146349cc55cSDimitry Andric Damp = 2; 1147349cc55cSDimitry Andric 1148349cc55cSDimitry Andric size_t K = 0; 1149349cc55cSDimitry Andric while (Delta > (Base - TMin) * TMax / 2) { 1150349cc55cSDimitry Andric Delta /= Base - TMin; 1151349cc55cSDimitry Andric K += Base; 1152349cc55cSDimitry Andric } 1153349cc55cSDimitry Andric return K + (((Base - TMin + 1) * Delta) / (Delta + Skew)); 1154349cc55cSDimitry Andric }; 1155349cc55cSDimitry Andric 1156349cc55cSDimitry Andric // Main decoding loop. 1157349cc55cSDimitry Andric for (size_t I = 0; InputIdx != Input.size(); I += 1) { 1158349cc55cSDimitry Andric size_t OldI = I; 1159349cc55cSDimitry Andric size_t W = 1; 1160349cc55cSDimitry Andric size_t Max = std::numeric_limits<size_t>::max(); 1161349cc55cSDimitry Andric for (size_t K = Base; true; K += Base) { 1162349cc55cSDimitry Andric if (InputIdx == Input.size()) 1163349cc55cSDimitry Andric return false; 1164349cc55cSDimitry Andric char C = Input[InputIdx++]; 1165349cc55cSDimitry Andric size_t Digit = 0; 1166349cc55cSDimitry Andric if (!decodePunycodeDigit(C, Digit)) 1167349cc55cSDimitry Andric return false; 1168349cc55cSDimitry Andric 1169349cc55cSDimitry Andric if (Digit > (Max - I) / W) 1170349cc55cSDimitry Andric return false; 1171349cc55cSDimitry Andric I += Digit * W; 1172349cc55cSDimitry Andric 1173349cc55cSDimitry Andric size_t T; 1174349cc55cSDimitry Andric if (K <= Bias) 1175349cc55cSDimitry Andric T = TMin; 1176349cc55cSDimitry Andric else if (K >= Bias + TMax) 1177349cc55cSDimitry Andric T = TMax; 1178349cc55cSDimitry Andric else 1179349cc55cSDimitry Andric T = K - Bias; 1180349cc55cSDimitry Andric 1181349cc55cSDimitry Andric if (Digit < T) 1182349cc55cSDimitry Andric break; 1183349cc55cSDimitry Andric 1184349cc55cSDimitry Andric if (W > Max / (Base - T)) 1185349cc55cSDimitry Andric return false; 1186349cc55cSDimitry Andric W *= (Base - T); 1187349cc55cSDimitry Andric } 1188349cc55cSDimitry Andric size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1; 1189349cc55cSDimitry Andric Bias = Adapt(I - OldI, NumPoints); 1190349cc55cSDimitry Andric 1191349cc55cSDimitry Andric if (I / NumPoints > Max - N) 1192349cc55cSDimitry Andric return false; 1193349cc55cSDimitry Andric N += I / NumPoints; 1194349cc55cSDimitry Andric I = I % NumPoints; 1195349cc55cSDimitry Andric 1196349cc55cSDimitry Andric // Insert N at position I in the output. 1197349cc55cSDimitry Andric char UTF8[4] = {}; 1198349cc55cSDimitry Andric if (!encodeUTF8(N, UTF8)) 1199349cc55cSDimitry Andric return false; 1200349cc55cSDimitry Andric Output.insert(OutputSize + I * 4, UTF8, 4); 1201349cc55cSDimitry Andric } 1202349cc55cSDimitry Andric 1203349cc55cSDimitry Andric removeNullBytes(Output, OutputSize); 1204349cc55cSDimitry Andric return true; 1205349cc55cSDimitry Andric } 1206349cc55cSDimitry Andric 1207349cc55cSDimitry Andric void Demangler::printIdentifier(Identifier Ident) { 1208349cc55cSDimitry Andric if (Error || !Print) 1209349cc55cSDimitry Andric return; 1210349cc55cSDimitry Andric 1211349cc55cSDimitry Andric if (Ident.Punycode) { 1212349cc55cSDimitry Andric if (!decodePunycode(Ident.Name, Output)) 1213349cc55cSDimitry Andric Error = true; 1214349cc55cSDimitry Andric } else { 1215349cc55cSDimitry Andric print(Ident.Name); 1216349cc55cSDimitry Andric } 1217349cc55cSDimitry Andric } 1218349cc55cSDimitry Andric 1219fe6060f1SDimitry Andric char Demangler::look() const { 1220fe6060f1SDimitry Andric if (Error || Position >= Input.size()) 1221fe6060f1SDimitry Andric return 0; 1222fe6060f1SDimitry Andric 1223fe6060f1SDimitry Andric return Input[Position]; 1224fe6060f1SDimitry Andric } 1225fe6060f1SDimitry Andric 1226fe6060f1SDimitry Andric char Demangler::consume() { 1227fe6060f1SDimitry Andric if (Error || Position >= Input.size()) { 1228fe6060f1SDimitry Andric Error = true; 1229fe6060f1SDimitry Andric return 0; 1230fe6060f1SDimitry Andric } 1231fe6060f1SDimitry Andric 1232fe6060f1SDimitry Andric return Input[Position++]; 1233fe6060f1SDimitry Andric } 1234fe6060f1SDimitry Andric 1235fe6060f1SDimitry Andric bool Demangler::consumeIf(char Prefix) { 1236fe6060f1SDimitry Andric if (Error || Position >= Input.size() || Input[Position] != Prefix) 1237fe6060f1SDimitry Andric return false; 1238fe6060f1SDimitry Andric 1239fe6060f1SDimitry Andric Position += 1; 1240fe6060f1SDimitry Andric return true; 1241fe6060f1SDimitry Andric } 1242fe6060f1SDimitry Andric 1243fe6060f1SDimitry Andric /// Computes A + B. When computation wraps around sets the error and returns 1244fe6060f1SDimitry Andric /// false. Otherwise assigns the result to A and returns true. 1245fe6060f1SDimitry Andric bool Demangler::addAssign(uint64_t &A, uint64_t B) { 1246fe6060f1SDimitry Andric if (A > std::numeric_limits<uint64_t>::max() - B) { 1247fe6060f1SDimitry Andric Error = true; 1248fe6060f1SDimitry Andric return false; 1249fe6060f1SDimitry Andric } 1250fe6060f1SDimitry Andric 1251fe6060f1SDimitry Andric A += B; 1252fe6060f1SDimitry Andric return true; 1253fe6060f1SDimitry Andric } 1254fe6060f1SDimitry Andric 1255fe6060f1SDimitry Andric /// Computes A * B. When computation wraps around sets the error and returns 1256fe6060f1SDimitry Andric /// false. Otherwise assigns the result to A and returns true. 1257fe6060f1SDimitry Andric bool Demangler::mulAssign(uint64_t &A, uint64_t B) { 1258fe6060f1SDimitry Andric if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) { 1259fe6060f1SDimitry Andric Error = true; 1260fe6060f1SDimitry Andric return false; 1261fe6060f1SDimitry Andric } 1262fe6060f1SDimitry Andric 1263fe6060f1SDimitry Andric A *= B; 1264fe6060f1SDimitry Andric return true; 1265fe6060f1SDimitry Andric } 1266