[flang] Treat pre-processed input as fixed (#117563)
[llvm-project.git] / libcxxabi / src / cxa_demangle.cpp
blob4756d8343630b96355cecc2929cdc42788380a0e
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 // FIXME: (possibly) incomplete list of features that clang mangles that this
10 // file does not yet support:
11 // - C++ modules TS
13 #include "abort_message.h"
14 #define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
16 #include "demangle/DemangleConfig.h"
17 #include "demangle/ItaniumDemangle.h"
18 #include "__cxxabi_config.h"
19 #include <cctype>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <exception>
24 #include <functional>
25 #include <numeric>
26 #include <string_view>
27 #include <utility>
29 using namespace itanium_demangle;
31 // <discriminator> := _ <non-negative number> # when number < 10
32 // := __ <non-negative number> _ # when number >= 10
33 // extension := decimal-digit+ # at the end of string
34 const char *itanium_demangle::parse_discriminator(const char *first,
35 const char *last) {
36 // parse but ignore discriminator
37 if (first != last) {
38 if (*first == '_') {
39 const char *t1 = first + 1;
40 if (t1 != last) {
41 if (std::isdigit(*t1))
42 first = t1 + 1;
43 else if (*t1 == '_') {
44 for (++t1; t1 != last && std::isdigit(*t1); ++t1)
46 if (t1 != last && *t1 == '_')
47 first = t1 + 1;
50 } else if (std::isdigit(*first)) {
51 const char *t1 = first + 1;
52 for (; t1 != last && std::isdigit(*t1); ++t1)
54 if (t1 == last)
55 first = last;
58 return first;
61 #ifndef NDEBUG
62 namespace {
63 struct DumpVisitor {
64 unsigned Depth = 0;
65 bool PendingNewline = false;
67 template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
68 return true;
70 static bool wantsNewline(NodeArray A) { return !A.empty(); }
71 static constexpr bool wantsNewline(...) { return false; }
73 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
74 for (bool B : {wantsNewline(Vs)...})
75 if (B)
76 return true;
77 return false;
80 void printStr(const char *S) { fprintf(stderr, "%s", S); }
81 void print(std::string_view SV) {
82 fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin());
84 void print(const Node *N) {
85 if (N)
86 N->visit(std::ref(*this));
87 else
88 printStr("<null>");
90 void print(NodeArray A) {
91 ++Depth;
92 printStr("{");
93 bool First = true;
94 for (const Node *N : A) {
95 if (First)
96 print(N);
97 else
98 printWithComma(N);
99 First = false;
101 printStr("}");
102 --Depth;
105 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
106 void print(bool B) { printStr(B ? "true" : "false"); }
108 template <class T>
109 typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
110 fprintf(stderr, "%llu", (unsigned long long)N);
113 template <class T>
114 typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
115 fprintf(stderr, "%lld", (long long)N);
118 void print(ReferenceKind RK) {
119 switch (RK) {
120 case ReferenceKind::LValue:
121 return printStr("ReferenceKind::LValue");
122 case ReferenceKind::RValue:
123 return printStr("ReferenceKind::RValue");
126 void print(FunctionRefQual RQ) {
127 switch (RQ) {
128 case FunctionRefQual::FrefQualNone:
129 return printStr("FunctionRefQual::FrefQualNone");
130 case FunctionRefQual::FrefQualLValue:
131 return printStr("FunctionRefQual::FrefQualLValue");
132 case FunctionRefQual::FrefQualRValue:
133 return printStr("FunctionRefQual::FrefQualRValue");
136 void print(Qualifiers Qs) {
137 if (!Qs) return printStr("QualNone");
138 struct QualName { Qualifiers Q; const char *Name; } Names[] = {
139 {QualConst, "QualConst"},
140 {QualVolatile, "QualVolatile"},
141 {QualRestrict, "QualRestrict"},
143 for (QualName Name : Names) {
144 if (Qs & Name.Q) {
145 printStr(Name.Name);
146 Qs = Qualifiers(Qs & ~Name.Q);
147 if (Qs) printStr(" | ");
151 void print(SpecialSubKind SSK) {
152 switch (SSK) {
153 case SpecialSubKind::allocator:
154 return printStr("SpecialSubKind::allocator");
155 case SpecialSubKind::basic_string:
156 return printStr("SpecialSubKind::basic_string");
157 case SpecialSubKind::string:
158 return printStr("SpecialSubKind::string");
159 case SpecialSubKind::istream:
160 return printStr("SpecialSubKind::istream");
161 case SpecialSubKind::ostream:
162 return printStr("SpecialSubKind::ostream");
163 case SpecialSubKind::iostream:
164 return printStr("SpecialSubKind::iostream");
167 void print(TemplateParamKind TPK) {
168 switch (TPK) {
169 case TemplateParamKind::Type:
170 return printStr("TemplateParamKind::Type");
171 case TemplateParamKind::NonType:
172 return printStr("TemplateParamKind::NonType");
173 case TemplateParamKind::Template:
174 return printStr("TemplateParamKind::Template");
177 void print(Node::Prec P) {
178 switch (P) {
179 case Node::Prec::Primary:
180 return printStr("Node::Prec::Primary");
181 case Node::Prec::Postfix:
182 return printStr("Node::Prec::Postfix");
183 case Node::Prec::Unary:
184 return printStr("Node::Prec::Unary");
185 case Node::Prec::Cast:
186 return printStr("Node::Prec::Cast");
187 case Node::Prec::PtrMem:
188 return printStr("Node::Prec::PtrMem");
189 case Node::Prec::Multiplicative:
190 return printStr("Node::Prec::Multiplicative");
191 case Node::Prec::Additive:
192 return printStr("Node::Prec::Additive");
193 case Node::Prec::Shift:
194 return printStr("Node::Prec::Shift");
195 case Node::Prec::Spaceship:
196 return printStr("Node::Prec::Spaceship");
197 case Node::Prec::Relational:
198 return printStr("Node::Prec::Relational");
199 case Node::Prec::Equality:
200 return printStr("Node::Prec::Equality");
201 case Node::Prec::And:
202 return printStr("Node::Prec::And");
203 case Node::Prec::Xor:
204 return printStr("Node::Prec::Xor");
205 case Node::Prec::Ior:
206 return printStr("Node::Prec::Ior");
207 case Node::Prec::AndIf:
208 return printStr("Node::Prec::AndIf");
209 case Node::Prec::OrIf:
210 return printStr("Node::Prec::OrIf");
211 case Node::Prec::Conditional:
212 return printStr("Node::Prec::Conditional");
213 case Node::Prec::Assign:
214 return printStr("Node::Prec::Assign");
215 case Node::Prec::Comma:
216 return printStr("Node::Prec::Comma");
217 case Node::Prec::Default:
218 return printStr("Node::Prec::Default");
222 void newLine() {
223 printStr("\n");
224 for (unsigned I = 0; I != Depth; ++I)
225 printStr(" ");
226 PendingNewline = false;
229 template<typename T> void printWithPendingNewline(T V) {
230 print(V);
231 if (wantsNewline(V))
232 PendingNewline = true;
235 template<typename T> void printWithComma(T V) {
236 if (PendingNewline || wantsNewline(V)) {
237 printStr(",");
238 newLine();
239 } else {
240 printStr(", ");
243 printWithPendingNewline(V);
246 struct CtorArgPrinter {
247 DumpVisitor &Visitor;
249 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
250 if (Visitor.anyWantNewline(V, Vs...))
251 Visitor.newLine();
252 Visitor.printWithPendingNewline(V);
253 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
254 (void)PrintInOrder;
258 template<typename NodeT> void operator()(const NodeT *Node) {
259 Depth += 2;
260 fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
261 Node->match(CtorArgPrinter{*this});
262 fprintf(stderr, ")");
263 Depth -= 2;
266 void operator()(const ForwardTemplateReference *Node) {
267 Depth += 2;
268 fprintf(stderr, "ForwardTemplateReference(");
269 if (Node->Ref && !Node->Printing) {
270 Node->Printing = true;
271 CtorArgPrinter{*this}(Node->Ref);
272 Node->Printing = false;
273 } else {
274 CtorArgPrinter{*this}(Node->Index);
276 fprintf(stderr, ")");
277 Depth -= 2;
282 void itanium_demangle::Node::dump() const {
283 DumpVisitor V;
284 visit(std::ref(V));
285 V.newLine();
287 #endif
289 namespace {
290 class BumpPointerAllocator {
291 struct BlockMeta {
292 BlockMeta* Next;
293 size_t Current;
296 static constexpr size_t AllocSize = 4096;
297 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
299 alignas(long double) char InitialBuffer[AllocSize];
300 BlockMeta* BlockList = nullptr;
302 void grow() {
303 char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
304 if (NewMeta == nullptr)
305 std::terminate();
306 BlockList = new (NewMeta) BlockMeta{BlockList, 0};
309 void* allocateMassive(size_t NBytes) {
310 NBytes += sizeof(BlockMeta);
311 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
312 if (NewMeta == nullptr)
313 std::terminate();
314 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
315 return static_cast<void*>(NewMeta + 1);
318 public:
319 BumpPointerAllocator()
320 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
322 void* allocate(size_t N) {
323 N = (N + 15u) & ~15u;
324 if (N + BlockList->Current >= UsableAllocSize) {
325 if (N > UsableAllocSize)
326 return allocateMassive(N);
327 grow();
329 BlockList->Current += N;
330 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
331 BlockList->Current - N);
334 void reset() {
335 while (BlockList) {
336 BlockMeta* Tmp = BlockList;
337 BlockList = BlockList->Next;
338 if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
339 std::free(Tmp);
341 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
344 ~BumpPointerAllocator() { reset(); }
347 class DefaultAllocator {
348 BumpPointerAllocator Alloc;
350 public:
351 void reset() { Alloc.reset(); }
353 template<typename T, typename ...Args> T *makeNode(Args &&...args) {
354 return new (Alloc.allocate(sizeof(T)))
355 T(std::forward<Args>(args)...);
358 void *allocateNodeArray(size_t sz) {
359 return Alloc.allocate(sizeof(Node *) * sz);
362 } // unnamed namespace
364 //===----------------------------------------------------------------------===//
365 // Code beyond this point should not be synchronized with LLVM.
366 //===----------------------------------------------------------------------===//
368 using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
370 namespace {
371 enum : int {
372 demangle_invalid_args = -3,
373 demangle_invalid_mangled_name = -2,
374 demangle_memory_alloc_failure = -1,
375 demangle_success = 0,
379 namespace __cxxabiv1 {
380 extern "C" _LIBCXXABI_FUNC_VIS char *
381 __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
382 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
383 if (Status)
384 *Status = demangle_invalid_args;
385 return nullptr;
388 int InternalStatus = demangle_success;
389 Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
390 Node *AST = Parser.parse();
392 if (AST == nullptr)
393 InternalStatus = demangle_invalid_mangled_name;
394 else {
395 OutputBuffer O(Buf, N);
396 DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");
397 AST->print(O);
398 O += '\0';
399 if (N != nullptr)
400 *N = O.getCurrentPosition();
401 Buf = O.getBuffer();
404 if (Status)
405 *Status = InternalStatus;
406 return InternalStatus == demangle_success ? Buf : nullptr;
408 } // __cxxabiv1