File: | tools/lldb/source/Utility/FastDemangle.cpp |
Warning: | line 357, column 5 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- FastDemangle.cpp ----------------------------------------*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | ||||
10 | #include "lldb/Utility/FastDemangle.h" | |||
11 | ||||
12 | #include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH | |||
13 | ||||
14 | #include <functional> | |||
15 | ||||
16 | #include <stdio.h> | |||
17 | #include <stdlib.h> | |||
18 | #include <string.h> | |||
19 | ||||
20 | //#define DEBUG_FAILURES 1 | |||
21 | //#define DEBUG_SUBSTITUTIONS 1 | |||
22 | //#define DEBUG_TEMPLATE_ARGS 1 | |||
23 | //#define DEBUG_HIGHWATER 1 | |||
24 | //#define DEBUG_REORDERING 1 | |||
25 | ||||
26 | namespace { | |||
27 | ||||
28 | /// Represents the collection of qualifiers on a type | |||
29 | ||||
30 | enum Qualifiers { | |||
31 | QualifierNone = 0, | |||
32 | QualifierConst = 1, | |||
33 | QualifierRestrict = 2, | |||
34 | QualifierVolatile = 4, | |||
35 | QualifierReference = 8, | |||
36 | QualifierRValueReference = 16, | |||
37 | QualifierPointer = 32 | |||
38 | }; | |||
39 | ||||
40 | /// Categorizes the recognized operators | |||
41 | ||||
42 | enum class OperatorKind { | |||
43 | Unary, | |||
44 | Postfix, | |||
45 | Binary, | |||
46 | Ternary, | |||
47 | Other, | |||
48 | ConversionOperator, | |||
49 | Vendor, | |||
50 | NoMatch | |||
51 | }; | |||
52 | ||||
53 | /// Represents one of the recognized two-character operator abbreviations used | |||
54 | /// when parsing operators as names and expressions | |||
55 | ||||
56 | struct Operator { | |||
57 | const char *name; | |||
58 | OperatorKind kind; | |||
59 | }; | |||
60 | ||||
61 | /// Represents a range of characters in the output buffer, typically for use | |||
62 | /// with RewriteRange() | |||
63 | ||||
64 | struct BufferRange { | |||
65 | int offset; | |||
66 | int length; | |||
67 | }; | |||
68 | ||||
69 | /// Transient state required while parsing a name | |||
70 | ||||
71 | struct NameState { | |||
72 | bool parse_function_params; | |||
73 | bool is_last_generic; | |||
74 | bool has_no_return_type; | |||
75 | BufferRange last_name_range; | |||
76 | }; | |||
77 | ||||
78 | /// LLDB's fast C++ demangler | |||
79 | /// | |||
80 | /// This is an incomplete implementation designed to speed up the demangling | |||
81 | /// process that is often a bottleneck when LLDB stops a process for the first | |||
82 | /// time. Where the implementation doesn't know how to demangle a symbol it | |||
83 | /// fails gracefully to allow the caller to fall back to the existing | |||
84 | /// demangler. | |||
85 | /// | |||
86 | /// Over time the full mangling spec should be supported without compromising | |||
87 | /// performance for the most common cases. | |||
88 | ||||
89 | class SymbolDemangler { | |||
90 | public: | |||
91 | //---------------------------------------------------- | |||
92 | // Public API | |||
93 | //---------------------------------------------------- | |||
94 | ||||
95 | /// Create a SymbolDemangler | |||
96 | /// | |||
97 | /// The newly created demangler allocates and owns scratch memory sufficient | |||
98 | /// for demangling typical symbols. Additional memory will be allocated if | |||
99 | /// needed and managed by the demangler instance. | |||
100 | ||||
101 | SymbolDemangler() { | |||
102 | m_buffer = (char *)malloc(8192); | |||
103 | m_buffer_end = m_buffer + 8192; | |||
104 | m_owns_buffer = true; | |||
105 | ||||
106 | m_rewrite_ranges = (BufferRange *)malloc(128 * sizeof(BufferRange)); | |||
107 | m_rewrite_ranges_size = 128; | |||
108 | m_owns_m_rewrite_ranges = true; | |||
109 | } | |||
110 | ||||
111 | /// Create a SymbolDemangler that uses provided scratch memory | |||
112 | /// | |||
113 | /// The provided memory is not owned by the demangler. It will be | |||
114 | /// overwritten during calls to GetDemangledCopy() but can be used for other | |||
115 | /// purposes between calls. The provided memory will not be freed when this | |||
116 | /// instance is destroyed. | |||
117 | /// | |||
118 | /// If demangling a symbol requires additional space it will be allocated | |||
119 | /// and managed by the demangler instance. | |||
120 | /// | |||
121 | /// @param storage_ptr Valid pointer to at least storage_size bytes of space | |||
122 | /// that the SymbolDemangler can use during demangling | |||
123 | /// | |||
124 | /// @param storage_size Number of bytes of space available scratch memory | |||
125 | /// referenced by storage_ptr | |||
126 | ||||
127 | SymbolDemangler(void *storage_ptr, size_t storage_size, | |||
128 | std::function<void(const char *)> builtins_hook = nullptr) | |||
129 | : m_builtins_hook(builtins_hook) { | |||
130 | // Use up to 1/8th of the provided space for rewrite ranges | |||
131 | m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange); | |||
132 | m_rewrite_ranges = (BufferRange *)storage_ptr; | |||
133 | m_owns_m_rewrite_ranges = false; | |||
134 | ||||
135 | // Use the rest for the character buffer | |||
136 | m_buffer = | |||
137 | (char *)storage_ptr + m_rewrite_ranges_size * sizeof(BufferRange); | |||
138 | m_buffer_end = (const char *)storage_ptr + storage_size; | |||
139 | m_owns_buffer = false; | |||
140 | } | |||
141 | ||||
142 | /// Destroys the SymbolDemangler and deallocates any scratch memory that it | |||
143 | /// owns | |||
144 | ||||
145 | ~SymbolDemangler() { | |||
146 | if (m_owns_buffer) | |||
147 | free(m_buffer); | |||
148 | if (m_owns_m_rewrite_ranges) | |||
149 | free(m_rewrite_ranges); | |||
150 | } | |||
151 | ||||
152 | #ifdef DEBUG_HIGHWATER | |||
153 | int highwater_store = 0; | |||
154 | int highwater_buffer = 0; | |||
155 | #endif | |||
156 | ||||
157 | /// Parses the provided mangled name and returns a newly allocated | |||
158 | /// demangling | |||
159 | /// | |||
160 | /// @param mangled_name Valid null-terminated C++ mangled name following the | |||
161 | /// Itanium C++ ABI mangling specification as implemented by Clang | |||
162 | /// | |||
163 | /// @result Newly allocated null-terminated demangled name when demangling | |||
164 | /// is successful, and nullptr when demangling fails. The caller is | |||
165 | /// responsible for freeing the allocated memory. | |||
166 | ||||
167 | char *GetDemangledCopy(const char *mangled_name, | |||
168 | long mangled_name_length = 0) { | |||
169 | if (!ParseMangling(mangled_name, mangled_name_length)) | |||
170 | return nullptr; | |||
171 | ||||
172 | #ifdef DEBUG_HIGHWATER | |||
173 | int rewrite_count = m_next_substitute_index + | |||
174 | (m_rewrite_ranges_size - 1 - m_next_template_arg_index); | |||
175 | int buffer_size = (int)(m_write_ptr - m_buffer); | |||
176 | if (rewrite_count > highwater_store) | |||
177 | highwater_store = rewrite_count; | |||
178 | if (buffer_size > highwater_buffer) | |||
179 | highwater_buffer = buffer_size; | |||
180 | #endif | |||
181 | ||||
182 | int length = (int)(m_write_ptr - m_buffer); | |||
183 | char *copy = (char *)malloc(length + 1); | |||
184 | memcpy(copy, m_buffer, length); | |||
185 | copy[length] = '\0'; | |||
186 | return copy; | |||
187 | } | |||
188 | ||||
189 | private: | |||
190 | //---------------------------------------------------- | |||
191 | // Grow methods | |||
192 | // | |||
193 | // Manage the storage used during demangling | |||
194 | //---------------------------------------------------- | |||
195 | ||||
196 | void GrowBuffer(long min_growth = 0) { | |||
197 | // By default, double the size of the buffer | |||
198 | long growth = m_buffer_end - m_buffer; | |||
199 | ||||
200 | // Avoid growing by more than 1MB at a time | |||
201 | if (growth > 1 << 20) | |||
202 | growth = 1 << 20; | |||
203 | ||||
204 | // ... but never grow by less than requested, or 1K, whichever is greater | |||
205 | if (min_growth < 1024) | |||
206 | min_growth = 1024; | |||
207 | if (growth < min_growth) | |||
208 | growth = min_growth; | |||
209 | ||||
210 | // Allocate the new m_buffer and migrate content | |||
211 | long new_size = (m_buffer_end - m_buffer) + growth; | |||
212 | char *new_buffer = (char *)malloc(new_size); | |||
213 | memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer); | |||
214 | if (m_owns_buffer) | |||
215 | free(m_buffer); | |||
216 | m_owns_buffer = true; | |||
217 | ||||
218 | // Update references to the new buffer | |||
219 | m_write_ptr = new_buffer + (m_write_ptr - m_buffer); | |||
220 | m_buffer = new_buffer; | |||
221 | m_buffer_end = m_buffer + new_size; | |||
222 | } | |||
223 | ||||
224 | void GrowRewriteRanges() { | |||
225 | // By default, double the size of the array | |||
226 | int growth = m_rewrite_ranges_size; | |||
227 | ||||
228 | // Apply reasonable minimum and maximum sizes for growth | |||
229 | if (growth > 128) | |||
230 | growth = 128; | |||
231 | if (growth < 16) | |||
232 | growth = 16; | |||
233 | ||||
234 | // Allocate the new array and migrate content | |||
235 | int bytes = (m_rewrite_ranges_size + growth) * sizeof(BufferRange); | |||
236 | BufferRange *new_ranges = (BufferRange *)malloc(bytes); | |||
237 | for (int index = 0; index < m_next_substitute_index; index++) { | |||
238 | new_ranges[index] = m_rewrite_ranges[index]; | |||
239 | } | |||
240 | for (int index = m_rewrite_ranges_size - 1; | |||
241 | index > m_next_template_arg_index; index--) { | |||
242 | new_ranges[index + growth] = m_rewrite_ranges[index]; | |||
243 | } | |||
244 | if (m_owns_m_rewrite_ranges) | |||
245 | free(m_rewrite_ranges); | |||
246 | m_owns_m_rewrite_ranges = true; | |||
247 | ||||
248 | // Update references to the new array | |||
249 | m_rewrite_ranges = new_ranges; | |||
250 | m_rewrite_ranges_size += growth; | |||
251 | m_next_template_arg_index += growth; | |||
252 | } | |||
253 | ||||
254 | //---------------------------------------------------- | |||
255 | // Range and state management | |||
256 | //---------------------------------------------------- | |||
257 | ||||
258 | int GetStartCookie() { return (int)(m_write_ptr - m_buffer); } | |||
259 | ||||
260 | BufferRange EndRange(int start_cookie) { | |||
261 | return {start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie))}; | |||
262 | } | |||
263 | ||||
264 | void ReorderRange(BufferRange source_range, int insertion_point_cookie) { | |||
265 | // Ensure there's room the preserve the source range | |||
266 | if (m_write_ptr + source_range.length > m_buffer_end) { | |||
267 | GrowBuffer(m_write_ptr + source_range.length - m_buffer_end); | |||
268 | } | |||
269 | ||||
270 | // Reorder the content | |||
271 | memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length); | |||
272 | memmove(m_buffer + insertion_point_cookie + source_range.length, | |||
273 | m_buffer + insertion_point_cookie, | |||
274 | source_range.offset - insertion_point_cookie); | |||
275 | memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length); | |||
276 | ||||
277 | // Fix up rewritable ranges, covering both substitutions and templates | |||
278 | int index = 0; | |||
279 | while (true) { | |||
280 | if (index == m_next_substitute_index) | |||
281 | index = m_next_template_arg_index + 1; | |||
282 | if (index == m_rewrite_ranges_size) | |||
283 | break; | |||
284 | ||||
285 | // Affected ranges are either shuffled forward when after the insertion | |||
286 | // but before the source, or backward when inside the source | |||
287 | int candidate_offset = m_rewrite_ranges[index].offset; | |||
288 | if (candidate_offset >= insertion_point_cookie) { | |||
289 | if (candidate_offset < source_range.offset) { | |||
290 | m_rewrite_ranges[index].offset += source_range.length; | |||
291 | } else if (candidate_offset >= source_range.offset) { | |||
292 | m_rewrite_ranges[index].offset -= | |||
293 | (source_range.offset - insertion_point_cookie); | |||
294 | } | |||
295 | } | |||
296 | ++index; | |||
297 | } | |||
298 | } | |||
299 | ||||
300 | void EndSubstitution(int start_cookie) { | |||
301 | if (m_next_substitute_index == m_next_template_arg_index) | |||
302 | GrowRewriteRanges(); | |||
303 | ||||
304 | int index = m_next_substitute_index++; | |||
305 | m_rewrite_ranges[index] = EndRange(start_cookie); | |||
306 | #ifdef DEBUG_SUBSTITUTIONS | |||
307 | printf("Saved substitution # %d = %.*s\n", index, | |||
308 | m_rewrite_ranges[index].length, m_buffer + start_cookie); | |||
309 | #endif | |||
310 | } | |||
311 | ||||
312 | void EndTemplateArg(int start_cookie) { | |||
313 | if (m_next_substitute_index == m_next_template_arg_index) | |||
314 | GrowRewriteRanges(); | |||
315 | ||||
316 | int index = m_next_template_arg_index--; | |||
317 | m_rewrite_ranges[index] = EndRange(start_cookie); | |||
318 | #ifdef DEBUG_TEMPLATE_ARGS | |||
319 | printf("Saved template arg # %d = %.*s\n", | |||
320 | m_rewrite_ranges_size - index - 1, m_rewrite_ranges[index].length, | |||
321 | m_buffer + start_cookie); | |||
322 | #endif | |||
323 | } | |||
324 | ||||
325 | void ResetTemplateArgs() { | |||
326 | // TODO: this works, but is it the right thing to do? | |||
327 | // Should we push/pop somehow at the call sites? | |||
328 | m_next_template_arg_index = m_rewrite_ranges_size - 1; | |||
329 | } | |||
330 | ||||
331 | //---------------------------------------------------- | |||
332 | // Write methods | |||
333 | // | |||
334 | // Appends content to the existing output buffer | |||
335 | //---------------------------------------------------- | |||
336 | ||||
337 | void Write(char character) { | |||
338 | if (m_write_ptr == m_buffer_end) | |||
339 | GrowBuffer(); | |||
340 | *m_write_ptr++ = character; | |||
341 | } | |||
342 | ||||
343 | void Write(const char *content) { Write(content, strlen(content)); } | |||
344 | ||||
345 | void Write(const char *content, long content_length) { | |||
346 | char *end_m_write_ptr = m_write_ptr + content_length; | |||
347 | if (end_m_write_ptr > m_buffer_end) { | |||
348 | if (content >= m_buffer && content < m_buffer_end) { | |||
349 | long offset = content - m_buffer; | |||
350 | GrowBuffer(end_m_write_ptr - m_buffer_end); | |||
351 | content = m_buffer + offset; | |||
352 | } else { | |||
353 | GrowBuffer(end_m_write_ptr - m_buffer_end); | |||
354 | } | |||
355 | end_m_write_ptr = m_write_ptr + content_length; | |||
356 | } | |||
357 | memcpy(m_write_ptr, content, content_length); | |||
| ||||
358 | m_write_ptr = end_m_write_ptr; | |||
359 | } | |||
360 | #define WRITE(x)Write(x, sizeof(x) - 1) Write(x, sizeof(x) - 1) | |||
361 | ||||
362 | void WriteTemplateStart() { Write('<'); } | |||
363 | ||||
364 | void WriteTemplateEnd() { | |||
365 | // Put a space between terminal > characters when nesting templates | |||
366 | if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>') | |||
367 | WRITE(" >")Write(" >", sizeof(" >") - 1); | |||
368 | else | |||
369 | Write('>'); | |||
370 | } | |||
371 | ||||
372 | void WriteCommaSpace() { WRITE(", ")Write(", ", sizeof(", ") - 1); } | |||
373 | ||||
374 | void WriteNamespaceSeparator() { WRITE("::")Write("::", sizeof("::") - 1); } | |||
375 | ||||
376 | void WriteStdPrefix() { WRITE("std::")Write("std::", sizeof("std::") - 1); } | |||
377 | ||||
378 | void WriteQualifiers(int qualifiers, bool space_before_reference = true) { | |||
379 | if (qualifiers & QualifierPointer) | |||
380 | Write('*'); | |||
381 | if (qualifiers & QualifierConst) | |||
382 | WRITE(" const")Write(" const", sizeof(" const") - 1); | |||
383 | if (qualifiers & QualifierVolatile) | |||
384 | WRITE(" volatile")Write(" volatile", sizeof(" volatile") - 1); | |||
385 | if (qualifiers & QualifierRestrict) | |||
386 | WRITE(" restrict")Write(" restrict", sizeof(" restrict") - 1); | |||
387 | if (qualifiers & QualifierReference) { | |||
388 | if (space_before_reference) | |||
389 | WRITE(" &")Write(" &", sizeof(" &") - 1); | |||
390 | else | |||
391 | Write('&'); | |||
392 | } | |||
393 | if (qualifiers & QualifierRValueReference) { | |||
394 | if (space_before_reference) | |||
395 | WRITE(" &&")Write(" &&", sizeof(" &&") - 1); | |||
396 | else | |||
397 | WRITE("&&")Write("&&", sizeof("&&") - 1); | |||
398 | } | |||
399 | } | |||
400 | ||||
401 | //---------------------------------------------------- | |||
402 | // Rewrite methods | |||
403 | // | |||
404 | // Write another copy of content already present earlier in the output buffer | |||
405 | //---------------------------------------------------- | |||
406 | ||||
407 | void RewriteRange(BufferRange range) { | |||
408 | Write(m_buffer + range.offset, range.length); | |||
409 | } | |||
410 | ||||
411 | bool RewriteSubstitution(int index) { | |||
412 | if (index < 0 || index >= m_next_substitute_index) { | |||
413 | #ifdef DEBUG_FAILURES | |||
414 | printf("*** Invalid substitution #%d\n", index); | |||
415 | #endif | |||
416 | return false; | |||
417 | } | |||
418 | RewriteRange(m_rewrite_ranges[index]); | |||
419 | return true; | |||
420 | } | |||
421 | ||||
422 | bool RewriteTemplateArg(int template_index) { | |||
423 | int index = m_rewrite_ranges_size - 1 - template_index; | |||
424 | if (template_index < 0 || index <= m_next_template_arg_index) { | |||
425 | #ifdef DEBUG_FAILURES | |||
426 | printf("*** Invalid template arg reference #%d\n", template_index); | |||
427 | #endif | |||
428 | return false; | |||
429 | } | |||
430 | RewriteRange(m_rewrite_ranges[index]); | |||
431 | return true; | |||
432 | } | |||
433 | ||||
434 | //---------------------------------------------------- | |||
435 | // TryParse methods | |||
436 | // | |||
437 | // Provide information with return values instead of writing to the output | |||
438 | // buffer | |||
439 | // | |||
440 | // Values indicating failure guarantee that the pre- call m_read_ptr is | |||
441 | // unchanged | |||
442 | //---------------------------------------------------- | |||
443 | ||||
444 | int TryParseNumber() { | |||
445 | unsigned char digit = *m_read_ptr - '0'; | |||
446 | if (digit > 9) | |||
447 | return -1; | |||
448 | ||||
449 | int count = digit; | |||
450 | while (true) { | |||
451 | digit = *++m_read_ptr - '0'; | |||
452 | if (digit > 9) | |||
453 | break; | |||
454 | ||||
455 | count = count * 10 + digit; | |||
456 | } | |||
457 | return count; | |||
458 | } | |||
459 | ||||
460 | int TryParseBase36Number() { | |||
461 | char digit = *m_read_ptr; | |||
462 | int count; | |||
463 | if (digit >= '0' && digit <= '9') | |||
464 | count = digit -= '0'; | |||
465 | else if (digit >= 'A' && digit <= 'Z') | |||
466 | count = digit -= ('A' - 10); | |||
467 | else | |||
468 | return -1; | |||
469 | ||||
470 | while (true) { | |||
471 | digit = *++m_read_ptr; | |||
472 | if (digit >= '0' && digit <= '9') | |||
473 | digit -= '0'; | |||
474 | else if (digit >= 'A' && digit <= 'Z') | |||
475 | digit -= ('A' - 10); | |||
476 | else | |||
477 | break; | |||
478 | ||||
479 | count = count * 36 + digit; | |||
480 | } | |||
481 | return count; | |||
482 | } | |||
483 | ||||
484 | // <builtin-type> ::= v # void | |||
485 | // ::= w # wchar_t | |||
486 | // ::= b # bool | |||
487 | // ::= c # char | |||
488 | // ::= a # signed char | |||
489 | // ::= h # unsigned char | |||
490 | // ::= s # short | |||
491 | // ::= t # unsigned short | |||
492 | // ::= i # int | |||
493 | // ::= j # unsigned int | |||
494 | // ::= l # long | |||
495 | // ::= m # unsigned long | |||
496 | // ::= x # long long, __int64 | |||
497 | // ::= y # unsigned long long, __int64 | |||
498 | // ::= n # __int128 | |||
499 | // ::= o # unsigned __int128 | |||
500 | // ::= f # float | |||
501 | // ::= d # double | |||
502 | // ::= e # long double, __float80 | |||
503 | // ::= g # __float128 | |||
504 | // ::= z # ellipsis | |||
505 | // ::= Dd # IEEE 754r decimal floating point (64 bits) | |||
506 | // ::= De # IEEE 754r decimal floating point (128 bits) | |||
507 | // ::= Df # IEEE 754r decimal floating point (32 bits) | |||
508 | // ::= Dh # IEEE 754r half-precision floating point (16 bits) | |||
509 | // ::= Di # char32_t | |||
510 | // ::= Ds # char16_t | |||
511 | // ::= Da # auto (in dependent new-expressions) | |||
512 | // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) | |||
513 | // ::= u <source-name> # vendor extended type | |||
514 | ||||
515 | const char *TryParseBuiltinType() { | |||
516 | if (m_builtins_hook) | |||
517 | m_builtins_hook(m_read_ptr); | |||
518 | ||||
519 | switch (*m_read_ptr++) { | |||
520 | case 'v': | |||
521 | return "void"; | |||
522 | case 'w': | |||
523 | return "wchar_t"; | |||
524 | case 'b': | |||
525 | return "bool"; | |||
526 | case 'c': | |||
527 | return "char"; | |||
528 | case 'a': | |||
529 | return "signed char"; | |||
530 | case 'h': | |||
531 | return "unsigned char"; | |||
532 | case 's': | |||
533 | return "short"; | |||
534 | case 't': | |||
535 | return "unsigned short"; | |||
536 | case 'i': | |||
537 | return "int"; | |||
538 | case 'j': | |||
539 | return "unsigned int"; | |||
540 | case 'l': | |||
541 | return "long"; | |||
542 | case 'm': | |||
543 | return "unsigned long"; | |||
544 | case 'x': | |||
545 | return "long long"; | |||
546 | case 'y': | |||
547 | return "unsigned long long"; | |||
548 | case 'n': | |||
549 | return "__int128"; | |||
550 | case 'o': | |||
551 | return "unsigned __int128"; | |||
552 | case 'f': | |||
553 | return "float"; | |||
554 | case 'd': | |||
555 | return "double"; | |||
556 | case 'e': | |||
557 | return "long double"; | |||
558 | case 'g': | |||
559 | return "__float128"; | |||
560 | case 'z': | |||
561 | return "..."; | |||
562 | case 'D': { | |||
563 | switch (*m_read_ptr++) { | |||
564 | case 'd': | |||
565 | return "decimal64"; | |||
566 | case 'e': | |||
567 | return "decimal128"; | |||
568 | case 'f': | |||
569 | return "decimal32"; | |||
570 | case 'h': | |||
571 | return "decimal16"; | |||
572 | case 'i': | |||
573 | return "char32_t"; | |||
574 | case 's': | |||
575 | return "char16_t"; | |||
576 | case 'a': | |||
577 | return "auto"; | |||
578 | case 'c': | |||
579 | return "decltype(auto)"; | |||
580 | case 'n': | |||
581 | return "std::nullptr_t"; | |||
582 | default: | |||
583 | --m_read_ptr; | |||
584 | } | |||
585 | } | |||
586 | } | |||
587 | --m_read_ptr; | |||
588 | return nullptr; | |||
589 | } | |||
590 | ||||
591 | // <operator-name> | |||
592 | // ::= aa # && | |||
593 | // ::= ad # & (unary) | |||
594 | // ::= an # & | |||
595 | // ::= aN # &= | |||
596 | // ::= aS # = | |||
597 | // ::= cl # () | |||
598 | // ::= cm # , | |||
599 | // ::= co # ~ | |||
600 | // ::= da # delete[] | |||
601 | // ::= de # * (unary) | |||
602 | // ::= dl # delete | |||
603 | // ::= dv # / | |||
604 | // ::= dV # /= | |||
605 | // ::= eo # ^ | |||
606 | // ::= eO # ^= | |||
607 | // ::= eq # == | |||
608 | // ::= ge # >= | |||
609 | // ::= gt # > | |||
610 | // ::= ix # [] | |||
611 | // ::= le # <= | |||
612 | // ::= ls # << | |||
613 | // ::= lS # <<= | |||
614 | // ::= lt # < | |||
615 | // ::= mi # - | |||
616 | // ::= mI # -= | |||
617 | // ::= ml # * | |||
618 | // ::= mL # *= | |||
619 | // ::= mm # -- (postfix in <expression> context) | |||
620 | // ::= na # new[] | |||
621 | // ::= ne # != | |||
622 | // ::= ng # - (unary) | |||
623 | // ::= nt # ! | |||
624 | // ::= nw # new | |||
625 | // ::= oo # || | |||
626 | // ::= or # | | |||
627 | // ::= oR # |= | |||
628 | // ::= pm # ->* | |||
629 | // ::= pl # + | |||
630 | // ::= pL # += | |||
631 | // ::= pp # ++ (postfix in <expression> context) | |||
632 | // ::= ps # + (unary) | |||
633 | // ::= pt # -> | |||
634 | // ::= qu # ? | |||
635 | // ::= rm # % | |||
636 | // ::= rM # %= | |||
637 | // ::= rs # >> | |||
638 | // ::= rS # >>= | |||
639 | // ::= cv <type> # (cast) | |||
640 | // ::= v <digit> <source-name> # vendor extended | |||
641 | // operator | |||
642 | ||||
643 | Operator TryParseOperator() { | |||
644 | switch (*m_read_ptr++) { | |||
645 | case 'a': | |||
646 | switch (*m_read_ptr++) { | |||
647 | case 'a': | |||
648 | return {"&&", OperatorKind::Binary}; | |||
649 | case 'd': | |||
650 | return {"&", OperatorKind::Unary}; | |||
651 | case 'n': | |||
652 | return {"&", OperatorKind::Binary}; | |||
653 | case 'N': | |||
654 | return {"&=", OperatorKind::Binary}; | |||
655 | case 'S': | |||
656 | return {"=", OperatorKind::Binary}; | |||
657 | } | |||
658 | --m_read_ptr; | |||
659 | break; | |||
660 | case 'c': | |||
661 | switch (*m_read_ptr++) { | |||
662 | case 'l': | |||
663 | return {"()", OperatorKind::Other}; | |||
664 | case 'm': | |||
665 | return {",", OperatorKind::Other}; | |||
666 | case 'o': | |||
667 | return {"~", OperatorKind::Unary}; | |||
668 | case 'v': | |||
669 | return {nullptr, OperatorKind::ConversionOperator}; | |||
670 | } | |||
671 | --m_read_ptr; | |||
672 | break; | |||
673 | case 'd': | |||
674 | switch (*m_read_ptr++) { | |||
675 | case 'a': | |||
676 | return {" delete[]", OperatorKind::Other}; | |||
677 | case 'e': | |||
678 | return {"*", OperatorKind::Unary}; | |||
679 | case 'l': | |||
680 | return {" delete", OperatorKind::Other}; | |||
681 | case 'v': | |||
682 | return {"/", OperatorKind::Binary}; | |||
683 | case 'V': | |||
684 | return {"/=", OperatorKind::Binary}; | |||
685 | } | |||
686 | --m_read_ptr; | |||
687 | break; | |||
688 | case 'e': | |||
689 | switch (*m_read_ptr++) { | |||
690 | case 'o': | |||
691 | return {"^", OperatorKind::Binary}; | |||
692 | case 'O': | |||
693 | return {"^=", OperatorKind::Binary}; | |||
694 | case 'q': | |||
695 | return {"==", OperatorKind::Binary}; | |||
696 | } | |||
697 | --m_read_ptr; | |||
698 | break; | |||
699 | case 'g': | |||
700 | switch (*m_read_ptr++) { | |||
701 | case 'e': | |||
702 | return {">=", OperatorKind::Binary}; | |||
703 | case 't': | |||
704 | return {">", OperatorKind::Binary}; | |||
705 | } | |||
706 | --m_read_ptr; | |||
707 | break; | |||
708 | case 'i': | |||
709 | switch (*m_read_ptr++) { | |||
710 | case 'x': | |||
711 | return {"[]", OperatorKind::Other}; | |||
712 | } | |||
713 | --m_read_ptr; | |||
714 | break; | |||
715 | case 'l': | |||
716 | switch (*m_read_ptr++) { | |||
717 | case 'e': | |||
718 | return {"<=", OperatorKind::Binary}; | |||
719 | case 's': | |||
720 | return {"<<", OperatorKind::Binary}; | |||
721 | case 'S': | |||
722 | return {"<<=", OperatorKind::Binary}; | |||
723 | case 't': | |||
724 | return {"<", OperatorKind::Binary}; | |||
725 | // case 'i': return { "?", OperatorKind::Binary }; | |||
726 | } | |||
727 | --m_read_ptr; | |||
728 | break; | |||
729 | case 'm': | |||
730 | switch (*m_read_ptr++) { | |||
731 | case 'i': | |||
732 | return {"-", OperatorKind::Binary}; | |||
733 | case 'I': | |||
734 | return {"-=", OperatorKind::Binary}; | |||
735 | case 'l': | |||
736 | return {"*", OperatorKind::Binary}; | |||
737 | case 'L': | |||
738 | return {"*=", OperatorKind::Binary}; | |||
739 | case 'm': | |||
740 | return {"--", OperatorKind::Postfix}; | |||
741 | } | |||
742 | --m_read_ptr; | |||
743 | break; | |||
744 | case 'n': | |||
745 | switch (*m_read_ptr++) { | |||
746 | case 'a': | |||
747 | return {" new[]", OperatorKind::Other}; | |||
748 | case 'e': | |||
749 | return {"!=", OperatorKind::Binary}; | |||
750 | case 'g': | |||
751 | return {"-", OperatorKind::Unary}; | |||
752 | case 't': | |||
753 | return {"!", OperatorKind::Unary}; | |||
754 | case 'w': | |||
755 | return {" new", OperatorKind::Other}; | |||
756 | } | |||
757 | --m_read_ptr; | |||
758 | break; | |||
759 | case 'o': | |||
760 | switch (*m_read_ptr++) { | |||
761 | case 'o': | |||
762 | return {"||", OperatorKind::Binary}; | |||
763 | case 'r': | |||
764 | return {"|", OperatorKind::Binary}; | |||
765 | case 'R': | |||
766 | return {"|=", OperatorKind::Binary}; | |||
767 | } | |||
768 | --m_read_ptr; | |||
769 | break; | |||
770 | case 'p': | |||
771 | switch (*m_read_ptr++) { | |||
772 | case 'm': | |||
773 | return {"->*", OperatorKind::Binary}; | |||
774 | case 's': | |||
775 | return {"+", OperatorKind::Unary}; | |||
776 | case 'l': | |||
777 | return {"+", OperatorKind::Binary}; | |||
778 | case 'L': | |||
779 | return {"+=", OperatorKind::Binary}; | |||
780 | case 'p': | |||
781 | return {"++", OperatorKind::Postfix}; | |||
782 | case 't': | |||
783 | return {"->", OperatorKind::Binary}; | |||
784 | } | |||
785 | --m_read_ptr; | |||
786 | break; | |||
787 | case 'q': | |||
788 | switch (*m_read_ptr++) { | |||
789 | case 'u': | |||
790 | return {"?", OperatorKind::Ternary}; | |||
791 | } | |||
792 | --m_read_ptr; | |||
793 | break; | |||
794 | case 'r': | |||
795 | switch (*m_read_ptr++) { | |||
796 | case 'm': | |||
797 | return {"%", OperatorKind::Binary}; | |||
798 | case 'M': | |||
799 | return {"%=", OperatorKind::Binary}; | |||
800 | case 's': | |||
801 | return {">>", OperatorKind::Binary}; | |||
802 | case 'S': | |||
803 | return {">=", OperatorKind::Binary}; | |||
804 | } | |||
805 | --m_read_ptr; | |||
806 | break; | |||
807 | case 'v': | |||
808 | char digit = *m_read_ptr; | |||
809 | if (digit >= '0' && digit <= '9') { | |||
810 | m_read_ptr++; | |||
811 | return {nullptr, OperatorKind::Vendor}; | |||
812 | } | |||
813 | --m_read_ptr; | |||
814 | break; | |||
815 | } | |||
816 | --m_read_ptr; | |||
817 | return {nullptr, OperatorKind::NoMatch}; | |||
818 | } | |||
819 | ||||
820 | // <CV-qualifiers> ::= [r] [V] [K] | |||
821 | // <ref-qualifier> ::= R # & ref-qualifier <ref-qualifier> | |||
822 | // ::= O # && ref-qualifier | |||
823 | ||||
824 | int TryParseQualifiers(bool allow_cv, bool allow_ro) { | |||
825 | int qualifiers = QualifierNone; | |||
826 | char next = *m_read_ptr; | |||
827 | if (allow_cv) { | |||
828 | if (next == 'r') // restrict | |||
829 | { | |||
830 | qualifiers |= QualifierRestrict; | |||
831 | next = *++m_read_ptr; | |||
832 | } | |||
833 | if (next == 'V') // volatile | |||
834 | { | |||
835 | qualifiers |= QualifierVolatile; | |||
836 | next = *++m_read_ptr; | |||
837 | } | |||
838 | if (next == 'K') // const | |||
839 | { | |||
840 | qualifiers |= QualifierConst; | |||
841 | next = *++m_read_ptr; | |||
842 | } | |||
843 | } | |||
844 | if (allow_ro) { | |||
845 | if (next == 'R') { | |||
846 | ++m_read_ptr; | |||
847 | qualifiers |= QualifierReference; | |||
848 | } else if (next == 'O') { | |||
849 | ++m_read_ptr; | |||
850 | qualifiers |= QualifierRValueReference; | |||
851 | } | |||
852 | } | |||
853 | return qualifiers; | |||
854 | } | |||
855 | ||||
856 | // <discriminator> := _ <non-negative number> # when number < 10 | |||
857 | // := __ <non-negative number> _ # when number >= 10 | |||
858 | // extension := decimal-digit+ | |||
859 | ||||
860 | int TryParseDiscriminator() { | |||
861 | const char *discriminator_start = m_read_ptr; | |||
862 | ||||
863 | // Test the extension first, since it's what Clang uses | |||
864 | int discriminator_value = TryParseNumber(); | |||
865 | if (discriminator_value != -1) | |||
866 | return discriminator_value; | |||
867 | ||||
868 | char next = *m_read_ptr; | |||
869 | if (next == '_') { | |||
870 | next = *++m_read_ptr; | |||
871 | if (next == '_') { | |||
872 | ++m_read_ptr; | |||
873 | discriminator_value = TryParseNumber(); | |||
874 | if (discriminator_value != -1 && *m_read_ptr++ != '_') { | |||
875 | return discriminator_value; | |||
876 | } | |||
877 | } else if (next >= '0' && next <= '9') { | |||
878 | ++m_read_ptr; | |||
879 | return next - '0'; | |||
880 | } | |||
881 | } | |||
882 | ||||
883 | // Not a valid discriminator | |||
884 | m_read_ptr = discriminator_start; | |||
885 | return -1; | |||
886 | } | |||
887 | ||||
888 | //---------------------------------------------------- | |||
889 | // Parse methods | |||
890 | // | |||
891 | // Consume input starting from m_read_ptr and produce buffered output at | |||
892 | // m_write_ptr | |||
893 | // | |||
894 | // Failures return false and may leave m_read_ptr in an indeterminate state | |||
895 | //---------------------------------------------------- | |||
896 | ||||
897 | bool Parse(char character) { | |||
898 | if (*m_read_ptr++ == character) | |||
899 | return true; | |||
900 | #ifdef DEBUG_FAILURES | |||
901 | printf("*** Expected '%c'\n", character); | |||
902 | #endif | |||
903 | return false; | |||
904 | } | |||
905 | ||||
906 | // <number> ::= [n] <non-negative decimal integer> | |||
907 | ||||
908 | bool ParseNumber(bool allow_negative = false) { | |||
909 | if (allow_negative && *m_read_ptr == 'n') { | |||
910 | Write('-'); | |||
911 | ++m_read_ptr; | |||
912 | } | |||
913 | const char *before_digits = m_read_ptr; | |||
914 | while (true) { | |||
915 | unsigned char digit = *m_read_ptr - '0'; | |||
916 | if (digit > 9) | |||
917 | break; | |||
918 | ++m_read_ptr; | |||
919 | } | |||
920 | if (int digit_count = (int)(m_read_ptr - before_digits)) { | |||
921 | Write(before_digits, digit_count); | |||
922 | return true; | |||
923 | } | |||
924 | #ifdef DEBUG_FAILURES | |||
925 | printf("*** Expected number\n"); | |||
926 | #endif | |||
927 | return false; | |||
928 | } | |||
929 | ||||
930 | // <substitution> ::= S <seq-id> _ | |||
931 | // ::= S_ | |||
932 | // <substitution> ::= Sa # ::std::allocator <substitution> ::= Sb # | |||
933 | // ::std::basic_string <substitution> ::= Ss # ::std::basic_string < char, | |||
934 | // ::std::char_traits<char>, | |||
935 | // ::std::allocator<char> > | |||
936 | // <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> | |||
937 | // > <substitution> ::= So # ::std::basic_ostream<char, | |||
938 | // std::char_traits<char> > <substitution> ::= Sd # | |||
939 | // ::std::basic_iostream<char, std::char_traits<char> > | |||
940 | ||||
941 | bool ParseSubstitution() { | |||
942 | const char *substitution; | |||
943 | switch (*m_read_ptr) { | |||
944 | case 'a': | |||
945 | substitution = "std::allocator"; | |||
946 | break; | |||
947 | case 'b': | |||
948 | substitution = "std::basic_string"; | |||
949 | break; | |||
950 | case 's': | |||
951 | substitution = "std::string"; | |||
952 | break; | |||
953 | case 'i': | |||
954 | substitution = "std::istream"; | |||
955 | break; | |||
956 | case 'o': | |||
957 | substitution = "std::ostream"; | |||
958 | break; | |||
959 | case 'd': | |||
960 | substitution = "std::iostream"; | |||
961 | break; | |||
962 | default: | |||
963 | // A failed attempt to parse a number will return -1 which turns out to be | |||
964 | // perfect here as S_ is the first substitution, S0_ the next and so | |||
965 | // forth | |||
966 | int substitution_index = TryParseBase36Number(); | |||
967 | if (*m_read_ptr++ != '_') { | |||
968 | #ifdef DEBUG_FAILURES | |||
969 | printf("*** Expected terminal _ in substitution\n"); | |||
970 | #endif | |||
971 | return false; | |||
972 | } | |||
973 | return RewriteSubstitution(substitution_index + 1); | |||
974 | } | |||
975 | Write(substitution); | |||
976 | ++m_read_ptr; | |||
977 | return true; | |||
978 | } | |||
979 | ||||
980 | // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E | |||
981 | // | |||
982 | // <bare-function-type> ::= <signature type>+ # types are possible | |||
983 | // return type, then parameter types | |||
984 | ||||
985 | bool ParseFunctionType(int inner_qualifiers = QualifierNone) { | |||
986 | #ifdef DEBUG_FAILURES | |||
987 | printf("*** Function types not supported\n"); | |||
988 | #endif | |||
989 | // TODO: first steps toward an implementation follow, but they're far | |||
990 | // from complete. Function types tend to bracket other types eg: int (*)() | |||
991 | // when used as the type for "name" becomes int (*name)(). This makes | |||
992 | // substitution et al ... interesting. | |||
993 | return false; | |||
994 | ||||
995 | #if 0 // TODO | |||
996 | if (*m_read_ptr == 'Y') | |||
997 | ++m_read_ptr; | |||
998 | ||||
999 | int return_type_start_cookie = GetStartCookie(); | |||
1000 | if (!ParseType()) | |||
1001 | return false; | |||
1002 | Write(' '); | |||
1003 | ||||
1004 | int insert_cookie = GetStartCookie(); | |||
1005 | Write('('); | |||
1006 | bool first_param = true; | |||
1007 | int qualifiers = QualifierNone; | |||
1008 | while (true) | |||
1009 | { | |||
1010 | switch (*m_read_ptr) | |||
1011 | { | |||
1012 | case 'E': | |||
1013 | ++m_read_ptr; | |||
1014 | Write(')'); | |||
1015 | break; | |||
1016 | case 'v': | |||
1017 | ++m_read_ptr; | |||
1018 | continue; | |||
1019 | case 'R': | |||
1020 | case 'O': | |||
1021 | if (*(m_read_ptr + 1) == 'E') | |||
1022 | { | |||
1023 | qualifiers = TryParseQualifiers (false, true); | |||
1024 | Parse('E'); | |||
1025 | break; | |||
1026 | } | |||
1027 | // fallthrough | |||
1028 | default: | |||
1029 | { | |||
1030 | if (first_param) | |||
1031 | first_param = false; | |||
1032 | else WriteCommaSpace(); | |||
1033 | ||||
1034 | if (!ParseType()) | |||
1035 | return false; | |||
1036 | continue; | |||
1037 | } | |||
1038 | } | |||
1039 | break; | |||
1040 | } | |||
1041 | ||||
1042 | if (qualifiers) | |||
1043 | { | |||
1044 | WriteQualifiers (qualifiers); | |||
1045 | EndSubstitution (return_type_start_cookie); | |||
1046 | } | |||
1047 | ||||
1048 | if (inner_qualifiers) | |||
1049 | { | |||
1050 | int qualifier_start_cookie = GetStartCookie(); | |||
1051 | Write ('('); | |||
1052 | WriteQualifiers (inner_qualifiers); | |||
1053 | Write (')'); | |||
1054 | ReorderRange (EndRange (qualifier_start_cookie), insert_cookie); | |||
1055 | } | |||
1056 | return true; | |||
1057 | #endif // TODO | |||
1058 | } | |||
1059 | ||||
1060 | // <array-type> ::= A <positive dimension number> _ <element type> | |||
1061 | // ::= A [<dimension expression>] _ <element type> | |||
1062 | ||||
1063 | bool ParseArrayType(int qualifiers = QualifierNone) { | |||
1064 | #ifdef DEBUG_FAILURES | |||
1065 | printf("*** Array type unsupported\n"); | |||
1066 | #endif | |||
1067 | // TODO: We fail horribly when recalling these as substitutions or | |||
1068 | // templates and trying to constify them eg: | |||
1069 | // _ZN4llvm2cl5applyIA28_cNS0_3optIbLb0ENS0_6parserIbEEEEEEvRKT_PT0_ | |||
1070 | // | |||
1071 | // TODO: Chances are we don't do any better with references and pointers | |||
1072 | // that should be type (&) [] instead of type & [] | |||
1073 | ||||
1074 | return false; | |||
1075 | ||||
1076 | #if 0 // TODO | |||
1077 | if (*m_read_ptr == '_') | |||
1078 | { | |||
1079 | ++m_read_ptr; | |||
1080 | if (!ParseType()) | |||
1081 | return false; | |||
1082 | if (qualifiers) | |||
1083 | WriteQualifiers(qualifiers); | |||
1084 | WRITE(" []")Write(" []", sizeof(" []") - 1); | |||
1085 | return true; | |||
1086 | } | |||
1087 | else | |||
1088 | { | |||
1089 | const char *before_digits = m_read_ptr; | |||
1090 | if (TryParseNumber() != -1) | |||
1091 | { | |||
1092 | const char *after_digits = m_read_ptr; | |||
1093 | if (!Parse('_')) | |||
1094 | return false; | |||
1095 | if (!ParseType()) | |||
1096 | return false; | |||
1097 | if (qualifiers) | |||
1098 | WriteQualifiers(qualifiers); | |||
1099 | Write(' '); | |||
1100 | Write('['); | |||
1101 | Write(before_digits, after_digits - before_digits); | |||
1102 | } | |||
1103 | else | |||
1104 | { | |||
1105 | int type_insertion_cookie = GetStartCookie(); | |||
1106 | if (!ParseExpression()) | |||
1107 | return false; | |||
1108 | if (!Parse('_')) | |||
1109 | return false; | |||
1110 | ||||
1111 | int type_start_cookie = GetStartCookie(); | |||
1112 | if (!ParseType()) | |||
1113 | return false; | |||
1114 | if (qualifiers) | |||
1115 | WriteQualifiers(qualifiers); | |||
1116 | Write(' '); | |||
1117 | Write('['); | |||
1118 | ReorderRange (EndRange (type_start_cookie), type_insertion_cookie); | |||
1119 | } | |||
1120 | Write(']'); | |||
1121 | return true; | |||
1122 | } | |||
1123 | #endif // TODO | |||
1124 | } | |||
1125 | ||||
1126 | // <pointer-to-member-type> ::= M <class type> <member type> | |||
1127 | ||||
1128 | // TODO: Determine how to handle pointers to function members correctly, | |||
1129 | // currently not an issue because we don't have function types at all... | |||
1130 | bool ParsePointerToMemberType() { | |||
1131 | int insertion_cookie = GetStartCookie(); | |||
1132 | Write(' '); | |||
1133 | if (!ParseType()) | |||
1134 | return false; | |||
1135 | WRITE("::*")Write("::*", sizeof("::*") - 1); | |||
1136 | ||||
1137 | int type_cookie = GetStartCookie(); | |||
1138 | if (!ParseType()) | |||
1139 | return false; | |||
1140 | ReorderRange(EndRange(type_cookie), insertion_cookie); | |||
1141 | return true; | |||
1142 | } | |||
1143 | ||||
1144 | // <template-param> ::= T_ # first template parameter | |||
1145 | // ::= T <parameter-2 non-negative number> _ | |||
1146 | ||||
1147 | bool ParseTemplateParam() { | |||
1148 | int count = TryParseNumber(); | |||
1149 | if (!Parse('_')) | |||
1150 | return false; | |||
1151 | ||||
1152 | // When no number is present we get -1, which is convenient since T_ is the | |||
1153 | // zeroth element T0_ is element 1, and so on | |||
1154 | return RewriteTemplateArg(count + 1); | |||
1155 | } | |||
1156 | ||||
1157 | // <vector-type> | |||
1158 | // Dv <dimension number> _ <vector type> | |||
1159 | bool TryParseVectorType() { | |||
1160 | const int dimension = TryParseNumber(); | |||
1161 | if (dimension == -1) | |||
1162 | return false; | |||
1163 | ||||
1164 | if (*m_read_ptr++ != '_') | |||
1165 | return false; | |||
1166 | ||||
1167 | char vec_dimens[32] = {'\0'}; | |||
1168 | ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension); | |||
1169 | ParseType(); | |||
1170 | Write(vec_dimens); | |||
1171 | return true; | |||
1172 | } | |||
1173 | ||||
1174 | // <type> ::= <builtin-type> | |||
1175 | // ::= <function-type> | |||
1176 | // ::= <class-enum-type> | |||
1177 | // ::= <array-type> | |||
1178 | // ::= <pointer-to-member-type> | |||
1179 | // ::= <template-param> | |||
1180 | // ::= <template-template-param> <template-args> | |||
1181 | // ::= <decltype> | |||
1182 | // ::= <substitution> | |||
1183 | // ::= <CV-qualifiers> <type> | |||
1184 | // ::= P <type> # pointer-to | |||
1185 | // ::= R <type> # reference-to | |||
1186 | // ::= O <type> # rvalue reference-to (C++0x) | |||
1187 | // ::= C <type> # complex pair (C 2000) | |||
1188 | // ::= G <type> # imaginary (C 2000) | |||
1189 | // ::= Dp <type> # pack expansion (C++0x) | |||
1190 | // ::= U <source-name> <type> # vendor extended type qualifier | |||
1191 | // extension := U <objc-name> <objc-type> # objc-type<identifier> extension | |||
1192 | // := <vector-type> # <vector-type> starts with Dv | |||
1193 | ||||
1194 | // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + | |||
1195 | // <number of digits in k1> + k1 <objc-type> := <source-name> # | |||
1196 | // PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source- | |||
1197 | // name> | |||
1198 | ||||
1199 | bool ParseType() { | |||
1200 | #ifdef DEBUG_FAILURES | |||
1201 | const char *failed_type = m_read_ptr; | |||
1202 | #endif | |||
1203 | int type_start_cookie = GetStartCookie(); | |||
1204 | bool suppress_substitution = false; | |||
1205 | ||||
1206 | int qualifiers = TryParseQualifiers(true, false); | |||
1207 | switch (*m_read_ptr) { | |||
1208 | case 'D': | |||
1209 | ++m_read_ptr; | |||
1210 | switch (*m_read_ptr++) { | |||
1211 | case 'p': | |||
1212 | if (!ParseType()) | |||
1213 | return false; | |||
1214 | break; | |||
1215 | case 'v': | |||
1216 | if (!TryParseVectorType()) | |||
1217 | return false; | |||
1218 | break; | |||
1219 | case 'T': | |||
1220 | case 't': | |||
1221 | default: | |||
1222 | #ifdef DEBUG_FAILURES | |||
1223 | printf("*** Unsupported type: %.3s\n", failed_type); | |||
1224 | #endif | |||
1225 | return false; | |||
1226 | } | |||
1227 | break; | |||
1228 | case 'T': | |||
1229 | ++m_read_ptr; | |||
1230 | if (!ParseTemplateParam()) | |||
1231 | return false; | |||
1232 | break; | |||
1233 | case 'M': | |||
1234 | ++m_read_ptr; | |||
1235 | if (!ParsePointerToMemberType()) | |||
1236 | return false; | |||
1237 | break; | |||
1238 | case 'A': | |||
1239 | ++m_read_ptr; | |||
1240 | if (!ParseArrayType()) | |||
1241 | return false; | |||
1242 | break; | |||
1243 | case 'F': | |||
1244 | ++m_read_ptr; | |||
1245 | if (!ParseFunctionType()) | |||
1246 | return false; | |||
1247 | break; | |||
1248 | case 'S': | |||
1249 | if (*++m_read_ptr == 't') { | |||
1250 | ++m_read_ptr; | |||
1251 | WriteStdPrefix(); | |||
1252 | if (!ParseName()) | |||
1253 | return false; | |||
1254 | } else { | |||
1255 | suppress_substitution = true; | |||
1256 | if (!ParseSubstitution()) | |||
1257 | return false; | |||
1258 | } | |||
1259 | break; | |||
1260 | case 'P': { | |||
1261 | switch (*++m_read_ptr) { | |||
1262 | case 'F': | |||
1263 | ++m_read_ptr; | |||
1264 | if (!ParseFunctionType(QualifierPointer)) | |||
1265 | return false; | |||
1266 | break; | |||
1267 | default: | |||
1268 | if (!ParseType()) | |||
1269 | return false; | |||
1270 | Write('*'); | |||
1271 | break; | |||
1272 | } | |||
1273 | break; | |||
1274 | } | |||
1275 | case 'R': { | |||
1276 | ++m_read_ptr; | |||
1277 | if (!ParseType()) | |||
1278 | return false; | |||
1279 | Write('&'); | |||
1280 | break; | |||
1281 | } | |||
1282 | case 'O': { | |||
1283 | ++m_read_ptr; | |||
1284 | if (!ParseType()) | |||
1285 | return false; | |||
1286 | Write('&'); | |||
1287 | Write('&'); | |||
1288 | break; | |||
1289 | } | |||
1290 | case 'C': | |||
1291 | case 'G': | |||
1292 | case 'U': | |||
1293 | #ifdef DEBUG_FAILURES | |||
1294 | printf("*** Unsupported type: %.3s\n", failed_type); | |||
1295 | #endif | |||
1296 | return false; | |||
1297 | // Test for common cases to avoid TryParseBuiltinType() overhead | |||
1298 | case 'N': | |||
1299 | case 'Z': | |||
1300 | case 'L': | |||
1301 | if (!ParseName()) | |||
1302 | return false; | |||
1303 | break; | |||
1304 | default: | |||
1305 | if (const char *builtin = TryParseBuiltinType()) { | |||
1306 | Write(builtin); | |||
1307 | suppress_substitution = true; | |||
1308 | } else { | |||
1309 | if (!ParseName()) | |||
1310 | return false; | |||
1311 | } | |||
1312 | break; | |||
1313 | } | |||
1314 | ||||
1315 | // Allow base substitutions to be suppressed, but always record | |||
1316 | // substitutions for the qualified variant | |||
1317 | if (!suppress_substitution) | |||
1318 | EndSubstitution(type_start_cookie); | |||
1319 | if (qualifiers) { | |||
1320 | WriteQualifiers(qualifiers, false); | |||
1321 | EndSubstitution(type_start_cookie); | |||
1322 | } | |||
1323 | return true; | |||
1324 | } | |||
1325 | ||||
1326 | // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ | |||
1327 | // ::= <closure-type-name> | |||
1328 | // | |||
1329 | // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ | |||
1330 | // | |||
1331 | // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda | |||
1332 | // has no parameters | |||
1333 | ||||
1334 | bool ParseUnnamedTypeName(NameState &name_state) { | |||
1335 | switch (*m_read_ptr++) { | |||
1336 | case 't': { | |||
1337 | int cookie = GetStartCookie(); | |||
1338 | WRITE("'unnamed")Write("'unnamed", sizeof("'unnamed") - 1); | |||
1339 | const char *before_digits = m_read_ptr; | |||
1340 | if (TryParseNumber() != -1) | |||
1341 | Write(before_digits, m_read_ptr - before_digits); | |||
1342 | if (!Parse('_')) | |||
1343 | return false; | |||
1344 | Write('\''); | |||
1345 | name_state.last_name_range = EndRange(cookie); | |||
1346 | return true; | |||
1347 | } | |||
1348 | case 'b': { | |||
1349 | int cookie = GetStartCookie(); | |||
1350 | WRITE("'block")Write("'block", sizeof("'block") - 1); | |||
1351 | const char *before_digits = m_read_ptr; | |||
1352 | if (TryParseNumber() != -1) | |||
1353 | Write(before_digits, m_read_ptr - before_digits); | |||
1354 | if (!Parse('_')) | |||
1355 | return false; | |||
1356 | Write('\''); | |||
1357 | name_state.last_name_range = EndRange(cookie); | |||
1358 | return true; | |||
1359 | } | |||
1360 | case 'l': | |||
1361 | #ifdef DEBUG_FAILURES | |||
1362 | printf("*** Lambda type names unsupported\n"); | |||
1363 | #endif | |||
1364 | return false; | |||
1365 | } | |||
1366 | #ifdef DEBUG_FAILURES | |||
1367 | printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2); | |||
1368 | #endif | |||
1369 | return false; | |||
1370 | } | |||
1371 | ||||
1372 | // <ctor-dtor-name> ::= C1 # complete object constructor | |||
1373 | // ::= C2 # base object constructor | |||
1374 | // ::= C3 # complete object allocating constructor | |||
1375 | ||||
1376 | bool ParseCtor(NameState &name_state) { | |||
1377 | char next = *m_read_ptr; | |||
1378 | if (next == '1' || next == '2' || next == '3' || next == '5') { | |||
1379 | RewriteRange(name_state.last_name_range); | |||
1380 | name_state.has_no_return_type = true; | |||
1381 | ++m_read_ptr; | |||
1382 | return true; | |||
1383 | } | |||
1384 | #ifdef DEBUG_FAILURES | |||
1385 | printf("*** Broken constructor\n"); | |||
1386 | #endif | |||
1387 | return false; | |||
1388 | } | |||
1389 | ||||
1390 | // <ctor-dtor-name> ::= D0 # deleting destructor | |||
1391 | // ::= D1 # complete object destructor | |||
1392 | // ::= D2 # base object destructor | |||
1393 | ||||
1394 | bool ParseDtor(NameState &name_state) { | |||
1395 | char next = *m_read_ptr; | |||
1396 | if (next == '0' || next == '1' || next == '2' || next == '5') { | |||
1397 | Write('~'); | |||
1398 | RewriteRange(name_state.last_name_range); | |||
1399 | name_state.has_no_return_type = true; | |||
1400 | ++m_read_ptr; | |||
1401 | return true; | |||
1402 | } | |||
1403 | #ifdef DEBUG_FAILURES | |||
1404 | printf("*** Broken destructor\n"); | |||
1405 | #endif | |||
1406 | return false; | |||
1407 | } | |||
1408 | ||||
1409 | // See TryParseOperator() | |||
1410 | ||||
1411 | bool ParseOperatorName(NameState &name_state) { | |||
1412 | #ifdef DEBUG_FAILURES | |||
1413 | const char *operator_ptr = m_read_ptr; | |||
1414 | #endif | |||
1415 | Operator parsed_operator = TryParseOperator(); | |||
1416 | if (parsed_operator.name) { | |||
1417 | WRITE("operator")Write("operator", sizeof("operator") - 1); | |||
1418 | Write(parsed_operator.name); | |||
1419 | return true; | |||
1420 | } | |||
1421 | ||||
1422 | // Handle special operators | |||
1423 | switch (parsed_operator.kind) { | |||
1424 | case OperatorKind::Vendor: | |||
1425 | WRITE("operator ")Write("operator ", sizeof("operator ") - 1); | |||
1426 | return ParseSourceName(); | |||
1427 | case OperatorKind::ConversionOperator: | |||
1428 | ResetTemplateArgs(); | |||
1429 | name_state.has_no_return_type = true; | |||
1430 | WRITE("operator ")Write("operator ", sizeof("operator ") - 1); | |||
1431 | return ParseType(); | |||
1432 | default: | |||
1433 | #ifdef DEBUG_FAILURES | |||
1434 | printf("*** Unknown operator: %.2s\n", operator_ptr); | |||
1435 | #endif | |||
1436 | return false; | |||
1437 | } | |||
1438 | } | |||
1439 | ||||
1440 | // <source-name> ::= <positive length number> <identifier> | |||
1441 | ||||
1442 | bool ParseSourceName() { | |||
1443 | int count = TryParseNumber(); | |||
1444 | if (count == -1) { | |||
1445 | #ifdef DEBUG_FAILURES | |||
1446 | printf("*** Malformed source name, missing length count\n"); | |||
1447 | #endif | |||
1448 | return false; | |||
1449 | } | |||
1450 | ||||
1451 | const char *next_m_read_ptr = m_read_ptr + count; | |||
1452 | if (next_m_read_ptr > m_read_end) { | |||
1453 | #ifdef DEBUG_FAILURES | |||
1454 | printf("*** Malformed source name, premature termination\n"); | |||
1455 | #endif | |||
1456 | return false; | |||
1457 | } | |||
1458 | ||||
1459 | if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0) | |||
1460 | WRITE("(anonymous namespace)")Write("(anonymous namespace)", sizeof("(anonymous namespace)" ) - 1); | |||
1461 | else | |||
1462 | Write(m_read_ptr, count); | |||
1463 | ||||
1464 | m_read_ptr = next_m_read_ptr; | |||
1465 | return true; | |||
1466 | } | |||
1467 | ||||
1468 | // <unqualified-name> ::= <operator-name> | |||
1469 | // ::= <ctor-dtor-name> | |||
1470 | // ::= <source-name> | |||
1471 | // ::= <unnamed-type-name> | |||
1472 | ||||
1473 | bool ParseUnqualifiedName(NameState &name_state) { | |||
1474 | // Note that these are detected directly in ParseNestedName for performance | |||
1475 | // rather than switching on the same options twice | |||
1476 | char next = *m_read_ptr; | |||
1477 | switch (next) { | |||
1478 | case 'C': | |||
1479 | ++m_read_ptr; | |||
1480 | return ParseCtor(name_state); | |||
1481 | case 'D': | |||
1482 | ++m_read_ptr; | |||
1483 | return ParseDtor(name_state); | |||
1484 | case 'U': | |||
1485 | ++m_read_ptr; | |||
1486 | return ParseUnnamedTypeName(name_state); | |||
1487 | case '0': | |||
1488 | case '1': | |||
1489 | case '2': | |||
1490 | case '3': | |||
1491 | case '4': | |||
1492 | case '5': | |||
1493 | case '6': | |||
1494 | case '7': | |||
1495 | case '8': | |||
1496 | case '9': { | |||
1497 | int name_start_cookie = GetStartCookie(); | |||
1498 | if (!ParseSourceName()) | |||
1499 | return false; | |||
1500 | name_state.last_name_range = EndRange(name_start_cookie); | |||
1501 | return true; | |||
1502 | } | |||
1503 | default: | |||
1504 | return ParseOperatorName(name_state); | |||
1505 | }; | |||
1506 | } | |||
1507 | ||||
1508 | // <unscoped-name> ::= <unqualified-name> | |||
1509 | // ::= St <unqualified-name> # ::std:: | |||
1510 | // extension ::= StL<unqualified-name> | |||
1511 | ||||
1512 | bool ParseUnscopedName(NameState &name_state) { | |||
1513 | if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't') { | |||
1514 | WriteStdPrefix(); | |||
1515 | if (*(m_read_ptr += 2) == 'L') | |||
1516 | ++m_read_ptr; | |||
1517 | } | |||
1518 | return ParseUnqualifiedName(name_state); | |||
1519 | } | |||
1520 | ||||
1521 | bool ParseIntegerLiteral(const char *prefix, const char *suffix, | |||
1522 | bool allow_negative) { | |||
1523 | if (prefix) | |||
1524 | Write(prefix); | |||
1525 | if (!ParseNumber(allow_negative)) | |||
1526 | return false; | |||
1527 | if (suffix) | |||
1528 | Write(suffix); | |||
1529 | return Parse('E'); | |||
1530 | } | |||
1531 | ||||
1532 | bool ParseBooleanLiteral() { | |||
1533 | switch (*m_read_ptr++) { | |||
1534 | case '0': | |||
1535 | WRITE("false")Write("false", sizeof("false") - 1); | |||
1536 | break; | |||
1537 | case '1': | |||
1538 | WRITE("true")Write("true", sizeof("true") - 1); | |||
1539 | break; | |||
1540 | default: | |||
1541 | #ifdef DEBUG_FAILURES | |||
1542 | printf("*** Boolean literal not 0 or 1\n"); | |||
1543 | #endif | |||
1544 | return false; | |||
1545 | } | |||
1546 | return Parse('E'); | |||
1547 | } | |||
1548 | ||||
1549 | // <expr-primary> ::= L <type> <value number> E # | |||
1550 | // integer literal | |||
1551 | // ::= L <type> <value float> E # | |||
1552 | // floating literal | |||
1553 | // ::= L <string type> E # | |||
1554 | // string literal | |||
1555 | // ::= L <nullptr type> E # | |||
1556 | // nullptr literal (i.e., "LDnE") | |||
1557 | // ::= L <type> <real-part float> _ <imag-part float> E # | |||
1558 | // complex floating point literal (C 2000) | |||
1559 | // ::= L <mangled-name> E # | |||
1560 | // external name | |||
1561 | ||||
1562 | bool ParseExpressionPrimary() { | |||
1563 | switch (*m_read_ptr++) { | |||
1564 | case 'b': | |||
1565 | return ParseBooleanLiteral(); | |||
1566 | case 'x': | |||
1567 | return ParseIntegerLiteral(nullptr, "ll", true); | |||
1568 | case 'l': | |||
1569 | return ParseIntegerLiteral(nullptr, "l", true); | |||
1570 | case 'i': | |||
1571 | return ParseIntegerLiteral(nullptr, nullptr, true); | |||
1572 | case 'n': | |||
1573 | return ParseIntegerLiteral("(__int128)", nullptr, true); | |||
1574 | case 'j': | |||
1575 | return ParseIntegerLiteral(nullptr, "u", false); | |||
1576 | case 'm': | |||
1577 | return ParseIntegerLiteral(nullptr, "ul", false); | |||
1578 | case 'y': | |||
1579 | return ParseIntegerLiteral(nullptr, "ull", false); | |||
1580 | case 'o': | |||
1581 | return ParseIntegerLiteral("(unsigned __int128)", nullptr, false); | |||
1582 | case '_': | |||
1583 | if (*m_read_ptr++ == 'Z') { | |||
1584 | if (!ParseEncoding()) | |||
1585 | return false; | |||
1586 | return Parse('E'); | |||
1587 | } | |||
1588 | --m_read_ptr; | |||
1589 | LLVM_FALLTHROUGH[[clang::fallthrough]]; | |||
1590 | case 'w': | |||
1591 | case 'c': | |||
1592 | case 'a': | |||
1593 | case 'h': | |||
1594 | case 's': | |||
1595 | case 't': | |||
1596 | case 'f': | |||
1597 | case 'd': | |||
1598 | case 'e': | |||
1599 | #ifdef DEBUG_FAILURES | |||
1600 | printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1); | |||
1601 | #endif | |||
1602 | return false; | |||
1603 | case 'T': | |||
1604 | // Invalid mangled name per | |||
1605 | // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html | |||
1606 | #ifdef DEBUG_FAILURES | |||
1607 | printf("*** Invalid primary expr encoding\n"); | |||
1608 | #endif | |||
1609 | return false; | |||
1610 | default: | |||
1611 | --m_read_ptr; | |||
1612 | Write('('); | |||
1613 | if (!ParseType()) | |||
1614 | return false; | |||
1615 | Write(')'); | |||
1616 | if (!ParseNumber()) | |||
1617 | return false; | |||
1618 | return Parse('E'); | |||
1619 | } | |||
1620 | } | |||
1621 | ||||
1622 | // <unresolved-type> ::= <template-param> | |||
1623 | // ::= <decltype> | |||
1624 | // ::= <substitution> | |||
1625 | ||||
1626 | bool ParseUnresolvedType() { | |||
1627 | int type_start_cookie = GetStartCookie(); | |||
1628 | switch (*m_read_ptr++) { | |||
| ||||
1629 | case 'T': | |||
1630 | if (!ParseTemplateParam()) | |||
1631 | return false; | |||
1632 | EndSubstitution(type_start_cookie); | |||
1633 | return true; | |||
1634 | case 'S': { | |||
1635 | if (*m_read_ptr != 't') | |||
1636 | return ParseSubstitution(); | |||
1637 | ||||
1638 | ++m_read_ptr; | |||
1639 | WriteStdPrefix(); | |||
1640 | NameState type_name = {}; | |||
1641 | if (!ParseUnqualifiedName(type_name)) | |||
1642 | return false; | |||
1643 | EndSubstitution(type_start_cookie); | |||
1644 | return true; | |||
1645 | } | |||
1646 | case 'D': | |||
1647 | default: | |||
1648 | #ifdef DEBUG_FAILURES | |||
1649 | printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1); | |||
1650 | #endif | |||
1651 | return false; | |||
1652 | } | |||
1653 | } | |||
1654 | ||||
1655 | // <base-unresolved-name> ::= <simple-id> # | |||
1656 | // unresolved name | |||
1657 | // extension ::= <operator-name> # | |||
1658 | // unresolved operator-function-id | |||
1659 | // extension ::= <operator-name> <template-args> # | |||
1660 | // unresolved operator template-id | |||
1661 | // ::= on <operator-name> # | |||
1662 | // unresolved operator-function-id | |||
1663 | // ::= on <operator-name> <template-args> # | |||
1664 | // unresolved operator template-id | |||
1665 | // ::= dn <destructor-name> # | |||
1666 | // destructor or pseudo-destructor; | |||
1667 | // # | |||
1668 | // e.g. | |||
1669 | // ~X | |||
1670 | // or | |||
1671 | // ~X<N-1> | |||
1672 | ||||
1673 | bool ParseBaseUnresolvedName() { | |||
1674 | #ifdef DEBUG_FAILURES | |||
1675 | printf("*** Base unresolved name unsupported\n"); | |||
1676 | #endif | |||
1677 | return false; | |||
1678 | } | |||
1679 | ||||
1680 | // <unresolved-name> | |||
1681 | // extension ::= srN <unresolved-type> [<template-args>] | |||
1682 | // <unresolved-qualifier-level>* E <base-unresolved-name> | |||
1683 | // ::= [gs] <base-unresolved-name> # x | |||
1684 | // or (with "gs") ::x | |||
1685 | // ::= [gs] sr <unresolved-qualifier-level>+ E | |||
1686 | // <base-unresolved-name> | |||
1687 | // # | |||
1688 | // A::x, | |||
1689 | // N::y, | |||
1690 | // A<T>::z; | |||
1691 | // "gs" | |||
1692 | // means | |||
1693 | // leading | |||
1694 | // "::" | |||
1695 | // ::= sr <unresolved-type> <base-unresolved-name> # | |||
1696 | // T::x / decltype(p)::x | |||
1697 | // extension ::= sr <unresolved-type> <template-args> | |||
1698 | // <base-unresolved-name> | |||
1699 | // # | |||
1700 | // T::N::x | |||
1701 | // /decltype(p)::N::x | |||
1702 | // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ | |||
1703 | // E <base-unresolved-name> | |||
1704 | ||||
1705 | bool ParseUnresolvedName() { | |||
1706 | #ifdef DEBUG_FAILURES | |||
1707 | printf("*** Unresolved names not supported\n"); | |||
1708 | #endif | |||
1709 | // TODO: grammar for all of this seems unclear... | |||
1710 | return false; | |||
1711 | ||||
1712 | #if 0 // TODO | |||
1713 | if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's') | |||
1714 | { | |||
1715 | m_read_ptr += 2; | |||
1716 | WriteNamespaceSeparator(); | |||
1717 | } | |||
1718 | #endif // TODO | |||
1719 | } | |||
1720 | ||||
1721 | // <expression> ::= <unary operator-name> <expression> | |||
1722 | // ::= <binary operator-name> <expression> <expression> | |||
1723 | // ::= <ternary operator-name> <expression> <expression> | |||
1724 | // <expression> | |||
1725 | // ::= cl <expression>+ E # | |||
1726 | // call | |||
1727 | // ::= cv <type> <expression> # | |||
1728 | // conversion with one argument | |||
1729 | // ::= cv <type> _ <expression>* E # | |||
1730 | // conversion with a different number of arguments | |||
1731 | // ::= [gs] nw <expression>* _ <type> E # new | |||
1732 | // (expr-list) type | |||
1733 | // ::= [gs] nw <expression>* _ <type> <initializer> # new | |||
1734 | // (expr-list) type (init) | |||
1735 | // ::= [gs] na <expression>* _ <type> E # | |||
1736 | // new[] (expr-list) type | |||
1737 | // ::= [gs] na <expression>* _ <type> <initializer> # | |||
1738 | // new[] (expr-list) type (init) | |||
1739 | // ::= [gs] dl <expression> # | |||
1740 | // delete expression | |||
1741 | // ::= [gs] da <expression> # | |||
1742 | // delete[] expression | |||
1743 | // ::= pp_ <expression> # | |||
1744 | // prefix ++ | |||
1745 | // ::= mm_ <expression> # | |||
1746 | // prefix -- | |||
1747 | // ::= ti <type> # | |||
1748 | // typeid (type) | |||
1749 | // ::= te <expression> # | |||
1750 | // typeid (expression) | |||
1751 | // ::= dc <type> <expression> # | |||
1752 | // dynamic_cast<type> (expression) | |||
1753 | // ::= sc <type> <expression> # | |||
1754 | // static_cast<type> (expression) | |||
1755 | // ::= cc <type> <expression> # | |||
1756 | // const_cast<type> (expression) | |||
1757 | // ::= rc <type> <expression> # | |||
1758 | // reinterpret_cast<type> (expression) | |||
1759 | // ::= st <type> # | |||
1760 | // sizeof (a type) | |||
1761 | // ::= sz <expression> # | |||
1762 | // sizeof (an expression) | |||
1763 | // ::= at <type> # | |||
1764 | // alignof (a type) | |||
1765 | // ::= az <expression> # | |||
1766 | // alignof (an expression) | |||
1767 | // ::= nx <expression> # | |||
1768 | // noexcept (expression) | |||
1769 | // ::= <template-param> | |||
1770 | // ::= <function-param> | |||
1771 | // ::= dt <expression> <unresolved-name> # | |||
1772 | // expr.name | |||
1773 | // ::= pt <expression> <unresolved-name> # | |||
1774 | // expr->name | |||
1775 | // ::= ds <expression> <expression> # | |||
1776 | // expr.*expr | |||
1777 | // ::= sZ <template-param> # | |||
1778 | // size of a parameter pack | |||
1779 | // ::= sZ <function-param> # | |||
1780 | // size of a function parameter pack | |||
1781 | // ::= sp <expression> # | |||
1782 | // pack expansion | |||
1783 | // ::= tw <expression> # | |||
1784 | // throw expression | |||
1785 | // ::= tr # | |||
1786 | // throw with no operand (rethrow) | |||
1787 | // ::= <unresolved-name> # | |||
1788 | // f(p), N::f(p), ::f(p), | |||
1789 | // # | |||
1790 | // freestanding | |||
1791 | // dependent | |||
1792 | // name | |||
1793 | // (e.g., | |||
1794 | // T::x), | |||
1795 | // # | |||
1796 | // objectless | |||
1797 | // nonstatic | |||
1798 | // member | |||
1799 | // reference | |||
1800 | // ::= <expr-primary> | |||
1801 | ||||
1802 | bool ParseExpression() { | |||
1803 | Operator expression_operator = TryParseOperator(); | |||
1804 | switch (expression_operator.kind) { | |||
1805 | case OperatorKind::Unary: | |||
1806 | Write(expression_operator.name); | |||
1807 | Write('('); | |||
1808 | if (!ParseExpression()) | |||
1809 | return false; | |||
1810 | Write(')'); | |||
1811 | return true; | |||
1812 | case OperatorKind::Binary: | |||
1813 | if (!ParseExpression()) | |||
1814 | return false; | |||
1815 | Write(expression_operator.name); | |||
1816 | return ParseExpression(); | |||
1817 | case OperatorKind::Ternary: | |||
1818 | if (!ParseExpression()) | |||
1819 | return false; | |||
1820 | Write('?'); | |||
1821 | if (!ParseExpression()) | |||
1822 | return false; | |||
1823 | Write(':'); | |||
1824 | return ParseExpression(); | |||
1825 | case OperatorKind::NoMatch: | |||
1826 | break; | |||
1827 | case OperatorKind::Other: | |||
1828 | default: | |||
1829 | #ifdef DEBUG_FAILURES | |||
1830 | printf("*** Unsupported operator: %s\n", expression_operator.name); | |||
1831 | #endif | |||
1832 | return false; | |||
1833 | } | |||
1834 | ||||
1835 | switch (*m_read_ptr++) { | |||
1836 | case 'T': | |||
1837 | return ParseTemplateParam(); | |||
1838 | case 'L': | |||
1839 | return ParseExpressionPrimary(); | |||
1840 | case 's': | |||
1841 | if (*m_read_ptr++ == 'r') | |||
1842 | return ParseUnresolvedName(); | |||
1843 | --m_read_ptr; | |||
1844 | LLVM_FALLTHROUGH[[clang::fallthrough]]; | |||
1845 | default: | |||
1846 | return ParseExpressionPrimary(); | |||
1847 | } | |||
1848 | } | |||
1849 | ||||
1850 | // <template-arg> ::= <type> # | |||
1851 | // type or template | |||
1852 | // ::= X <expression> E # | |||
1853 | // expression | |||
1854 | // ::= <expr-primary> # | |||
1855 | // simple expressions | |||
1856 | // ::= J <template-arg>* E # | |||
1857 | // argument pack | |||
1858 | // ::= LZ <encoding> E # | |||
1859 | // extension | |||
1860 | ||||
1861 | bool ParseTemplateArg() { | |||
1862 | switch (*m_read_ptr) { | |||
1863 | case 'J': | |||
1864 | #ifdef DEBUG_FAILURES | |||
1865 | printf("*** Template argument packs unsupported\n"); | |||
1866 | #endif | |||
1867 | return false; | |||
1868 | case 'X': | |||
1869 | ++m_read_ptr; | |||
1870 | if (!ParseExpression()) | |||
1871 | return false; | |||
1872 | return Parse('E'); | |||
1873 | case 'L': | |||
1874 | ++m_read_ptr; | |||
1875 | return ParseExpressionPrimary(); | |||
1876 | default: | |||
1877 | return ParseType(); | |||
1878 | } | |||
1879 | } | |||
1880 | ||||
1881 | // <template-args> ::= I <template-arg>* E | |||
1882 | // extension, the abi says <template-arg>+ | |||
1883 | ||||
1884 | bool ParseTemplateArgs(bool record_template_args = false) { | |||
1885 | if (record_template_args) | |||
1886 | ResetTemplateArgs(); | |||
1887 | ||||
1888 | bool first_arg = true; | |||
1889 | while (*m_read_ptr != 'E') { | |||
1890 | if (first_arg) | |||
1891 | first_arg = false; | |||
1892 | else | |||
1893 | WriteCommaSpace(); | |||
1894 | ||||
1895 | int template_start_cookie = GetStartCookie(); | |||
1896 | if (!ParseTemplateArg()) | |||
1897 | return false; | |||
1898 | if (record_template_args) | |||
1899 | EndTemplateArg(template_start_cookie); | |||
1900 | } | |||
1901 | ++m_read_ptr; | |||
1902 | return true; | |||
1903 | } | |||
1904 | ||||
1905 | // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> | |||
1906 | // <unqualified-name> E | |||
1907 | // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> | |||
1908 | // <template-args> E | |||
1909 | // | |||
1910 | // <prefix> ::= <prefix> <unqualified-name> | |||
1911 | // ::= <template-prefix> <template-args> | |||
1912 | // ::= <template-param> | |||
1913 | // ::= <decltype> | |||
1914 | // ::= # empty | |||
1915 | // ::= <substitution> | |||
1916 | // ::= <prefix> <data-member-prefix> | |||
1917 | // extension ::= L | |||
1918 | // | |||
1919 | // <template-prefix> ::= <prefix> <template unqualified-name> | |||
1920 | // ::= <template-param> | |||
1921 | // ::= <substitution> | |||
1922 | // | |||
1923 | // <unqualified-name> ::= <operator-name> | |||
1924 | // ::= <ctor-dtor-name> | |||
1925 | // ::= <source-name> | |||
1926 | // ::= <unnamed-type-name> | |||
1927 | ||||
1928 | bool ParseNestedName(NameState &name_state, | |||
1929 | bool parse_discriminator = false) { | |||
1930 | int qualifiers = TryParseQualifiers(true, true); | |||
1931 | bool first_part = true; | |||
1932 | bool suppress_substitution = true; | |||
1933 | int name_start_cookie = GetStartCookie(); | |||
1934 | while (true) { | |||
1935 | char next = *m_read_ptr; | |||
1936 | if (next == 'E') { | |||
1937 | ++m_read_ptr; | |||
1938 | break; | |||
1939 | } | |||
1940 | ||||
1941 | // Record a substitution candidate for all prefixes, but not the full | |||
1942 | // name | |||
1943 | if (suppress_substitution) | |||
1944 | suppress_substitution = false; | |||
1945 | else | |||
1946 | EndSubstitution(name_start_cookie); | |||
1947 | ||||
1948 | if (next == 'I') { | |||
1949 | ++m_read_ptr; | |||
1950 | name_state.is_last_generic = true; | |||
1951 | WriteTemplateStart(); | |||
1952 | if (!ParseTemplateArgs(name_state.parse_function_params)) | |||
1953 | return false; | |||
1954 | WriteTemplateEnd(); | |||
1955 | continue; | |||
1956 | } | |||
1957 | ||||
1958 | if (first_part) | |||
1959 | first_part = false; | |||
1960 | else | |||
1961 | WriteNamespaceSeparator(); | |||
1962 | ||||
1963 | name_state.is_last_generic = false; | |||
1964 | switch (next) { | |||
1965 | case '0': | |||
1966 | case '1': | |||
1967 | case '2': | |||
1968 | case '3': | |||
1969 | case '4': | |||
1970 | case '5': | |||
1971 | case '6': | |||
1972 | case '7': | |||
1973 | case '8': | |||
1974 | case '9': { | |||
1975 | int name_start_cookie = GetStartCookie(); | |||
1976 | if (!ParseSourceName()) | |||
1977 | return false; | |||
1978 | name_state.last_name_range = EndRange(name_start_cookie); | |||
1979 | continue; | |||
1980 | } | |||
1981 | case 'S': | |||
1982 | if (*++m_read_ptr == 't') { | |||
1983 | WriteStdPrefix(); | |||
1984 | ++m_read_ptr; | |||
1985 | if (!ParseUnqualifiedName(name_state)) | |||
1986 | return false; | |||
1987 | } else { | |||
1988 | if (!ParseSubstitution()) | |||
1989 | return false; | |||
1990 | suppress_substitution = true; | |||
1991 | } | |||
1992 | continue; | |||
1993 | case 'T': | |||
1994 | ++m_read_ptr; | |||
1995 | if (!ParseTemplateParam()) | |||
1996 | return false; | |||
1997 | continue; | |||
1998 | case 'C': | |||
1999 | ++m_read_ptr; | |||
2000 | if (!ParseCtor(name_state)) | |||
2001 | return false; | |||
2002 | continue; | |||
2003 | case 'D': { | |||
2004 | switch (*(m_read_ptr + 1)) { | |||
2005 | case 't': | |||
2006 | case 'T': | |||
2007 | #ifdef DEBUG_FAILURES | |||
2008 | printf("*** Decltype unsupported\n"); | |||
2009 | #endif | |||
2010 | return false; | |||
2011 | } | |||
2012 | ++m_read_ptr; | |||
2013 | if (!ParseDtor(name_state)) | |||
2014 | return false; | |||
2015 | continue; | |||
2016 | } | |||
2017 | case 'U': | |||
2018 | ++m_read_ptr; | |||
2019 | if (!ParseUnnamedTypeName(name_state)) | |||
2020 | return false; | |||
2021 | continue; | |||
2022 | case 'L': | |||
2023 | ++m_read_ptr; | |||
2024 | if (!ParseUnqualifiedName(name_state)) | |||
2025 | return false; | |||
2026 | continue; | |||
2027 | default: | |||
2028 | if (!ParseOperatorName(name_state)) | |||
2029 | return false; | |||
2030 | } | |||
2031 | } | |||
2032 | ||||
2033 | if (parse_discriminator) | |||
2034 | TryParseDiscriminator(); | |||
2035 | if (name_state.parse_function_params && | |||
2036 | !ParseFunctionArgs(name_state, name_start_cookie)) { | |||
2037 | return false; | |||
2038 | } | |||
2039 | if (qualifiers) | |||
2040 | WriteQualifiers(qualifiers); | |||
2041 | return true; | |||
2042 | } | |||
2043 | ||||
2044 | // <local-name> := Z <function encoding> E <entity name> [<discriminator>] | |||
2045 | // := Z <function encoding> E s [<discriminator>] | |||
2046 | // := Z <function encoding> Ed [ <parameter number> ] _ <entity | |||
2047 | // name> | |||
2048 | ||||
2049 | bool ParseLocalName(bool parse_function_params) { | |||
2050 | if (!ParseEncoding()) | |||
2051 | return false; | |||
2052 | if (!Parse('E')) | |||
2053 | return false; | |||
2054 | ||||
2055 | switch (*m_read_ptr) { | |||
2056 | case 's': | |||
2057 | ++m_read_ptr; | |||
2058 | TryParseDiscriminator(); // Optional and ignored | |||
2059 | WRITE("::string literal")Write("::string literal", sizeof("::string literal") - 1); | |||
2060 | break; | |||
2061 | case 'd': | |||
2062 | ++m_read_ptr; | |||
2063 | TryParseNumber(); // Optional and ignored | |||
2064 | if (!Parse('_')) | |||
2065 | return false; | |||
2066 | WriteNamespaceSeparator(); | |||
2067 | if (!ParseName()) | |||
2068 | return false; | |||
2069 | break; | |||
2070 | default: | |||
2071 | WriteNamespaceSeparator(); | |||
2072 | if (!ParseName(parse_function_params, true)) | |||
2073 | return false; | |||
2074 | TryParseDiscriminator(); // Optional and ignored | |||
2075 | } | |||
2076 | return true; | |||
2077 | } | |||
2078 | ||||
2079 | // <name> ::= <nested-name> | |||
2080 | // ::= <local-name> | |||
2081 | // ::= <unscoped-template-name> <template-args> | |||
2082 | // ::= <unscoped-name> | |||
2083 | ||||
2084 | // <unscoped-template-name> ::= <unscoped-name> | |||
2085 | // ::= <substitution> | |||
2086 | ||||
2087 | bool ParseName(bool parse_function_params = false, | |||
2088 | bool parse_discriminator = false) { | |||
2089 | NameState name_state = {parse_function_params, false, false, {0, 0}}; | |||
2090 | int name_start_cookie = GetStartCookie(); | |||
2091 | ||||
2092 | switch (*m_read_ptr) { | |||
2093 | case 'N': | |||
2094 | ++m_read_ptr; | |||
2095 | return ParseNestedName(name_state, parse_discriminator); | |||
2096 | case 'Z': { | |||
2097 | ++m_read_ptr; | |||
2098 | if (!ParseLocalName(parse_function_params)) | |||
2099 | return false; | |||
2100 | break; | |||
2101 | } | |||
2102 | case 'L': | |||
2103 | ++m_read_ptr; | |||
2104 | LLVM_FALLTHROUGH[[clang::fallthrough]]; | |||
2105 | default: { | |||
2106 | if (!ParseUnscopedName(name_state)) | |||
2107 | return false; | |||
2108 | ||||
2109 | if (*m_read_ptr == 'I') { | |||
2110 | EndSubstitution(name_start_cookie); | |||
2111 | ||||
2112 | ++m_read_ptr; | |||
2113 | name_state.is_last_generic = true; | |||
2114 | WriteTemplateStart(); | |||
2115 | if (!ParseTemplateArgs(parse_function_params)) | |||
2116 | return false; | |||
2117 | WriteTemplateEnd(); | |||
2118 | } | |||
2119 | break; | |||
2120 | } | |||
2121 | } | |||
2122 | if (parse_discriminator) | |||
2123 | TryParseDiscriminator(); | |||
2124 | if (parse_function_params && | |||
2125 | !ParseFunctionArgs(name_state, name_start_cookie)) { | |||
2126 | return false; | |||
2127 | } | |||
2128 | return true; | |||
2129 | } | |||
2130 | ||||
2131 | // <call-offset> ::= h <nv-offset> _ | |||
2132 | // ::= v <v-offset> _ | |||
2133 | // | |||
2134 | // <nv-offset> ::= <offset number> | |||
2135 | // # non-virtual base override | |||
2136 | // | |||
2137 | // <v-offset> ::= <offset number> _ <virtual offset number> | |||
2138 | // # virtual base override, with vcall offset | |||
2139 | ||||
2140 | bool ParseCallOffset() { | |||
2141 | switch (*m_read_ptr++) { | |||
2142 | case 'h': | |||
2143 | if (*m_read_ptr == 'n') | |||
2144 | ++m_read_ptr; | |||
2145 | if (TryParseNumber() == -1 || *m_read_ptr++ != '_') | |||
2146 | break; | |||
2147 | return true; | |||
2148 | case 'v': | |||
2149 | if (*m_read_ptr == 'n') | |||
2150 | ++m_read_ptr; | |||
2151 | if (TryParseNumber() == -1 || *m_read_ptr++ != '_') | |||
2152 | break; | |||
2153 | if (*m_read_ptr == 'n') | |||
2154 | ++m_read_ptr; | |||
2155 | if (TryParseNumber() == -1 || *m_read_ptr++ != '_') | |||
2156 | break; | |||
2157 | return true; | |||
2158 | } | |||
2159 | #ifdef DEBUG_FAILURES | |||
2160 | printf("*** Malformed call offset\n"); | |||
2161 | #endif | |||
2162 | return false; | |||
2163 | } | |||
2164 | ||||
2165 | // <special-name> ::= TV <type> # virtual table | |||
2166 | // ::= TT <type> # VTT structure (construction vtable index) | |||
2167 | // ::= TI <type> # typeinfo structure | |||
2168 | // ::= TS <type> # typeinfo name (null-terminated byte | |||
2169 | // string) | |||
2170 | // ::= Tc <call-offset> <call-offset> <base encoding> | |||
2171 | // # base is the nominal target function of thunk | |||
2172 | // # first call-offset is 'this' adjustment | |||
2173 | // # second call-offset is result adjustment | |||
2174 | // ::= T <call-offset> <base encoding> | |||
2175 | // # base is the nominal target function of thunk | |||
2176 | // extension ::= TC <first type> <number> _ <second type> # construction | |||
2177 | // vtable for second-in-first | |||
2178 | ||||
2179 | bool ParseSpecialNameT() { | |||
2180 | switch (*m_read_ptr++) { | |||
2181 | case 'V': | |||
2182 | WRITE("vtable for ")Write("vtable for ", sizeof("vtable for ") - 1); | |||
2183 | return ParseType(); | |||
2184 | case 'T': | |||
2185 | WRITE("VTT for ")Write("VTT for ", sizeof("VTT for ") - 1); | |||
2186 | return ParseType(); | |||
2187 | case 'I': | |||
2188 | WRITE("typeinfo for ")Write("typeinfo for ", sizeof("typeinfo for ") - 1); | |||
2189 | return ParseType(); | |||
2190 | case 'S': | |||
2191 | WRITE("typeinfo name for ")Write("typeinfo name for ", sizeof("typeinfo name for ") - 1); | |||
2192 | return ParseType(); | |||
2193 | case 'c': | |||
2194 | case 'C': | |||
2195 | #ifdef DEBUG_FAILURES | |||
2196 | printf("*** Unsupported thunk or construction vtable name: %.3s\n", | |||
2197 | m_read_ptr - 1); | |||
2198 | #endif | |||
2199 | return false; | |||
2200 | default: | |||
2201 | if (*--m_read_ptr == 'v') { | |||
2202 | WRITE("virtual thunk to ")Write("virtual thunk to ", sizeof("virtual thunk to ") - 1); | |||
2203 | } else { | |||
2204 | WRITE("non-virtual thunk to ")Write("non-virtual thunk to ", sizeof("non-virtual thunk to " ) - 1); | |||
2205 | } | |||
2206 | if (!ParseCallOffset()) | |||
2207 | return false; | |||
2208 | return ParseEncoding(); | |||
2209 | } | |||
2210 | } | |||
2211 | ||||
2212 | // <special-name> ::= GV <object name> # Guard variable for one-time | |||
2213 | // initialization | |||
2214 | // # No <type> | |||
2215 | // extension ::= GR <object name> # reference temporary for object | |||
2216 | ||||
2217 | bool ParseSpecialNameG() { | |||
2218 | switch (*m_read_ptr++) { | |||
2219 | case 'V': | |||
2220 | WRITE("guard variable for ")Write("guard variable for ", sizeof("guard variable for ") - 1 ); | |||
2221 | if (!ParseName(true)) | |||
2222 | return false; | |||
2223 | break; | |||
2224 | case 'R': | |||
2225 | WRITE("reference temporary for ")Write("reference temporary for ", sizeof("reference temporary for " ) - 1); | |||
2226 | if (!ParseName(true)) | |||
2227 | return false; | |||
2228 | break; | |||
2229 | default: | |||
2230 | #ifdef DEBUG_FAILURES | |||
2231 | printf("*** Unknown G encoding\n"); | |||
2232 | #endif | |||
2233 | return false; | |||
2234 | } | |||
2235 | return true; | |||
2236 | } | |||
2237 | ||||
2238 | // <bare-function-type> ::= <signature type>+ # types are possible | |||
2239 | // return type, then parameter types | |||
2240 | ||||
2241 | bool ParseFunctionArgs(NameState &name_state, int return_insert_cookie) { | |||
2242 | char next = *m_read_ptr; | |||
2243 | if (next == 'E' || next == '\0' || next == '.') | |||
2244 | return true; | |||
2245 | ||||
2246 | // Clang has a bad habit of making unique manglings by just sticking | |||
2247 | // numbers on the end of a symbol, which is ambiguous with malformed source | |||
2248 | // name manglings | |||
2249 | const char *before_clang_uniquing_test = m_read_ptr; | |||
2250 | if (TryParseNumber()) { | |||
2251 | if (*m_read_ptr == '\0') | |||
2252 | return true; | |||
2253 | m_read_ptr = before_clang_uniquing_test; | |||
2254 | } | |||
2255 | ||||
2256 | if (name_state.is_last_generic && !name_state.has_no_return_type) { | |||
2257 | int return_type_start_cookie = GetStartCookie(); | |||
2258 | if (!ParseType()) | |||
2259 | return false; | |||
2260 | Write(' '); | |||
2261 | ReorderRange(EndRange(return_type_start_cookie), return_insert_cookie); | |||
2262 | } | |||
2263 | ||||
2264 | Write('('); | |||
2265 | bool first_param = true; | |||
2266 | while (true) { | |||
2267 | switch (*m_read_ptr) { | |||
2268 | case '\0': | |||
2269 | case 'E': | |||
2270 | case '.': | |||
2271 | break; | |||
2272 | case 'v': | |||
2273 | ++m_read_ptr; | |||
2274 | continue; | |||
2275 | case '_': | |||
2276 | // Not a formal part of the mangling specification, but clang emits | |||
2277 | // suffixes starting with _block_invoke | |||
2278 | if (strncmp(m_read_ptr, "_block_invoke", 13) == 0) { | |||
2279 | m_read_ptr += strlen(m_read_ptr); | |||
2280 | break; | |||
2281 | } | |||
2282 | LLVM_FALLTHROUGH[[clang::fallthrough]]; | |||
2283 | default: | |||
2284 | if (first_param) | |||
2285 | first_param = false; | |||
2286 | else | |||
2287 | WriteCommaSpace(); | |||
2288 | ||||
2289 | if (!ParseType()) | |||
2290 | return false; | |||
2291 | continue; | |||
2292 | } | |||
2293 | break; | |||
2294 | } | |||
2295 | Write(')'); | |||
2296 | return true; | |||
2297 | } | |||
2298 | ||||
2299 | // <encoding> ::= <function name> <bare-function-type> | |||
2300 | // ::= <data name> | |||
2301 | // ::= <special-name> | |||
2302 | ||||
2303 | bool ParseEncoding() { | |||
2304 | switch (*m_read_ptr) { | |||
2305 | case 'T': | |||
2306 | ++m_read_ptr; | |||
2307 | if (!ParseSpecialNameT()) | |||
2308 | return false; | |||
2309 | break; | |||
2310 | case 'G': | |||
2311 | ++m_read_ptr; | |||
2312 | if (!ParseSpecialNameG()) | |||
2313 | return false; | |||
2314 | break; | |||
2315 | default: | |||
2316 | if (!ParseName(true)) | |||
2317 | return false; | |||
2318 | break; | |||
2319 | } | |||
2320 | return true; | |||
2321 | } | |||
2322 | ||||
2323 | bool ParseMangling(const char *mangled_name, long mangled_name_length = 0) { | |||
2324 | if (!mangled_name_length) | |||
2325 | mangled_name_length = strlen(mangled_name); | |||
2326 | m_read_end = mangled_name + mangled_name_length; | |||
2327 | m_read_ptr = mangled_name; | |||
2328 | m_write_ptr = m_buffer; | |||
2329 | m_next_substitute_index = 0; | |||
2330 | m_next_template_arg_index = m_rewrite_ranges_size - 1; | |||
2331 | ||||
2332 | if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z') { | |||
2333 | #ifdef DEBUG_FAILURES | |||
2334 | printf("*** Missing _Z prefix\n"); | |||
2335 | #endif | |||
2336 | return false; | |||
2337 | } | |||
2338 | if (!ParseEncoding()) | |||
2339 | return false; | |||
2340 | switch (*m_read_ptr) { | |||
2341 | case '.': | |||
2342 | Write(' '); | |||
2343 | Write('('); | |||
2344 | Write(m_read_ptr, m_read_end - m_read_ptr); | |||
2345 | Write(')'); | |||
2346 | LLVM_FALLTHROUGH[[clang::fallthrough]]; | |||
2347 | case '\0': | |||
2348 | return true; | |||
2349 | default: | |||
2350 | #ifdef DEBUG_FAILURES | |||
2351 | printf("*** Unparsed mangled content\n"); | |||
2352 | #endif | |||
2353 | return false; | |||
2354 | } | |||
2355 | } | |||
2356 | ||||
2357 | private: | |||
2358 | // External scratch storage used during demanglings | |||
2359 | ||||
2360 | char *m_buffer; | |||
2361 | const char *m_buffer_end; | |||
2362 | BufferRange *m_rewrite_ranges; | |||
2363 | int m_rewrite_ranges_size; | |||
2364 | bool m_owns_buffer; | |||
2365 | bool m_owns_m_rewrite_ranges; | |||
2366 | ||||
2367 | // Internal state used during demangling | |||
2368 | ||||
2369 | const char *m_read_ptr; | |||
2370 | const char *m_read_end; | |||
2371 | char *m_write_ptr; | |||
2372 | int m_next_template_arg_index; | |||
2373 | int m_next_substitute_index; | |||
2374 | std::function<void(const char *s)> m_builtins_hook; | |||
2375 | }; | |||
2376 | ||||
2377 | } // Anonymous namespace | |||
2378 | ||||
2379 | // Public entry points referenced from Mangled.cpp | |||
2380 | namespace lldb_private { | |||
2381 | char *FastDemangle(const char *mangled_name) { | |||
2382 | char buffer[16384]; | |||
2383 | SymbolDemangler demangler(buffer, sizeof(buffer)); | |||
2384 | return demangler.GetDemangledCopy(mangled_name); | |||
2385 | } | |||
2386 | ||||
2387 | char *FastDemangle(const char *mangled_name, size_t mangled_name_length, | |||
2388 | std::function<void(const char *s)> builtins_hook) { | |||
2389 | char buffer[16384]; | |||
2390 | SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook); | |||
2391 | return demangler.GetDemangledCopy(mangled_name, mangled_name_length); | |||
2392 | } | |||
2393 | } // lldb_private namespace |