xref: /freebsd-src/contrib/llvm-project/llvm/lib/Demangle/RustDemangle.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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