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