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