diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-08-30 07:14:22 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-08-30 18:22:56 +0200 |
commit | 5092df19372bd6957bd43649da43add30777212d (patch) | |
tree | bfc20215881a8e8699739069dab898b95dfd3ec6 | |
parent | af6ca21ed0f2715aad0b2ae80d200589b5e31089 (diff) |
kill demangle
17 files changed, 0 insertions, 11634 deletions
diff --git a/demangle/CMakeLists.txt b/demangle/CMakeLists.txt deleted file mode 100644 index ce3222a4..00000000 --- a/demangle/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -cmake_minimum_required(VERSION 3.18 FATAL_ERROR) -project(demumble CXX) - -set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) -set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_DEFAULT 23) -set(CMAKE_CXX_STANDARD_REQUIRED TRUE) -set(CMAKE_CXX_EXTENSIONS FALSE) - -if (NOT MSVC) - add_compile_options(-Wall -fno-exceptions -fno-rtti) - # 10.9 chosen somewhat arbitrary; it's the first target where clang defaults - # to libc++ and ld64 defaults to stripping __TEXT,__eh_frame. - if (APPLE) - add_compile_options(-mmacosx-version-min=10.9) - else() - add_compile_options(-fno-plt) - endif() - add_compile_options(-Wno-error -Wno-sign-conversion -Wno-unused -Wno-unused-parameter) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$") - add_compile_options(-Wno-shorten-64-to-32 -Wno-implicit-int-conversion -Wno-class-varargs -Wno-extra-semi-stmt) - endif() -else() - add_compile_options(-Zc:inline -permissive- -GR-) - add_compile_options(-wd4100 -wd4244 -wd4267) - add_definitions(-D_HAS_EXCEPTIONS=0 -DNOMINMAX -D_USE_MATH_DEFINES=1) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) # The LLVM build sets this. -endif() - -include_directories(SYSTEM third_party/llvm/include) -add_library(demumble STATIC - third_party/llvm/lib/Demangle/Demangle.cpp - third_party/llvm/lib/Demangle/ItaniumDemangle.cpp - third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp - third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp - demangle.cpp) -target_link_libraries(demumble PUBLIC Corrade::Containers) diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp deleted file mode 100644 index f3cfd231..00000000 --- a/demangle/demangle.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "demangle.h" -#include <cstdlib> -#include <string> -#include "llvm/Demangle/Demangle.h" - -using namespace Corrade::Containers; - -String demangle_symbol(const char* symbol) -{ - if (!symbol || !*symbol) - return {}; - if (const auto str = llvm::demangle(symbol); !str.empty()) - return String{str.data(), str.size()}; - return {}; -} diff --git a/demangle/demangle.h b/demangle/demangle.h deleted file mode 100644 index 632f9c14..00000000 --- a/demangle/demangle.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include <Corrade/Containers/String.h> - -Corrade::Containers::String demangle_symbol(const char* symbol); diff --git a/demangle/third_party/llvm/LICENSE.txt b/demangle/third_party/llvm/LICENSE.txt deleted file mode 100644 index fa6ac540..00000000 --- a/demangle/third_party/llvm/LICENSE.txt +++ /dev/null @@ -1,279 +0,0 @@ -============================================================================== -The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: -============================================================================== - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ----- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - -============================================================================== -Software from third parties included in the LLVM Project: -============================================================================== -The LLVM Project contains third party software which is under different license -terms. All such code will be identified clearly using at least one of two -mechanisms: -1) It will be in a separate directory tree with its own `LICENSE.txt` or - `LICENSE` file at the top containing the specific license and restrictions - which apply to that software, or -2) It will contain specific license and restriction terms at the top of every - file. - -============================================================================== -Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - diff --git a/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h b/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h deleted file mode 100644 index c17ff4ca..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/Compiler.h +++ /dev/null @@ -1,549 +0,0 @@ -//===--- Compiler.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// -// This file contains a variety of feature test macros copied from -// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take -// a dependency on LLVMSupport. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEMANGLE_COMPILER_H -#define LLVM_DEMANGLE_COMPILER_H - -#ifdef __cplusplus -#include <new> -#endif -#include <stddef.h> - -#if defined(_MSC_VER) -#include <sal.h> -#endif - -#ifndef __has_feature -# define __has_feature(x) 0 -#endif - -#ifndef __has_extension -# define __has_extension(x) 0 -#endif - -#ifndef __has_attribute -# define __has_attribute(x) 0 -#endif - -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in -// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid. -#ifndef LLVM_HAS_CPP_ATTRIBUTE -#if defined(__cplusplus) && defined(__has_cpp_attribute) -# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define LLVM_HAS_CPP_ATTRIBUTE(x) 0 -#endif -#endif - -/// \macro LLVM_GNUC_PREREQ -/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't -/// available. -#ifndef LLVM_GNUC_PREREQ -# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LLVM_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ - ((maj) << 20) + ((min) << 10) + (patch)) -# elif defined(__GNUC__) && defined(__GNUC_MINOR__) -# define LLVM_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) -# else -# define LLVM_GNUC_PREREQ(maj, min, patch) 0 -# endif -#endif - -/// \macro LLVM_MSC_PREREQ -/// Is the compiler MSVC of at least the specified version? -/// The common \param version values to check for are: -/// * 1910: VS2017, version 15.1 & 15.2 -/// * 1911: VS2017, version 15.3 & 15.4 -/// * 1912: VS2017, version 15.5 -/// * 1913: VS2017, version 15.6 -/// * 1914: VS2017, version 15.7 -/// * 1915: VS2017, version 15.8 -/// * 1916: VS2017, version 15.9 -/// * 1920: VS2019, version 16.0 -/// * 1921: VS2019, version 16.1 -#ifdef _MSC_VER -#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version)) - -// We require at least MSVC 2017. -#if !LLVM_MSC_PREREQ(1910) -#error LLVM requires at least MSVC 2017. -#endif - -#else -#define LLVM_MSC_PREREQ(version) 0 -#endif - -/// Does the compiler support ref-qualifiers for *this? -/// -/// Sadly, this is separate from just rvalue reference support because GCC -/// and MSVC implemented this later than everything else. This appears to be -/// corrected in MSVC 2019 but not MSVC 2017. -#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \ - LLVM_MSC_PREREQ(1920) -#define LLVM_HAS_RVALUE_REFERENCE_THIS 1 -#else -#define LLVM_HAS_RVALUE_REFERENCE_THIS 0 -#endif - -/// Expands to '&' if ref-qualifiers for *this are supported. -/// -/// This can be used to provide lvalue/rvalue overrides of member functions. -/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS -#if LLVM_HAS_RVALUE_REFERENCE_THIS -#define LLVM_LVALUE_FUNCTION & -#else -#define LLVM_LVALUE_FUNCTION -#endif - -/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked -/// into a shared library, then the class should be private to the library and -/// not accessible from outside it. Can also be used to mark variables and -/// functions, making them private to any shared library they are linked into. -/// On PE/COFF targets, library visibility is the default, so this isn't needed. -/// -/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with -/// this attribute will be made public and visible outside of any shared library -/// they are linked in to. -#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ - !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32) -#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) -#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default"))) -#else -#define LLVM_LIBRARY_VISIBILITY -#define LLVM_EXTERNAL_VISIBILITY -#endif - -#if defined(__GNUC__) -#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality) -#else -#define LLVM_PREFETCH(addr, rw, locality) -#endif - -#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0) -#define LLVM_ATTRIBUTE_USED __attribute__((__used__)) -#else -#define LLVM_ATTRIBUTE_USED -#endif - -/// LLVM_NODISCARD - Warn if a type or return value is discarded. - -// Use the 'nodiscard' attribute in C++17 or newer mode. -#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) -#define LLVM_NODISCARD [[nodiscard]] -#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result) -#define LLVM_NODISCARD [[clang::warn_unused_result]] -// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also -// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518). -// Use the 'nodiscard' attribute in C++14 mode only with GCC. -// TODO: remove this workaround when PR33518 is resolved. -#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) -#define LLVM_NODISCARD [[nodiscard]] -#else -#define LLVM_NODISCARD -#endif - -// Indicate that a non-static, non-const C++ member function reinitializes -// the entire object to a known state, independent of the previous state of -// the object. -// -// The clang-tidy check bugprone-use-after-move recognizes this attribute as a -// marker that a moved-from object has left the indeterminate state and can be -// reused. -#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes) -#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] -#else -#define LLVM_ATTRIBUTE_REINITIALIZES -#endif - -// Some compilers warn about unused functions. When a function is sometimes -// used or not depending on build settings (e.g. a function only called from -// within "assert"), this attribute can be used to suppress such warnings. -// -// However, it shouldn't be used for unused *variables*, as those have a much -// more portable solution: -// (void)unused_var_name; -// Prefer cast-to-void wherever it is sufficient. -#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0) -#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__)) -#else -#define LLVM_ATTRIBUTE_UNUSED -#endif - -// FIXME: Provide this for PE/COFF targets. -#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ - (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)) -#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__)) -#else -#define LLVM_ATTRIBUTE_WEAK -#endif - -// Prior to clang 3.2, clang did not accept any spelling of -// __has_attribute(const), so assume it is supported. -#if defined(__clang__) || defined(__GNUC__) -// aka 'CONST' but following LLVM Conventions. -#define LLVM_READNONE __attribute__((__const__)) -#else -#define LLVM_READNONE -#endif - -#if __has_attribute(pure) || defined(__GNUC__) -// aka 'PURE' but following LLVM Conventions. -#define LLVM_READONLY __attribute__((__pure__)) -#else -#define LLVM_READONLY -#endif - -#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0) -#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) -#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) -#else -#define LLVM_LIKELY(EXPR) (EXPR) -#define LLVM_UNLIKELY(EXPR) (EXPR) -#endif - -/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, -/// mark a method "not for inlining". -#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0) -#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) -#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline) -#else -#define LLVM_ATTRIBUTE_NOINLINE -#endif - -/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do -/// so, mark a method "always inline" because it is performance sensitive. GCC -/// 3.4 supported this but is buggy in various cases and produces unimplemented -/// errors, just use it in GCC 4.0 and later. -#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0) -#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline)) -#elif defined(_MSC_VER) -#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline -#else -#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline -#endif - -#ifdef __GNUC__ -#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) -#elif defined(_MSC_VER) -#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) -#else -#define LLVM_ATTRIBUTE_NORETURN -#endif - -#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0) -#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) -#elif defined(_MSC_VER) -#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_ -#else -#define LLVM_ATTRIBUTE_RETURNS_NONNULL -#endif - -/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a -/// pointer that does not alias any other valid pointer. -#ifdef __GNUC__ -#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) -#elif defined(_MSC_VER) -#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) -#else -#define LLVM_ATTRIBUTE_RETURNS_NOALIAS -#endif - -/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements. -#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough) -#define LLVM_FALLTHROUGH [[fallthrough]] -#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough) -#define LLVM_FALLTHROUGH [[gnu::fallthrough]] -#elif __has_attribute(fallthrough) -#define LLVM_FALLTHROUGH __attribute__((fallthrough)) -#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough) -#define LLVM_FALLTHROUGH [[clang::fallthrough]] -#else -#define LLVM_FALLTHROUGH -#endif - -/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that -/// they are constant initialized. -#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization) -#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \ - [[clang::require_constant_initialization]] -#else -#define LLVM_REQUIRE_CONSTANT_INITIALIZATION -#endif - -/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable -/// lifetime warnings. -#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner) -#define LLVM_GSL_OWNER [[gsl::Owner]] -#else -#define LLVM_GSL_OWNER -#endif - -/// LLVM_GSL_POINTER - Apply this to non-owning classes like -/// StringRef to enable lifetime warnings. -#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer) -#define LLVM_GSL_POINTER [[gsl::Pointer]] -#else -#define LLVM_GSL_POINTER -#endif - -/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress -/// pedantic diagnostics. -#ifdef __GNUC__ -#define LLVM_EXTENSION __extension__ -#else -#define LLVM_EXTENSION -#endif - -// LLVM_ATTRIBUTE_DEPRECATED(decl, "message") -// This macro will be removed. -// Use C++14's attribute instead: [[deprecated("message")]] -#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl - -/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands -/// to an expression which states that it is undefined behavior for the -/// compiler to reach this point. Otherwise is not defined. -#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0) -# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -# define LLVM_BUILTIN_UNREACHABLE __assume(false) -#endif - -/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression -/// which causes the program to exit abnormally. -#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0) -# define LLVM_BUILTIN_TRAP __builtin_trap() -#elif defined(_MSC_VER) -// The __debugbreak intrinsic is supported by MSVC, does not require forward -// declarations involving platform-specific typedefs (unlike RaiseException), -// results in a call to vectored exception handlers, and encodes to a short -// instruction that still causes the trapping behavior we want. -# define LLVM_BUILTIN_TRAP __debugbreak() -#else -# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0 -#endif - -/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to -/// an expression which causes the program to break while running -/// under a debugger. -#if __has_builtin(__builtin_debugtrap) -# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap() -#elif defined(_MSC_VER) -// The __debugbreak intrinsic is supported by MSVC and breaks while -// running under the debugger, and also supports invoking a debugger -// when the OS is configured appropriately. -# define LLVM_BUILTIN_DEBUGTRAP __debugbreak() -#else -// Just continue execution when built with compilers that have no -// support. This is a debugging aid and not intended to force the -// program to abort if encountered. -# define LLVM_BUILTIN_DEBUGTRAP -#endif - -/// \macro LLVM_ASSUME_ALIGNED -/// Returns a pointer with an assumed alignment. -#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0) -# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a) -#elif defined(LLVM_BUILTIN_UNREACHABLE) -# define LLVM_ASSUME_ALIGNED(p, a) \ - (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p))) -#else -# define LLVM_ASSUME_ALIGNED(p, a) (p) -#endif - -/// \macro LLVM_PACKED -/// Used to specify a packed structure. -/// LLVM_PACKED( -/// struct A { -/// int i; -/// int j; -/// int k; -/// long long l; -/// }); -/// -/// LLVM_PACKED_START -/// struct B { -/// int i; -/// int j; -/// int k; -/// long long l; -/// }; -/// LLVM_PACKED_END -#ifdef _MSC_VER -# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop)) -# define LLVM_PACKED_START __pragma(pack(push, 1)) -# define LLVM_PACKED_END __pragma(pack(pop)) -#else -# define LLVM_PACKED(d) d __attribute__((packed)) -# define LLVM_PACKED_START _Pragma("pack(push, 1)") -# define LLVM_PACKED_END _Pragma("pack(pop)") -#endif - -/// \macro LLVM_PTR_SIZE -/// A constant integer equivalent to the value of sizeof(void*). -/// Generally used in combination with alignas or when doing computation in the -/// preprocessor. -#ifdef __SIZEOF_POINTER__ -# define LLVM_PTR_SIZE __SIZEOF_POINTER__ -#elif defined(_WIN64) -# define LLVM_PTR_SIZE 8 -#elif defined(_WIN32) -# define LLVM_PTR_SIZE 4 -#elif defined(_MSC_VER) -# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC" -#else -# define LLVM_PTR_SIZE sizeof(void *) -#endif - -/// \macro LLVM_MEMORY_SANITIZER_BUILD -/// Whether LLVM itself is built with MemorySanitizer instrumentation. -#if __has_feature(memory_sanitizer) -# define LLVM_MEMORY_SANITIZER_BUILD 1 -# include <sanitizer/msan_interface.h> -# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory)) -#else -# define LLVM_MEMORY_SANITIZER_BUILD 0 -# define __msan_allocated_memory(p, size) -# define __msan_unpoison(p, size) -# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE -#endif - -/// \macro LLVM_ADDRESS_SANITIZER_BUILD -/// Whether LLVM itself is built with AddressSanitizer instrumentation. -#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -# define LLVM_ADDRESS_SANITIZER_BUILD 1 -# include <sanitizer/asan_interface.h> -#else -# define LLVM_ADDRESS_SANITIZER_BUILD 0 -# define __asan_poison_memory_region(p, size) -# define __asan_unpoison_memory_region(p, size) -#endif - -/// \macro LLVM_THREAD_SANITIZER_BUILD -/// Whether LLVM itself is built with ThreadSanitizer instrumentation. -#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) -# define LLVM_THREAD_SANITIZER_BUILD 1 -#else -# define LLVM_THREAD_SANITIZER_BUILD 0 -#endif - -#if LLVM_THREAD_SANITIZER_BUILD -// Thread Sanitizer is a tool that finds races in code. -// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations . -// tsan detects these exact functions by name. -#ifdef __cplusplus -extern "C" { -#endif -void AnnotateHappensAfter(const char *file, int line, const volatile void *cv); -void AnnotateHappensBefore(const char *file, int line, const volatile void *cv); -void AnnotateIgnoreWritesBegin(const char *file, int line); -void AnnotateIgnoreWritesEnd(const char *file, int line); -#ifdef __cplusplus -} -#endif - -// This marker is used to define a happens-before arc. The race detector will -// infer an arc from the begin to the end when they share the same pointer -// argument. -# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv) - -// This marker defines the destination of a happens-before arc. -# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv) - -// Ignore any races on writes between here and the next TsanIgnoreWritesEnd. -# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__) - -// Resume checking for racy writes. -# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__) -#else -# define TsanHappensBefore(cv) -# define TsanHappensAfter(cv) -# define TsanIgnoreWritesBegin() -# define TsanIgnoreWritesEnd() -#endif - -/// \macro LLVM_NO_SANITIZE -/// Disable a particular sanitizer for a function. -#if __has_attribute(no_sanitize) -#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND))) -#else -#define LLVM_NO_SANITIZE(KIND) -#endif - -/// Mark debug helper function definitions like dump() that should not be -/// stripped from debug builds. -/// Note that you should also surround dump() functions with -/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always -/// get stripped in release builds. -// FIXME: Move this to a private config.h as it's not usable in public headers. -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED -#else -#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE -#endif - -/// \macro LLVM_PRETTY_FUNCTION -/// Gets a user-friendly looking function signature for the current scope -/// using the best available method on each platform. The exact format of the -/// resulting string is implementation specific and non-portable, so this should -/// only be used, for example, for logging or diagnostics. -#if defined(_MSC_VER) -#define LLVM_PRETTY_FUNCTION __FUNCSIG__ -#elif defined(__GNUC__) || defined(__clang__) -#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#else -#define LLVM_PRETTY_FUNCTION __func__ -#endif - -/// \macro LLVM_THREAD_LOCAL -/// A thread-local storage specifier which can be used with globals, -/// extern globals, and static globals. -/// -/// This is essentially an extremely restricted analog to C++11's thread_local -/// support. It uses thread_local if available, falling back on gcc __thread -/// if not. __thread doesn't support many of the C++11 thread_local's -/// features. You should only use this for PODs that you can statically -/// initialize to some constant value. In almost all circumstances this is most -/// appropriate for use with a pointer, integer, or small aggregation of -/// pointers and integers. -#if LLVM_ENABLE_THREADS -#if __has_feature(cxx_thread_local) || defined(_MSC_VER) -#define LLVM_THREAD_LOCAL thread_local -#else -// Clang, GCC, and other compatible compilers used __thread prior to C++11 and -// we only need the restricted functionality that provides. -#define LLVM_THREAD_LOCAL __thread -#endif -#else // !LLVM_ENABLE_THREADS -// If threading is disabled entirely, this compiles to nothing and you get -// a normal global variable. -#define LLVM_THREAD_LOCAL -#endif - -/// \macro LLVM_ENABLE_EXCEPTIONS -/// Whether LLVM is built with exception support. -#if __has_feature(cxx_exceptions) -#define LLVM_ENABLE_EXCEPTIONS 1 -#elif defined(__GNUC__) && defined(__EXCEPTIONS) -#define LLVM_ENABLE_EXCEPTIONS 1 -#elif defined(_MSC_VER) && defined(_CPPUNWIND) -#define LLVM_ENABLE_EXCEPTIONS 1 -#endif - -#endif diff --git a/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h b/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h deleted file mode 100644 index 6133d0b9..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/Demangle.h +++ /dev/null @@ -1,133 +0,0 @@ -//===--- Demangle.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEMANGLE_DEMANGLE_H -#define LLVM_DEMANGLE_DEMANGLE_H - -#include <cstddef> -#include <string> - -namespace llvm { -/// This is a llvm local version of __cxa_demangle. Other than the name and -/// being in the llvm namespace it is identical. -/// -/// The mangled_name is demangled into buf and returned. If the buffer is not -/// large enough, realloc is used to expand it. -/// -/// The *status will be set to a value from the following enumeration -enum : int { - demangle_unknown_error = -4, - demangle_invalid_args = -3, - demangle_invalid_mangled_name = -2, - demangle_memory_alloc_failure = -1, - demangle_success = 0, -}; - -char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, - int *status); - -enum MSDemangleFlags { - MSDF_None = 0, - MSDF_DumpBackrefs = 1 << 0, - MSDF_NoAccessSpecifier = 1 << 1, - MSDF_NoCallingConvention = 1 << 2, - MSDF_NoReturnType = 1 << 3, - MSDF_NoMemberType = 1 << 4, - MSDF_NoVariableType = 1 << 5, -}; - -/// Demangles the Microsoft symbol pointed at by mangled_name and returns it. -/// Returns a pointer to the start of a null-terminated demangled string on -/// success, or nullptr on error. -/// If n_read is non-null and demangling was successful, it receives how many -/// bytes of the input string were consumed. -/// buf can point to a *n_buf bytes large buffer where the demangled name is -/// stored. If the buffer is too small, it is grown with realloc(). If buf is -/// nullptr, then this malloc()s memory for the result. -/// *n_buf stores the size of buf on input if buf is non-nullptr, and it -/// receives the size of the demangled string on output if n_buf is not nullptr. -/// status receives one of the demangle_ enum entries above if it's not nullptr. -/// Flags controls various details of the demangled representation. -char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf, - size_t *n_buf, int *status, - MSDemangleFlags Flags = MSDF_None); - -// Demangles a Rust v0 mangled symbol. -char *rustDemangle(const char *MangledName); - -// Demangles a D mangled symbol. -char *dlangDemangle(const char *MangledName); - -/// Attempt to demangle a string using different demangling schemes. -/// The function uses heuristics to determine which demangling scheme to use. -/// \param MangledName - reference to string to demangle. -/// \returns - the demangled string, or a copy of the input string if no -/// demangling occurred. -std::string demangle(const std::string &MangledName); - -bool nonMicrosoftDemangle(const char *MangledName, std::string &Result); - -/// "Partial" demangler. This supports demangling a string into an AST -/// (typically an intermediate stage in itaniumDemangle) and querying certain -/// properties or partially printing the demangled name. -struct ItaniumPartialDemangler { - ItaniumPartialDemangler(); - - ItaniumPartialDemangler(ItaniumPartialDemangler &&Other); - ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other); - - /// Demangle into an AST. Subsequent calls to the rest of the member functions - /// implicitly operate on the AST this produces. - /// \return true on error, false otherwise - bool partialDemangle(const char *MangledName); - - /// Just print the entire mangled name into Buf. Buf and N behave like the - /// second and third parameters to itaniumDemangle. - char *finishDemangle(char *Buf, size_t *N) const; - - /// Get the base name of a function. This doesn't include trailing template - /// arguments, ie for "a::b<int>" this function returns "b". - char *getFunctionBaseName(char *Buf, size_t *N) const; - - /// Get the context name for a function. For "a::b::c", this function returns - /// "a::b". - char *getFunctionDeclContextName(char *Buf, size_t *N) const; - - /// Get the entire name of this function. - char *getFunctionName(char *Buf, size_t *N) const; - - /// Get the parameters for this function. - char *getFunctionParameters(char *Buf, size_t *N) const; - char *getFunctionReturnType(char *Buf, size_t *N) const; - - /// If this function has any any cv or reference qualifiers. These imply that - /// the function is a non-static member function. - bool hasFunctionQualifiers() const; - - /// If this symbol describes a constructor or destructor. - bool isCtorOrDtor() const; - - /// If this symbol describes a function. - bool isFunction() const; - - /// If this symbol describes a variable. - bool isData() const; - - /// If this symbol is a <special-name>. These are generally implicitly - /// generated by the implementation, such as vtables and typeinfo names. - bool isSpecialName() const; - - ~ItaniumPartialDemangler(); - -private: - void *RootNode; - void *Context; -}; -} // namespace llvm - -#endif diff --git a/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h b/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h deleted file mode 100644 index 2ff95dd8..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/DemangleConfig.h +++ /dev/null @@ -1,92 +0,0 @@ -//===--- DemangleConfig.h ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains a variety of feature test macros copied from -// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take -// a dependency on LLVMSupport. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H -#define LLVM_DEMANGLE_DEMANGLECONFIG_H - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -#ifndef __has_cpp_attribute -#define __has_cpp_attribute(x) 0 -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -#ifndef DEMANGLE_GNUC_PREREQ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ - ((maj) << 20) + ((min) << 10) + (patch)) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) -#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) -#else -#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0 -#endif -#endif - -#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0) -#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__)) -#else -#define DEMANGLE_ATTRIBUTE_USED -#endif - -#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0) -#define DEMANGLE_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -#define DEMANGLE_UNREACHABLE __assume(false) -#else -#define DEMANGLE_UNREACHABLE -#endif - -#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0) -#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) -#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline) -#else -#define DEMANGLE_ATTRIBUTE_NOINLINE -#endif - -#if !defined(NDEBUG) -#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED -#else -#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE -#endif - -#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough) -#define DEMANGLE_FALLTHROUGH [[fallthrough]] -#elif __has_cpp_attribute(gnu::fallthrough) -#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]] -#elif !__cplusplus -// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious -// error when __has_cpp_attribute is given a scoped attribute in C mode. -#define DEMANGLE_FALLTHROUGH -#elif __has_cpp_attribute(clang::fallthrough) -#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]] -#else -#define DEMANGLE_FALLTHROUGH -#endif - -#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle { -#define DEMANGLE_NAMESPACE_END } } - -#endif diff --git a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h deleted file mode 100644 index ea55f4a6..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ /dev/null @@ -1,5500 +0,0 @@ -//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===// -// Do not edit! See README.txt. -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Generic itanium demangler library. -// There are two copies of this file in the source tree. The one under -// libcxxabi is the original and the one under llvm is the copy. Use -// cp-to-llvm.sh to update the copy. See README.txt for more details. -// -//===----------------------------------------------------------------------===// - -#ifndef DEMANGLE_ITANIUMDEMANGLE_H -#define DEMANGLE_ITANIUMDEMANGLE_H - -#include "DemangleConfig.h" -#include "StringView.h" -#include "Utility.h" -#include <algorithm> -#include <cassert> -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <limits> -#include <new> -#include <utility> - -DEMANGLE_NAMESPACE_BEGIN - -template <class T, size_t N> class PODSmallVector { - static_assert(std::is_pod<T>::value, - "T is required to be a plain old data type"); - - T *First = nullptr; - T *Last = nullptr; - T *Cap = nullptr; - T Inline[N] = {0}; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector &) = delete; - PODSmallVector &operator=(const PODSmallVector &) = delete; - - PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector &operator=(PODSmallVector &&Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - // NOLINTNEXTLINE(readability-identifier-naming) - void push_back(const T &Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - // NOLINTNEXTLINE(readability-identifier-naming) - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T *begin() { return First; } - T *end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - T &back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T &operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - -// Base class of all AST nodes. The AST is built by the parser, then is -// traversed by the printLeft/Right functions to produce a demangled string. -class Node { -public: - enum Kind : unsigned char { -#define NODE(NodeKind) K##NodeKind, -#include "ItaniumNodes.def" - }; - - /// Three-way bool to track a cached value. Unknown is possible if this node - /// has an unexpanded parameter pack below it that may affect this cache. - enum class Cache : unsigned char { Yes, No, Unknown, }; - - /// Operator precedence for expression nodes. Used to determine required - /// parens in expression emission. - enum class Prec { - Primary, - Postfix, - Unary, - Cast, - PtrMem, - Multiplicative, - Additive, - Shift, - Spaceship, - Relational, - Equality, - And, - Xor, - Ior, - AndIf, - OrIf, - Conditional, - Assign, - Comma, - Default, - }; - -private: - Kind K; - - Prec Precedence : 6; - - // FIXME: Make these protected. -public: - /// Tracks if this node has a component on its right side, in which case we - /// need to call printRight. - Cache RHSComponentCache : 2; - - /// Track if this node is a (possibly qualified) array type. This can affect - /// how we format the output string. - Cache ArrayCache : 2; - - /// Track if this node is a (possibly qualified) function type. This can - /// affect how we format the output string. - Cache FunctionCache : 2; - -public: - Node(Kind K_, Prec Precedence_ = Prec::Primary, - Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No, - Cache FunctionCache_ = Cache::No) - : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_), - ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {} - Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No, - Cache FunctionCache_ = Cache::No) - : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_, - FunctionCache_) {} - - /// Visit the most-derived object corresponding to this object. - template<typename Fn> void visit(Fn F) const; - - // The following function is provided by all derived classes: - // - // Call F with arguments that, when passed to the constructor of this node, - // would construct an equivalent node. - //template<typename Fn> void match(Fn F) const; - - bool hasRHSComponent(OutputBuffer &OB) const { - if (RHSComponentCache != Cache::Unknown) - return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(OB); - } - - bool hasArray(OutputBuffer &OB) const { - if (ArrayCache != Cache::Unknown) - return ArrayCache == Cache::Yes; - return hasArraySlow(OB); - } - - bool hasFunction(OutputBuffer &OB) const { - if (FunctionCache != Cache::Unknown) - return FunctionCache == Cache::Yes; - return hasFunctionSlow(OB); - } - - Kind getKind() const { return K; } - - Prec getPrecedence() const { return Precedence; } - - virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } - virtual bool hasArraySlow(OutputBuffer &) const { return false; } - virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } - - // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to - // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } - - // Print this node as an expression operand, surrounding it in parentheses if - // its precedence is [Strictly] weaker than P. - void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default, - bool StrictlyWorse = false) const { - bool Paren = - unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse); - if (Paren) - OB.printOpen(); - print(OB); - if (Paren) - OB.printClose(); - } - - void print(OutputBuffer &OB) const { - printLeft(OB); - if (RHSComponentCache != Cache::No) - printRight(OB); - } - - // Print the "left" side of this Node into OutputBuffer. - virtual void printLeft(OutputBuffer &) const = 0; - - // Print the "right". This distinction is necessary to represent C++ types - // that appear on the RHS of their subtype, such as arrays or functions. - // Since most types don't have such a component, provide a default - // implementation. - virtual void printRight(OutputBuffer &) const {} - - virtual StringView getBaseName() const { return StringView(); } - - // Silence compiler warnings, this dtor will never be called. - virtual ~Node() = default; - -#ifndef NDEBUG - DEMANGLE_DUMP_METHOD void dump() const; -#endif -}; - -class NodeArray { - Node **Elements; - size_t NumElements; - -public: - NodeArray() : Elements(nullptr), NumElements(0) {} - NodeArray(Node **Elements_, size_t NumElements_) - : Elements(Elements_), NumElements(NumElements_) {} - - bool empty() const { return NumElements == 0; } - size_t size() const { return NumElements; } - - Node **begin() const { return Elements; } - Node **end() const { return Elements + NumElements; } - - Node *operator[](size_t Idx) const { return Elements[Idx]; } - - void printWithComma(OutputBuffer &OB) const { - bool FirstElement = true; - for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = OB.getCurrentPosition(); - if (!FirstElement) - OB += ", "; - size_t AfterComma = OB.getCurrentPosition(); - Elements[Idx]->printAsOperand(OB, Node::Prec::Comma); - - // Elements[Idx] is an empty parameter pack expansion, we should erase the - // comma we just printed. - if (AfterComma == OB.getCurrentPosition()) { - OB.setCurrentPosition(BeforeComma); - continue; - } - - FirstElement = false; - } - } -}; - -struct NodeArrayNode : Node { - NodeArray Array; - NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} - - template<typename Fn> void match(Fn F) const { F(Array); } - - void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } -}; - -class DotSuffix final : public Node { - const Node *Prefix; - const StringView Suffix; - -public: - DotSuffix(const Node *Prefix_, StringView Suffix_) - : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} - - template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); } - - void printLeft(OutputBuffer &OB) const override { - Prefix->print(OB); - OB += " ("; - OB += Suffix; - OB += ")"; - } -}; - -class VendorExtQualType final : public Node { - const Node *Ty; - StringView Ext; - const Node *TA; - -public: - VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - - const Node *getTy() const { return Ty; } - StringView getExt() const { return Ext; } - const Node *getTA() const { return TA; } - - template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); } - - void printLeft(OutputBuffer &OB) const override { - Ty->print(OB); - OB += " "; - OB += Ext; - if (TA != nullptr) - TA->print(OB); - } -}; - -enum FunctionRefQual : unsigned char { - FrefQualNone, - FrefQualLValue, - FrefQualRValue, -}; - -enum Qualifiers { - QualNone = 0, - QualConst = 0x1, - QualVolatile = 0x2, - QualRestrict = 0x4, -}; - -inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { - return Q1 = static_cast<Qualifiers>(Q1 | Q2); -} - -class QualType final : public Node { -protected: - const Qualifiers Quals; - const Node *Child; - - void printQuals(OutputBuffer &OB) const { - if (Quals & QualConst) - OB += " const"; - if (Quals & QualVolatile) - OB += " volatile"; - if (Quals & QualRestrict) - OB += " restrict"; - } - -public: - QualType(const Node *Child_, Qualifiers Quals_) - : Node(KQualType, Child_->RHSComponentCache, - Child_->ArrayCache, Child_->FunctionCache), - Quals(Quals_), Child(Child_) {} - - Qualifiers getQuals() const { return Quals; } - const Node *getChild() const { return Child; } - - template<typename Fn> void match(Fn F) const { F(Child, Quals); } - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - return Child->hasRHSComponent(OB); - } - bool hasArraySlow(OutputBuffer &OB) const override { - return Child->hasArray(OB); - } - bool hasFunctionSlow(OutputBuffer &OB) const override { - return Child->hasFunction(OB); - } - - void printLeft(OutputBuffer &OB) const override { - Child->printLeft(OB); - printQuals(OB); - } - - void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } -}; - -class ConversionOperatorType final : public Node { - const Node *Ty; - -public: - ConversionOperatorType(const Node *Ty_) - : Node(KConversionOperatorType), Ty(Ty_) {} - - template<typename Fn> void match(Fn F) const { F(Ty); } - - void printLeft(OutputBuffer &OB) const override { - OB += "operator "; - Ty->print(OB); - } -}; - -class PostfixQualifiedType final : public Node { - const Node *Ty; - const StringView Postfix; - -public: - PostfixQualifiedType(const Node *Ty_, StringView Postfix_) - : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Postfix); } - - void printLeft(OutputBuffer &OB) const override { - Ty->printLeft(OB); - OB += Postfix; - } -}; - -class NameType final : public Node { - const StringView Name; - -public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Name); } - - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } - - void printLeft(OutputBuffer &OB) const override { OB += Name; } -}; - -class BitIntType final : public Node { - const Node *Size; - bool Signed; - -public: - BitIntType(const Node *Size_, bool Signed_) - : Node(KBitIntType), Size(Size_), Signed(Signed_) {} - - template <typename Fn> void match(Fn F) const { F(Size, Signed); } - - void printLeft(OutputBuffer &OB) const override { - if (!Signed) - OB += "unsigned "; - OB += "_BitInt"; - OB.printOpen(); - Size->printAsOperand(OB); - OB.printClose(); - } -}; - -class ElaboratedTypeSpefType : public Node { - StringView Kind; - Node *Child; -public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) - : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Kind, Child); } - - void printLeft(OutputBuffer &OB) const override { - OB += Kind; - OB += ' '; - Child->print(OB); - } -}; - -struct AbiTagAttr : Node { - Node *Base; - StringView Tag; - - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), - Base(Base_), Tag(Tag_) {} - - template<typename Fn> void match(Fn F) const { F(Base, Tag); } - - void printLeft(OutputBuffer &OB) const override { - Base->printLeft(OB); - OB += "[abi:"; - OB += Tag; - OB += "]"; - } -}; - -class EnableIfAttr : public Node { - NodeArray Conditions; -public: - EnableIfAttr(NodeArray Conditions_) - : Node(KEnableIfAttr), Conditions(Conditions_) {} - - template<typename Fn> void match(Fn F) const { F(Conditions); } - - void printLeft(OutputBuffer &OB) const override { - OB += " [enable_if:"; - Conditions.printWithComma(OB); - OB += ']'; - } -}; - -class ObjCProtoName : public Node { - const Node *Ty; - StringView Protocol; - - friend class PointerType; - -public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) - : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } - - bool isObjCObject() const { - return Ty->getKind() == KNameType && - static_cast<const NameType *>(Ty)->getName() == "objc_object"; - } - - void printLeft(OutputBuffer &OB) const override { - Ty->print(OB); - OB += "<"; - OB += Protocol; - OB += ">"; - } -}; - -class PointerType final : public Node { - const Node *Pointee; - -public: - PointerType(const Node *Pointee_) - : Node(KPointerType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} - - const Node *getPointee() const { return Pointee; } - - template<typename Fn> void match(Fn F) const { F(Pointee); } - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - return Pointee->hasRHSComponent(OB); - } - - void printLeft(OutputBuffer &OB) const override { - // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - Pointee->printLeft(OB); - if (Pointee->hasArray(OB)) - OB += " "; - if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) - OB += "("; - OB += "*"; - } else { - const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); - OB += "id<"; - OB += objcProto->Protocol; - OB += ">"; - } - } - - void printRight(OutputBuffer &OB) const override { - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) - OB += ")"; - Pointee->printRight(OB); - } - } -}; - -enum class ReferenceKind { - LValue, - RValue, -}; - -// Represents either a LValue or an RValue reference type. -class ReferenceType : public Node { - const Node *Pointee; - ReferenceKind RK; - - mutable bool Printing = false; - - // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The - // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any - // other combination collapses to a lvalue ref. - // - // A combination of a TemplateForwardReference and a back-ref Substitution - // from an ill-formed string may have created a cycle; use cycle detection to - // avoid looping forever. - std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const { - auto SoFar = std::make_pair(RK, Pointee); - // Track the chain of nodes for the Floyd's 'tortoise and hare' - // cycle-detection algorithm, since getSyntaxNode(S) is impure - PODSmallVector<const Node *, 8> Prev; - for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(OB); - if (SN->getKind() != KReferenceType) - break; - auto *RT = static_cast<const ReferenceType *>(SN); - SoFar.second = RT->Pointee; - SoFar.first = std::min(SoFar.first, RT->RK); - - // The middle of Prev is the 'slow' pointer moving at half speed - Prev.push_back(SoFar.second); - if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { - // Cycle detected - SoFar.second = nullptr; - break; - } - } - return SoFar; - } - -public: - ReferenceType(const Node *Pointee_, ReferenceKind RK_) - : Node(KReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_), RK(RK_) {} - - template<typename Fn> void match(Fn F) const { F(Pointee, RK); } - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - return Pointee->hasRHSComponent(OB); - } - - void printLeft(OutputBuffer &OB) const override { - if (Printing) - return; - ScopedOverride<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB); - if (!Collapsed.second) - return; - Collapsed.second->printLeft(OB); - if (Collapsed.second->hasArray(OB)) - OB += " "; - if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) - OB += "("; - - OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); - } - void printRight(OutputBuffer &OB) const override { - if (Printing) - return; - ScopedOverride<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB); - if (!Collapsed.second) - return; - if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) - OB += ")"; - Collapsed.second->printRight(OB); - } -}; - -class PointerToMemberType final : public Node { - const Node *ClassType; - const Node *MemberType; - -public: - PointerToMemberType(const Node *ClassType_, const Node *MemberType_) - : Node(KPointerToMemberType, MemberType_->RHSComponentCache), - ClassType(ClassType_), MemberType(MemberType_) {} - - template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); } - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - return MemberType->hasRHSComponent(OB); - } - - void printLeft(OutputBuffer &OB) const override { - MemberType->printLeft(OB); - if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) - OB += "("; - else - OB += " "; - ClassType->print(OB); - OB += "::*"; - } - - void printRight(OutputBuffer &OB) const override { - if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) - OB += ")"; - MemberType->printRight(OB); - } -}; - -class ArrayType final : public Node { - const Node *Base; - Node *Dimension; - -public: - ArrayType(const Node *Base_, Node *Dimension_) - : Node(KArrayType, - /*RHSComponentCache=*/Cache::Yes, - /*ArrayCache=*/Cache::Yes), - Base(Base_), Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(Base, Dimension); } - - bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } - bool hasArraySlow(OutputBuffer &) const override { return true; } - - void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - - void printRight(OutputBuffer &OB) const override { - if (OB.back() != ']') - OB += " "; - OB += "["; - if (Dimension) - Dimension->print(OB); - OB += "]"; - Base->printRight(OB); - } -}; - -class FunctionType final : public Node { - const Node *Ret; - NodeArray Params; - Qualifiers CVQuals; - FunctionRefQual RefQual; - const Node *ExceptionSpec; - -public: - FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, - FunctionRefQual RefQual_, const Node *ExceptionSpec_) - : Node(KFunctionType, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), - ExceptionSpec(ExceptionSpec_) {} - - template<typename Fn> void match(Fn F) const { - F(Ret, Params, CVQuals, RefQual, ExceptionSpec); - } - - bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } - bool hasFunctionSlow(OutputBuffer &) const override { return true; } - - // Handle C++'s ... quirky decl grammar by using the left & right - // distinction. Consider: - // int (*f(float))(char) {} - // f is a function that takes a float and returns a pointer to a function - // that takes a char and returns an int. If we're trying to print f, start - // by printing out the return types's left, then print our parameters, then - // finally print right of the return type. - void printLeft(OutputBuffer &OB) const override { - Ret->printLeft(OB); - OB += " "; - } - - void printRight(OutputBuffer &OB) const override { - OB.printOpen(); - Params.printWithComma(OB); - OB.printClose(); - Ret->printRight(OB); - - if (CVQuals & QualConst) - OB += " const"; - if (CVQuals & QualVolatile) - OB += " volatile"; - if (CVQuals & QualRestrict) - OB += " restrict"; - - if (RefQual == FrefQualLValue) - OB += " &"; - else if (RefQual == FrefQualRValue) - OB += " &&"; - - if (ExceptionSpec != nullptr) { - OB += ' '; - ExceptionSpec->print(OB); - } - } -}; - -class NoexceptSpec : public Node { - const Node *E; -public: - NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} - - template<typename Fn> void match(Fn F) const { F(E); } - - void printLeft(OutputBuffer &OB) const override { - OB += "noexcept"; - OB.printOpen(); - E->printAsOperand(OB); - OB.printClose(); - } -}; - -class DynamicExceptionSpec : public Node { - NodeArray Types; -public: - DynamicExceptionSpec(NodeArray Types_) - : Node(KDynamicExceptionSpec), Types(Types_) {} - - template<typename Fn> void match(Fn F) const { F(Types); } - - void printLeft(OutputBuffer &OB) const override { - OB += "throw"; - OB.printOpen(); - Types.printWithComma(OB); - OB.printClose(); - } -}; - -class FunctionEncoding final : public Node { - const Node *Ret; - const Node *Name; - NodeArray Params; - const Node *Attrs; - Qualifiers CVQuals; - FunctionRefQual RefQual; - -public: - FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, - const Node *Attrs_, Qualifiers CVQuals_, - FunctionRefQual RefQual_) - : Node(KFunctionEncoding, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), - CVQuals(CVQuals_), RefQual(RefQual_) {} - - template<typename Fn> void match(Fn F) const { - F(Ret, Name, Params, Attrs, CVQuals, RefQual); - } - - Qualifiers getCVQuals() const { return CVQuals; } - FunctionRefQual getRefQual() const { return RefQual; } - NodeArray getParams() const { return Params; } - const Node *getReturnType() const { return Ret; } - - bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } - bool hasFunctionSlow(OutputBuffer &) const override { return true; } - - const Node *getName() const { return Name; } - - void printLeft(OutputBuffer &OB) const override { - if (Ret) { - Ret->printLeft(OB); - if (!Ret->hasRHSComponent(OB)) - OB += " "; - } - Name->print(OB); - } - - void printRight(OutputBuffer &OB) const override { - OB.printOpen(); - Params.printWithComma(OB); - OB.printClose(); - if (Ret) - Ret->printRight(OB); - - if (CVQuals & QualConst) - OB += " const"; - if (CVQuals & QualVolatile) - OB += " volatile"; - if (CVQuals & QualRestrict) - OB += " restrict"; - - if (RefQual == FrefQualLValue) - OB += " &"; - else if (RefQual == FrefQualRValue) - OB += " &&"; - - if (Attrs != nullptr) - Attrs->print(OB); - } -}; - -class LiteralOperator : public Node { - const Node *OpName; - -public: - LiteralOperator(const Node *OpName_) - : Node(KLiteralOperator), OpName(OpName_) {} - - template<typename Fn> void match(Fn F) const { F(OpName); } - - void printLeft(OutputBuffer &OB) const override { - OB += "operator\"\" "; - OpName->print(OB); - } -}; - -class SpecialName final : public Node { - const StringView Special; - const Node *Child; - -public: - SpecialName(StringView Special_, const Node *Child_) - : Node(KSpecialName), Special(Special_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Special, Child); } - - void printLeft(OutputBuffer &OB) const override { - OB += Special; - Child->print(OB); - } -}; - -class CtorVtableSpecialName final : public Node { - const Node *FirstType; - const Node *SecondType; - -public: - CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) - : Node(KCtorVtableSpecialName), - FirstType(FirstType_), SecondType(SecondType_) {} - - template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } - - void printLeft(OutputBuffer &OB) const override { - OB += "construction vtable for "; - FirstType->print(OB); - OB += "-in-"; - SecondType->print(OB); - } -}; - -struct NestedName : Node { - Node *Qual; - Node *Name; - - NestedName(Node *Qual_, Node *Name_) - : Node(KNestedName), Qual(Qual_), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Qual, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputBuffer &OB) const override { - Qual->print(OB); - OB += "::"; - Name->print(OB); - } -}; - -struct ModuleName : Node { - ModuleName *Parent; - Node *Name; - bool IsPartition; - - ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) - : Node(KModuleName), Parent(Parent_), Name(Name_), - IsPartition(IsPartition_) {} - - template <typename Fn> void match(Fn F) const { - F(Parent, Name, IsPartition); - } - - void printLeft(OutputBuffer &OB) const override { - if (Parent) - Parent->print(OB); - if (Parent || IsPartition) - OB += IsPartition ? ':' : '.'; - Name->print(OB); - } -}; - -struct ModuleEntity : Node { - ModuleName *Module; - Node *Name; - - ModuleEntity(ModuleName *Module_, Node *Name_) - : Node(KModuleEntity), Module(Module_), Name(Name_) {} - - template <typename Fn> void match(Fn F) const { F(Module, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputBuffer &OB) const override { - Name->print(OB); - OB += '@'; - Module->print(OB); - } -}; - -struct LocalName : Node { - Node *Encoding; - Node *Entity; - - LocalName(Node *Encoding_, Node *Entity_) - : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} - - template<typename Fn> void match(Fn F) const { F(Encoding, Entity); } - - void printLeft(OutputBuffer &OB) const override { - Encoding->print(OB); - OB += "::"; - Entity->print(OB); - } -}; - -class QualifiedName final : public Node { - // qualifier::name - const Node *Qualifier; - const Node *Name; - -public: - QualifiedName(const Node *Qualifier_, const Node *Name_) - : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Qualifier, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputBuffer &OB) const override { - Qualifier->print(OB); - OB += "::"; - Name->print(OB); - } -}; - -class VectorType final : public Node { - const Node *BaseType; - const Node *Dimension; - -public: - VectorType(const Node *BaseType_, const Node *Dimension_) - : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} - - const Node *getBaseType() const { return BaseType; } - const Node *getDimension() const { return Dimension; } - - template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } - - void printLeft(OutputBuffer &OB) const override { - BaseType->print(OB); - OB += " vector["; - if (Dimension) - Dimension->print(OB); - OB += "]"; - } -}; - -class PixelVectorType final : public Node { - const Node *Dimension; - -public: - PixelVectorType(const Node *Dimension_) - : Node(KPixelVectorType), Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(Dimension); } - - void printLeft(OutputBuffer &OB) const override { - // FIXME: This should demangle as "vector pixel". - OB += "pixel vector["; - Dimension->print(OB); - OB += "]"; - } -}; - -class BinaryFPType final : public Node { - const Node *Dimension; - -public: - BinaryFPType(const Node *Dimension_) - : Node(KBinaryFPType), Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(Dimension); } - - void printLeft(OutputBuffer &OB) const override { - OB += "_Float"; - Dimension->print(OB); - } -}; - -enum class TemplateParamKind { Type, NonType, Template }; - -/// An invented name for a template parameter for which we don't have a -/// corresponding template argument. -/// -/// This node is created when parsing the <lambda-sig> for a lambda with -/// explicit template arguments, which might be referenced in the parameter -/// types appearing later in the <lambda-sig>. -class SyntheticTemplateParamName final : public Node { - TemplateParamKind Kind; - unsigned Index; - -public: - SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_) - : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {} - - template<typename Fn> void match(Fn F) const { F(Kind, Index); } - - void printLeft(OutputBuffer &OB) const override { - switch (Kind) { - case TemplateParamKind::Type: - OB += "$T"; - break; - case TemplateParamKind::NonType: - OB += "$N"; - break; - case TemplateParamKind::Template: - OB += "$TT"; - break; - } - if (Index > 0) - OB << Index - 1; - } -}; - -/// A template type parameter declaration, 'typename T'. -class TypeTemplateParamDecl final : public Node { - Node *Name; - -public: - TypeTemplateParamDecl(Node *Name_) - : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Name); } - - void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - - void printRight(OutputBuffer &OB) const override { Name->print(OB); } -}; - -/// A non-type template parameter declaration, 'int N'. -class NonTypeTemplateParamDecl final : public Node { - Node *Name; - Node *Type; - -public: - NonTypeTemplateParamDecl(Node *Name_, Node *Type_) - : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {} - - template<typename Fn> void match(Fn F) const { F(Name, Type); } - - void printLeft(OutputBuffer &OB) const override { - Type->printLeft(OB); - if (!Type->hasRHSComponent(OB)) - OB += " "; - } - - void printRight(OutputBuffer &OB) const override { - Name->print(OB); - Type->printRight(OB); - } -}; - -/// A template template parameter declaration, -/// 'template<typename T> typename N'. -class TemplateTemplateParamDecl final : public Node { - Node *Name; - NodeArray Params; - -public: - TemplateTemplateParamDecl(Node *Name_, NodeArray Params_) - : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_), - Params(Params_) {} - - template<typename Fn> void match(Fn F) const { F(Name, Params); } - - void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); - OB += "template<"; - Params.printWithComma(OB); - OB += "> typename "; - } - - void printRight(OutputBuffer &OB) const override { Name->print(OB); } -}; - -/// A template parameter pack declaration, 'typename ...T'. -class TemplateParamPackDecl final : public Node { - Node *Param; - -public: - TemplateParamPackDecl(Node *Param_) - : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {} - - template<typename Fn> void match(Fn F) const { F(Param); } - - void printLeft(OutputBuffer &OB) const override { - Param->printLeft(OB); - OB += "..."; - } - - void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } -}; - -/// An unexpanded parameter pack (either in the expression or type context). If -/// this AST is correct, this node will have a ParameterPackExpansion node above -/// it. -/// -/// This node is created when some <template-args> are found that apply to an -/// <encoding>, and is stored in the TemplateParams table. In order for this to -/// appear in the final AST, it has to referenced via a <template-param> (ie, -/// T_). -class ParameterPack final : public Node { - NodeArray Data; - - // Setup OutputBuffer for a pack expansion, unless we're already expanding - // one. - void initializePackExpansion(OutputBuffer &OB) const { - if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) { - OB.CurrentPackMax = static_cast<unsigned>(Data.size()); - OB.CurrentPackIndex = 0; - } - } - -public: - ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { - ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->ArrayCache == Cache::No; - })) - ArrayCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->FunctionCache == Cache::No; - })) - FunctionCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->RHSComponentCache == Cache::No; - })) - RHSComponentCache = Cache::No; - } - - template<typename Fn> void match(Fn F) const { F(Data); } - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); - } - bool hasArraySlow(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(OB); - } - bool hasFunctionSlow(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(OB); - } - const Node *getSyntaxNode(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; - } - - void printLeft(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printLeft(OB); - } - void printRight(OutputBuffer &OB) const override { - initializePackExpansion(OB); - size_t Idx = OB.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printRight(OB); - } -}; - -/// A variadic template argument. This node represents an occurrence of -/// J<something>E in some <template-args>. It isn't itself unexpanded, unless -/// one of it's Elements is. The parser inserts a ParameterPack into the -/// TemplateParams table if the <template-args> this pack belongs to apply to an -/// <encoding>. -class TemplateArgumentPack final : public Node { - NodeArray Elements; -public: - TemplateArgumentPack(NodeArray Elements_) - : Node(KTemplateArgumentPack), Elements(Elements_) {} - - template<typename Fn> void match(Fn F) const { F(Elements); } - - NodeArray getElements() const { return Elements; } - - void printLeft(OutputBuffer &OB) const override { - Elements.printWithComma(OB); - } -}; - -/// A pack expansion. Below this node, there are some unexpanded ParameterPacks -/// which each have Child->ParameterPackSize elements. -class ParameterPackExpansion final : public Node { - const Node *Child; - -public: - ParameterPackExpansion(const Node *Child_) - : Node(KParameterPackExpansion), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - const Node *getChild() const { return Child; } - - void printLeft(OutputBuffer &OB) const override { - constexpr unsigned Max = std::numeric_limits<unsigned>::max(); - ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max); - ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max); - size_t StreamPos = OB.getCurrentPosition(); - - // Print the first element in the pack. If Child contains a ParameterPack, - // it will set up S.CurrentPackMax and print the first element. - Child->print(OB); - - // No ParameterPack was found in Child. This can occur if we've found a pack - // expansion on a <function-param>. - if (OB.CurrentPackMax == Max) { - OB += "..."; - return; - } - - // We found a ParameterPack, but it has no elements. Erase whatever we may - // of printed. - if (OB.CurrentPackMax == 0) { - OB.setCurrentPosition(StreamPos); - return; - } - - // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { - OB += ", "; - OB.CurrentPackIndex = I; - Child->print(OB); - } - } -}; - -class TemplateArgs final : public Node { - NodeArray Params; - -public: - TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} - - template<typename Fn> void match(Fn F) const { F(Params); } - - NodeArray getParams() { return Params; } - - void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); - OB += "<"; - Params.printWithComma(OB); - OB += ">"; - } -}; - -/// A forward-reference to a template argument that was not known at the point -/// where the template parameter name was parsed in a mangling. -/// -/// This is created when demangling the name of a specialization of a -/// conversion function template: -/// -/// \code -/// struct A { -/// template<typename T> operator T*(); -/// }; -/// \endcode -/// -/// When demangling a specialization of the conversion function template, we -/// encounter the name of the template (including the \c T) before we reach -/// the template argument list, so we cannot substitute the parameter name -/// for the corresponding argument while parsing. Instead, we create a -/// \c ForwardTemplateReference node that is resolved after we parse the -/// template arguments. -struct ForwardTemplateReference : Node { - size_t Index; - Node *Ref = nullptr; - - // If we're currently printing this node. It is possible (though invalid) for - // a forward template reference to refer to itself via a substitution. This - // creates a cyclic AST, which will stack overflow printing. To fix this, bail - // out if more than one print* function is active. - mutable bool Printing = false; - - ForwardTemplateReference(size_t Index_) - : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, - Cache::Unknown), - Index(Index_) {} - - // We don't provide a matcher for these, because the value of the node is - // not determined by its construction parameters, and it generally needs - // special handling. - template<typename Fn> void match(Fn F) const = delete; - - bool hasRHSComponentSlow(OutputBuffer &OB) const override { - if (Printing) - return false; - ScopedOverride<bool> SavePrinting(Printing, true); - return Ref->hasRHSComponent(OB); - } - bool hasArraySlow(OutputBuffer &OB) const override { - if (Printing) - return false; - ScopedOverride<bool> SavePrinting(Printing, true); - return Ref->hasArray(OB); - } - bool hasFunctionSlow(OutputBuffer &OB) const override { - if (Printing) - return false; - ScopedOverride<bool> SavePrinting(Printing, true); - return Ref->hasFunction(OB); - } - const Node *getSyntaxNode(OutputBuffer &OB) const override { - if (Printing) - return this; - ScopedOverride<bool> SavePrinting(Printing, true); - return Ref->getSyntaxNode(OB); - } - - void printLeft(OutputBuffer &OB) const override { - if (Printing) - return; - ScopedOverride<bool> SavePrinting(Printing, true); - Ref->printLeft(OB); - } - void printRight(OutputBuffer &OB) const override { - if (Printing) - return; - ScopedOverride<bool> SavePrinting(Printing, true); - Ref->printRight(OB); - } -}; - -struct NameWithTemplateArgs : Node { - // name<template_args> - Node *Name; - Node *TemplateArgs; - - NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) - : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} - - template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputBuffer &OB) const override { - Name->print(OB); - TemplateArgs->print(OB); - } -}; - -class GlobalQualifiedName final : public Node { - Node *Child; - -public: - GlobalQualifiedName(Node* Child_) - : Node(KGlobalQualifiedName), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputBuffer &OB) const override { - OB += "::"; - Child->print(OB); - } -}; - -enum class SpecialSubKind { - allocator, - basic_string, - string, - istream, - ostream, - iostream, -}; - -class SpecialSubstitution; -class ExpandedSpecialSubstitution : public Node { -protected: - SpecialSubKind SSK; - - ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) - : Node(K_), SSK(SSK_) {} -public: - ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} - inline ExpandedSpecialSubstitution(SpecialSubstitution const *); - - template<typename Fn> void match(Fn F) const { F(SSK); } - -protected: - bool isInstantiation() const { - return unsigned(SSK) >= unsigned(SpecialSubKind::string); - } - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("basic_string"); - case SpecialSubKind::istream: - return StringView("basic_istream"); - case SpecialSubKind::ostream: - return StringView("basic_ostream"); - case SpecialSubKind::iostream: - return StringView("basic_iostream"); - } - DEMANGLE_UNREACHABLE; - } - -private: - void printLeft(OutputBuffer &OB) const override { - OB << "std::" << getBaseName(); - if (isInstantiation()) { - OB << "<char, std::char_traits<char>"; - if (SSK == SpecialSubKind::string) - OB << ", std::allocator<char>"; - OB << ">"; - } - } -}; - -class SpecialSubstitution final : public ExpandedSpecialSubstitution { -public: - SpecialSubstitution(SpecialSubKind SSK_) - : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} - - template<typename Fn> void match(Fn F) const { F(SSK); } - - StringView getBaseName() const override { - auto SV = ExpandedSpecialSubstitution::getBaseName (); - if (isInstantiation()) { - // The instantiations are typedefs that drop the "basic_" prefix. - assert(SV.startsWith("basic_")); - SV = SV.dropFront(sizeof("basic_") - 1); - } - return SV; - } - - void printLeft(OutputBuffer &OB) const override { - OB << "std::" << getBaseName(); - } -}; - -inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( - SpecialSubstitution const *SS) - : ExpandedSpecialSubstitution(SS->SSK) {} - -class CtorDtorName final : public Node { - const Node *Basename; - const bool IsDtor; - const int Variant; - -public: - CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) - : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), - Variant(Variant_) {} - - template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } - - void printLeft(OutputBuffer &OB) const override { - if (IsDtor) - OB += "~"; - OB += Basename->getBaseName(); - } -}; - -class DtorName : public Node { - const Node *Base; - -public: - DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} - - template<typename Fn> void match(Fn F) const { F(Base); } - - void printLeft(OutputBuffer &OB) const override { - OB += "~"; - Base->printLeft(OB); - } -}; - -class UnnamedTypeName : public Node { - const StringView Count; - -public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} - - template<typename Fn> void match(Fn F) const { F(Count); } - - void printLeft(OutputBuffer &OB) const override { - OB += "'unnamed"; - OB += Count; - OB += "\'"; - } -}; - -class ClosureTypeName : public Node { - NodeArray TemplateParams; - NodeArray Params; - StringView Count; - -public: - ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, - StringView Count_) - : Node(KClosureTypeName), TemplateParams(TemplateParams_), - Params(Params_), Count(Count_) {} - - template<typename Fn> void match(Fn F) const { - F(TemplateParams, Params, Count); - } - - void printDeclarator(OutputBuffer &OB) const { - if (!TemplateParams.empty()) { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); - OB += "<"; - TemplateParams.printWithComma(OB); - OB += ">"; - } - OB.printOpen(); - Params.printWithComma(OB); - OB.printClose(); - } - - void printLeft(OutputBuffer &OB) const override { - OB += "\'lambda"; - OB += Count; - OB += "\'"; - printDeclarator(OB); - } -}; - -class StructuredBindingName : public Node { - NodeArray Bindings; -public: - StructuredBindingName(NodeArray Bindings_) - : Node(KStructuredBindingName), Bindings(Bindings_) {} - - template<typename Fn> void match(Fn F) const { F(Bindings); } - - void printLeft(OutputBuffer &OB) const override { - OB.printOpen('['); - Bindings.printWithComma(OB); - OB.printClose(']'); - } -}; - -// -- Expression Nodes -- - -class BinaryExpr : public Node { - const Node *LHS; - const StringView InfixOperator; - const Node *RHS; - -public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_, - Prec Prec_) - : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), - RHS(RHS_) {} - - template <typename Fn> void match(Fn F) const { - F(LHS, InfixOperator, RHS, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - bool ParenAll = OB.isGtInsideTemplateArgs() && - (InfixOperator == ">" || InfixOperator == ">>"); - if (ParenAll) - OB.printOpen(); - // Assignment is right associative, with special LHS precedence. - bool IsAssign = getPrecedence() == Prec::Assign; - LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign); - // No space before comma operator - if (!(InfixOperator == ",")) - OB += " "; - OB += InfixOperator; - OB += " "; - RHS->printAsOperand(OB, getPrecedence(), IsAssign); - if (ParenAll) - OB.printClose(); - } -}; - -class ArraySubscriptExpr : public Node { - const Node *Op1; - const Node *Op2; - -public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) - : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} - - template <typename Fn> void match(Fn F) const { - F(Op1, Op2, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - Op1->printAsOperand(OB, getPrecedence()); - OB.printOpen('['); - Op2->printAsOperand(OB); - OB.printClose(']'); - } -}; - -class PostfixExpr : public Node { - const Node *Child; - const StringView Operator; - -public: - PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_) - : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} - - template <typename Fn> void match(Fn F) const { - F(Child, Operator, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - Child->printAsOperand(OB, getPrecedence(), true); - OB += Operator; - } -}; - -class ConditionalExpr : public Node { - const Node *Cond; - const Node *Then; - const Node *Else; - -public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, - Prec Prec_) - : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} - - template <typename Fn> void match(Fn F) const { - F(Cond, Then, Else, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - Cond->printAsOperand(OB, getPrecedence()); - OB += " ? "; - Then->printAsOperand(OB); - OB += " : "; - Else->printAsOperand(OB, Prec::Assign, true); - } -}; - -class MemberExpr : public Node { - const Node *LHS; - const StringView Kind; - const Node *RHS; - -public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_) - : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - - template <typename Fn> void match(Fn F) const { - F(LHS, Kind, RHS, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - LHS->printAsOperand(OB, getPrecedence(), true); - OB += Kind; - RHS->printAsOperand(OB, getPrecedence(), false); - } -}; - -class SubobjectExpr : public Node { - const Node *Type; - const Node *SubExpr; - StringView Offset; - NodeArray UnionSelectors; - bool OnePastTheEnd; - -public: - SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, - NodeArray UnionSelectors_, bool OnePastTheEnd_) - : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), - UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} - - template<typename Fn> void match(Fn F) const { - F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); - } - - void printLeft(OutputBuffer &OB) const override { - SubExpr->print(OB); - OB += ".<"; - Type->print(OB); - OB += " at offset "; - if (Offset.empty()) { - OB += "0"; - } else if (Offset[0] == 'n') { - OB += "-"; - OB += Offset.dropFront(); - } else { - OB += Offset; - } - OB += ">"; - } -}; - -class EnclosingExpr : public Node { - const StringView Prefix; - const Node *Infix; - const StringView Postfix; - -public: - EnclosingExpr(StringView Prefix_, const Node *Infix_, - Prec Prec_ = Prec::Primary) - : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} - - template <typename Fn> void match(Fn F) const { - F(Prefix, Infix, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - OB += Prefix; - OB.printOpen(); - Infix->print(OB); - OB.printClose(); - OB += Postfix; - } -}; - -class CastExpr : public Node { - // cast_kind<to>(from) - const StringView CastKind; - const Node *To; - const Node *From; - -public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_, Prec Prec_) - : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} - - template <typename Fn> void match(Fn F) const { - F(CastKind, To, From, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - OB += CastKind; - { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); - OB += "<"; - To->printLeft(OB); - OB += ">"; - } - OB.printOpen(); - From->printAsOperand(OB); - OB.printClose(); - } -}; - -class SizeofParamPackExpr : public Node { - const Node *Pack; - -public: - SizeofParamPackExpr(const Node *Pack_) - : Node(KSizeofParamPackExpr), Pack(Pack_) {} - - template<typename Fn> void match(Fn F) const { F(Pack); } - - void printLeft(OutputBuffer &OB) const override { - OB += "sizeof..."; - OB.printOpen(); - ParameterPackExpansion PPE(Pack); - PPE.printLeft(OB); - OB.printClose(); - } -}; - -class CallExpr : public Node { - const Node *Callee; - NodeArray Args; - -public: - CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) - : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} - - template <typename Fn> void match(Fn F) const { - F(Callee, Args, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - Callee->print(OB); - OB.printOpen(); - Args.printWithComma(OB); - OB.printClose(); - } -}; - -class NewExpr : public Node { - // new (expr_list) type(init_list) - NodeArray ExprList; - Node *Type; - NodeArray InitList; - bool IsGlobal; // ::operator new ? - bool IsArray; // new[] ? -public: - NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_, Prec Prec_) - : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), - InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - template<typename Fn> void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - if (IsGlobal) - OB += "::"; - OB += "new"; - if (IsArray) - OB += "[]"; - if (!ExprList.empty()) { - OB.printOpen(); - ExprList.printWithComma(OB); - OB.printClose(); - } - OB += " "; - Type->print(OB); - if (!InitList.empty()) { - OB.printOpen(); - InitList.printWithComma(OB); - OB.printClose(); - } - } -}; - -class DeleteExpr : public Node { - Node *Op; - bool IsGlobal; - bool IsArray; - -public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) - : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), - IsArray(IsArray_) {} - - template <typename Fn> void match(Fn F) const { - F(Op, IsGlobal, IsArray, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - if (IsGlobal) - OB += "::"; - OB += "delete"; - if (IsArray) - OB += "[]"; - OB += ' '; - Op->print(OB); - } -}; - -class PrefixExpr : public Node { - StringView Prefix; - Node *Child; - -public: - PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_) - : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} - - template <typename Fn> void match(Fn F) const { - F(Prefix, Child, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - OB += Prefix; - Child->printAsOperand(OB, getPrecedence()); - } -}; - -class FunctionParam : public Node { - StringView Number; - -public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} - - template<typename Fn> void match(Fn F) const { F(Number); } - - void printLeft(OutputBuffer &OB) const override { - OB += "fp"; - OB += Number; - } -}; - -class ConversionExpr : public Node { - const Node *Type; - NodeArray Expressions; - -public: - ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) - : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} - - template <typename Fn> void match(Fn F) const { - F(Type, Expressions, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - OB.printOpen(); - Type->print(OB); - OB.printClose(); - OB.printOpen(); - Expressions.printWithComma(OB); - OB.printClose(); - } -}; - -class PointerToMemberConversionExpr : public Node { - const Node *Type; - const Node *SubExpr; - StringView Offset; - -public: - PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, - StringView Offset_, Prec Prec_) - : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), - SubExpr(SubExpr_), Offset(Offset_) {} - - template <typename Fn> void match(Fn F) const { - F(Type, SubExpr, Offset, getPrecedence()); - } - - void printLeft(OutputBuffer &OB) const override { - OB.printOpen(); - Type->print(OB); - OB.printClose(); - OB.printOpen(); - SubExpr->print(OB); - OB.printClose(); - } -}; - -class InitListExpr : public Node { - const Node *Ty; - NodeArray Inits; -public: - InitListExpr(const Node *Ty_, NodeArray Inits_) - : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Inits); } - - void printLeft(OutputBuffer &OB) const override { - if (Ty) - Ty->print(OB); - OB += '{'; - Inits.printWithComma(OB); - OB += '}'; - } -}; - -class BracedExpr : public Node { - const Node *Elem; - const Node *Init; - bool IsArray; -public: - BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) - : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} - - template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } - - void printLeft(OutputBuffer &OB) const override { - if (IsArray) { - OB += '['; - Elem->print(OB); - OB += ']'; - } else { - OB += '.'; - Elem->print(OB); - } - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - OB += " = "; - Init->print(OB); - } -}; - -class BracedRangeExpr : public Node { - const Node *First; - const Node *Last; - const Node *Init; -public: - BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) - : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} - - template<typename Fn> void match(Fn F) const { F(First, Last, Init); } - - void printLeft(OutputBuffer &OB) const override { - OB += '['; - First->print(OB); - OB += " ... "; - Last->print(OB); - OB += ']'; - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - OB += " = "; - Init->print(OB); - } -}; - -class FoldExpr : public Node { - const Node *Pack, *Init; - StringView OperatorName; - bool IsLeftFold; - -public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, - const Node *Init_) - : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), - IsLeftFold(IsLeftFold_) {} - - template<typename Fn> void match(Fn F) const { - F(IsLeftFold, OperatorName, Pack, Init); - } - - void printLeft(OutputBuffer &OB) const override { - auto PrintPack = [&] { - OB.printOpen(); - ParameterPackExpansion(Pack).print(OB); - OB.printClose(); - }; - - OB.printOpen(); - // Either '[init op ]... op pack' or 'pack op ...[ op init]' - // Refactored to '[(init|pack) op ]...[ op (pack|init)]' - // Fold expr operands are cast-expressions - if (!IsLeftFold || Init != nullptr) { - // '(init|pack) op ' - if (IsLeftFold) - Init->printAsOperand(OB, Prec::Cast, true); - else - PrintPack(); - OB << " " << OperatorName << " "; - } - OB << "..."; - if (IsLeftFold || Init != nullptr) { - // ' op (init|pack)' - OB << " " << OperatorName << " "; - if (IsLeftFold) - PrintPack(); - else - Init->printAsOperand(OB, Prec::Cast, true); - } - OB.printClose(); - } -}; - -class ThrowExpr : public Node { - const Node *Op; - -public: - ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} - - template<typename Fn> void match(Fn F) const { F(Op); } - - void printLeft(OutputBuffer &OB) const override { - OB += "throw "; - Op->print(OB); - } -}; - -class BoolExpr : public Node { - bool Value; - -public: - BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} - - template<typename Fn> void match(Fn F) const { F(Value); } - - void printLeft(OutputBuffer &OB) const override { - OB += Value ? StringView("true") : StringView("false"); - } -}; - -class StringLiteral : public Node { - const Node *Type; - -public: - StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {} - - template<typename Fn> void match(Fn F) const { F(Type); } - - void printLeft(OutputBuffer &OB) const override { - OB += "\"<"; - Type->print(OB); - OB += ">\""; - } -}; - -class LambdaExpr : public Node { - const Node *Type; - -public: - LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {} - - template<typename Fn> void match(Fn F) const { F(Type); } - - void printLeft(OutputBuffer &OB) const override { - OB += "[]"; - if (Type->getKind() == KClosureTypeName) - static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB); - OB += "{...}"; - } -}; - -class EnumLiteral : public Node { - // ty(integer) - const Node *Ty; - StringView Integer; - -public: - EnumLiteral(const Node *Ty_, StringView Integer_) - : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Integer); } - - void printLeft(OutputBuffer &OB) const override { - OB.printOpen(); - Ty->print(OB); - OB.printClose(); - - if (Integer[0] == 'n') - OB << "-" << Integer.dropFront(1); - else - OB << Integer; - } -}; - -class IntegerLiteral : public Node { - StringView Type; - StringView Value; - -public: - IntegerLiteral(StringView Type_, StringView Value_) - : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} - - template<typename Fn> void match(Fn F) const { F(Type, Value); } - - void printLeft(OutputBuffer &OB) const override { - if (Type.size() > 3) { - OB.printOpen(); - OB += Type; - OB.printClose(); - } - - if (Value[0] == 'n') { - OB += '-'; - OB += Value.dropFront(1); - } else - OB += Value; - - if (Type.size() <= 3) - OB += Type; - } -}; - -template <class Float> struct FloatData; - -namespace float_literal_impl { -constexpr Node::Kind getFloatLiteralKind(float *) { - return Node::KFloatLiteral; -} -constexpr Node::Kind getFloatLiteralKind(double *) { - return Node::KDoubleLiteral; -} -constexpr Node::Kind getFloatLiteralKind(long double *) { - return Node::KLongDoubleLiteral; -} -} - -template <class Float> class FloatLiteralImpl : public Node { - const StringView Contents; - - static constexpr Kind KindForClass = - float_literal_impl::getFloatLiteralKind((Float *)nullptr); - -public: - FloatLiteralImpl(StringView Contents_) - : Node(KindForClass), Contents(Contents_) {} - - template<typename Fn> void match(Fn F) const { F(Contents); } - - void printLeft(OutputBuffer &OB) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - - const size_t N = FloatData<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) { - last = first + N; - union { - Float value; - char buf[sizeof(Float)]; - }; - const char *t = first; - char *e = buf; - for (; t != last; ++t, ++e) { - unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - *e = static_cast<char>((d1 << 4) + d0); - } -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[FloatData<Float>::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); - OB += StringView(num, num + n); - } - } -}; - -using FloatLiteral = FloatLiteralImpl<float>; -using DoubleLiteral = FloatLiteralImpl<double>; -using LongDoubleLiteral = FloatLiteralImpl<long double>; - -/// Visit the node. Calls \c F(P), where \c P is the node cast to the -/// appropriate derived class. -template<typename Fn> -void Node::visit(Fn F) const { - switch (K) { -#define NODE(X) \ - case K##X: \ - return F(static_cast<const X *>(this)); -#include "ItaniumNodes.def" - } - assert(0 && "unknown mangling node kind"); -} - -/// Determine the kind of a node from its type. -template<typename NodeT> struct NodeKind; -#define NODE(X) \ - template <> struct NodeKind<X> { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ - }; -#include "ItaniumNodes.def" - -template <typename Derived, typename Alloc> struct AbstractManglingParser { - const char *First; - const char *Last; - - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser collapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector<Node *, 32> Names; - - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector<Node *, 32> Subs; - - using TemplateParamList = PODSmallVector<Node *, 8>; - - class ScopedTemplateParamList { - AbstractManglingParser *Parser; - size_t OldNumTemplateParamLists; - TemplateParamList Params; - - public: - ScopedTemplateParamList(AbstractManglingParser *TheParser) - : Parser(TheParser), - OldNumTemplateParamLists(TheParser->TemplateParams.size()) { - Parser->TemplateParams.push_back(&Params); - } - ~ScopedTemplateParamList() { - assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists); - Parser->TemplateParams.dropBack(OldNumTemplateParamLists); - } - }; - - // Template parameter table. Like the above, but referenced like "T42_". - // This has a smaller size compared to Subs and Names because it can be - // stored on the stack. - TemplateParamList OuterTemplateParams; - - // Lists of template parameters indexed by template parameter depth, - // referenced like "TL2_4_". If nonempty, element 0 is always - // OuterTemplateParams; inner elements are always template parameter lists of - // lambda expressions. For a generic lambda with no explicit template - // parameter list, the corresponding parameter list pointer will be null. - PODSmallVector<TemplateParamList *, 4> TemplateParams; - - // Set of unresolved forward <template-param> references. These can occur in a - // conversion operator's type, and are resolved in the enclosing <encoding>. - PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; - - bool TryToParseTemplateArgs = true; - bool PermitForwardTemplateReferences = false; - size_t ParsingLambdaParamsAtLevel = (size_t)-1; - - unsigned NumSyntheticTemplateParameters[3] = {}; - - Alloc ASTAllocator; - - AbstractManglingParser(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - - Derived &getDerived() { return static_cast<Derived &>(*this); } - - void reset(const char *First_, const char *Last_) { - First = First_; - Last = Last_; - Names.clear(); - Subs.clear(); - TemplateParams.clear(); - ParsingLambdaParamsAtLevel = (size_t)-1; - TryToParseTemplateArgs = true; - PermitForwardTemplateReferences = false; - for (int I = 0; I != 3; ++I) - NumSyntheticTemplateParameters[I] = 0; - ASTAllocator.reset(); - } - - template <class T, class... Args> Node *make(Args &&... args) { - return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...); - } - - template <class It> NodeArray makeNodeArray(It begin, It end) { - size_t sz = static_cast<size_t>(end - begin); - void *mem = ASTAllocator.allocateNodeArray(sz); - Node **data = new (mem) Node *[sz]; - std::copy(begin, end, data); - return NodeArray(data, sz); - } - - NodeArray popTrailingNodeArray(size_t FromPosition) { - assert(FromPosition <= Names.size()); - NodeArray res = - makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); - return res; - } - - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { - First += S.size(); - return true; - } - return false; - } - - bool consumeIf(char C) { - if (First != Last && *First == C) { - ++First; - return true; - } - return false; - } - - char consume() { return First != Last ? *First++ : '\0'; } - - char look(unsigned Lookahead = 0) const { - if (static_cast<size_t>(Last - First) <= Lookahead) - return '\0'; - return First[Lookahead]; - } - - size_t numLeft() const { return static_cast<size_t>(Last - First); } - - StringView parseNumber(bool AllowNegative = false); - Qualifiers parseCVQualifiers(); - bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); - - bool parseSeqId(size_t *Out); - Node *parseSubstitution(); - Node *parseTemplateParam(); - Node *parseTemplateParamDecl(); - Node *parseTemplateArgs(bool TagTemplates = false); - Node *parseTemplateArg(); - - /// Parse the <expr> production. - Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind, Node::Prec Prec); - Node *parseBinaryExpr(StringView Kind, Node::Prec Prec); - Node *parseIntegerLiteral(StringView Lit); - Node *parseExprPrimary(); - template <class Float> Node *parseFloatingLiteral(); - Node *parseFunctionParam(); - Node *parseConversionExpr(); - Node *parseBracedExpr(); - Node *parseFoldExpr(); - Node *parsePointerToMemberConversionExpr(Node::Prec Prec); - Node *parseSubobjectExpr(); - - /// Parse the <type> production. - Node *parseType(); - Node *parseFunctionType(); - Node *parseVectorType(); - Node *parseDecltype(); - Node *parseArrayType(); - Node *parsePointerToMemberType(); - Node *parseClassEnumType(); - Node *parseQualifiedType(); - - Node *parseEncoding(); - bool parseCallOffset(); - Node *parseSpecialName(); - - /// Holds some extra information about a <name> that is being parsed. This - /// information is only pertinent if the <name> refers to an <encoding>. - struct NameState { - bool CtorDtorConversion = false; - bool EndsWithTemplateArgs = false; - Qualifiers CVQualifiers = QualNone; - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ForwardTemplateRefsBegin; - - NameState(AbstractManglingParser *Enclosing) - : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} - }; - - bool resolveForwardTemplateRefs(NameState &State) { - size_t I = State.ForwardTemplateRefsBegin; - size_t E = ForwardTemplateRefs.size(); - for (; I < E; ++I) { - size_t Idx = ForwardTemplateRefs[I]->Index; - if (TemplateParams.empty() || !TemplateParams[0] || - Idx >= TemplateParams[0]->size()) - return true; - ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx]; - } - ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); - return false; - } - - /// Parse the <name> production> - Node *parseName(NameState *State = nullptr); - Node *parseLocalName(NameState *State); - Node *parseOperatorName(NameState *State); - bool parseModuleNameOpt(ModuleName *&Module); - Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); - Node *parseUnnamedTypeName(NameState *State); - Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State, bool *isSubstName); - Node *parseNestedName(NameState *State); - Node *parseCtorDtorName(Node *&SoFar, NameState *State); - - Node *parseAbiTags(Node *N); - - struct OperatorInfo { - enum OIKind : unsigned char { - Prefix, // Prefix unary: @ expr - Postfix, // Postfix unary: expr @ - Binary, // Binary: lhs @ rhs - Array, // Array index: lhs [ rhs ] - Member, // Member access: lhs @ rhs - New, // New - Del, // Delete - Call, // Function call: expr (expr*) - CCast, // C cast: (type)expr - Conditional, // Conditional: expr ? expr : expr - NameOnly, // Overload only, not allowed in expression. - // Below do not have operator names - NamedCast, // Named cast, @<type>(expr) - OfIdOp, // alignof, sizeof, typeid - - Unnameable = NamedCast, - }; - char Enc[2]; // Encoding - OIKind Kind; // Kind of operator - bool Flag : 1; // Entry-specific flag - Node::Prec Prec : 7; // Precedence - const char *Name; // Spelling - - public: - constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P, - const char *N) - : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {} - - public: - bool operator<(const OperatorInfo &Other) const { - return *this < Other.Enc; - } - bool operator<(const char *Peek) const { - return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]); - } - bool operator==(const char *Peek) const { - return Enc[0] == Peek[0] && Enc[1] == Peek[1]; - } - bool operator!=(const char *Peek) const { return !this->operator==(Peek); } - - public: - StringView getSymbol() const { - StringView Res = Name; - if (Kind < Unnameable) { - assert(Res.startsWith("operator") && - "operator name does not start with 'operator'"); - Res = Res.dropFront(sizeof("operator") - 1); - Res.consumeFront(' '); - } - return Res; - } - StringView getName() const { return Name; } - OIKind getKind() const { return Kind; } - bool getFlag() const { return Flag; } - Node::Prec getPrecedence() const { return Prec; } - }; - static const OperatorInfo Ops[]; - static const size_t NumOps; - const OperatorInfo *parseOperatorEncoding(); - - /// Parse the <unresolved-name> production. - Node *parseUnresolvedName(bool Global); - Node *parseSimpleId(); - Node *parseBaseUnresolvedName(); - Node *parseUnresolvedType(); - Node *parseDestructorName(); - - /// Top-level entry point into the parser. - Node *parse(); -}; - -const char* parse_discriminator(const char* first, const char* last); - -// <name> ::= <nested-name> // N -// ::= <local-name> # See Scope Encoding below // Z -// ::= <unscoped-template-name> <template-args> -// ::= <unscoped-name> -// -// <unscoped-template-name> ::= <unscoped-name> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { - if (look() == 'N') - return getDerived().parseNestedName(State); - if (look() == 'Z') - return getDerived().parseLocalName(State); - - Node *Result = nullptr; - bool IsSubst = false; - - Result = getDerived().parseUnscopedName(State, &IsSubst); - if (!Result) - return nullptr; - - if (look() == 'I') { - // ::= <unscoped-template-name> <template-args> - if (!IsSubst) - // An unscoped-template-name is substitutable. - Subs.push_back(Result); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) - State->EndsWithTemplateArgs = true; - Result = make<NameWithTemplateArgs>(Result, TA); - } else if (IsSubst) { - // The substitution case must be followed by <template-args>. - return nullptr; - } - - return Result; -} - -// <local-name> := Z <function encoding> E <entity name> [<discriminator>] -// := Z <function encoding> E s [<discriminator>] -// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) { - if (!consumeIf('Z')) - return nullptr; - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf('E')) - return nullptr; - - if (consumeIf('s')) { - First = parse_discriminator(First, Last); - auto *StringLitName = make<NameType>("string literal"); - if (!StringLitName) - return nullptr; - return make<LocalName>(Encoding, StringLitName); - } - - if (consumeIf('d')) { - parseNumber(true); - if (!consumeIf('_')) - return nullptr; - Node *N = getDerived().parseName(State); - if (N == nullptr) - return nullptr; - return make<LocalName>(Encoding, N); - } - - Node *Entity = getDerived().parseName(State); - if (Entity == nullptr) - return nullptr; - First = parse_discriminator(First, Last); - return make<LocalName>(Encoding, Entity); -} - -// <unscoped-name> ::= <unqualified-name> -// ::= St <unqualified-name> # ::std:: -// [*] extension -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State, - bool *IsSubst) { - - Node *Std = nullptr; - if (consumeIf("St")) { - Std = make<NameType>("std"); - if (Std == nullptr) - return nullptr; - } - - Node *Res = nullptr; - ModuleName *Module = nullptr; - if (look() == 'S') { - Node *S = getDerived().parseSubstitution(); - if (!S) - return nullptr; - if (S->getKind() == Node::KModuleName) - Module = static_cast<ModuleName *>(S); - else if (IsSubst && Std == nullptr) { - Res = S; - *IsSubst = true; - } else { - return nullptr; - } - } - - if (Res == nullptr || Std != nullptr) { - Res = getDerived().parseUnqualifiedName(State, Std, Module); - } - - return Res; -} - -// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>] -// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>] -// ::= [<module-name>] L? <source-name> [<abi-tags>] -// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>] -// # structured binding declaration -// ::= [<module-name>] L? DC <source-name>+ E -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName( - NameState *State, Node *Scope, ModuleName *Module) { - if (getDerived().parseModuleNameOpt(Module)) - return nullptr; - - consumeIf('L'); - - Node *Result; - if (look() >= '1' && look() <= '9') { - Result = getDerived().parseSourceName(State); - } else if (look() == 'U') { - Result = getDerived().parseUnnamedTypeName(State); - } else if (consumeIf("DC")) { - // Structured binding - size_t BindingsBegin = Names.size(); - do { - Node *Binding = getDerived().parseSourceName(State); - if (Binding == nullptr) - return nullptr; - Names.push_back(Binding); - } while (!consumeIf('E')); - Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); - } else if (look() == 'C' || look() == 'D') { - // A <ctor-dtor-name>. - if (Scope == nullptr || Module != nullptr) - return nullptr; - Result = getDerived().parseCtorDtorName(Scope, State); - } else { - Result = getDerived().parseOperatorName(State); - } - - if (Result != nullptr && Module != nullptr) - Result = make<ModuleEntity>(Module, Result); - if (Result != nullptr) - Result = getDerived().parseAbiTags(Result); - if (Result != nullptr && Scope != nullptr) - Result = make<NestedName>(Scope, Result); - - return Result; -} - -// <module-name> ::= <module-subname> -// ::= <module-name> <module-subname> -// ::= <substitution> # passed in by caller -// <module-subname> ::= W <source-name> -// ::= W P <source-name> -template <typename Derived, typename Alloc> -bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt( - ModuleName *&Module) { - while (consumeIf('W')) { - bool IsPartition = consumeIf('P'); - Node *Sub = getDerived().parseSourceName(nullptr); - if (!Sub) - return true; - Module = - static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition)); - Subs.push_back(Module); - } - - return false; -} - -// <unnamed-type-name> ::= Ut [<nonnegative number>] _ -// ::= <closure-type-name> -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// -// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { - // <template-params> refer to the innermost <template-args>. Clear out any - // outer args that we may have inserted into TemplateParams. - if (State != nullptr) - TemplateParams.clear(); - - if (consumeIf("Ut")) { - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<UnnamedTypeName>(Count); - } - if (consumeIf("Ul")) { - ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel, - TemplateParams.size()); - ScopedTemplateParamList LambdaTemplateParams(this); - - size_t ParamsBegin = Names.size(); - while (look() == 'T' && - StringView("yptn").find(look(1)) != StringView::npos) { - Node *T = parseTemplateParamDecl(); - if (!T) - return nullptr; - Names.push_back(T); - } - NodeArray TempParams = popTrailingNodeArray(ParamsBegin); - - // FIXME: If TempParams is empty and none of the function parameters - // includes 'auto', we should remove LambdaTemplateParams from the - // TemplateParams list. Unfortunately, we don't find out whether there are - // any 'auto' parameters until too late in an example such as: - // - // template<typename T> void f( - // decltype([](decltype([]<typename T>(T v) {}), - // auto) {})) {} - // template<typename T> void f( - // decltype([](decltype([]<typename T>(T w) {}), - // int) {})) {} - // - // Here, the type of v is at level 2 but the type of w is at level 1. We - // don't find this out until we encounter the type of the next parameter. - // - // However, compilers can't actually cope with the former example in - // practice, and it's likely to be made ill-formed in future, so we don't - // need to support it here. - // - // If we encounter an 'auto' in the function parameter types, we will - // recreate a template parameter scope for it, but any intervening lambdas - // will be parsed in the 'wrong' template parameter depth. - if (TempParams.empty()) - TemplateParams.pop_back(); - - if (!consumeIf("vE")) { - do { - Node *P = getDerived().parseType(); - if (P == nullptr) - return nullptr; - Names.push_back(P); - } while (!consumeIf('E')); - } - NodeArray Params = popTrailingNodeArray(ParamsBegin); - - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<ClosureTypeName>(TempParams, Params, Count); - } - if (consumeIf("Ub")) { - (void)parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<NameType>("'block-literal'"); - } - return nullptr; -} - -// <source-name> ::= <positive length number> <identifier> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) { - size_t Length = 0; - if (parsePositiveInteger(&Length)) - return nullptr; - if (numLeft() < Length || Length == 0) - return nullptr; - StringView Name(First, First + Length); - First += Length; - if (Name.startsWith("_GLOBAL__N")) - return make<NameType>("(anonymous namespace)"); - return make<NameType>(Name); -} - -// Operator encodings -template <typename Derived, typename Alloc> -const typename AbstractManglingParser< - Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived, - Alloc>::Ops[] = { - // Keep ordered by encoding - {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, - {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, - {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, - {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, - {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, - {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "}, - {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, - "operator co_await"}, - {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "}, - {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, - {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, - {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, - {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, - {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast - {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, - {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, - "operator delete[]"}, - {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"}, - {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, - {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, - "operator delete"}, - {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, - "operator.*"}, - {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix, - "operator."}, - {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"}, - {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="}, - {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"}, - {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="}, - {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="}, - {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"}, - {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"}, - {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="}, - {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="}, - {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"}, - {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"}, - {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="}, - {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="}, - {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"}, - {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative, - "operator*"}, - {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"}, - {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary, - "operator new[]"}, - {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, - {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, - {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, - {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"}, - {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, - {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, - {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, - {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="}, - {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"}, - {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, - "operator->*"}, - {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"}, - {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"}, - {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix, - "operator->"}, - {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional, - "operator?"}, - {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="}, - {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="}, - {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, - "reinterpret_cast"}, - {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, - "operator%"}, - {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, - {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"}, - {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, - {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, - {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "}, - {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, - "typeid "}, - {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "}, -}; -template <typename Derived, typename Alloc> -const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) / - sizeof(Ops[0]); - -// If the next 2 chars are an operator encoding, consume them and return their -// OperatorInfo. Otherwise return nullptr. -template <typename Derived, typename Alloc> -const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo * -AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { - if (numLeft() < 2) - return nullptr; - - // We can't use lower_bound as that can link to symbols in the C++ library, - // and this must remain independant of that. - size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. - while (upper != lower) { - size_t middle = (upper + lower) / 2; - if (Ops[middle] < First) - lower = middle + 1; - else - upper = middle; - } - if (Ops[lower] != First) - return nullptr; - - First += 2; - return &Ops[lower]; -} - -// <operator-name> ::= See parseOperatorEncoding() -// ::= li <source-name> # operator "" -// ::= v <digit> <source-name> # vendor extended operator -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { - if (const auto *Op = parseOperatorEncoding()) { - if (Op->getKind() == OperatorInfo::CCast) { - // ::= cv <type> # (cast) - ScopedOverride<bool> SaveTemplate(TryToParseTemplateArgs, false); - // If we're parsing an encoding, State != nullptr and the conversion - // operators' <type> could have a <template-param> that refers to some - // <template-arg>s further ahead in the mangled name. - ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences, - PermitForwardTemplateReferences || - State != nullptr); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (State) State->CtorDtorConversion = true; - return make<ConversionOperatorType>(Ty); - } - - if (Op->getKind() >= OperatorInfo::Unnameable) - /* Not a nameable operator. */ - return nullptr; - if (Op->getKind() == OperatorInfo::Member && !Op->getFlag()) - /* Not a nameable MemberExpr */ - return nullptr; - - return make<NameType>(Op->getName()); - } - - if (consumeIf("li")) { - // ::= li <source-name> # operator "" - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<LiteralOperator>(SN); - } - - if (consumeIf('v')) { - // ::= v <digit> <source-name> # vendor extended operator - if (look() >= '0' && look() <= '9') { - First++; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<ConversionOperatorType>(SN); - } - return nullptr; - } - - return nullptr; -} - -// <ctor-dtor-name> ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// extension ::= C4 # gcc old-style "[unified]" constructor -// extension ::= C5 # the COMDAT used for ctors -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor -// extension ::= D4 # gcc old-style "[unified]" destructor -// extension ::= D5 # the COMDAT used for dtors -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, - NameState *State) { - if (SoFar->getKind() == Node::KSpecialSubstitution) { - // Expand the special substitution. - SoFar = make<ExpandedSpecialSubstitution>( - static_cast<SpecialSubstitution *>(SoFar)); - if (!SoFar) - return nullptr; - } - - if (consumeIf('C')) { - bool IsInherited = consumeIf('I'); - if (look() != '1' && look() != '2' && look() != '3' && look() != '4' && - look() != '5') - return nullptr; - int Variant = look() - '0'; - ++First; - if (State) State->CtorDtorConversion = true; - if (IsInherited) { - if (getDerived().parseName(State) == nullptr) - return nullptr; - } - return make<CtorDtorName>(SoFar, /*IsDtor=*/false, Variant); - } - - if (look() == 'D' && (look(1) == '0' || look(1) == '1' || look(1) == '2' || - look(1) == '4' || look(1) == '5')) { - int Variant = look(1) - '0'; - First += 2; - if (State) State->CtorDtorConversion = true; - return make<CtorDtorName>(SoFar, /*IsDtor=*/true, Variant); - } - - return nullptr; -} - -// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> -// <unqualified-name> E -// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> -// <template-args> E -// -// <prefix> ::= <prefix> <unqualified-name> -// ::= <template-prefix> <template-args> -// ::= <template-param> -// ::= <decltype> -// ::= # empty -// ::= <substitution> -// ::= <prefix> <data-member-prefix> -// [*] extension -// -// <data-member-prefix> := <member source-name> [<template-args>] M -// -// <template-prefix> ::= <prefix> <template unqualified-name> -// ::= <template-param> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) { - if (!consumeIf('N')) - return nullptr; - - Qualifiers CVTmp = parseCVQualifiers(); - if (State) State->CVQualifiers = CVTmp; - - if (consumeIf('O')) { - if (State) State->ReferenceQualifier = FrefQualRValue; - } else if (consumeIf('R')) { - if (State) State->ReferenceQualifier = FrefQualLValue; - } else { - if (State) State->ReferenceQualifier = FrefQualNone; - } - - Node *SoFar = nullptr; - while (!consumeIf('E')) { - if (State) - // Only set end-with-template on the case that does that. - State->EndsWithTemplateArgs = false; - - if (look() == 'T') { - // ::= <template-param> - if (SoFar != nullptr) - return nullptr; // Cannot have a prefix. - SoFar = getDerived().parseTemplateParam(); - } else if (look() == 'I') { - // ::= <template-prefix> <template-args> - if (SoFar == nullptr) - return nullptr; // Must have a prefix. - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (SoFar->getKind() == Node::KNameWithTemplateArgs) - // Semantically <template-args> <template-args> cannot be generated by a - // C++ entity. There will always be [something like] a name between - // them. - return nullptr; - if (State) - State->EndsWithTemplateArgs = true; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - // ::= <decltype> - if (SoFar != nullptr) - return nullptr; // Cannot have a prefix. - SoFar = getDerived().parseDecltype(); - } else { - ModuleName *Module = nullptr; - - if (look() == 'S') { - // ::= <substitution> - Node *S = nullptr; - if (look(1) == 't') { - First += 2; - S = make<NameType>("std"); - } else { - S = getDerived().parseSubstitution(); - } - if (!S) - return nullptr; - if (S->getKind() == Node::KModuleName) { - Module = static_cast<ModuleName *>(S); - } else if (SoFar != nullptr) { - return nullptr; // Cannot have a prefix. - } else { - SoFar = S; - continue; // Do not push a new substitution. - } - } - - // ::= [<prefix>] <unqualified-name> - SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); - } - - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - - // No longer used. - // <data-member-prefix> := <member source-name> [<template-args>] M - consumeIf('M'); - } - - if (SoFar == nullptr || Subs.empty()) - return nullptr; - - Subs.pop_back(); - return SoFar; -} - -// <simple-id> ::= <source-name> [ <template-args> ] -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() { - Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr); - if (SN == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(SN, TA); - } - return SN; -} - -// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) -// ::= <simple-id> # e.g., ~A<2*N> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() { - Node *Result; - if (std::isdigit(look())) - Result = getDerived().parseSimpleId(); - else - Result = getDerived().parseUnresolvedType(); - if (Result == nullptr) - return nullptr; - return make<DtorName>(Result); -} - -// <unresolved-type> ::= <template-param> -// ::= <decltype> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() { - if (look() == 'T') { - Node *TP = getDerived().parseTemplateParam(); - if (TP == nullptr) - return nullptr; - Subs.push_back(TP); - return TP; - } - if (look() == 'D') { - Node *DT = getDerived().parseDecltype(); - if (DT == nullptr) - return nullptr; - Subs.push_back(DT); - return DT; - } - return getDerived().parseSubstitution(); -} - -// <base-unresolved-name> ::= <simple-id> # unresolved name -// extension ::= <operator-name> # unresolved operator-function-id -// extension ::= <operator-name> <template-args> # unresolved operator template-id -// ::= on <operator-name> # unresolved operator-function-id -// ::= on <operator-name> <template-args> # unresolved operator template-id -// ::= dn <destructor-name> # destructor or pseudo-destructor; -// # e.g. ~X or ~X<N-1> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() { - if (std::isdigit(look())) - return getDerived().parseSimpleId(); - - if (consumeIf("dn")) - return getDerived().parseDestructorName(); - - consumeIf("on"); - - Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr); - if (Oper == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(Oper, TA); - } - return Oper; -} - -// <unresolved-name> -// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> -// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -// # A::x, N::y, A<T>::z; "gs" means leading "::" -// [gs] has been parsed by caller. -// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x -// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -// -// <unresolved-qualifier-level> ::= <simple-id> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) { - Node *SoFar = nullptr; - - // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> - // srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> - if (consumeIf("srN")) { - SoFar = getDerived().parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - } - - while (!consumeIf('E')) { - Node *Qual = getDerived().parseSimpleId(); - if (Qual == nullptr) - return nullptr; - SoFar = make<QualifiedName>(SoFar, Qual); - if (!SoFar) - return nullptr; - } - - Node *Base = getDerived().parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); - } - - // [gs] <base-unresolved-name> # x or (with "gs") ::x - if (!consumeIf("sr")) { - SoFar = getDerived().parseBaseUnresolvedName(); - if (SoFar == nullptr) - return nullptr; - if (Global) - SoFar = make<GlobalQualifiedName>(SoFar); - return SoFar; - } - - // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> - if (std::isdigit(look())) { - do { - Node *Qual = getDerived().parseSimpleId(); - if (Qual == nullptr) - return nullptr; - if (SoFar) - SoFar = make<QualifiedName>(SoFar, Qual); - else if (Global) - SoFar = make<GlobalQualifiedName>(Qual); - else - SoFar = Qual; - if (!SoFar) - return nullptr; - } while (!consumeIf('E')); - } - // sr <unresolved-type> <base-unresolved-name> - // sr <unresolved-type> <template-args> <base-unresolved-name> - else { - SoFar = getDerived().parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - } - } - - assert(SoFar != nullptr); - - Node *Base = getDerived().parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); -} - -// <abi-tags> ::= <abi-tag> [<abi-tags>] -// <abi-tag> ::= B <source-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { - while (consumeIf('B')) { - StringView SN = parseBareSourceName(); - if (SN.empty()) - return nullptr; - N = make<AbiTagAttr>(N, SN); - if (!N) - return nullptr; - } - return N; -} - -// <number> ::= [n] <non-negative decimal integer> -template <typename Alloc, typename Derived> -StringView -AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { - const char *Tmp = First; - if (AllowNegative) - consumeIf('n'); - if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); - while (numLeft() != 0 && std::isdigit(*First)) - ++First; - return StringView(Tmp, First); -} - -// <positive length number> ::= [0-9]* -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) { - *Out = 0; - if (look() < '0' || look() > '9') - return true; - while (look() >= '0' && look() <= '9') { - *Out *= 10; - *Out += static_cast<size_t>(consume() - '0'); - } - return false; -} - -template <typename Alloc, typename Derived> -StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { - size_t Int = 0; - if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); - First += Int; - return R; -} - -// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E -// -// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw()) -// ::= DO <expression> E # computed (instantiation-dependent) noexcept -// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types -// -// <ref-qualifier> ::= R # & ref-qualifier -// <ref-qualifier> ::= O # && ref-qualifier -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() { - Qualifiers CVQuals = parseCVQualifiers(); - - Node *ExceptionSpec = nullptr; - if (consumeIf("Do")) { - ExceptionSpec = make<NameType>("noexcept"); - if (!ExceptionSpec) - return nullptr; - } else if (consumeIf("DO")) { - Node *E = getDerived().parseExpr(); - if (E == nullptr || !consumeIf('E')) - return nullptr; - ExceptionSpec = make<NoexceptSpec>(E); - if (!ExceptionSpec) - return nullptr; - } else if (consumeIf("Dw")) { - size_t SpecsBegin = Names.size(); - while (!consumeIf('E')) { - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - ExceptionSpec = - make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin)); - if (!ExceptionSpec) - return nullptr; - } - - consumeIf("Dx"); // transaction safe - - if (!consumeIf('F')) - return nullptr; - consumeIf('Y'); // extern "C" - Node *ReturnType = getDerived().parseType(); - if (ReturnType == nullptr) - return nullptr; - - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ParamsBegin = Names.size(); - while (true) { - if (consumeIf('E')) - break; - if (consumeIf('v')) - continue; - if (consumeIf("RE")) { - ReferenceQualifier = FrefQualLValue; - break; - } - if (consumeIf("OE")) { - ReferenceQualifier = FrefQualRValue; - break; - } - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - - NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make<FunctionType>(ReturnType, Params, CVQuals, - ReferenceQualifier, ExceptionSpec); -} - -// extension: -// <vector-type> ::= Dv <positive dimension number> _ <extended element type> -// ::= Dv [<dimension expression>] _ <element type> -// <extended element type> ::= <element type> -// ::= p # AltiVec vector pixel -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() { - if (!consumeIf("Dv")) - return nullptr; - if (look() >= '1' && look() <= '9') { - Node *DimensionNumber = make<NameType>(parseNumber()); - if (!DimensionNumber) - return nullptr; - if (!consumeIf('_')) - return nullptr; - if (consumeIf('p')) - return make<PixelVectorType>(DimensionNumber); - Node *ElemType = getDerived().parseType(); - if (ElemType == nullptr) - return nullptr; - return make<VectorType>(ElemType, DimensionNumber); - } - - if (!consumeIf('_')) { - Node *DimExpr = getDerived().parseExpr(); - if (!DimExpr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Node *ElemType = getDerived().parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, DimExpr); - } - Node *ElemType = getDerived().parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, /*Dimension=*/nullptr); -} - -// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) -// ::= DT <expression> E # decltype of an expression (C++0x) -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() { - if (!consumeIf('D')) - return nullptr; - if (!consumeIf('t') && !consumeIf('T')) - return nullptr; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return nullptr; - if (!consumeIf('E')) - return nullptr; - return make<EnclosingExpr>("decltype", E); -} - -// <array-type> ::= A <positive dimension number> _ <element type> -// ::= A [<dimension expression>] _ <element type> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() { - if (!consumeIf('A')) - return nullptr; - - Node *Dimension = nullptr; - - if (std::isdigit(look())) { - Dimension = make<NameType>(parseNumber()); - if (!Dimension) - return nullptr; - if (!consumeIf('_')) - return nullptr; - } else if (!consumeIf('_')) { - Node *DimExpr = getDerived().parseExpr(); - if (DimExpr == nullptr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Dimension = DimExpr; - } - - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<ArrayType>(Ty, Dimension); -} - -// <pointer-to-member-type> ::= M <class type> <member type> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() { - if (!consumeIf('M')) - return nullptr; - Node *ClassType = getDerived().parseType(); - if (ClassType == nullptr) - return nullptr; - Node *MemberType = getDerived().parseType(); - if (MemberType == nullptr) - return nullptr; - return make<PointerToMemberType>(ClassType, MemberType); -} - -// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier -// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class' -// ::= Tu <name> # dependent elaborated type specifier using 'union' -// ::= Te <name> # dependent elaborated type specifier using 'enum' -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { - StringView ElabSpef; - if (consumeIf("Ts")) - ElabSpef = "struct"; - else if (consumeIf("Tu")) - ElabSpef = "union"; - else if (consumeIf("Te")) - ElabSpef = "enum"; - - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - - if (!ElabSpef.empty()) - return make<ElaboratedTypeSpefType>(ElabSpef, Name); - - return Name; -} - -// <qualified-type> ::= <qualifiers> <type> -// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers> -// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { - if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); - if (Qual.empty()) - return nullptr; - - // extension ::= U <objc-name> <objc-type> # objc-type<identifier> - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; - { - ScopedOverride<const char *> SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); - Proto = parseBareSourceName(); - } - if (Proto.empty()) - return nullptr; - Node *Child = getDerived().parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<ObjCProtoName>(Child, Proto); - } - - Node *TA = nullptr; - if (look() == 'I') { - TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - } - - Node *Child = getDerived().parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<VendorExtQualType>(Child, Qual, TA); - } - - Qualifiers Quals = parseCVQualifiers(); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (Quals != QualNone) - Ty = make<QualType>(Ty, Quals); - return Ty; -} - -// <type> ::= <builtin-type> -// ::= <qualified-type> -// ::= <function-type> -// ::= <class-enum-type> -// ::= <array-type> -// ::= <pointer-to-member-type> -// ::= <template-param> -// ::= <template-template-param> <template-args> -// ::= <decltype> -// ::= P <type> # pointer -// ::= R <type> # l-value reference -// ::= O <type> # r-value reference (C++11) -// ::= C <type> # complex pair (C99) -// ::= G <type> # imaginary (C99) -// ::= <substitution> # See Compression below -// extension ::= U <objc-name> <objc-type> # objc-type<identifier> -// extension ::= <vector-type> # <vector-type> starts with Dv -// -// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 -// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseType() { - Node *Result = nullptr; - - switch (look()) { - // ::= <qualified-type> - case 'r': - case 'V': - case 'K': { - unsigned AfterQuals = 0; - if (look(AfterQuals) == 'r') ++AfterQuals; - if (look(AfterQuals) == 'V') ++AfterQuals; - if (look(AfterQuals) == 'K') ++AfterQuals; - - if (look(AfterQuals) == 'F' || - (look(AfterQuals) == 'D' && - (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' || - look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) { - Result = getDerived().parseFunctionType(); - break; - } - DEMANGLE_FALLTHROUGH; - } - case 'U': { - Result = getDerived().parseQualifiedType(); - break; - } - // <builtin-type> ::= v # void - case 'v': - ++First; - return make<NameType>("void"); - // ::= w # wchar_t - case 'w': - ++First; - return make<NameType>("wchar_t"); - // ::= b # bool - case 'b': - ++First; - return make<NameType>("bool"); - // ::= c # char - case 'c': - ++First; - return make<NameType>("char"); - // ::= a # signed char - case 'a': - ++First; - return make<NameType>("signed char"); - // ::= h # unsigned char - case 'h': - ++First; - return make<NameType>("unsigned char"); - // ::= s # short - case 's': - ++First; - return make<NameType>("short"); - // ::= t # unsigned short - case 't': - ++First; - return make<NameType>("unsigned short"); - // ::= i # int - case 'i': - ++First; - return make<NameType>("int"); - // ::= j # unsigned int - case 'j': - ++First; - return make<NameType>("unsigned int"); - // ::= l # long - case 'l': - ++First; - return make<NameType>("long"); - // ::= m # unsigned long - case 'm': - ++First; - return make<NameType>("unsigned long"); - // ::= x # long long, __int64 - case 'x': - ++First; - return make<NameType>("long long"); - // ::= y # unsigned long long, __int64 - case 'y': - ++First; - return make<NameType>("unsigned long long"); - // ::= n # __int128 - case 'n': - ++First; - return make<NameType>("__int128"); - // ::= o # unsigned __int128 - case 'o': - ++First; - return make<NameType>("unsigned __int128"); - // ::= f # float - case 'f': - ++First; - return make<NameType>("float"); - // ::= d # double - case 'd': - ++First; - return make<NameType>("double"); - // ::= e # long double, __float80 - case 'e': - ++First; - return make<NameType>("long double"); - // ::= g # __float128 - case 'g': - ++First; - return make<NameType>("__float128"); - // ::= z # ellipsis - case 'z': - ++First; - return make<NameType>("..."); - - // <builtin-type> ::= u <source-name> # vendor extended type - case 'u': { - ++First; - StringView Res = parseBareSourceName(); - if (Res.empty()) - return nullptr; - // Typically, <builtin-type>s are not considered substitution candidates, - // but the exception to that exception is vendor extended types (Itanium C++ - // ABI 5.9.1). - Result = make<NameType>(Res); - break; - } - case 'D': - switch (look(1)) { - // ::= Dd # IEEE 754r decimal floating point (64 bits) - case 'd': - First += 2; - return make<NameType>("decimal64"); - // ::= De # IEEE 754r decimal floating point (128 bits) - case 'e': - First += 2; - return make<NameType>("decimal128"); - // ::= Df # IEEE 754r decimal floating point (32 bits) - case 'f': - First += 2; - return make<NameType>("decimal32"); - // ::= Dh # IEEE 754r half-precision floating point (16 bits) - case 'h': - First += 2; - return make<NameType>("half"); - // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits) - case 'F': { - First += 2; - Node *DimensionNumber = make<NameType>(parseNumber()); - if (!DimensionNumber) - return nullptr; - if (!consumeIf('_')) - return nullptr; - return make<BinaryFPType>(DimensionNumber); - } - // ::= DB <number> _ # C23 signed _BitInt(N) - // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N) - // ::= DU <number> _ # C23 unsigned _BitInt(N) - // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N) - case 'B': - case 'U': { - bool Signed = look(1) == 'B'; - First += 2; - Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber()) - : getDerived().parseExpr(); - if (!Size) - return nullptr; - if (!consumeIf('_')) - return nullptr; - return make<BitIntType>(Size, Signed); - } - // ::= Di # char32_t - case 'i': - First += 2; - return make<NameType>("char32_t"); - // ::= Ds # char16_t - case 's': - First += 2; - return make<NameType>("char16_t"); - // ::= Du # char8_t (C++2a, not yet in the Itanium spec) - case 'u': - First += 2; - return make<NameType>("char8_t"); - // ::= Da # auto (in dependent new-expressions) - case 'a': - First += 2; - return make<NameType>("auto"); - // ::= Dc # decltype(auto) - case 'c': - First += 2; - return make<NameType>("decltype(auto)"); - // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) - case 'n': - First += 2; - return make<NameType>("std::nullptr_t"); - - // ::= <decltype> - case 't': - case 'T': { - Result = getDerived().parseDecltype(); - break; - } - // extension ::= <vector-type> # <vector-type> starts with Dv - case 'v': { - Result = getDerived().parseVectorType(); - break; - } - // ::= Dp <type> # pack expansion (C++0x) - case 'p': { - First += 2; - Node *Child = getDerived().parseType(); - if (!Child) - return nullptr; - Result = make<ParameterPackExpansion>(Child); - break; - } - // Exception specifier on a function type. - case 'o': - case 'O': - case 'w': - // Transaction safe function type. - case 'x': - Result = getDerived().parseFunctionType(); - break; - } - break; - // ::= <function-type> - case 'F': { - Result = getDerived().parseFunctionType(); - break; - } - // ::= <array-type> - case 'A': { - Result = getDerived().parseArrayType(); - break; - } - // ::= <pointer-to-member-type> - case 'M': { - Result = getDerived().parsePointerToMemberType(); - break; - } - // ::= <template-param> - case 'T': { - // This could be an elaborate type specifier on a <class-enum-type>. - if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') { - Result = getDerived().parseClassEnumType(); - break; - } - - Result = getDerived().parseTemplateParam(); - if (Result == nullptr) - return nullptr; - - // Result could be either of: - // <type> ::= <template-param> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (TryToParseTemplateArgs && look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Result, TA); - } - break; - } - // ::= P <type> # pointer - case 'P': { - ++First; - Node *Ptr = getDerived().parseType(); - if (Ptr == nullptr) - return nullptr; - Result = make<PointerType>(Ptr); - break; - } - // ::= R <type> # l-value reference - case 'R': { - ++First; - Node *Ref = getDerived().parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::LValue); - break; - } - // ::= O <type> # r-value reference (C++11) - case 'O': { - ++First; - Node *Ref = getDerived().parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::RValue); - break; - } - // ::= C <type> # complex pair (C99) - case 'C': { - ++First; - Node *P = getDerived().parseType(); - if (P == nullptr) - return nullptr; - Result = make<PostfixQualifiedType>(P, " complex"); - break; - } - // ::= G <type> # imaginary (C99) - case 'G': { - ++First; - Node *P = getDerived().parseType(); - if (P == nullptr) - return P; - Result = make<PostfixQualifiedType>(P, " imaginary"); - break; - } - // ::= <substitution> # See Compression below - case 'S': { - if (look(1) != 't') { - bool IsSubst = false; - Result = getDerived().parseUnscopedName(nullptr, &IsSubst); - if (!Result) - return nullptr; - - // Sub could be either of: - // <type> ::= <substitution> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { - if (!IsSubst) - Subs.push_back(Result); - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Result, TA); - } else if (IsSubst) { - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Result; - } - break; - } - DEMANGLE_FALLTHROUGH; - } - // ::= <class-enum-type> - default: { - Result = getDerived().parseClassEnumType(); - break; - } - } - - // If we parsed a type, insert it into the substitution table. Note that all - // <builtin-type>s and <substitution>s have already bailed out, because they - // don't get substitutions. - if (Result != nullptr) - Subs.push_back(Result); - return Result; -} - -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind, - Node::Prec Prec) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return nullptr; - return make<PrefixExpr>(Kind, E, Prec); -} - -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind, - Node::Prec Prec) { - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<BinaryExpr>(LHS, Kind, RHS, Prec); -} - -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); - if (!Tmp.empty() && consumeIf('E')) - return make<IntegerLiteral>(Lit, Tmp); - return nullptr; -} - -// <CV-Qualifiers> ::= [r] [V] [K] -template <typename Alloc, typename Derived> -Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() { - Qualifiers CVR = QualNone; - if (consumeIf('r')) - CVR |= QualRestrict; - if (consumeIf('V')) - CVR |= QualVolatile; - if (consumeIf('K')) - CVR |= QualConst; - return CVR; -} - -// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters -// ::= fpT # 'this' expression (not part of standard?) -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { - if (consumeIf("fpT")) - return make<NameType>("this"); - if (consumeIf("fp")) { - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - if (consumeIf("fL")) { - if (parseNumber().empty()) - return nullptr; - if (!consumeIf('p')) - return nullptr; - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - return nullptr; -} - -// cv <type> <expression> # conversion with one argument -// cv <type> _ <expression>* E # conversion with a different number of arguments -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() { - if (!consumeIf("cv")) - return nullptr; - Node *Ty; - { - ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false); - Ty = getDerived().parseType(); - } - - if (Ty == nullptr) - return nullptr; - - if (consumeIf('_')) { - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - NodeArray Exprs = popTrailingNodeArray(ExprsBegin); - return make<ConversionExpr>(Ty, Exprs); - } - - Node *E[1] = {getDerived().parseExpr()}; - if (E[0] == nullptr) - return nullptr; - return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1)); -} - -// <expr-primary> ::= L <type> <value number> E # integer literal -// ::= L <type> <value float> E # floating literal -// ::= L <string type> E # string literal -// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") -// ::= L <lambda type> E # lambda expression -// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) -// ::= L <mangled-name> E # external name -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { - if (!consumeIf('L')) - return nullptr; - switch (look()) { - case 'w': - ++First; - return getDerived().parseIntegerLiteral("wchar_t"); - case 'b': - if (consumeIf("b0E")) - return make<BoolExpr>(0); - if (consumeIf("b1E")) - return make<BoolExpr>(1); - return nullptr; - case 'c': - ++First; - return getDerived().parseIntegerLiteral("char"); - case 'a': - ++First; - return getDerived().parseIntegerLiteral("signed char"); - case 'h': - ++First; - return getDerived().parseIntegerLiteral("unsigned char"); - case 's': - ++First; - return getDerived().parseIntegerLiteral("short"); - case 't': - ++First; - return getDerived().parseIntegerLiteral("unsigned short"); - case 'i': - ++First; - return getDerived().parseIntegerLiteral(""); - case 'j': - ++First; - return getDerived().parseIntegerLiteral("u"); - case 'l': - ++First; - return getDerived().parseIntegerLiteral("l"); - case 'm': - ++First; - return getDerived().parseIntegerLiteral("ul"); - case 'x': - ++First; - return getDerived().parseIntegerLiteral("ll"); - case 'y': - ++First; - return getDerived().parseIntegerLiteral("ull"); - case 'n': - ++First; - return getDerived().parseIntegerLiteral("__int128"); - case 'o': - ++First; - return getDerived().parseIntegerLiteral("unsigned __int128"); - case 'f': - ++First; - return getDerived().template parseFloatingLiteral<float>(); - case 'd': - ++First; - return getDerived().template parseFloatingLiteral<double>(); - case 'e': - ++First; -#if defined(__powerpc__) || defined(__s390__) - // Handle cases where long doubles encoded with e have the same size - // and representation as doubles. - return getDerived().template parseFloatingLiteral<double>(); -#else - return getDerived().template parseFloatingLiteral<long double>(); -#endif - case '_': - if (consumeIf("_Z")) { - Node *R = getDerived().parseEncoding(); - if (R != nullptr && consumeIf('E')) - return R; - } - return nullptr; - case 'A': { - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - // FIXME: We need to include the string contents in the mangling. - if (consumeIf('E')) - return make<StringLiteral>(T); - return nullptr; - } - case 'D': - if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E'))) - return make<NameType>("nullptr"); - return nullptr; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - return nullptr; - case 'U': { - // FIXME: Should we support LUb... for block literals? - if (look(1) != 'l') - return nullptr; - Node *T = parseUnnamedTypeName(nullptr); - if (!T || !consumeIf('E')) - return nullptr; - return make<LambdaExpr>(T); - } - default: { - // might be named type - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - StringView N = parseNumber(/*AllowNegative=*/true); - if (N.empty()) - return nullptr; - if (!consumeIf('E')) - return nullptr; - return make<EnumLiteral>(T, N); - } - } -} - -// <braced-expression> ::= <expression> -// ::= di <field source-name> <braced-expression> # .name = expr -// ::= dx <index expression> <braced-expression> # [expr] = expr -// ::= dX <range begin expression> <range end expression> <braced-expression> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() { - if (look() == 'd') { - switch (look(1)) { - case 'i': { - First += 2; - Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr); - if (Field == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Field, Init, /*isArray=*/false); - } - case 'x': { - First += 2; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Index, Init, /*isArray=*/true); - } - case 'X': { - First += 2; - Node *RangeBegin = getDerived().parseExpr(); - if (RangeBegin == nullptr) - return nullptr; - Node *RangeEnd = getDerived().parseExpr(); - if (RangeEnd == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init); - } - } - } - return getDerived().parseExpr(); -} - -// (not yet in the spec) -// <fold-expr> ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { - if (!consumeIf('f')) - return nullptr; - - bool IsLeftFold = false, HasInitializer = false; - switch (look()) { - default: - return nullptr; - case 'L': - IsLeftFold = true; - HasInitializer = true; - break; - case 'R': - HasInitializer = true; - break; - case 'l': - IsLeftFold = true; - break; - case 'r': - break; - } - ++First; - - const auto *Op = parseOperatorEncoding(); - if (!Op) - return nullptr; - if (!(Op->getKind() == OperatorInfo::Binary - || (Op->getKind() == OperatorInfo::Member - && Op->getName().back() == '*'))) - return nullptr; - - Node *Pack = getDerived().parseExpr(); - if (Pack == nullptr) - return nullptr; - - Node *Init = nullptr; - if (HasInitializer) { - Init = getDerived().parseExpr(); - if (Init == nullptr) - return nullptr; - } - - if (IsLeftFold && Init) - std::swap(Pack, Init); - - return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init); -} - -// <expression> ::= mc <parameter type> <expr> [<offset number>] E -// -// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr( - Node::Prec Prec) { - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - Node *Expr = getDerived().parseExpr(); - if (!Expr) - return nullptr; - StringView Offset = getDerived().parseNumber(true); - if (!consumeIf('E')) - return nullptr; - return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec); -} - -// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E -// <union-selector> ::= _ [<number>] -// -// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() { - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - Node *Expr = getDerived().parseExpr(); - if (!Expr) - return nullptr; - StringView Offset = getDerived().parseNumber(true); - size_t SelectorsBegin = Names.size(); - while (consumeIf('_')) { - Node *Selector = make<NameType>(parseNumber()); - if (!Selector) - return nullptr; - Names.push_back(Selector); - } - bool OnePastTheEnd = consumeIf('p'); - if (!consumeIf('E')) - return nullptr; - return make<SubobjectExpr>( - Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); -} - -// <expression> ::= <unary operator-name> <expression> -// ::= <binary operator-name> <expression> <expression> -// ::= <ternary operator-name> <expression> <expression> <expression> -// ::= cl <expression>+ E # call -// ::= cv <type> <expression> # conversion with one argument -// ::= cv <type> _ <expression>* E # conversion with a different number of arguments -// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type -// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type -// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// ::= [gs] dl <expression> # delete expression -// ::= [gs] da <expression> # delete[] expression -// ::= pp_ <expression> # prefix ++ -// ::= mm_ <expression> # prefix -- -// ::= ti <type> # typeid (type) -// ::= te <expression> # typeid (expression) -// ::= dc <type> <expression> # dynamic_cast<type> (expression) -// ::= sc <type> <expression> # static_cast<type> (expression) -// ::= cc <type> <expression> # const_cast<type> (expression) -// ::= rc <type> <expression> # reinterpret_cast<type> (expression) -// ::= st <type> # sizeof (a type) -// ::= sz <expression> # sizeof (an expression) -// ::= at <type> # alignof (a type) -// ::= az <expression> # alignof (an expression) -// ::= nx <expression> # noexcept (expression) -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> # expr.name -// ::= pt <expression> <unresolved-name> # expr->name -// ::= ds <expression> <expression> # expr.*expr -// ::= sZ <template-param> # size of a parameter pack -// ::= sZ <function-param> # size of a function parameter pack -// ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template -// ::= sp <expression> # pack expansion -// ::= tw <expression> # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= <unresolved-name> # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -// ::= <expr-primary> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { - bool Global = consumeIf("gs"); - - const auto *Op = parseOperatorEncoding(); - if (Op) { - auto Sym = Op->getSymbol(); - switch (Op->getKind()) { - case OperatorInfo::Binary: - // Binary operator: lhs @ rhs - return getDerived().parseBinaryExpr(Sym, Op->getPrecedence()); - case OperatorInfo::Prefix: - // Prefix unary operator: @ expr - return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); - case OperatorInfo::Postfix: { - // Postfix unary operator: expr @ - if (consumeIf('_')) - return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<PostfixExpr>(Ex, Sym, Op->getPrecedence()); - } - case OperatorInfo::Array: { - // Array Index: lhs [ rhs ] - Node *Base = getDerived().parseExpr(); - if (Base == nullptr) - return nullptr; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return nullptr; - return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence()); - } - case OperatorInfo::Member: { - // Member access lhs @ rhs - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence()); - } - case OperatorInfo::New: { - // New - // # new (expr-list) type [(init)] - // [gs] nw <expression>* _ <type> [pi <expression>*] E - // # new[] (expr-list) type [(init)] - // [gs] na <expression>* _ <type> [pi <expression>*] E - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - bool HaveInits = consumeIf("pi"); - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - if (!HaveInits) - return nullptr; - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make<NewExpr>(ExprList, Ty, Inits, Global, - /*IsArray=*/Op->getFlag(), Op->getPrecedence()); - } - case OperatorInfo::Del: { - // Delete - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(), - Op->getPrecedence()); - } - case OperatorInfo::Call: { - // Function Call - Node *Callee = getDerived().parseExpr(); - if (Callee == nullptr) - return nullptr; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin), - Op->getPrecedence()); - } - case OperatorInfo::CCast: { - // C Cast: (type)expr - Node *Ty; - { - ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false); - Ty = getDerived().parseType(); - } - if (Ty == nullptr) - return nullptr; - - size_t ExprsBegin = Names.size(); - bool IsMany = consumeIf('_'); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - if (!IsMany) - break; - } - NodeArray Exprs = popTrailingNodeArray(ExprsBegin); - if (!IsMany && Exprs.size() != 1) - return nullptr; - return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence()); - } - case OperatorInfo::Conditional: { - // Conditional operator: expr ? expr : expr - Node *Cond = getDerived().parseExpr(); - if (Cond == nullptr) - return nullptr; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<ConditionalExpr>(Cond, LHS, RHS, Op->getPrecedence()); - } - case OperatorInfo::NamedCast: { - // Named cast operation, @<type>(expr) - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence()); - } - case OperatorInfo::OfIdOp: { - // [sizeof/alignof/typeid] ( <type>|<expr> ) - Node *Arg = - Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); - if (!Arg) - return nullptr; - return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence()); - } - case OperatorInfo::NameOnly: { - // Not valid as an expression operand. - return nullptr; - } - } - DEMANGLE_UNREACHABLE; - } - - if (numLeft() < 2) - return nullptr; - - if (look() == 'L') - return getDerived().parseExprPrimary(); - if (look() == 'T') - return getDerived().parseTemplateParam(); - if (look() == 'f') { - // Disambiguate a fold expression from a <function-param>. - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - if (consumeIf("il")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); - } - if (consumeIf("mc")) - return parsePointerToMemberConversionExpr(Node::Prec::Unary); - if (consumeIf("nx")) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary); - } - if (consumeIf("so")) - return parseSubobjectExpr(); - if (consumeIf("sp")) { - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make<ParameterPackExpansion>(Child); - } - if (consumeIf("sZ")) { - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make<SizeofParamPackExpr>(R); - } - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make<EnclosingExpr>("sizeof... ", FP); - } - if (consumeIf("sP")) { - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); - if (!Pack) - return nullptr; - return make<EnclosingExpr>("sizeof... ", Pack); - } - if (consumeIf("tl")) { - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); - } - if (consumeIf("tr")) - return make<NameType>("throw"); - if (consumeIf("tw")) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<ThrowExpr>(Ex); - } - if (consumeIf('u')) { - Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); - if (!Name) - return nullptr; - // Special case legacy __uuidof mangling. The 't' and 'z' appear where the - // standard encoding expects a <template-arg>, and would be otherwise be - // interpreted as <type> node 'short' or 'ellipsis'. However, neither - // __uuidof(short) nor __uuidof(...) can actually appear, so there is no - // actual conflict here. - bool IsUUID = false; - Node *UUID = nullptr; - if (Name->getBaseName() == "__uuidof") { - if (consumeIf('t')) { - UUID = getDerived().parseType(); - IsUUID = true; - } else if (consumeIf('z')) { - UUID = getDerived().parseExpr(); - IsUUID = true; - } - } - size_t ExprsBegin = Names.size(); - if (IsUUID) { - if (UUID == nullptr) - return nullptr; - Names.push_back(UUID); - } else { - while (!consumeIf('E')) { - Node *E = getDerived().parseTemplateArg(); - if (E == nullptr) - return E; - Names.push_back(E); - } - } - return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin), - Node::Prec::Postfix); - } - - // Only unresolved names remain. - return getDerived().parseUnresolvedName(Global); -} - -// <call-offset> ::= h <nv-offset> _ -// ::= v <v-offset> _ -// -// <nv-offset> ::= <offset number> -// # non-virtual base override -// -// <v-offset> ::= <offset number> _ <virtual offset number> -// # virtual base override, with vcall offset -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() { - // Just scan through the call offset, we never add this information into the - // output. - if (consumeIf('h')) - return parseNumber(true).empty() || !consumeIf('_'); - if (consumeIf('v')) - return parseNumber(true).empty() || !consumeIf('_') || - parseNumber(true).empty() || !consumeIf('_'); - return true; -} - -// <special-name> ::= TV <type> # virtual table -// ::= TT <type> # VTT structure (construction vtable index) -// ::= TI <type> # typeinfo structure -// ::= TS <type> # typeinfo name (null-terminated byte string) -// ::= Tc <call-offset> <call-offset> <base encoding> -// # base is the nominal target function of thunk -// # first call-offset is 'this' adjustment -// # second call-offset is result adjustment -// ::= T <call-offset> <base encoding> -// # base is the nominal target function of thunk -// # Guard variable for one-time initialization -// ::= GV <object name> -// # No <type> -// ::= TW <object name> # Thread-local wrapper -// ::= TH <object name> # Thread-local initialization -// ::= GR <object name> _ # First temporary -// ::= GR <object name> <seq-id> _ # Subsequent temporaries -// # construction vtable for second-in-first -// extension ::= TC <first type> <number> _ <second type> -// extension ::= GR <object name> # reference temporary for object -// extension ::= GI <module name> # module global initializer -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { - switch (look()) { - case 'T': - switch (look(1)) { - // TA <template-arg> # template parameter object - // - // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63 - case 'A': { - First += 2; - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - return make<SpecialName>("template parameter object for ", Arg); - } - // TV <type> # virtual table - case 'V': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("vtable for ", Ty); - } - // TT <type> # VTT structure (construction vtable index) - case 'T': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("VTT for ", Ty); - } - // TI <type> # typeinfo structure - case 'I': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo for ", Ty); - } - // TS <type> # typeinfo name (null-terminated byte string) - case 'S': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo name for ", Ty); - } - // Tc <call-offset> <call-offset> <base encoding> - case 'c': { - First += 2; - if (parseCallOffset() || parseCallOffset()) - return nullptr; - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr) - return nullptr; - return make<SpecialName>("covariant return thunk to ", Encoding); - } - // extension ::= TC <first type> <number> _ <second type> - // # construction vtable for second-in-first - case 'C': { - First += 2; - Node *FirstType = getDerived().parseType(); - if (FirstType == nullptr) - return nullptr; - if (parseNumber(true).empty() || !consumeIf('_')) - return nullptr; - Node *SecondType = getDerived().parseType(); - if (SecondType == nullptr) - return nullptr; - return make<CtorVtableSpecialName>(SecondType, FirstType); - } - // TW <object name> # Thread-local wrapper - case 'W': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local wrapper routine for ", Name); - } - // TH <object name> # Thread-local initialization - case 'H': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local initialization routine for ", Name); - } - // T <call-offset> <base encoding> - default: { - ++First; - bool IsVirt = look() == 'v'; - if (parseCallOffset()) - return nullptr; - Node *BaseEncoding = getDerived().parseEncoding(); - if (BaseEncoding == nullptr) - return nullptr; - if (IsVirt) - return make<SpecialName>("virtual thunk to ", BaseEncoding); - else - return make<SpecialName>("non-virtual thunk to ", BaseEncoding); - } - } - case 'G': - switch (look(1)) { - // GV <object name> # Guard variable for one-time initialization - case 'V': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("guard variable for ", Name); - } - // GR <object name> # reference temporary for object - // GR <object name> _ # First temporary - // GR <object name> <seq-id> _ # Subsequent temporaries - case 'R': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - size_t Count; - bool ParsedSeqId = !parseSeqId(&Count); - if (!consumeIf('_') && ParsedSeqId) - return nullptr; - return make<SpecialName>("reference temporary for ", Name); - } - // GI <module-name> v - case 'I': { - First += 2; - ModuleName *Module = nullptr; - if (getDerived().parseModuleNameOpt(Module)) - return nullptr; - if (Module == nullptr) - return nullptr; - return make<SpecialName>("initializer for module ", Module); - } - } - } - return nullptr; -} - -// <encoding> ::= <function name> <bare-function-type> -// ::= <data name> -// ::= <special-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { - // The template parameters of an encoding are unrelated to those of the - // enclosing context. - class SaveTemplateParams { - AbstractManglingParser *Parser; - decltype(TemplateParams) OldParams; - decltype(OuterTemplateParams) OldOuterParams; - - public: - SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { - OldParams = std::move(Parser->TemplateParams); - OldOuterParams = std::move(Parser->OuterTemplateParams); - Parser->TemplateParams.clear(); - Parser->OuterTemplateParams.clear(); - } - ~SaveTemplateParams() { - Parser->TemplateParams = std::move(OldParams); - Parser->OuterTemplateParams = std::move(OldOuterParams); - } - } SaveTemplateParams(this); - - if (look() == 'G' || look() == 'T') - return getDerived().parseSpecialName(); - - auto IsEndOfEncoding = [&] { - // The set of chars that can potentially follow an <encoding> (none of which - // can start a <type>). Enumerating these allows us to avoid speculative - // parsing. - return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_'; - }; - - NameState NameInfo(this); - Node *Name = getDerived().parseName(&NameInfo); - if (Name == nullptr) - return nullptr; - - if (resolveForwardTemplateRefs(NameInfo)) - return nullptr; - - if (IsEndOfEncoding()) - return Name; - - Node *Attrs = nullptr; - if (consumeIf("Ua9enable_ifI")) { - size_t BeforeArgs = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs)); - if (!Attrs) - return nullptr; - } - - Node *ReturnType = nullptr; - if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) { - ReturnType = getDerived().parseType(); - if (ReturnType == nullptr) - return nullptr; - } - - if (consumeIf('v')) - return make<FunctionEncoding>(ReturnType, Name, NodeArray(), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); - - size_t ParamsBegin = Names.size(); - do { - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - Names.push_back(Ty); - } while (!IsEndOfEncoding()); - - return make<FunctionEncoding>(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); -} - -template <class Float> -struct FloatData; - -template <> -struct FloatData<float> -{ - static const size_t mangled_size = 8; - static const size_t max_demangled_size = 24; - static constexpr const char* spec = "%af"; -}; - -template <> -struct FloatData<double> -{ - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static constexpr const char* spec = "%a"; -}; - -template <> -struct FloatData<long double> -{ -#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) || defined(__riscv) - static const size_t mangled_size = 32; -#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) - static const size_t mangled_size = 16; -#else - static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms -#endif - // `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes. - // 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits. - // Negatives are one character longer than positives. - // `0x1.` and `p` are constant, and exponents `+16383` and `-16382` are the - // same length. 1 sign bit, 112 mantissa bits, and 15 exponent bits == 128. - static const size_t max_demangled_size = 42; - static constexpr const char *spec = "%LaL"; -}; - -template <typename Alloc, typename Derived> -template <class Float> -Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() { - const size_t N = FloatData<Float>::mangled_size; - if (numLeft() <= N) - return nullptr; - StringView Data(First, First + N); - for (char C : Data) - if (!std::isxdigit(C)) - return nullptr; - First += N; - if (!consumeIf('E')) - return nullptr; - return make<FloatLiteralImpl<Float>>(Data); -} - -// <seq-id> ::= <0-9A-Z>+ -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) { - if (!(look() >= '0' && look() <= '9') && - !(look() >= 'A' && look() <= 'Z')) - return true; - - size_t Id = 0; - while (true) { - if (look() >= '0' && look() <= '9') { - Id *= 36; - Id += static_cast<size_t>(look() - '0'); - } else if (look() >= 'A' && look() <= 'Z') { - Id *= 36; - Id += static_cast<size_t>(look() - 'A') + 10; - } else { - *Out = Id; - return false; - } - ++First; - } -} - -// <substitution> ::= S <seq-id> _ -// ::= S_ -// <substitution> ::= Sa # ::std::allocator -// <substitution> ::= Sb # ::std::basic_string -// <substitution> ::= Ss # ::std::basic_string < char, -// ::std::char_traits<char>, -// ::std::allocator<char> > -// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > -// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > -// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > -// The St case is handled specially in parseNestedName. -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { - if (!consumeIf('S')) - return nullptr; - - if (look() >= 'a' && look() <= 'z') { - SpecialSubKind Kind; - switch (look()) { - case 'a': - Kind = SpecialSubKind::allocator; - break; - case 'b': - Kind = SpecialSubKind::basic_string; - break; - case 'd': - Kind = SpecialSubKind::iostream; - break; - case 'i': - Kind = SpecialSubKind::istream; - break; - case 'o': - Kind = SpecialSubKind::ostream; - break; - case 's': - Kind = SpecialSubKind::string; - break; - default: - return nullptr; - } - ++First; - auto *SpecialSub = make<SpecialSubstitution>(Kind); - if (!SpecialSub) - return nullptr; - - // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> - // has ABI tags, the tags are appended to the substitution; the result is a - // substitutable component. - Node *WithTags = getDerived().parseAbiTags(SpecialSub); - if (WithTags != SpecialSub) { - Subs.push_back(WithTags); - SpecialSub = WithTags; - } - return SpecialSub; - } - - // ::= S_ - if (consumeIf('_')) { - if (Subs.empty()) - return nullptr; - return Subs[0]; - } - - // ::= S <seq-id> _ - size_t Index = 0; - if (parseSeqId(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_') || Index >= Subs.size()) - return nullptr; - return Subs[Index]; -} - -// <template-param> ::= T_ # first template parameter -// ::= T <parameter-2 non-negative number> _ -// ::= TL <level-1> __ -// ::= TL <level-1> _ <parameter-2 non-negative number> _ -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { - if (!consumeIf('T')) - return nullptr; - - size_t Level = 0; - if (consumeIf('L')) { - if (parsePositiveInteger(&Level)) - return nullptr; - ++Level; - if (!consumeIf('_')) - return nullptr; - } - - size_t Index = 0; - if (!consumeIf('_')) { - if (parsePositiveInteger(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_')) - return nullptr; - } - - // If we're in a context where this <template-param> refers to a - // <template-arg> further ahead in the mangled name (currently just conversion - // operator types), then we should only look it up in the right context. - // This can only happen at the outermost level. - if (PermitForwardTemplateReferences && Level == 0) { - Node *ForwardRef = make<ForwardTemplateReference>(Index); - if (!ForwardRef) - return nullptr; - assert(ForwardRef->getKind() == Node::KForwardTemplateReference); - ForwardTemplateRefs.push_back( - static_cast<ForwardTemplateReference *>(ForwardRef)); - return ForwardRef; - } - - if (Level >= TemplateParams.size() || !TemplateParams[Level] || - Index >= TemplateParams[Level]->size()) { - // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter - // list are mangled as the corresponding artificial template type parameter. - if (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) { - // This will be popped by the ScopedTemplateParamList in - // parseUnnamedTypeName. - if (Level == TemplateParams.size()) - TemplateParams.push_back(nullptr); - return make<NameType>("auto"); - } - - return nullptr; - } - - return (*TemplateParams[Level])[Index]; -} - -// <template-param-decl> ::= Ty # type parameter -// ::= Tn <type> # non-type parameter -// ::= Tt <template-param-decl>* E # template parameter -// ::= Tp <template-param-decl> # parameter pack -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { - auto InventTemplateParamName = [&](TemplateParamKind Kind) { - unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; - Node *N = make<SyntheticTemplateParamName>(Kind, Index); - if (N) TemplateParams.back()->push_back(N); - return N; - }; - - if (consumeIf("Ty")) { - Node *Name = InventTemplateParamName(TemplateParamKind::Type); - if (!Name) - return nullptr; - return make<TypeTemplateParamDecl>(Name); - } - - if (consumeIf("Tn")) { - Node *Name = InventTemplateParamName(TemplateParamKind::NonType); - if (!Name) - return nullptr; - Node *Type = parseType(); - if (!Type) - return nullptr; - return make<NonTypeTemplateParamDecl>(Name, Type); - } - - if (consumeIf("Tt")) { - Node *Name = InventTemplateParamName(TemplateParamKind::Template); - if (!Name) - return nullptr; - size_t ParamsBegin = Names.size(); - ScopedTemplateParamList TemplateTemplateParamParams(this); - while (!consumeIf("E")) { - Node *P = parseTemplateParamDecl(); - if (!P) - return nullptr; - Names.push_back(P); - } - NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make<TemplateTemplateParamDecl>(Name, Params); - } - - if (consumeIf("Tp")) { - Node *P = parseTemplateParamDecl(); - if (!P) - return nullptr; - return make<TemplateParamPackDecl>(P); - } - - return nullptr; -} - -// <template-arg> ::= <type> # type or template -// ::= X <expression> E # expression -// ::= <expr-primary> # simple expressions -// ::= J <template-arg>* E # argument pack -// ::= LZ <encoding> E # extension -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() { - switch (look()) { - case 'X': { - ++First; - Node *Arg = getDerived().parseExpr(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - case 'J': { - ++First; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - NodeArray Args = popTrailingNodeArray(ArgsBegin); - return make<TemplateArgumentPack>(Args); - } - case 'L': { - // ::= LZ <encoding> E # extension - if (look(1) == 'Z') { - First += 2; - Node *Arg = getDerived().parseEncoding(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - // ::= <expr-primary> # simple expressions - return getDerived().parseExprPrimary(); - } - default: - return getDerived().parseType(); - } -} - -// <template-args> ::= I <template-arg>* E -// extension, the abi says <template-arg>+ -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { - if (!consumeIf('I')) - return nullptr; - - // <template-params> refer to the innermost <template-args>. Clear out any - // outer args that we may have inserted into TemplateParams. - if (TagTemplates) { - TemplateParams.clear(); - TemplateParams.push_back(&OuterTemplateParams); - OuterTemplateParams.clear(); - } - - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - if (TagTemplates) { - auto OldParams = std::move(TemplateParams); - Node *Arg = getDerived().parseTemplateArg(); - TemplateParams = std::move(OldParams); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - Node *TableEntry = Arg; - if (Arg->getKind() == Node::KTemplateArgumentPack) { - TableEntry = make<ParameterPack>( - static_cast<TemplateArgumentPack*>(TableEntry)->getElements()); - if (!TableEntry) - return nullptr; - } - TemplateParams.back()->push_back(TableEntry); - } else { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - } - return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); -} - -// <mangled-name> ::= _Z <encoding> -// ::= <type> -// extension ::= ___Z <encoding> _block_invoke -// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+ -// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+ -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parse() { - if (consumeIf("_Z") || consumeIf("__Z")) { - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr) - return nullptr; - if (look() == '.') { - Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); - First = Last; - } - if (numLeft() != 0) - return nullptr; - return Encoding; - } - - if (consumeIf("___Z") || consumeIf("____Z")) { - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf("_block_invoke")) - return nullptr; - bool RequireNumber = consumeIf('_'); - if (parseNumber().empty() && RequireNumber) - return nullptr; - if (look() == '.') - First = Last; - if (numLeft() != 0) - return nullptr; - return make<SpecialName>("invocation function for block in ", Encoding); - } - - Node *Ty = getDerived().parseType(); - if (numLeft() != 0) - return nullptr; - return Ty; -} - -template <typename Alloc> -struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> { - using AbstractManglingParser<ManglingParser<Alloc>, - Alloc>::AbstractManglingParser; -}; - -DEMANGLE_NAMESPACE_END - -#endif // DEMANGLE_ITANIUMDEMANGLE_H diff --git a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def b/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def deleted file mode 100644 index c0e277d5..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def +++ /dev/null @@ -1,95 +0,0 @@ -//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===// -// Do not edit! See README.txt. -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Define the demangler's node names - -#ifndef NODE -#error Define NODE to handle nodes -#endif - -NODE(NodeArrayNode) -NODE(DotSuffix) -NODE(VendorExtQualType) -NODE(QualType) -NODE(ConversionOperatorType) -NODE(PostfixQualifiedType) -NODE(ElaboratedTypeSpefType) -NODE(NameType) -NODE(AbiTagAttr) -NODE(EnableIfAttr) -NODE(ObjCProtoName) -NODE(PointerType) -NODE(ReferenceType) -NODE(PointerToMemberType) -NODE(ArrayType) -NODE(FunctionType) -NODE(NoexceptSpec) -NODE(DynamicExceptionSpec) -NODE(FunctionEncoding) -NODE(LiteralOperator) -NODE(SpecialName) -NODE(CtorVtableSpecialName) -NODE(QualifiedName) -NODE(NestedName) -NODE(LocalName) -NODE(ModuleName) -NODE(ModuleEntity) -NODE(VectorType) -NODE(PixelVectorType) -NODE(BinaryFPType) -NODE(BitIntType) -NODE(SyntheticTemplateParamName) -NODE(TypeTemplateParamDecl) -NODE(NonTypeTemplateParamDecl) -NODE(TemplateTemplateParamDecl) -NODE(TemplateParamPackDecl) -NODE(ParameterPack) -NODE(TemplateArgumentPack) -NODE(ParameterPackExpansion) -NODE(TemplateArgs) -NODE(ForwardTemplateReference) -NODE(NameWithTemplateArgs) -NODE(GlobalQualifiedName) -NODE(ExpandedSpecialSubstitution) -NODE(SpecialSubstitution) -NODE(CtorDtorName) -NODE(DtorName) -NODE(UnnamedTypeName) -NODE(ClosureTypeName) -NODE(StructuredBindingName) -NODE(BinaryExpr) -NODE(ArraySubscriptExpr) -NODE(PostfixExpr) -NODE(ConditionalExpr) -NODE(MemberExpr) -NODE(SubobjectExpr) -NODE(EnclosingExpr) -NODE(CastExpr) -NODE(SizeofParamPackExpr) -NODE(CallExpr) -NODE(NewExpr) -NODE(DeleteExpr) -NODE(PrefixExpr) -NODE(FunctionParam) -NODE(ConversionExpr) -NODE(PointerToMemberConversionExpr) -NODE(InitListExpr) -NODE(FoldExpr) -NODE(ThrowExpr) -NODE(BoolExpr) -NODE(StringLiteral) -NODE(LambdaExpr) -NODE(EnumLiteral) -NODE(IntegerLiteral) -NODE(FloatLiteral) -NODE(DoubleLiteral) -NODE(LongDoubleLiteral) -NODE(BracedExpr) -NODE(BracedRangeExpr) - -#undef NODE diff --git a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h deleted file mode 100644 index f1a5e1b6..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ /dev/null @@ -1,276 +0,0 @@ -//===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H -#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H - -#include "llvm/Demangle/MicrosoftDemangleNodes.h" -#include "llvm/Demangle/StringView.h" - -#include <utility> - -namespace llvm { -namespace ms_demangle { -// This memory allocator is extremely fast, but it doesn't call dtors -// for allocated objects. That means you can't use STL containers -// (such as std::vector) with this allocator. But it pays off -- -// the demangler is 3x faster with this allocator compared to one with -// STL containers. -constexpr size_t AllocUnit = 4096; - -class ArenaAllocator { - struct AllocatorNode { - uint8_t *Buf = nullptr; - size_t Used = 0; - size_t Capacity = 0; - AllocatorNode *Next = nullptr; - }; - - void addNode(size_t Capacity) { - AllocatorNode *NewHead = new AllocatorNode; - NewHead->Buf = new uint8_t[Capacity]; - NewHead->Next = Head; - NewHead->Capacity = Capacity; - Head = NewHead; - NewHead->Used = 0; - } - -public: - ArenaAllocator() { addNode(AllocUnit); } - - ~ArenaAllocator() { - while (Head) { - assert(Head->Buf); - delete[] Head->Buf; - AllocatorNode *Next = Head->Next; - delete Head; - Head = Next; - } - } - - char *allocUnalignedBuffer(size_t Size) { - assert(Head && Head->Buf); - - uint8_t *P = Head->Buf + Head->Used; - - Head->Used += Size; - if (Head->Used <= Head->Capacity) - return reinterpret_cast<char *>(P); - - addNode(std::max(AllocUnit, Size)); - Head->Used = Size; - return reinterpret_cast<char *>(Head->Buf); - } - - template <typename T, typename... Args> T *allocArray(size_t Count) { - size_t Size = Count * sizeof(T); - assert(Head && Head->Buf); - - size_t P = (size_t)Head->Buf + Head->Used; - uintptr_t AlignedP = - (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); - uint8_t *PP = (uint8_t *)AlignedP; - size_t Adjustment = AlignedP - P; - - Head->Used += Size + Adjustment; - if (Head->Used <= Head->Capacity) - return new (PP) T[Count](); - - addNode(std::max(AllocUnit, Size)); - Head->Used = Size; - return new (Head->Buf) T[Count](); - } - - template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) { - constexpr size_t Size = sizeof(T); - assert(Head && Head->Buf); - - size_t P = (size_t)Head->Buf + Head->Used; - uintptr_t AlignedP = - (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1)); - uint8_t *PP = (uint8_t *)AlignedP; - size_t Adjustment = AlignedP - P; - - Head->Used += Size + Adjustment; - if (Head->Used <= Head->Capacity) - return new (PP) T(std::forward<Args>(ConstructorArgs)...); - - static_assert(Size < AllocUnit); - addNode(AllocUnit); - Head->Used = Size; - return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...); - } - -private: - AllocatorNode *Head = nullptr; -}; - -struct BackrefContext { - static constexpr size_t Max = 10; - - TypeNode *FunctionParams[Max]; - size_t FunctionParamCount = 0; - - // The first 10 BackReferences in a mangled name can be back-referenced by - // special name @[0-9]. This is a storage for the first 10 BackReferences. - NamedIdentifierNode *Names[Max]; - size_t NamesCount = 0; -}; - -enum class QualifierMangleMode { Drop, Mangle, Result }; - -enum NameBackrefBehavior : uint8_t { - NBB_None = 0, // don't save any names as backrefs. - NBB_Template = 1 << 0, // save template instanations. - NBB_Simple = 1 << 1, // save simple names. -}; - -enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder }; - -// Demangler class takes the main role in demangling symbols. -// It has a set of functions to parse mangled symbols into Type instances. -// It also has a set of functions to convert Type instances to strings. -class Demangler { -public: - Demangler() = default; - virtual ~Demangler() = default; - - // You are supposed to call parse() first and then check if error is true. If - // it is false, call output() to write the formatted name to the given stream. - SymbolNode *parse(StringView &MangledName); - - TagTypeNode *parseTagUniqueName(StringView &MangledName); - - // True if an error occurred. - bool Error = false; - - void dumpBackReferences(); - -private: - SymbolNode *demangleEncodedSymbol(StringView &MangledName, - QualifiedNameNode *QN); - SymbolNode *demangleDeclarator(StringView &MangledName); - SymbolNode *demangleMD5Name(StringView &MangledName); - SymbolNode *demangleTypeinfoName(StringView &MangledName); - - VariableSymbolNode *demangleVariableEncoding(StringView &MangledName, - StorageClass SC); - FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName); - - Qualifiers demanglePointerExtQualifiers(StringView &MangledName); - - // Parser functions. This is a recursive-descent parser. - TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM); - PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName); - CustomTypeNode *demangleCustomType(StringView &MangledName); - TagTypeNode *demangleClassType(StringView &MangledName); - PointerTypeNode *demanglePointerType(StringView &MangledName); - PointerTypeNode *demangleMemberPointerType(StringView &MangledName); - FunctionSignatureNode *demangleFunctionType(StringView &MangledName, - bool HasThisQuals); - - ArrayTypeNode *demangleArrayType(StringView &MangledName); - - NodeArrayNode *demangleFunctionParameterList(StringView &MangledName, - bool &IsVariadic); - NodeArrayNode *demangleTemplateParameterList(StringView &MangledName); - - std::pair<uint64_t, bool> demangleNumber(StringView &MangledName); - uint64_t demangleUnsigned(StringView &MangledName); - int64_t demangleSigned(StringView &MangledName); - - void memorizeString(StringView s); - void memorizeIdentifier(IdentifierNode *Identifier); - - /// Allocate a copy of \p Borrowed into memory that we own. - StringView copyString(StringView Borrowed); - - QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName); - QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName); - - IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName, - bool Memorize); - IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName, - NameBackrefBehavior NBB); - - QualifiedNameNode *demangleNameScopeChain(StringView &MangledName, - IdentifierNode *UnqualifiedName); - IdentifierNode *demangleNameScopePiece(StringView &MangledName); - - NamedIdentifierNode *demangleBackRefName(StringView &MangledName); - IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName, - NameBackrefBehavior NBB); - IntrinsicFunctionKind - translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group); - IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName); - IdentifierNode * - demangleFunctionIdentifierCode(StringView &MangledName, - FunctionIdentifierCodeGroup Group); - StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName, - bool IsDestructor); - ConversionOperatorIdentifierNode * - demangleConversionOperatorIdentifier(StringView &MangledName); - LiteralOperatorIdentifierNode * - demangleLiteralOperatorIdentifier(StringView &MangledName); - - SymbolNode *demangleSpecialIntrinsic(StringView &MangledName); - SpecialTableSymbolNode * - demangleSpecialTableSymbolNode(StringView &MangledName, - SpecialIntrinsicKind SIK); - LocalStaticGuardVariableNode * - demangleLocalStaticGuard(StringView &MangledName, bool IsThread); - VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, - StringView &MangledName, - StringView VariableName); - VariableSymbolNode * - demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, - StringView &MangledName); - FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName, - bool IsDestructor); - - NamedIdentifierNode *demangleSimpleName(StringView &MangledName, - bool Memorize); - NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName); - NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName); - EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName); - FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName); - - StringView demangleSimpleString(StringView &MangledName, bool Memorize); - - FuncClass demangleFunctionClass(StringView &MangledName); - CallingConv demangleCallingConvention(StringView &MangledName); - StorageClass demangleVariableStorageClass(StringView &MangledName); - bool demangleThrowSpecification(StringView &MangledName); - wchar_t demangleWcharLiteral(StringView &MangledName); - uint8_t demangleCharLiteral(StringView &MangledName); - - std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName); - - // Memory allocator. - ArenaAllocator Arena; - - // A single type uses one global back-ref table for all function params. - // This means back-refs can even go "into" other types. Examples: - // - // // Second int* is a back-ref to first. - // void foo(int *, int*); - // - // // Second int* is not a back-ref to first (first is not a function param). - // int* foo(int*); - // - // // Second int* is a back-ref to first (ALL function types share the same - // // back-ref map. - // using F = void(*)(int*); - // F G(int *); - BackrefContext Backrefs; -}; - -} // namespace ms_demangle -} // namespace llvm - -#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H diff --git a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h deleted file mode 100644 index 8ad24723..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ /dev/null @@ -1,629 +0,0 @@ -//===- MicrosoftDemangleNodes.h ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the AST nodes used in the MSVC demangler. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H -#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H - -#include "llvm/Demangle/StringView.h" -#include <array> -#include <cstdint> -#include <string> - -namespace llvm { -namespace itanium_demangle { -class OutputBuffer; -} -} - -using llvm::itanium_demangle::OutputBuffer; -using llvm::itanium_demangle::StringView; - -namespace llvm { -namespace ms_demangle { - -// Storage classes -enum Qualifiers : uint8_t { - Q_None = 0, - Q_Const = 1 << 0, - Q_Volatile = 1 << 1, - Q_Far = 1 << 2, - Q_Huge = 1 << 3, - Q_Unaligned = 1 << 4, - Q_Restrict = 1 << 5, - Q_Pointer64 = 1 << 6 -}; - -enum class StorageClass : uint8_t { - None, - PrivateStatic, - ProtectedStatic, - PublicStatic, - Global, - FunctionLocalStatic, -}; - -enum class PointerAffinity { None, Pointer, Reference, RValueReference }; -enum class FunctionRefQualifier { None, Reference, RValueReference }; - -// Calling conventions -enum class CallingConv : uint8_t { - None, - Cdecl, - Pascal, - Thiscall, - Stdcall, - Fastcall, - Clrcall, - Eabi, - Vectorcall, - Regcall, - Swift, // Clang-only - SwiftAsync, // Clang-only -}; - -enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef }; - -enum OutputFlags { - OF_Default = 0, - OF_NoCallingConvention = 1, - OF_NoTagSpecifier = 2, - OF_NoAccessSpecifier = 4, - OF_NoMemberType = 8, - OF_NoReturnType = 16, - OF_NoVariableType = 32, -}; - -// Types -enum class PrimitiveKind { - Void, - Bool, - Char, - Schar, - Uchar, - Char8, - Char16, - Char32, - Short, - Ushort, - Int, - Uint, - Long, - Ulong, - Int64, - Uint64, - Wchar, - Float, - Double, - Ldouble, - Nullptr, -}; - -enum class CharKind { - Char, - Char16, - Char32, - Wchar, -}; - -enum class IntrinsicFunctionKind : uint8_t { - None, - New, // ?2 # operator new - Delete, // ?3 # operator delete - Assign, // ?4 # operator= - RightShift, // ?5 # operator>> - LeftShift, // ?6 # operator<< - LogicalNot, // ?7 # operator! - Equals, // ?8 # operator== - NotEquals, // ?9 # operator!= - ArraySubscript, // ?A # operator[] - Pointer, // ?C # operator-> - Dereference, // ?D # operator* - Increment, // ?E # operator++ - Decrement, // ?F # operator-- - Minus, // ?G # operator- - Plus, // ?H # operator+ - BitwiseAnd, // ?I # operator& - MemberPointer, // ?J # operator->* - Divide, // ?K # operator/ - Modulus, // ?L # operator% - LessThan, // ?M operator< - LessThanEqual, // ?N operator<= - GreaterThan, // ?O operator> - GreaterThanEqual, // ?P operator>= - Comma, // ?Q operator, - Parens, // ?R operator() - BitwiseNot, // ?S operator~ - BitwiseXor, // ?T operator^ - BitwiseOr, // ?U operator| - LogicalAnd, // ?V operator&& - LogicalOr, // ?W operator|| - TimesEqual, // ?X operator*= - PlusEqual, // ?Y operator+= - MinusEqual, // ?Z operator-= - DivEqual, // ?_0 operator/= - ModEqual, // ?_1 operator%= - RshEqual, // ?_2 operator>>= - LshEqual, // ?_3 operator<<= - BitwiseAndEqual, // ?_4 operator&= - BitwiseOrEqual, // ?_5 operator|= - BitwiseXorEqual, // ?_6 operator^= - VbaseDtor, // ?_D # vbase destructor - VecDelDtor, // ?_E # vector deleting destructor - DefaultCtorClosure, // ?_F # default constructor closure - ScalarDelDtor, // ?_G # scalar deleting destructor - VecCtorIter, // ?_H # vector constructor iterator - VecDtorIter, // ?_I # vector destructor iterator - VecVbaseCtorIter, // ?_J # vector vbase constructor iterator - VdispMap, // ?_K # virtual displacement map - EHVecCtorIter, // ?_L # eh vector constructor iterator - EHVecDtorIter, // ?_M # eh vector destructor iterator - EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator - CopyCtorClosure, // ?_O # copy constructor closure - LocalVftableCtorClosure, // ?_T # local vftable constructor closure - ArrayNew, // ?_U operator new[] - ArrayDelete, // ?_V operator delete[] - ManVectorCtorIter, // ?__A managed vector ctor iterator - ManVectorDtorIter, // ?__B managed vector dtor iterator - EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator - EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iterator - VectorCopyCtorIter, // ?__G vector copy constructor iterator - VectorVbaseCopyCtorIter, // ?__H vector vbase copy constructor iterator - ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor - CoAwait, // ?__L operator co_await - Spaceship, // ?__M operator<=> - MaxIntrinsic -}; - -enum class SpecialIntrinsicKind { - None, - Vftable, - Vbtable, - Typeof, - VcallThunk, - LocalStaticGuard, - StringLiteralSymbol, - UdtReturning, - Unknown, - DynamicInitializer, - DynamicAtexitDestructor, - RttiTypeDescriptor, - RttiBaseClassDescriptor, - RttiBaseClassArray, - RttiClassHierarchyDescriptor, - RttiCompleteObjLocator, - LocalVftable, - LocalStaticThreadGuard, -}; - -// Function classes -enum FuncClass : uint16_t { - FC_None = 0, - FC_Public = 1 << 0, - FC_Protected = 1 << 1, - FC_Private = 1 << 2, - FC_Global = 1 << 3, - FC_Static = 1 << 4, - FC_Virtual = 1 << 5, - FC_Far = 1 << 6, - FC_ExternC = 1 << 7, - FC_NoParameterList = 1 << 8, - FC_VirtualThisAdjust = 1 << 9, - FC_VirtualThisAdjustEx = 1 << 10, - FC_StaticThisAdjust = 1 << 11, -}; - -enum class TagKind { Class, Struct, Union, Enum }; - -enum class NodeKind { - Unknown, - Md5Symbol, - PrimitiveType, - FunctionSignature, - Identifier, - NamedIdentifier, - VcallThunkIdentifier, - LocalStaticGuardIdentifier, - IntrinsicFunctionIdentifier, - ConversionOperatorIdentifier, - DynamicStructorIdentifier, - StructorIdentifier, - LiteralOperatorIdentifier, - ThunkSignature, - PointerType, - TagType, - ArrayType, - Custom, - IntrinsicType, - NodeArray, - QualifiedName, - TemplateParameterReference, - EncodedStringLiteral, - IntegerLiteral, - RttiBaseClassDescriptor, - LocalStaticGuardVariable, - FunctionSymbol, - VariableSymbol, - SpecialTableSymbol -}; - -struct Node { - explicit Node(NodeKind K) : Kind(K) {} - virtual ~Node() = default; - - NodeKind kind() const { return Kind; } - - virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0; - - std::string toString(OutputFlags Flags = OF_Default) const; - -private: - NodeKind Kind; -}; - -struct TypeNode; -struct PrimitiveTypeNode; -struct FunctionSignatureNode; -struct IdentifierNode; -struct NamedIdentifierNode; -struct VcallThunkIdentifierNode; -struct IntrinsicFunctionIdentifierNode; -struct LiteralOperatorIdentifierNode; -struct ConversionOperatorIdentifierNode; -struct StructorIdentifierNode; -struct ThunkSignatureNode; -struct PointerTypeNode; -struct ArrayTypeNode; -struct TagTypeNode; -struct NodeArrayNode; -struct QualifiedNameNode; -struct TemplateParameterReferenceNode; -struct EncodedStringLiteralNode; -struct IntegerLiteralNode; -struct RttiBaseClassDescriptorNode; -struct LocalStaticGuardVariableNode; -struct SymbolNode; -struct FunctionSymbolNode; -struct VariableSymbolNode; -struct SpecialTableSymbolNode; - -struct TypeNode : public Node { - explicit TypeNode(NodeKind K) : Node(K) {} - - virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0; - virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0; - - void output(OutputBuffer &OB, OutputFlags Flags) const override { - outputPre(OB, Flags); - outputPost(OB, Flags); - } - - Qualifiers Quals = Q_None; -}; - -struct PrimitiveTypeNode : public TypeNode { - explicit PrimitiveTypeNode(PrimitiveKind K) - : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {} - - PrimitiveKind PrimKind; -}; - -struct FunctionSignatureNode : public TypeNode { - explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {} - FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - // Valid if this FunctionTypeNode is the Pointee of a PointerType or - // MemberPointerType. - PointerAffinity Affinity = PointerAffinity::None; - - // The function's calling convention. - CallingConv CallConvention = CallingConv::None; - - // Function flags (gloabl, public, etc) - FuncClass FunctionClass = FC_Global; - - FunctionRefQualifier RefQualifier = FunctionRefQualifier::None; - - // The return type of the function. - TypeNode *ReturnType = nullptr; - - // True if this is a C-style ... varargs function. - bool IsVariadic = false; - - // Function parameters - NodeArrayNode *Params = nullptr; - - // True if the function type is noexcept. - bool IsNoexcept = false; -}; - -struct IdentifierNode : public Node { - explicit IdentifierNode(NodeKind K) : Node(K) {} - - NodeArrayNode *TemplateParams = nullptr; - -protected: - void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const; -}; - -struct VcallThunkIdentifierNode : public IdentifierNode { - VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - uint64_t OffsetInVTable = 0; -}; - -struct DynamicStructorIdentifierNode : public IdentifierNode { - DynamicStructorIdentifierNode() - : IdentifierNode(NodeKind::DynamicStructorIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - VariableSymbolNode *Variable = nullptr; - QualifiedNameNode *Name = nullptr; - bool IsDestructor = false; -}; - -struct NamedIdentifierNode : public IdentifierNode { - NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - StringView Name; -}; - -struct IntrinsicFunctionIdentifierNode : public IdentifierNode { - explicit IntrinsicFunctionIdentifierNode(IntrinsicFunctionKind Operator) - : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier), - Operator(Operator) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - IntrinsicFunctionKind Operator; -}; - -struct LiteralOperatorIdentifierNode : public IdentifierNode { - LiteralOperatorIdentifierNode() - : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - StringView Name; -}; - -struct LocalStaticGuardIdentifierNode : public IdentifierNode { - LocalStaticGuardIdentifierNode() - : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - bool IsThread = false; - uint32_t ScopeIndex = 0; -}; - -struct ConversionOperatorIdentifierNode : public IdentifierNode { - ConversionOperatorIdentifierNode() - : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - // The type that this operator converts too. - TypeNode *TargetType = nullptr; -}; - -struct StructorIdentifierNode : public IdentifierNode { - StructorIdentifierNode() : IdentifierNode(NodeKind::StructorIdentifier) {} - explicit StructorIdentifierNode(bool IsDestructor) - : IdentifierNode(NodeKind::StructorIdentifier), - IsDestructor(IsDestructor) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - // The name of the class that this is a structor of. - IdentifierNode *Class = nullptr; - bool IsDestructor = false; -}; - -struct ThunkSignatureNode : public FunctionSignatureNode { - ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - struct ThisAdjustor { - uint32_t StaticOffset = 0; - int32_t VBPtrOffset = 0; - int32_t VBOffsetOffset = 0; - int32_t VtordispOffset = 0; - }; - - ThisAdjustor ThisAdjust; -}; - -struct PointerTypeNode : public TypeNode { - PointerTypeNode() : TypeNode(NodeKind::PointerType) {} - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - // Is this a pointer, reference, or rvalue-reference? - PointerAffinity Affinity = PointerAffinity::None; - - // If this is a member pointer, this is the class that the member is in. - QualifiedNameNode *ClassParent = nullptr; - - // Represents a type X in "a pointer to X", "a reference to X", or - // "rvalue-reference to X" - TypeNode *Pointee = nullptr; -}; - -struct TagTypeNode : public TypeNode { - explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - QualifiedNameNode *QualifiedName = nullptr; - TagKind Tag; -}; - -struct ArrayTypeNode : public TypeNode { - ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const; - void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const; - - // A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]` - NodeArrayNode *Dimensions = nullptr; - - // The type of array element. - TypeNode *ElementType = nullptr; -}; - -struct IntrinsicNode : public TypeNode { - IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {} - void output(OutputBuffer &OB, OutputFlags Flags) const override {} -}; - -struct CustomTypeNode : public TypeNode { - CustomTypeNode() : TypeNode(NodeKind::Custom) {} - - void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; - void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - - IdentifierNode *Identifier = nullptr; -}; - -struct NodeArrayNode : public Node { - NodeArrayNode() : Node(NodeKind::NodeArray) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const; - - Node **Nodes = nullptr; - size_t Count = 0; -}; - -struct QualifiedNameNode : public Node { - QualifiedNameNode() : Node(NodeKind::QualifiedName) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - NodeArrayNode *Components = nullptr; - - IdentifierNode *getUnqualifiedIdentifier() { - Node *LastComponent = Components->Nodes[Components->Count - 1]; - return static_cast<IdentifierNode *>(LastComponent); - } -}; - -struct TemplateParameterReferenceNode : public Node { - TemplateParameterReferenceNode() - : Node(NodeKind::TemplateParameterReference) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - SymbolNode *Symbol = nullptr; - - int ThunkOffsetCount = 0; - std::array<int64_t, 3> ThunkOffsets; - PointerAffinity Affinity = PointerAffinity::None; - bool IsMemberPointer = false; -}; - -struct IntegerLiteralNode : public Node { - IntegerLiteralNode() : Node(NodeKind::IntegerLiteral) {} - IntegerLiteralNode(uint64_t Value, bool IsNegative) - : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - uint64_t Value = 0; - bool IsNegative = false; -}; - -struct RttiBaseClassDescriptorNode : public IdentifierNode { - RttiBaseClassDescriptorNode() - : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - uint32_t NVOffset = 0; - int32_t VBPtrOffset = 0; - uint32_t VBTableOffset = 0; - uint32_t Flags = 0; -}; - -struct SymbolNode : public Node { - explicit SymbolNode(NodeKind K) : Node(K) {} - void output(OutputBuffer &OB, OutputFlags Flags) const override; - QualifiedNameNode *Name = nullptr; -}; - -struct SpecialTableSymbolNode : public SymbolNode { - explicit SpecialTableSymbolNode() - : SymbolNode(NodeKind::SpecialTableSymbol) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - QualifiedNameNode *TargetName = nullptr; - Qualifiers Quals = Qualifiers::Q_None; -}; - -struct LocalStaticGuardVariableNode : public SymbolNode { - LocalStaticGuardVariableNode() - : SymbolNode(NodeKind::LocalStaticGuardVariable) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - bool IsVisible = false; -}; - -struct EncodedStringLiteralNode : public SymbolNode { - EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - StringView DecodedString; - bool IsTruncated = false; - CharKind Char = CharKind::Char; -}; - -struct VariableSymbolNode : public SymbolNode { - VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - StorageClass SC = StorageClass::None; - TypeNode *Type = nullptr; -}; - -struct FunctionSymbolNode : public SymbolNode { - FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {} - - void output(OutputBuffer &OB, OutputFlags Flags) const override; - - FunctionSignatureNode *Signature = nullptr; -}; - -} // namespace ms_demangle -} // namespace llvm - -#endif diff --git a/demangle/third_party/llvm/include/llvm/Demangle/StringView.h b/demangle/third_party/llvm/include/llvm/Demangle/StringView.h deleted file mode 100644 index 6bbb8837..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/StringView.h +++ /dev/null @@ -1,122 +0,0 @@ -//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===// -// Do not edit! See README.txt. -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// FIXME: Use std::string_view instead when we support C++17. -// There are two copies of this file in the source tree. The one under -// libcxxabi is the original and the one under llvm is the copy. Use -// cp-to-llvm.sh to update the copy. See README.txt for more details. -// -//===----------------------------------------------------------------------===// - -#ifndef DEMANGLE_STRINGVIEW_H -#define DEMANGLE_STRINGVIEW_H - -#include "DemangleConfig.h" -#include <cassert> -#include <cstring> - -DEMANGLE_NAMESPACE_BEGIN - -class StringView { - const char *First; - const char *Last; - -public: - static const size_t npos = ~size_t(0); - - template <size_t N> - StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} - StringView(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - StringView(const char *First_, size_t Len) - : First(First_), Last(First_ + Len) {} - StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} - StringView() : First(nullptr), Last(nullptr) {} - - StringView substr(size_t Pos, size_t Len = npos) const { - assert(Pos <= size()); - if (Len > size() - Pos) - Len = size() - Pos; - return StringView(begin() + Pos, Len); - } - - size_t find(char C, size_t From = 0) const { - // Avoid calling memchr with nullptr. - if (From < size()) { - // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + From, C, size() - From)) - return size_t(static_cast<const char *>(P) - First); - } - return npos; - } - - StringView dropFront(size_t N = 1) const { - if (N >= size()) - N = size(); - return StringView(First + N, Last); - } - - StringView dropBack(size_t N = 1) const { - if (N >= size()) - N = size(); - return StringView(First, Last - N); - } - - char front() const { - assert(!empty()); - return *begin(); - } - - char back() const { - assert(!empty()); - return *(end() - 1); - } - - char popFront() { - assert(!empty()); - return *First++; - } - - bool consumeFront(char C) { - if (!startsWith(C)) - return false; - *this = dropFront(1); - return true; - } - - bool consumeFront(StringView S) { - if (!startsWith(S)) - return false; - *this = dropFront(S.size()); - return true; - } - - bool startsWith(char C) const { return !empty() && *begin() == C; } - - bool startsWith(StringView Str) const { - if (Str.size() > size()) - return false; - return std::strncmp(Str.begin(), begin(), Str.size()) == 0; - } - - const char &operator[](size_t Idx) const { return *(begin() + Idx); } - - const char *begin() const { return First; } - const char *end() const { return Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - bool empty() const { return First == Last; } -}; - -inline bool operator==(const StringView &LHS, const StringView &RHS) { - return LHS.size() == RHS.size() && - std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; -} - -DEMANGLE_NAMESPACE_END - -#endif diff --git a/demangle/third_party/llvm/include/llvm/Demangle/Utility.h b/demangle/third_party/llvm/include/llvm/Demangle/Utility.h deleted file mode 100644 index 855c56e9..00000000 --- a/demangle/third_party/llvm/include/llvm/Demangle/Utility.h +++ /dev/null @@ -1,199 +0,0 @@ -//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===// -// Do not edit! See README.txt. -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Provide some utility classes for use in the demangler. -// There are two copies of this file in the source tree. The one in libcxxabi -// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update -// the copy. See README.txt for more details. -// -//===----------------------------------------------------------------------===// - -#ifndef DEMANGLE_UTILITY_H -#define DEMANGLE_UTILITY_H - -#include "StringView.h" -#include <array> -#include <cstdint> -#include <cstdlib> -#include <cstring> -#include <exception> -#include <limits> - -DEMANGLE_NAMESPACE_BEGIN - -// Stream that AST nodes write their string representation into after the AST -// has been parsed. -class OutputBuffer { - char *Buffer = nullptr; - size_t CurrentPosition = 0; - size_t BufferCapacity = 0; - - // Ensure there are at least N more positions in the buffer. - void grow(size_t N) { - size_t Need = N + CurrentPosition; - if (Need > BufferCapacity) { - // Reduce the number of reallocations, with a bit of hysteresis. The - // number here is chosen so the first allocation will more-than-likely not - // allocate more than 1K. - Need += 1024 - 32; - BufferCapacity *= 2; - if (BufferCapacity < Need) - BufferCapacity = Need; - Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); - if (Buffer == nullptr) - std::terminate(); - } - } - - OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { - std::array<char, 21> Temp; - char *TempPtr = Temp.data() + Temp.size(); - - // Output at least one character. - do { - *--TempPtr = char('0' + N % 10); - N /= 10; - } while (N); - - // Add negative sign. - if (isNeg) - *--TempPtr = '-'; - - return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); - } - -public: - OutputBuffer(char *StartBuf, size_t Size) - : Buffer(StartBuf), BufferCapacity(Size) {} - OutputBuffer(char *StartBuf, size_t *SizePtr) - : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} - OutputBuffer() = default; - // Non-copyable - OutputBuffer(const OutputBuffer &) = delete; - OutputBuffer &operator=(const OutputBuffer &) = delete; - - operator StringView() const { return StringView(Buffer, CurrentPosition); } - - /// If a ParameterPackExpansion (or similar type) is encountered, the offset - /// into the pack that we're currently printing. - unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); - unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); - - /// When zero, we're printing template args and '>' needs to be parenthesized. - /// Use a counter so we can simply increment inside parentheses. - unsigned GtIsGt = 1; - - bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } - - void printOpen(char Open = '(') { - GtIsGt++; - *this += Open; - } - void printClose(char Close = ')') { - GtIsGt--; - *this += Close; - } - - OutputBuffer &operator+=(StringView R) { - if (size_t Size = R.size()) { - grow(Size); - std::memcpy(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; - } - return *this; - } - - OutputBuffer &operator+=(char C) { - grow(1); - Buffer[CurrentPosition++] = C; - return *this; - } - - OutputBuffer &prepend(StringView R) { - size_t Size = R.size(); - - grow(Size); - std::memmove(Buffer + Size, Buffer, CurrentPosition); - std::memcpy(Buffer, R.begin(), Size); - CurrentPosition += Size; - - return *this; - } - - OutputBuffer &operator<<(StringView R) { return (*this += R); } - - OutputBuffer &operator<<(char C) { return (*this += C); } - - OutputBuffer &operator<<(long long N) { - return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0); - } - - OutputBuffer &operator<<(unsigned long long N) { - return writeUnsigned(N, false); - } - - OutputBuffer &operator<<(long N) { - return this->operator<<(static_cast<long long>(N)); - } - - OutputBuffer &operator<<(unsigned long N) { - return this->operator<<(static_cast<unsigned long long>(N)); - } - - OutputBuffer &operator<<(int N) { - return this->operator<<(static_cast<long long>(N)); - } - - OutputBuffer &operator<<(unsigned int N) { - return this->operator<<(static_cast<unsigned long long>(N)); - } - - void insert(size_t Pos, const char *S, size_t N) { - assert(Pos <= CurrentPosition); - if (N == 0) - return; - grow(N); - std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); - std::memcpy(Buffer + Pos, S, N); - CurrentPosition += N; - } - - size_t getCurrentPosition() const { return CurrentPosition; } - void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } - - char back() const { - assert(CurrentPosition); - return Buffer[CurrentPosition - 1]; - } - - bool empty() const { return CurrentPosition == 0; } - - char *getBuffer() { return Buffer; } - char *getBufferEnd() { return Buffer + CurrentPosition - 1; } - size_t getBufferCapacity() const { return BufferCapacity; } -}; - -template <class T> class ScopedOverride { - T &Loc; - T Original; - -public: - ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} - - ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { - Loc_ = std::move(NewVal); - } - ~ScopedOverride() { Loc = std::move(Original); } - - ScopedOverride(const ScopedOverride &) = delete; - ScopedOverride &operator=(const ScopedOverride &) = delete; -}; - -DEMANGLE_NAMESPACE_END - -#endif diff --git a/demangle/third_party/llvm/lib/Demangle/Demangle.cpp b/demangle/third_party/llvm/lib/Demangle/Demangle.cpp deleted file mode 100644 index b5f2369d..00000000 --- a/demangle/third_party/llvm/lib/Demangle/Demangle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- Demangle.cpp - Common demangling functions ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file This file contains definitions of common demangling functions. -/// -//===----------------------------------------------------------------------===// - -#include "llvm/Demangle/Demangle.h" -#include <cstdlib> -#include <cstring> - -static bool isItaniumEncoding(const char *S) { - // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'. - return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0; -} - -#if 0 -static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; } - -static bool isDLangEncoding(const std::string &MangledName) { - return MangledName.size() >= 2 && MangledName[0] == '_' && - MangledName[1] == 'D'; -} -#endif - -std::string llvm::demangle(const std::string &MangledName) { - std::string Result; - const char *S = MangledName.c_str(); - - if (nonMicrosoftDemangle(S, Result)) - return Result; - - if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result)) - return Result; - - if (char *Demangled = - microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) { - Result = Demangled; - std::free(Demangled); - return Result; - } - - return MangledName; -} - -bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) { - char *Demangled = nullptr; - if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr); -#if 0 - else if (isRustEncoding(MangledName)) - Demangled = rustDemangle(MangledName); - else if (isDLangEncoding(MangledName)) - Demangled = dlangDemangle(MangledName); -#endif - - if (!Demangled) - return false; - - Result = Demangled; - std::free(Demangled); - return true; -} diff --git a/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp deleted file mode 100644 index 9b646ea8..00000000 --- a/demangle/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp +++ /dev/null @@ -1,608 +0,0 @@ -//===------------------------- ItaniumDemangle.cpp ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - -#include "llvm/Demangle/Demangle.h" -#include "llvm/Demangle/ItaniumDemangle.h" - -#include <cassert> -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <functional> -#include <utility> - -using namespace llvm; -using namespace llvm::itanium_demangle; - -constexpr const char *itanium_demangle::FloatData<float>::spec; -constexpr const char *itanium_demangle::FloatData<double>::spec; -constexpr const char *itanium_demangle::FloatData<long double>::spec; - -// <discriminator> := _ <non-negative number> # when number < 10 -// := __ <non-negative number> _ # when number >= 10 -// extension := decimal-digit+ # at the end of string -const char *itanium_demangle::parse_discriminator(const char *first, - const char *last) { - // parse but ignore discriminator - if (first != last) { - if (*first == '_') { - const char *t1 = first + 1; - if (t1 != last) { - if (std::isdigit(*t1)) - first = t1 + 1; - else if (*t1 == '_') { - for (++t1; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 != last && *t1 == '_') - first = t1 + 1; - } - } - } else if (std::isdigit(*first)) { - const char *t1 = first + 1; - for (; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 == last) - first = last; - } - } - return first; -} - -#ifndef NDEBUG -namespace { -struct DumpVisitor { - unsigned Depth = 0; - bool PendingNewline = false; - - template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { - return true; - } - static bool wantsNewline(NodeArray A) { return !A.empty(); } - static constexpr bool wantsNewline(...) { return false; } - - template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { - for (bool B : {wantsNewline(Vs)...}) - if (B) - return true; - return false; - } - - void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); - } - void print(const Node *N) { - if (N) - N->visit(std::ref(*this)); - else - printStr("<null>"); - } - void print(NodeArray A) { - ++Depth; - printStr("{"); - bool First = true; - for (const Node *N : A) { - if (First) - print(N); - else - printWithComma(N); - First = false; - } - printStr("}"); - --Depth; - } - - // Overload used when T is exactly 'bool', not merely convertible to 'bool'. - void print(bool B) { printStr(B ? "true" : "false"); } - - template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) { - fprintf(stderr, "%llu", (unsigned long long)N); - } - - template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) { - fprintf(stderr, "%lld", (long long)N); - } - - void print(ReferenceKind RK) { - switch (RK) { - case ReferenceKind::LValue: - return printStr("ReferenceKind::LValue"); - case ReferenceKind::RValue: - return printStr("ReferenceKind::RValue"); - } - } - void print(FunctionRefQual RQ) { - switch (RQ) { - case FunctionRefQual::FrefQualNone: - return printStr("FunctionRefQual::FrefQualNone"); - case FunctionRefQual::FrefQualLValue: - return printStr("FunctionRefQual::FrefQualLValue"); - case FunctionRefQual::FrefQualRValue: - return printStr("FunctionRefQual::FrefQualRValue"); - } - } - void print(Qualifiers Qs) { - if (!Qs) return printStr("QualNone"); - struct QualName { Qualifiers Q; const char *Name; } Names[] = { - {QualConst, "QualConst"}, - {QualVolatile, "QualVolatile"}, - {QualRestrict, "QualRestrict"}, - }; - for (QualName Name : Names) { - if (Qs & Name.Q) { - printStr(Name.Name); - Qs = Qualifiers(Qs & ~Name.Q); - if (Qs) printStr(" | "); - } - } - } - void print(SpecialSubKind SSK) { - switch (SSK) { - case SpecialSubKind::allocator: - return printStr("SpecialSubKind::allocator"); - case SpecialSubKind::basic_string: - return printStr("SpecialSubKind::basic_string"); - case SpecialSubKind::string: - return printStr("SpecialSubKind::string"); - case SpecialSubKind::istream: - return printStr("SpecialSubKind::istream"); - case SpecialSubKind::ostream: - return printStr("SpecialSubKind::ostream"); - case SpecialSubKind::iostream: - return printStr("SpecialSubKind::iostream"); - } - } - void print(TemplateParamKind TPK) { - switch (TPK) { - case TemplateParamKind::Type: - return printStr("TemplateParamKind::Type"); - case TemplateParamKind::NonType: - return printStr("TemplateParamKind::NonType"); - case TemplateParamKind::Template: - return printStr("TemplateParamKind::Template"); - } - } - void print(Node::Prec P) { - switch (P) { - case Node::Prec::Primary: - return printStr("Node::Prec::Primary"); - case Node::Prec::Postfix: - return printStr("Node::Prec::Postfix"); - case Node::Prec::Unary: - return printStr("Node::Prec::Unary"); - case Node::Prec::Cast: - return printStr("Node::Prec::Cast"); - case Node::Prec::PtrMem: - return printStr("Node::Prec::PtrMem"); - case Node::Prec::Multiplicative: - return printStr("Node::Prec::Multiplicative"); - case Node::Prec::Additive: - return printStr("Node::Prec::Additive"); - case Node::Prec::Shift: - return printStr("Node::Prec::Shift"); - case Node::Prec::Spaceship: - return printStr("Node::Prec::Spaceship"); - case Node::Prec::Relational: - return printStr("Node::Prec::Relational"); - case Node::Prec::Equality: - return printStr("Node::Prec::Equality"); - case Node::Prec::And: - return printStr("Node::Prec::And"); - case Node::Prec::Xor: - return printStr("Node::Prec::Xor"); - case Node::Prec::Ior: - return printStr("Node::Prec::Ior"); - case Node::Prec::AndIf: - return printStr("Node::Prec::AndIf"); - case Node::Prec::OrIf: - return printStr("Node::Prec::OrIf"); - case Node::Prec::Conditional: - return printStr("Node::Prec::Conditional"); - case Node::Prec::Assign: - return printStr("Node::Prec::Assign"); - case Node::Prec::Comma: - return printStr("Node::Prec::Comma"); - case Node::Prec::Default: - return printStr("Node::Prec::Default"); - } - } - - void newLine() { - printStr("\n"); - for (unsigned I = 0; I != Depth; ++I) - printStr(" "); - PendingNewline = false; - } - - template<typename T> void printWithPendingNewline(T V) { - print(V); - if (wantsNewline(V)) - PendingNewline = true; - } - - template<typename T> void printWithComma(T V) { - if (PendingNewline || wantsNewline(V)) { - printStr(","); - newLine(); - } else { - printStr(", "); - } - - printWithPendingNewline(V); - } - - struct CtorArgPrinter { - DumpVisitor &Visitor; - - template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { - if (Visitor.anyWantNewline(V, Vs...)) - Visitor.newLine(); - Visitor.printWithPendingNewline(V); - int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; - (void)PrintInOrder; - } - }; - - template<typename NodeT> void operator()(const NodeT *Node) { - Depth += 2; - fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); - Node->match(CtorArgPrinter{*this}); - fprintf(stderr, ")"); - Depth -= 2; - } - - void operator()(const ForwardTemplateReference *Node) { - Depth += 2; - fprintf(stderr, "ForwardTemplateReference("); - if (Node->Ref && !Node->Printing) { - Node->Printing = true; - CtorArgPrinter{*this}(Node->Ref); - Node->Printing = false; - } else { - CtorArgPrinter{*this}(Node->Index); - } - fprintf(stderr, ")"); - Depth -= 2; - } -}; -} - -void itanium_demangle::Node::dump() const { - DumpVisitor V; - visit(std::ref(V)); - V.newLine(); -} -#endif - -namespace { -class BumpPointerAllocator { - struct BlockMeta { - BlockMeta* Next; - size_t Current; - }; - - static constexpr size_t AllocSize = 4096; - static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); - - alignas(long double) char InitialBuffer[AllocSize]; - BlockMeta* BlockList = nullptr; - - void grow() { - char* NewMeta = static_cast<char *>(std::malloc(AllocSize)); - if (NewMeta == nullptr) - std::terminate(); - BlockList = new (NewMeta) BlockMeta{BlockList, 0}; - } - - void* allocateMassive(size_t NBytes) { - NBytes += sizeof(BlockMeta); - BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes)); - if (NewMeta == nullptr) - std::terminate(); - BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; - return static_cast<void*>(NewMeta + 1); - } - -public: - BumpPointerAllocator() - : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} - - void* allocate(size_t N) { - N = (N + 15u) & ~15u; - if (N + BlockList->Current >= UsableAllocSize) { - if (N > UsableAllocSize) - return allocateMassive(N); - grow(); - } - BlockList->Current += N; - return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + - BlockList->Current - N); - } - - void reset() { - while (BlockList) { - BlockMeta* Tmp = BlockList; - BlockList = BlockList->Next; - if (reinterpret_cast<char*>(Tmp) != InitialBuffer) - std::free(Tmp); - } - BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; - } - - ~BumpPointerAllocator() { reset(); } -}; - -class DefaultAllocator { - BumpPointerAllocator Alloc; - -public: - void reset() { Alloc.reset(); } - - template<typename T, typename ...Args> T *makeNode(Args &&...args) { - return new (Alloc.allocate(sizeof(T))) - T(std::forward<Args>(args)...); - } - - void *allocateNodeArray(size_t sz) { - return Alloc.allocate(sizeof(Node *) * sz); - } -}; -} // unnamed namespace - -//===----------------------------------------------------------------------===// -// Code beyond this point should not be synchronized with libc++abi. -//===----------------------------------------------------------------------===// - -using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; - -char *llvm::itaniumDemangle(const char *MangledName, char *Buf, - size_t *N, int *Status) { - if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status) - *Status = demangle_invalid_args; - return nullptr; - } - - int InternalStatus = demangle_success; - Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - Node *AST = Parser.parse(); - - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else { - OutputBuffer OB(Buf, N); - assert(Parser.ForwardTemplateRefs.empty()); - AST->print(OB); - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - Buf = OB.getBuffer(); - } - - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; -} - -ItaniumPartialDemangler::ItaniumPartialDemangler() - : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} - -ItaniumPartialDemangler::~ItaniumPartialDemangler() { - delete static_cast<Demangler *>(Context); -} - -ItaniumPartialDemangler::ItaniumPartialDemangler( - ItaniumPartialDemangler &&Other) - : RootNode(Other.RootNode), Context(Other.Context) { - Other.Context = Other.RootNode = nullptr; -} - -ItaniumPartialDemangler &ItaniumPartialDemangler:: -operator=(ItaniumPartialDemangler &&Other) { - std::swap(RootNode, Other.RootNode); - std::swap(Context, Other.Context); - return *this; -} - -// Demangle MangledName into an AST, storing it into this->RootNode. -bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { - Demangler *Parser = static_cast<Demangler *>(Context); - size_t Len = std::strlen(MangledName); - Parser->reset(MangledName, MangledName + Len); - RootNode = Parser->parse(); - return RootNode == nullptr; -} - -static char *printNode(const Node *RootNode, char *Buf, size_t *N) { - OutputBuffer OB(Buf, N); - RootNode->print(OB); - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - return OB.getBuffer(); -} - -char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { - if (!isFunction()) - return nullptr; - - const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); - - while (true) { - switch (Name->getKind()) { - case Node::KAbiTagAttr: - Name = static_cast<const AbiTagAttr *>(Name)->Base; - continue; - case Node::KModuleEntity: - Name = static_cast<const ModuleEntity *>(Name)->Name; - continue; - case Node::KNestedName: - Name = static_cast<const NestedName *>(Name)->Name; - continue; - case Node::KLocalName: - Name = static_cast<const LocalName *>(Name)->Entity; - continue; - case Node::KNameWithTemplateArgs: - Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; - continue; - default: - return printNode(Name, Buf, N); - } - } -} - -char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, - size_t *N) const { - if (!isFunction()) - return nullptr; - const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); - - OutputBuffer OB(Buf, N); - - KeepGoingLocalFunction: - while (true) { - if (Name->getKind() == Node::KAbiTagAttr) { - Name = static_cast<const AbiTagAttr *>(Name)->Base; - continue; - } - if (Name->getKind() == Node::KNameWithTemplateArgs) { - Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; - continue; - } - break; - } - - if (Name->getKind() == Node::KModuleEntity) - Name = static_cast<const ModuleEntity *>(Name)->Name; - - switch (Name->getKind()) { - case Node::KNestedName: - static_cast<const NestedName *>(Name)->Qual->print(OB); - break; - case Node::KLocalName: { - auto *LN = static_cast<const LocalName *>(Name); - LN->Encoding->print(OB); - OB += "::"; - Name = LN->Entity; - goto KeepGoingLocalFunction; - } - default: - break; - } - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - return OB.getBuffer(); -} - -char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { - if (!isFunction()) - return nullptr; - auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); - return printNode(Name, Buf, N); -} - -char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, - size_t *N) const { - if (!isFunction()) - return nullptr; - NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); - - OutputBuffer OB(Buf, N); - - OB += '('; - Params.printWithComma(OB); - OB += ')'; - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - return OB.getBuffer(); -} - -char *ItaniumPartialDemangler::getFunctionReturnType( - char *Buf, size_t *N) const { - if (!isFunction()) - return nullptr; - - OutputBuffer OB(Buf, N); - - if (const Node *Ret = - static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) - Ret->print(OB); - - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - return OB.getBuffer(); -} - -char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { - assert(RootNode != nullptr && "must call partialDemangle()"); - return printNode(static_cast<Node *>(RootNode), Buf, N); -} - -bool ItaniumPartialDemangler::hasFunctionQualifiers() const { - assert(RootNode != nullptr && "must call partialDemangle()"); - if (!isFunction()) - return false; - auto *E = static_cast<const FunctionEncoding *>(RootNode); - return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; -} - -bool ItaniumPartialDemangler::isCtorOrDtor() const { - const Node *N = static_cast<const Node *>(RootNode); - while (N) { - switch (N->getKind()) { - default: - return false; - case Node::KCtorDtorName: - return true; - - case Node::KAbiTagAttr: - N = static_cast<const AbiTagAttr *>(N)->Base; - break; - case Node::KFunctionEncoding: - N = static_cast<const FunctionEncoding *>(N)->getName(); - break; - case Node::KLocalName: - N = static_cast<const LocalName *>(N)->Entity; - break; - case Node::KNameWithTemplateArgs: - N = static_cast<const NameWithTemplateArgs *>(N)->Name; - break; - case Node::KNestedName: - N = static_cast<const NestedName *>(N)->Name; - break; - case Node::KModuleEntity: - N = static_cast<const ModuleEntity *>(N)->Name; - break; - } - } - return false; -} - -bool ItaniumPartialDemangler::isFunction() const { - assert(RootNode != nullptr && "must call partialDemangle()"); - return static_cast<const Node *>(RootNode)->getKind() == - Node::KFunctionEncoding; -} - -bool ItaniumPartialDemangler::isSpecialName() const { - assert(RootNode != nullptr && "must call partialDemangle()"); - auto K = static_cast<const Node *>(RootNode)->getKind(); - return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; -} - -bool ItaniumPartialDemangler::isData() const { - return !isFunction() && !isSpecialName(); -} diff --git a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp deleted file mode 100644 index c21b0a30..00000000 --- a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ /dev/null @@ -1,2368 +0,0 @@ -//===- MicrosoftDemangle.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a demangler for MSVC-style mangled symbols. -// -// This file has no dependencies on the rest of LLVM so that it can be -// easily reused in other programs such as libcxxabi. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Demangle/MicrosoftDemangle.h" -#include "llvm/Demangle/Demangle.h" -#include "llvm/Demangle/MicrosoftDemangleNodes.h" - -#include "llvm/Demangle/DemangleConfig.h" -#include "llvm/Demangle/StringView.h" -#include "llvm/Demangle/Utility.h" - -#include <array> -#include <cctype> -#include <cstdio> -#include <tuple> - -using namespace llvm; -using namespace ms_demangle; - -static bool startsWithDigit(StringView S) { - return !S.empty() && std::isdigit(S.front()); -} - - -struct NodeList { - Node *N = nullptr; - NodeList *Next = nullptr; -}; - -static bool isMemberPointer(StringView MangledName, bool &Error) { - Error = false; - switch (MangledName.popFront()) { - case '$': - // This is probably an rvalue reference (e.g. $$Q), and you cannot have an - // rvalue reference to a member. - return false; - case 'A': - // 'A' indicates a reference, and you cannot have a reference to a member - // function or member. - return false; - case 'P': - case 'Q': - case 'R': - case 'S': - // These 4 values indicate some kind of pointer, but we still don't know - // what. - break; - default: - // isMemberPointer() is called only if isPointerType() returns true, - // and it rejects other prefixes. - DEMANGLE_UNREACHABLE; - } - - // If it starts with a number, then 6 indicates a non-member function - // pointer, and 8 indicates a member function pointer. - if (startsWithDigit(MangledName)) { - if (MangledName[0] != '6' && MangledName[0] != '8') { - Error = true; - return false; - } - return (MangledName[0] == '8'); - } - - // Remove ext qualifiers since those can appear on either type and are - // therefore not indicative. - MangledName.consumeFront('E'); // 64-bit - MangledName.consumeFront('I'); // restrict - MangledName.consumeFront('F'); // unaligned - - if (MangledName.empty()) { - Error = true; - return false; - } - - // The next value should be either ABCD (non-member) or QRST (member). - switch (MangledName.front()) { - case 'A': - case 'B': - case 'C': - case 'D': - return false; - case 'Q': - case 'R': - case 'S': - case 'T': - return true; - default: - Error = true; - return false; - } -} - -static SpecialIntrinsicKind -consumeSpecialIntrinsicKind(StringView &MangledName) { - if (MangledName.consumeFront("?_7")) - return SpecialIntrinsicKind::Vftable; - if (MangledName.consumeFront("?_8")) - return SpecialIntrinsicKind::Vbtable; - if (MangledName.consumeFront("?_9")) - return SpecialIntrinsicKind::VcallThunk; - if (MangledName.consumeFront("?_A")) - return SpecialIntrinsicKind::Typeof; - if (MangledName.consumeFront("?_B")) - return SpecialIntrinsicKind::LocalStaticGuard; - if (MangledName.consumeFront("?_C")) - return SpecialIntrinsicKind::StringLiteralSymbol; - if (MangledName.consumeFront("?_P")) - return SpecialIntrinsicKind::UdtReturning; - if (MangledName.consumeFront("?_R0")) - return SpecialIntrinsicKind::RttiTypeDescriptor; - if (MangledName.consumeFront("?_R1")) - return SpecialIntrinsicKind::RttiBaseClassDescriptor; - if (MangledName.consumeFront("?_R2")) - return SpecialIntrinsicKind::RttiBaseClassArray; - if (MangledName.consumeFront("?_R3")) - return SpecialIntrinsicKind::RttiClassHierarchyDescriptor; - if (MangledName.consumeFront("?_R4")) - return SpecialIntrinsicKind::RttiCompleteObjLocator; - if (MangledName.consumeFront("?_S")) - return SpecialIntrinsicKind::LocalVftable; - if (MangledName.consumeFront("?__E")) - return SpecialIntrinsicKind::DynamicInitializer; - if (MangledName.consumeFront("?__F")) - return SpecialIntrinsicKind::DynamicAtexitDestructor; - if (MangledName.consumeFront("?__J")) - return SpecialIntrinsicKind::LocalStaticThreadGuard; - return SpecialIntrinsicKind::None; -} - -static bool startsWithLocalScopePattern(StringView S) { - if (!S.consumeFront('?')) - return false; - - size_t End = S.find('?'); - if (End == StringView::npos) - return false; - StringView Candidate = S.substr(0, End); - if (Candidate.empty()) - return false; - - // \?[0-9]\? - // ?@? is the discriminator 0. - if (Candidate.size() == 1) - return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9'); - - // If it's not 0-9, then it's an encoded number terminated with an @ - if (Candidate.back() != '@') - return false; - Candidate = Candidate.dropBack(); - - // An encoded number starts with B-P and all subsequent digits are in A-P. - // Note that the reason the first digit cannot be A is two fold. First, it - // would create an ambiguity with ?A which delimits the beginning of an - // anonymous namespace. Second, A represents 0, and you don't start a multi - // digit number with a leading 0. Presumably the anonymous namespace - // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J. - if (Candidate[0] < 'B' || Candidate[0] > 'P') - return false; - Candidate = Candidate.dropFront(); - while (!Candidate.empty()) { - if (Candidate[0] < 'A' || Candidate[0] > 'P') - return false; - Candidate = Candidate.dropFront(); - } - - return true; -} - -static bool isTagType(StringView S) { - switch (S.front()) { - case 'T': // union - case 'U': // struct - case 'V': // class - case 'W': // enum - return true; - } - return false; -} - -static bool isCustomType(StringView S) { return S[0] == '?'; } - -static bool isPointerType(StringView S) { - if (S.startsWith("$$Q")) // foo && - return true; - - switch (S.front()) { - case 'A': // foo & - case 'P': // foo * - case 'Q': // foo *const - case 'R': // foo *volatile - case 'S': // foo *const volatile - return true; - } - return false; -} - -static bool isArrayType(StringView S) { return S[0] == 'Y'; } - -static bool isFunctionType(StringView S) { - return S.startsWith("$$A8@@") || S.startsWith("$$A6"); -} - -static FunctionRefQualifier -demangleFunctionRefQualifier(StringView &MangledName) { - if (MangledName.consumeFront('G')) - return FunctionRefQualifier::Reference; - else if (MangledName.consumeFront('H')) - return FunctionRefQualifier::RValueReference; - return FunctionRefQualifier::None; -} - -static std::pair<Qualifiers, PointerAffinity> -demanglePointerCVQualifiers(StringView &MangledName) { - if (MangledName.consumeFront("$$Q")) - return std::make_pair(Q_None, PointerAffinity::RValueReference); - - switch (MangledName.popFront()) { - case 'A': - return std::make_pair(Q_None, PointerAffinity::Reference); - case 'P': - return std::make_pair(Q_None, PointerAffinity::Pointer); - case 'Q': - return std::make_pair(Q_Const, PointerAffinity::Pointer); - case 'R': - return std::make_pair(Q_Volatile, PointerAffinity::Pointer); - case 'S': - return std::make_pair(Qualifiers(Q_Const | Q_Volatile), - PointerAffinity::Pointer); - } - // This function is only called if isPointerType() returns true, - // and it only returns true for the six cases listed above. - DEMANGLE_UNREACHABLE; -} - -StringView Demangler::copyString(StringView Borrowed) { - char *Stable = Arena.allocUnalignedBuffer(Borrowed.size()); - // This is not a micro-optimization, it avoids UB, should Borrowed be an null - // buffer. - if (Borrowed.size()) - std::memcpy(Stable, Borrowed.begin(), Borrowed.size()); - - return {Stable, Borrowed.size()}; -} - -SpecialTableSymbolNode * -Demangler::demangleSpecialTableSymbolNode(StringView &MangledName, - SpecialIntrinsicKind K) { - NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>(); - switch (K) { - case SpecialIntrinsicKind::Vftable: - NI->Name = "`vftable'"; - break; - case SpecialIntrinsicKind::Vbtable: - NI->Name = "`vbtable'"; - break; - case SpecialIntrinsicKind::LocalVftable: - NI->Name = "`local vftable'"; - break; - case SpecialIntrinsicKind::RttiCompleteObjLocator: - NI->Name = "`RTTI Complete Object Locator'"; - break; - default: - DEMANGLE_UNREACHABLE; - } - QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); - SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>(); - STSN->Name = QN; - bool IsMember = false; - if (MangledName.empty()) { - Error = true; - return nullptr; - } - char Front = MangledName.popFront(); - if (Front != '6' && Front != '7') { - Error = true; - return nullptr; - } - - std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName); - if (!MangledName.consumeFront('@')) - STSN->TargetName = demangleFullyQualifiedTypeName(MangledName); - return STSN; -} - -LocalStaticGuardVariableNode * -Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) { - LocalStaticGuardIdentifierNode *LSGI = - Arena.alloc<LocalStaticGuardIdentifierNode>(); - LSGI->IsThread = IsThread; - QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI); - LocalStaticGuardVariableNode *LSGVN = - Arena.alloc<LocalStaticGuardVariableNode>(); - LSGVN->Name = QN; - - if (MangledName.consumeFront("4IA")) - LSGVN->IsVisible = false; - else if (MangledName.consumeFront("5")) - LSGVN->IsVisible = true; - else { - Error = true; - return nullptr; - } - - if (!MangledName.empty()) - LSGI->ScopeIndex = demangleUnsigned(MangledName); - return LSGVN; -} - -static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena, - StringView Name) { - NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>(); - Id->Name = Name; - return Id; -} - -static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, - IdentifierNode *Identifier) { - QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>(); - QN->Components = Arena.alloc<NodeArrayNode>(); - QN->Components->Count = 1; - QN->Components->Nodes = Arena.allocArray<Node *>(1); - QN->Components->Nodes[0] = Identifier; - return QN; -} - -static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, - StringView Name) { - NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name); - return synthesizeQualifiedName(Arena, Id); -} - -static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena, - TypeNode *Type, - StringView VariableName) { - VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); - VSN->Type = Type; - VSN->Name = synthesizeQualifiedName(Arena, VariableName); - return VSN; -} - -VariableSymbolNode *Demangler::demangleUntypedVariable( - ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) { - NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName); - QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); - VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); - VSN->Name = QN; - if (MangledName.consumeFront("8")) - return VSN; - - Error = true; - return nullptr; -} - -VariableSymbolNode * -Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, - StringView &MangledName) { - RttiBaseClassDescriptorNode *RBCDN = - Arena.alloc<RttiBaseClassDescriptorNode>(); - RBCDN->NVOffset = demangleUnsigned(MangledName); - RBCDN->VBPtrOffset = demangleSigned(MangledName); - RBCDN->VBTableOffset = demangleUnsigned(MangledName); - RBCDN->Flags = demangleUnsigned(MangledName); - if (Error) - return nullptr; - - VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); - VSN->Name = demangleNameScopeChain(MangledName, RBCDN); - MangledName.consumeFront('8'); - return VSN; -} - -FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, - bool IsDestructor) { - DynamicStructorIdentifierNode *DSIN = - Arena.alloc<DynamicStructorIdentifierNode>(); - DSIN->IsDestructor = IsDestructor; - - bool IsKnownStaticDataMember = false; - if (MangledName.consumeFront('?')) - IsKnownStaticDataMember = true; - - SymbolNode *Symbol = demangleDeclarator(MangledName); - if (Error) - return nullptr; - - FunctionSymbolNode *FSN = nullptr; - - if (Symbol->kind() == NodeKind::VariableSymbol) { - DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol); - - // Older versions of clang mangled this type of symbol incorrectly. They - // would omit the leading ? and they would only emit a single @ at the end. - // The correct mangling is a leading ? and 2 trailing @ signs. Handle - // both cases. - int AtCount = IsKnownStaticDataMember ? 2 : 1; - for (int I = 0; I < AtCount; ++I) { - if (MangledName.consumeFront('@')) - continue; - Error = true; - return nullptr; - } - - FSN = demangleFunctionEncoding(MangledName); - if (FSN) - FSN->Name = synthesizeQualifiedName(Arena, DSIN); - } else { - if (IsKnownStaticDataMember) { - // This was supposed to be a static data member, but we got a function. - Error = true; - return nullptr; - } - - FSN = static_cast<FunctionSymbolNode *>(Symbol); - DSIN->Name = Symbol->Name; - FSN->Name = synthesizeQualifiedName(Arena, DSIN); - } - - return FSN; -} - -SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { - SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName); - - switch (SIK) { - case SpecialIntrinsicKind::None: - return nullptr; - case SpecialIntrinsicKind::StringLiteralSymbol: - return demangleStringLiteral(MangledName); - case SpecialIntrinsicKind::Vftable: - case SpecialIntrinsicKind::Vbtable: - case SpecialIntrinsicKind::LocalVftable: - case SpecialIntrinsicKind::RttiCompleteObjLocator: - return demangleSpecialTableSymbolNode(MangledName, SIK); - case SpecialIntrinsicKind::VcallThunk: - return demangleVcallThunkNode(MangledName); - case SpecialIntrinsicKind::LocalStaticGuard: - return demangleLocalStaticGuard(MangledName, /*IsThread=*/false); - case SpecialIntrinsicKind::LocalStaticThreadGuard: - return demangleLocalStaticGuard(MangledName, /*IsThread=*/true); - case SpecialIntrinsicKind::RttiTypeDescriptor: { - TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); - if (Error) - break; - if (!MangledName.consumeFront("@8")) - break; - if (!MangledName.empty()) - break; - return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'"); - } - case SpecialIntrinsicKind::RttiBaseClassArray: - return demangleUntypedVariable(Arena, MangledName, - "`RTTI Base Class Array'"); - case SpecialIntrinsicKind::RttiClassHierarchyDescriptor: - return demangleUntypedVariable(Arena, MangledName, - "`RTTI Class Hierarchy Descriptor'"); - case SpecialIntrinsicKind::RttiBaseClassDescriptor: - return demangleRttiBaseClassDescriptorNode(Arena, MangledName); - case SpecialIntrinsicKind::DynamicInitializer: - return demangleInitFiniStub(MangledName, /*IsDestructor=*/false); - case SpecialIntrinsicKind::DynamicAtexitDestructor: - return demangleInitFiniStub(MangledName, /*IsDestructor=*/true); - case SpecialIntrinsicKind::Typeof: - case SpecialIntrinsicKind::UdtReturning: - // It's unclear which tools produces these manglings, so demangling - // support is not (yet?) implemented. - break; - case SpecialIntrinsicKind::Unknown: - DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind. - } - Error = true; - return nullptr; -} - -IdentifierNode * -Demangler::demangleFunctionIdentifierCode(StringView &MangledName) { - assert(MangledName.startsWith('?')); - MangledName = MangledName.dropFront(); - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - if (MangledName.consumeFront("__")) - return demangleFunctionIdentifierCode( - MangledName, FunctionIdentifierCodeGroup::DoubleUnder); - if (MangledName.consumeFront("_")) - return demangleFunctionIdentifierCode(MangledName, - FunctionIdentifierCodeGroup::Under); - return demangleFunctionIdentifierCode(MangledName, - FunctionIdentifierCodeGroup::Basic); -} - -StructorIdentifierNode * -Demangler::demangleStructorIdentifier(StringView &MangledName, - bool IsDestructor) { - StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>(); - N->IsDestructor = IsDestructor; - return N; -} - -ConversionOperatorIdentifierNode * -Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) { - ConversionOperatorIdentifierNode *N = - Arena.alloc<ConversionOperatorIdentifierNode>(); - return N; -} - -LiteralOperatorIdentifierNode * -Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) { - LiteralOperatorIdentifierNode *N = - Arena.alloc<LiteralOperatorIdentifierNode>(); - N->Name = demangleSimpleString(MangledName, /*Memorize=*/false); - return N; -} - -IntrinsicFunctionKind -Demangler::translateIntrinsicFunctionCode(char CH, - FunctionIdentifierCodeGroup Group) { - using IFK = IntrinsicFunctionKind; - if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) { - Error = true; - return IFK::None; - } - - // Not all ? identifiers are intrinsics *functions*. This function only maps - // operator codes for the special functions, all others are handled elsewhere, - // hence the IFK::None entries in the table. - static IFK Basic[36] = { - IFK::None, // ?0 # Foo::Foo() - IFK::None, // ?1 # Foo::~Foo() - IFK::New, // ?2 # operator new - IFK::Delete, // ?3 # operator delete - IFK::Assign, // ?4 # operator= - IFK::RightShift, // ?5 # operator>> - IFK::LeftShift, // ?6 # operator<< - IFK::LogicalNot, // ?7 # operator! - IFK::Equals, // ?8 # operator== - IFK::NotEquals, // ?9 # operator!= - IFK::ArraySubscript, // ?A # operator[] - IFK::None, // ?B # Foo::operator <type>() - IFK::Pointer, // ?C # operator-> - IFK::Dereference, // ?D # operator* - IFK::Increment, // ?E # operator++ - IFK::Decrement, // ?F # operator-- - IFK::Minus, // ?G # operator- - IFK::Plus, // ?H # operator+ - IFK::BitwiseAnd, // ?I # operator& - IFK::MemberPointer, // ?J # operator->* - IFK::Divide, // ?K # operator/ - IFK::Modulus, // ?L # operator% - IFK::LessThan, // ?M operator< - IFK::LessThanEqual, // ?N operator<= - IFK::GreaterThan, // ?O operator> - IFK::GreaterThanEqual, // ?P operator>= - IFK::Comma, // ?Q operator, - IFK::Parens, // ?R operator() - IFK::BitwiseNot, // ?S operator~ - IFK::BitwiseXor, // ?T operator^ - IFK::BitwiseOr, // ?U operator| - IFK::LogicalAnd, // ?V operator&& - IFK::LogicalOr, // ?W operator|| - IFK::TimesEqual, // ?X operator*= - IFK::PlusEqual, // ?Y operator+= - IFK::MinusEqual, // ?Z operator-= - }; - static IFK Under[36] = { - IFK::DivEqual, // ?_0 operator/= - IFK::ModEqual, // ?_1 operator%= - IFK::RshEqual, // ?_2 operator>>= - IFK::LshEqual, // ?_3 operator<<= - IFK::BitwiseAndEqual, // ?_4 operator&= - IFK::BitwiseOrEqual, // ?_5 operator|= - IFK::BitwiseXorEqual, // ?_6 operator^= - IFK::None, // ?_7 # vftable - IFK::None, // ?_8 # vbtable - IFK::None, // ?_9 # vcall - IFK::None, // ?_A # typeof - IFK::None, // ?_B # local static guard - IFK::None, // ?_C # string literal - IFK::VbaseDtor, // ?_D # vbase destructor - IFK::VecDelDtor, // ?_E # vector deleting destructor - IFK::DefaultCtorClosure, // ?_F # default constructor closure - IFK::ScalarDelDtor, // ?_G # scalar deleting destructor - IFK::VecCtorIter, // ?_H # vector constructor iterator - IFK::VecDtorIter, // ?_I # vector destructor iterator - IFK::VecVbaseCtorIter, // ?_J # vector vbase constructor iterator - IFK::VdispMap, // ?_K # virtual displacement map - IFK::EHVecCtorIter, // ?_L # eh vector constructor iterator - IFK::EHVecDtorIter, // ?_M # eh vector destructor iterator - IFK::EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator - IFK::CopyCtorClosure, // ?_O # copy constructor closure - IFK::None, // ?_P<name> # udt returning <name> - IFK::None, // ?_Q # <unknown> - IFK::None, // ?_R0 - ?_R4 # RTTI Codes - IFK::None, // ?_S # local vftable - IFK::LocalVftableCtorClosure, // ?_T # local vftable constructor closure - IFK::ArrayNew, // ?_U operator new[] - IFK::ArrayDelete, // ?_V operator delete[] - IFK::None, // ?_W <unused> - IFK::None, // ?_X <unused> - IFK::None, // ?_Y <unused> - IFK::None, // ?_Z <unused> - }; - static IFK DoubleUnder[36] = { - IFK::None, // ?__0 <unused> - IFK::None, // ?__1 <unused> - IFK::None, // ?__2 <unused> - IFK::None, // ?__3 <unused> - IFK::None, // ?__4 <unused> - IFK::None, // ?__5 <unused> - IFK::None, // ?__6 <unused> - IFK::None, // ?__7 <unused> - IFK::None, // ?__8 <unused> - IFK::None, // ?__9 <unused> - IFK::ManVectorCtorIter, // ?__A managed vector ctor iterator - IFK::ManVectorDtorIter, // ?__B managed vector dtor iterator - IFK::EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator - IFK::EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iter - IFK::None, // ?__E dynamic initializer for `T' - IFK::None, // ?__F dynamic atexit destructor for `T' - IFK::VectorCopyCtorIter, // ?__G vector copy constructor iter - IFK::VectorVbaseCopyCtorIter, // ?__H vector vbase copy ctor iter - IFK::ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy ctor - // iter - IFK::None, // ?__J local static thread guard - IFK::None, // ?__K operator ""_name - IFK::CoAwait, // ?__L operator co_await - IFK::Spaceship, // ?__M operator<=> - IFK::None, // ?__N <unused> - IFK::None, // ?__O <unused> - IFK::None, // ?__P <unused> - IFK::None, // ?__Q <unused> - IFK::None, // ?__R <unused> - IFK::None, // ?__S <unused> - IFK::None, // ?__T <unused> - IFK::None, // ?__U <unused> - IFK::None, // ?__V <unused> - IFK::None, // ?__W <unused> - IFK::None, // ?__X <unused> - IFK::None, // ?__Y <unused> - IFK::None, // ?__Z <unused> - }; - - int Index = (CH >= '0' && CH <= '9') ? (CH - '0') : (CH - 'A' + 10); - switch (Group) { - case FunctionIdentifierCodeGroup::Basic: - return Basic[Index]; - case FunctionIdentifierCodeGroup::Under: - return Under[Index]; - case FunctionIdentifierCodeGroup::DoubleUnder: - return DoubleUnder[Index]; - } - DEMANGLE_UNREACHABLE; -} - -IdentifierNode * -Demangler::demangleFunctionIdentifierCode(StringView &MangledName, - FunctionIdentifierCodeGroup Group) { - if (MangledName.empty()) { - Error = true; - return nullptr; - } - switch (Group) { - case FunctionIdentifierCodeGroup::Basic: - switch (char CH = MangledName.popFront()) { - case '0': - case '1': - return demangleStructorIdentifier(MangledName, CH == '1'); - case 'B': - return demangleConversionOperatorIdentifier(MangledName); - default: - return Arena.alloc<IntrinsicFunctionIdentifierNode>( - translateIntrinsicFunctionCode(CH, Group)); - } - case FunctionIdentifierCodeGroup::Under: - return Arena.alloc<IntrinsicFunctionIdentifierNode>( - translateIntrinsicFunctionCode(MangledName.popFront(), Group)); - case FunctionIdentifierCodeGroup::DoubleUnder: - switch (char CH = MangledName.popFront()) { - case 'K': - return demangleLiteralOperatorIdentifier(MangledName); - default: - return Arena.alloc<IntrinsicFunctionIdentifierNode>( - translateIntrinsicFunctionCode(CH, Group)); - } - } - - DEMANGLE_UNREACHABLE; -} - -SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName, - QualifiedNameNode *Name) { - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - // Read a variable. - switch (MangledName.front()) { - case '0': - case '1': - case '2': - case '3': - case '4': { - StorageClass SC = demangleVariableStorageClass(MangledName); - return demangleVariableEncoding(MangledName, SC); - } - } - FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName); - - IdentifierNode *UQN = Name->getUnqualifiedIdentifier(); - if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) { - ConversionOperatorIdentifierNode *COIN = - static_cast<ConversionOperatorIdentifierNode *>(UQN); - if (FSN) - COIN->TargetType = FSN->Signature->ReturnType; - } - return FSN; -} - -SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) { - // What follows is a main symbol name. This may include namespaces or class - // back references. - QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName); - if (Error) - return nullptr; - - SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN); - if (Error) - return nullptr; - Symbol->Name = QN; - - IdentifierNode *UQN = QN->getUnqualifiedIdentifier(); - if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) { - ConversionOperatorIdentifierNode *COIN = - static_cast<ConversionOperatorIdentifierNode *>(UQN); - if (!COIN->TargetType) { - Error = true; - return nullptr; - } - } - return Symbol; -} - -SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) { - assert(MangledName.startsWith("??@")); - // This is an MD5 mangled name. We can't demangle it, just return the - // mangled name. - // An MD5 mangled name is ??@ followed by 32 characters and a terminating @. - size_t MD5Last = MangledName.find('@', strlen("??@")); - if (MD5Last == StringView::npos) { - Error = true; - return nullptr; - } - const char *Start = MangledName.begin(); - MangledName = MangledName.dropFront(MD5Last + 1); - - // There are two additional special cases for MD5 names: - // 1. For complete object locators where the object name is long enough - // for the object to have an MD5 name, the complete object locator is - // called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual - // leading "??_R4". This is handled here. - // 2. For catchable types, in versions of MSVC before 2015 (<1900) or after - // 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8 - // instead of_CT??@...@8 with just one MD5 name. Since we don't yet - // demangle catchable types anywhere, this isn't handled for MD5 names - // either. - MangledName.consumeFront("??_R4@"); - - StringView MD5(Start, MangledName.begin()); - SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol); - S->Name = synthesizeQualifiedName(Arena, MD5); - - return S; -} - -SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) { - assert(MangledName.startsWith('.')); - MangledName.consumeFront('.'); - - TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); - if (Error || !MangledName.empty()) { - Error = true; - return nullptr; - } - return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'"); -} - -// Parser entry point. -SymbolNode *Demangler::parse(StringView &MangledName) { - // Typeinfo names are strings stored in RTTI data. They're not symbol names. - // It's still useful to demangle them. They're the only demangled entity - // that doesn't start with a "?" but a ".". - if (MangledName.startsWith('.')) - return demangleTypeinfoName(MangledName); - - if (MangledName.startsWith("??@")) - return demangleMD5Name(MangledName); - - // MSVC-style mangled symbols must start with '?'. - if (!MangledName.startsWith('?')) { - Error = true; - return nullptr; - } - - MangledName.consumeFront('?'); - - // ?$ is a template instantiation, but all other names that start with ? are - // operators / special names. - if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName)) - return SI; - - return demangleDeclarator(MangledName); -} - -TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) { - if (!MangledName.consumeFront(".?A")) { - Error = true; - return nullptr; - } - MangledName.consumeFront(".?A"); - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - return demangleClassType(MangledName); -} - -// <type-encoding> ::= <storage-class> <variable-type> -// <storage-class> ::= 0 # private static member -// ::= 1 # protected static member -// ::= 2 # public static member -// ::= 3 # global -// ::= 4 # static local - -VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName, - StorageClass SC) { - VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>(); - - VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop); - VSN->SC = SC; - - if (Error) - return nullptr; - - // <variable-type> ::= <type> <cvr-qualifiers> - // ::= <type> <pointee-cvr-qualifiers> # pointers, references - switch (VSN->Type->kind()) { - case NodeKind::PointerType: { - PointerTypeNode *PTN = static_cast<PointerTypeNode *>(VSN->Type); - - Qualifiers ExtraChildQuals = Q_None; - PTN->Quals = Qualifiers(VSN->Type->Quals | - demanglePointerExtQualifiers(MangledName)); - - bool IsMember = false; - std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName); - - if (PTN->ClassParent) { - QualifiedNameNode *BackRefName = - demangleFullyQualifiedTypeName(MangledName); - (void)BackRefName; - } - PTN->Pointee->Quals = Qualifiers(PTN->Pointee->Quals | ExtraChildQuals); - - break; - } - default: - VSN->Type->Quals = demangleQualifiers(MangledName).first; - break; - } - - return VSN; -} - -// Sometimes numbers are encoded in mangled symbols. For example, -// "int (*x)[20]" is a valid C type (x is a pointer to an array of -// length 20), so we need some way to embed numbers as part of symbols. -// This function parses it. -// -// <number> ::= [?] <non-negative integer> -// -// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10 -// ::= <hex digit>+ @ # when Number == 0 or >= 10 -// -// <hex-digit> ::= [A-P] # A = 0, B = 1, ... -std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) { - bool IsNegative = MangledName.consumeFront('?'); - - if (startsWithDigit(MangledName)) { - uint64_t Ret = MangledName[0] - '0' + 1; - MangledName = MangledName.dropFront(1); - return {Ret, IsNegative}; - } - - uint64_t Ret = 0; - for (size_t i = 0; i < MangledName.size(); ++i) { - char C = MangledName[i]; - if (C == '@') { - MangledName = MangledName.dropFront(i + 1); - return {Ret, IsNegative}; - } - if ('A' <= C && C <= 'P') { - Ret = (Ret << 4) + (C - 'A'); - continue; - } - break; - } - - Error = true; - return {0ULL, false}; -} - -uint64_t Demangler::demangleUnsigned(StringView &MangledName) { - bool IsNegative = false; - uint64_t Number = 0; - std::tie(Number, IsNegative) = demangleNumber(MangledName); - if (IsNegative) - Error = true; - return Number; -} - -int64_t Demangler::demangleSigned(StringView &MangledName) { - bool IsNegative = false; - uint64_t Number = 0; - std::tie(Number, IsNegative) = demangleNumber(MangledName); - if (Number > INT64_MAX) - Error = true; - int64_t I = static_cast<int64_t>(Number); - return IsNegative ? -I : I; -} - -// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9. -// Memorize it. -void Demangler::memorizeString(StringView S) { - if (Backrefs.NamesCount >= BackrefContext::Max) - return; - for (size_t i = 0; i < Backrefs.NamesCount; ++i) - if (S == Backrefs.Names[i]->Name) - return; - NamedIdentifierNode *N = Arena.alloc<NamedIdentifierNode>(); - N->Name = S; - Backrefs.Names[Backrefs.NamesCount++] = N; -} - -NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { - assert(startsWithDigit(MangledName)); - - size_t I = MangledName[0] - '0'; - if (I >= Backrefs.NamesCount) { - Error = true; - return nullptr; - } - - MangledName = MangledName.dropFront(); - return Backrefs.Names[I]; -} - -void Demangler::memorizeIdentifier(IdentifierNode *Identifier) { - // Render this class template name into a string buffer so that we can - // memorize it for the purpose of back-referencing. - OutputBuffer OB; - Identifier->output(OB, OF_Default); - StringView Owned = copyString(OB); - memorizeString(Owned); - std::free(OB.getBuffer()); -} - -IdentifierNode * -Demangler::demangleTemplateInstantiationName(StringView &MangledName, - NameBackrefBehavior NBB) { - assert(MangledName.startsWith("?$")); - MangledName.consumeFront("?$"); - - BackrefContext OuterContext; - std::swap(OuterContext, Backrefs); - - IdentifierNode *Identifier = - demangleUnqualifiedSymbolName(MangledName, NBB_Simple); - if (!Error) - Identifier->TemplateParams = demangleTemplateParameterList(MangledName); - - std::swap(OuterContext, Backrefs); - if (Error) - return nullptr; - - if (NBB & NBB_Template) { - // NBB_Template is only set for types and non-leaf names ("a::" in "a::b"). - // Structors and conversion operators only makes sense in a leaf name, so - // reject them in NBB_Template contexts. - if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier || - Identifier->kind() == NodeKind::StructorIdentifier) { - Error = true; - return nullptr; - } - - memorizeIdentifier(Identifier); - } - - return Identifier; -} - -NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName, - bool Memorize) { - StringView S = demangleSimpleString(MangledName, Memorize); - if (Error) - return nullptr; - - NamedIdentifierNode *Name = Arena.alloc<NamedIdentifierNode>(); - Name->Name = S; - return Name; -} - -static bool isRebasedHexDigit(char C) { return (C >= 'A' && C <= 'P'); } - -static uint8_t rebasedHexDigitToNumber(char C) { - assert(isRebasedHexDigit(C)); - return (C <= 'J') ? (C - 'A') : (10 + C - 'K'); -} - -uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { - assert(!MangledName.empty()); - if (!MangledName.startsWith('?')) - return MangledName.popFront(); - - MangledName = MangledName.dropFront(); - if (MangledName.empty()) - goto CharLiteralError; - - if (MangledName.consumeFront('$')) { - // Two hex digits - if (MangledName.size() < 2) - goto CharLiteralError; - StringView Nibbles = MangledName.substr(0, 2); - if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1])) - goto CharLiteralError; - // Don't append the null terminator. - uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]); - uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]); - MangledName = MangledName.dropFront(2); - return (C1 << 4) | C2; - } - - if (startsWithDigit(MangledName)) { - const char *Lookup = ",/\\:. \n\t'-"; - char C = Lookup[MangledName[0] - '0']; - MangledName = MangledName.dropFront(); - return C; - } - - if (MangledName[0] >= 'a' && MangledName[0] <= 'z') { - char Lookup[26] = {'\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', - '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', - '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', - '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'}; - char C = Lookup[MangledName[0] - 'a']; - MangledName = MangledName.dropFront(); - return C; - } - - if (MangledName[0] >= 'A' && MangledName[0] <= 'Z') { - char Lookup[26] = {'\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', - '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', - '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', - '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'}; - char C = Lookup[MangledName[0] - 'A']; - MangledName = MangledName.dropFront(); - return C; - } - -CharLiteralError: - Error = true; - return '\0'; -} - -wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) { - uint8_t C1, C2; - - C1 = demangleCharLiteral(MangledName); - if (Error || MangledName.empty()) - goto WCharLiteralError; - C2 = demangleCharLiteral(MangledName); - if (Error) - goto WCharLiteralError; - - return ((wchar_t)C1 << 8) | (wchar_t)C2; - -WCharLiteralError: - Error = true; - return L'\0'; -} - -static void writeHexDigit(char *Buffer, uint8_t Digit) { - assert(Digit <= 15); - *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10); -} - -static void outputHex(OutputBuffer &OB, unsigned C) { - assert (C != 0); - - // It's easier to do the math if we can work from right to left, but we need - // to print the numbers from left to right. So render this into a temporary - // buffer first, then output the temporary buffer. Each byte is of the form - // \xAB, which means that each byte needs 4 characters. Since there are at - // most 4 bytes, we need a 4*4+1 = 17 character temporary buffer. - char TempBuffer[17]; - - ::memset(TempBuffer, 0, sizeof(TempBuffer)); - constexpr int MaxPos = sizeof(TempBuffer) - 1; - - int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0. - while (C != 0) { - for (int I = 0; I < 2; ++I) { - writeHexDigit(&TempBuffer[Pos--], C % 16); - C /= 16; - } - } - TempBuffer[Pos--] = 'x'; - assert(Pos >= 0); - TempBuffer[Pos--] = '\\'; - OB << StringView(&TempBuffer[Pos + 1]); -} - -static void outputEscapedChar(OutputBuffer &OB, unsigned C) { - switch (C) { - case '\0': // nul - OB << "\\0"; - return; - case '\'': // single quote - OB << "\\\'"; - return; - case '\"': // double quote - OB << "\\\""; - return; - case '\\': // backslash - OB << "\\\\"; - return; - case '\a': // bell - OB << "\\a"; - return; - case '\b': // backspace - OB << "\\b"; - return; - case '\f': // form feed - OB << "\\f"; - return; - case '\n': // new line - OB << "\\n"; - return; - case '\r': // carriage return - OB << "\\r"; - return; - case '\t': // tab - OB << "\\t"; - return; - case '\v': // vertical tab - OB << "\\v"; - return; - default: - break; - } - - if (C > 0x1F && C < 0x7F) { - // Standard ascii char. - OB << (char)C; - return; - } - - outputHex(OB, C); -} - -static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { - const uint8_t *End = StringBytes + Length - 1; - unsigned Count = 0; - while (Length > 0 && *End == 0) { - --Length; - --End; - ++Count; - } - return Count; -} - -static unsigned countEmbeddedNulls(const uint8_t *StringBytes, - unsigned Length) { - unsigned Result = 0; - for (unsigned I = 0; I < Length; ++I) { - if (*StringBytes++ == 0) - ++Result; - } - return Result; -} - -// A mangled (non-wide) string literal stores the total length of the string it -// refers to (passed in NumBytes), and it contains up to 32 bytes of actual text -// (passed in StringBytes, NumChars). -static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars, - uint64_t NumBytes) { - assert(NumBytes > 0); - - // If the number of bytes is odd, this is guaranteed to be a char string. - if (NumBytes % 2 == 1) - return 1; - - // All strings can encode at most 32 bytes of data. If it's less than that, - // then we encoded the entire string. In this case we check for a 1-byte, - // 2-byte, or 4-byte null terminator. - if (NumBytes < 32) { - unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars); - if (TrailingNulls >= 4 && NumBytes % 4 == 0) - return 4; - if (TrailingNulls >= 2) - return 2; - return 1; - } - - // The whole string was not able to be encoded. Try to look at embedded null - // terminators to guess. The heuristic is that we count all embedded null - // terminators. If more than 2/3 are null, it's a char32. If more than 1/3 - // are null, it's a char16. Otherwise it's a char8. This obviously isn't - // perfect and is biased towards languages that have ascii alphabets, but this - // was always going to be best effort since the encoding is lossy. - unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars); - if (Nulls >= 2 * NumChars / 3 && NumBytes % 4 == 0) - return 4; - if (Nulls >= NumChars / 3) - return 2; - return 1; -} - -static unsigned decodeMultiByteChar(const uint8_t *StringBytes, - unsigned CharIndex, unsigned CharBytes) { - assert(CharBytes == 1 || CharBytes == 2 || CharBytes == 4); - unsigned Offset = CharIndex * CharBytes; - unsigned Result = 0; - StringBytes = StringBytes + Offset; - for (unsigned I = 0; I < CharBytes; ++I) { - unsigned C = static_cast<unsigned>(StringBytes[I]); - Result |= C << (8 * I); - } - return Result; -} - -FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { - FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>(); - VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>(); - FSN->Signature = Arena.alloc<ThunkSignatureNode>(); - FSN->Signature->FunctionClass = FC_NoParameterList; - - FSN->Name = demangleNameScopeChain(MangledName, VTIN); - if (!Error) - Error = !MangledName.consumeFront("$B"); - if (!Error) - VTIN->OffsetInVTable = demangleUnsigned(MangledName); - if (!Error) - Error = !MangledName.consumeFront('A'); - if (!Error) - FSN->Signature->CallConvention = demangleCallingConvention(MangledName); - return (Error) ? nullptr : FSN; -} - -EncodedStringLiteralNode * -Demangler::demangleStringLiteral(StringView &MangledName) { - // This function uses goto, so declare all variables up front. - OutputBuffer OB; - StringView CRC; - uint64_t StringByteSize; - bool IsWcharT = false; - bool IsNegative = false; - size_t CrcEndPos = 0; - - EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>(); - - // Prefix indicating the beginning of a string literal - if (!MangledName.consumeFront("@_")) - goto StringLiteralError; - if (MangledName.empty()) - goto StringLiteralError; - - // Char Type (regular or wchar_t) - switch (MangledName.popFront()) { - case '1': - IsWcharT = true; - DEMANGLE_FALLTHROUGH; - case '0': - break; - default: - goto StringLiteralError; - } - - // Encoded Length - std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName); - if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1)) - goto StringLiteralError; - - // CRC 32 (always 8 characters plus a terminator) - CrcEndPos = MangledName.find('@'); - if (CrcEndPos == StringView::npos) - goto StringLiteralError; - CRC = MangledName.substr(0, CrcEndPos); - MangledName = MangledName.dropFront(CrcEndPos + 1); - if (MangledName.empty()) - goto StringLiteralError; - - if (IsWcharT) { - Result->Char = CharKind::Wchar; - if (StringByteSize > 64) - Result->IsTruncated = true; - - while (!MangledName.consumeFront('@')) { - if (MangledName.size() < 2) - goto StringLiteralError; - wchar_t W = demangleWcharLiteral(MangledName); - if (StringByteSize != 2 || Result->IsTruncated) - outputEscapedChar(OB, W); - StringByteSize -= 2; - if (Error) - goto StringLiteralError; - } - } else { - // The max byte length is actually 32, but some compilers mangled strings - // incorrectly, so we have to assume it can go higher. - constexpr unsigned MaxStringByteLength = 32 * 4; - uint8_t StringBytes[MaxStringByteLength]; - - unsigned BytesDecoded = 0; - while (!MangledName.consumeFront('@')) { - if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength) - goto StringLiteralError; - StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName); - } - - if (StringByteSize > BytesDecoded) - Result->IsTruncated = true; - - unsigned CharBytes = - guessCharByteSize(StringBytes, BytesDecoded, StringByteSize); - assert(StringByteSize % CharBytes == 0); - switch (CharBytes) { - case 1: - Result->Char = CharKind::Char; - break; - case 2: - Result->Char = CharKind::Char16; - break; - case 4: - Result->Char = CharKind::Char32; - break; - default: - DEMANGLE_UNREACHABLE; - } - const unsigned NumChars = BytesDecoded / CharBytes; - for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) { - unsigned NextChar = - decodeMultiByteChar(StringBytes, CharIndex, CharBytes); - if (CharIndex + 1 < NumChars || Result->IsTruncated) - outputEscapedChar(OB, NextChar); - } - } - - Result->DecodedString = copyString(OB); - std::free(OB.getBuffer()); - return Result; - -StringLiteralError: - Error = true; - std::free(OB.getBuffer()); - return nullptr; -} - -// Returns MangledName's prefix before the first '@', or an error if -// MangledName contains no '@' or the prefix has length 0. -StringView Demangler::demangleSimpleString(StringView &MangledName, - bool Memorize) { - StringView S; - for (size_t i = 0; i < MangledName.size(); ++i) { - if (MangledName[i] != '@') - continue; - if (i == 0) - break; - S = MangledName.substr(0, i); - MangledName = MangledName.dropFront(i + 1); - - if (Memorize) - memorizeString(S); - return S; - } - - Error = true; - return {}; -} - -NamedIdentifierNode * -Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { - assert(MangledName.startsWith("?A")); - MangledName.consumeFront("?A"); - - NamedIdentifierNode *Node = Arena.alloc<NamedIdentifierNode>(); - Node->Name = "`anonymous namespace'"; - size_t EndPos = MangledName.find('@'); - if (EndPos == StringView::npos) { - Error = true; - return nullptr; - } - StringView NamespaceKey = MangledName.substr(0, EndPos); - memorizeString(NamespaceKey); - MangledName = MangledName.substr(EndPos + 1); - return Node; -} - -NamedIdentifierNode * -Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { - assert(startsWithLocalScopePattern(MangledName)); - - NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>(); - MangledName.consumeFront('?'); - uint64_t Number = 0; - bool IsNegative = false; - std::tie(Number, IsNegative) = demangleNumber(MangledName); - assert(!IsNegative); - - // One ? to terminate the number - MangledName.consumeFront('?'); - - assert(!Error); - Node *Scope = parse(MangledName); - if (Error) - return nullptr; - - // Render the parent symbol's name into a buffer. - OutputBuffer OB; - OB << '`'; - Scope->output(OB, OF_Default); - OB << '\''; - OB << "::`" << Number << "'"; - - Identifier->Name = copyString(OB); - std::free(OB.getBuffer()); - return Identifier; -} - -// Parses a type name in the form of A@B@C@@ which represents C::B::A. -QualifiedNameNode * -Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { - IdentifierNode *Identifier = - demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); - if (Error) - return nullptr; - assert(Identifier); - - QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); - if (Error) - return nullptr; - assert(QN); - return QN; -} - -// Parses a symbol name in the form of A@B@C@@ which represents C::B::A. -// Symbol names have slightly different rules regarding what can appear -// so we separate out the implementations for flexibility. -QualifiedNameNode * -Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { - // This is the final component of a symbol name (i.e. the leftmost component - // of a mangled name. Since the only possible template instantiation that - // can appear in this context is a function template, and since those are - // not saved for the purposes of name backreferences, only backref simple - // names. - IdentifierNode *Identifier = - demangleUnqualifiedSymbolName(MangledName, NBB_Simple); - if (Error) - return nullptr; - - QualifiedNameNode *QN = demangleNameScopeChain(MangledName, Identifier); - if (Error) - return nullptr; - - if (Identifier->kind() == NodeKind::StructorIdentifier) { - if (QN->Components->Count < 2) { - Error = true; - return nullptr; - } - StructorIdentifierNode *SIN = - static_cast<StructorIdentifierNode *>(Identifier); - Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2]; - SIN->Class = static_cast<IdentifierNode *>(ClassNode); - } - assert(QN); - return QN; -} - -IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName, - bool Memorize) { - // An inner-most name can be a back-reference, because a fully-qualified name - // (e.g. Scope + Inner) can contain other fully qualified names inside of - // them (for example template parameters), and these nested parameters can - // refer to previously mangled types. - if (startsWithDigit(MangledName)) - return demangleBackRefName(MangledName); - - if (MangledName.startsWith("?$")) - return demangleTemplateInstantiationName(MangledName, NBB_Template); - - return demangleSimpleName(MangledName, Memorize); -} - -IdentifierNode * -Demangler::demangleUnqualifiedSymbolName(StringView &MangledName, - NameBackrefBehavior NBB) { - if (startsWithDigit(MangledName)) - return demangleBackRefName(MangledName); - if (MangledName.startsWith("?$")) - return demangleTemplateInstantiationName(MangledName, NBB); - if (MangledName.startsWith('?')) - return demangleFunctionIdentifierCode(MangledName); - return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0); -} - -IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) { - if (startsWithDigit(MangledName)) - return demangleBackRefName(MangledName); - - if (MangledName.startsWith("?$")) - return demangleTemplateInstantiationName(MangledName, NBB_Template); - - if (MangledName.startsWith("?A")) - return demangleAnonymousNamespaceName(MangledName); - - if (startsWithLocalScopePattern(MangledName)) - return demangleLocallyScopedNamePiece(MangledName); - - return demangleSimpleName(MangledName, /*Memorize=*/true); -} - -static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head, - size_t Count) { - NodeArrayNode *N = Arena.alloc<NodeArrayNode>(); - N->Count = Count; - N->Nodes = Arena.allocArray<Node *>(Count); - for (size_t I = 0; I < Count; ++I) { - N->Nodes[I] = Head->N; - Head = Head->Next; - } - return N; -} - -QualifiedNameNode * -Demangler::demangleNameScopeChain(StringView &MangledName, - IdentifierNode *UnqualifiedName) { - NodeList *Head = Arena.alloc<NodeList>(); - - Head->N = UnqualifiedName; - - size_t Count = 1; - while (!MangledName.consumeFront("@")) { - ++Count; - NodeList *NewHead = Arena.alloc<NodeList>(); - NewHead->Next = Head; - Head = NewHead; - - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - assert(!Error); - IdentifierNode *Elem = demangleNameScopePiece(MangledName); - if (Error) - return nullptr; - - Head->N = Elem; - } - - QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>(); - QN->Components = nodeListToNodeArray(Arena, Head, Count); - return QN; -} - -FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { - switch (MangledName.popFront()) { - case '9': - return FuncClass(FC_ExternC | FC_NoParameterList); - case 'A': - return FC_Private; - case 'B': - return FuncClass(FC_Private | FC_Far); - case 'C': - return FuncClass(FC_Private | FC_Static); - case 'D': - return FuncClass(FC_Private | FC_Static | FC_Far); - case 'E': - return FuncClass(FC_Private | FC_Virtual); - case 'F': - return FuncClass(FC_Private | FC_Virtual | FC_Far); - case 'G': - return FuncClass(FC_Private | FC_StaticThisAdjust); - case 'H': - return FuncClass(FC_Private | FC_StaticThisAdjust | FC_Far); - case 'I': - return FuncClass(FC_Protected); - case 'J': - return FuncClass(FC_Protected | FC_Far); - case 'K': - return FuncClass(FC_Protected | FC_Static); - case 'L': - return FuncClass(FC_Protected | FC_Static | FC_Far); - case 'M': - return FuncClass(FC_Protected | FC_Virtual); - case 'N': - return FuncClass(FC_Protected | FC_Virtual | FC_Far); - case 'O': - return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust); - case 'P': - return FuncClass(FC_Protected | FC_Virtual | FC_StaticThisAdjust | FC_Far); - case 'Q': - return FuncClass(FC_Public); - case 'R': - return FuncClass(FC_Public | FC_Far); - case 'S': - return FuncClass(FC_Public | FC_Static); - case 'T': - return FuncClass(FC_Public | FC_Static | FC_Far); - case 'U': - return FuncClass(FC_Public | FC_Virtual); - case 'V': - return FuncClass(FC_Public | FC_Virtual | FC_Far); - case 'W': - return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust); - case 'X': - return FuncClass(FC_Public | FC_Virtual | FC_StaticThisAdjust | FC_Far); - case 'Y': - return FuncClass(FC_Global); - case 'Z': - return FuncClass(FC_Global | FC_Far); - case '$': { - FuncClass VFlag = FC_VirtualThisAdjust; - if (MangledName.consumeFront('R')) - VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx); - if (MangledName.empty()) - break; - switch (MangledName.popFront()) { - case '0': - return FuncClass(FC_Private | FC_Virtual | VFlag); - case '1': - return FuncClass(FC_Private | FC_Virtual | VFlag | FC_Far); - case '2': - return FuncClass(FC_Protected | FC_Virtual | VFlag); - case '3': - return FuncClass(FC_Protected | FC_Virtual | VFlag | FC_Far); - case '4': - return FuncClass(FC_Public | FC_Virtual | VFlag); - case '5': - return FuncClass(FC_Public | FC_Virtual | VFlag | FC_Far); - } - } - } - - Error = true; - return FC_Public; -} - -CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { - if (MangledName.empty()) { - Error = true; - return CallingConv::None; - } - - switch (MangledName.popFront()) { - case 'A': - case 'B': - return CallingConv::Cdecl; - case 'C': - case 'D': - return CallingConv::Pascal; - case 'E': - case 'F': - return CallingConv::Thiscall; - case 'G': - case 'H': - return CallingConv::Stdcall; - case 'I': - case 'J': - return CallingConv::Fastcall; - case 'M': - case 'N': - return CallingConv::Clrcall; - case 'O': - case 'P': - return CallingConv::Eabi; - case 'Q': - return CallingConv::Vectorcall; - case 'S': - return CallingConv::Swift; - case 'W': - return CallingConv::SwiftAsync; - } - - return CallingConv::None; -} - -StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { - assert(MangledName.front() >= '0' && MangledName.front() <= '4'); - - switch (MangledName.popFront()) { - case '0': - return StorageClass::PrivateStatic; - case '1': - return StorageClass::ProtectedStatic; - case '2': - return StorageClass::PublicStatic; - case '3': - return StorageClass::Global; - case '4': - return StorageClass::FunctionLocalStatic; - } - DEMANGLE_UNREACHABLE; -} - -std::pair<Qualifiers, bool> -Demangler::demangleQualifiers(StringView &MangledName) { - if (MangledName.empty()) { - Error = true; - return std::make_pair(Q_None, false); - } - - switch (MangledName.popFront()) { - // Member qualifiers - case 'Q': - return std::make_pair(Q_None, true); - case 'R': - return std::make_pair(Q_Const, true); - case 'S': - return std::make_pair(Q_Volatile, true); - case 'T': - return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true); - // Non-Member qualifiers - case 'A': - return std::make_pair(Q_None, false); - case 'B': - return std::make_pair(Q_Const, false); - case 'C': - return std::make_pair(Q_Volatile, false); - case 'D': - return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false); - } - Error = true; - return std::make_pair(Q_None, false); -} - -// <variable-type> ::= <type> <cvr-qualifiers> -// ::= <type> <pointee-cvr-qualifiers> # pointers, references -TypeNode *Demangler::demangleType(StringView &MangledName, - QualifierMangleMode QMM) { - Qualifiers Quals = Q_None; - bool IsMember = false; - if (QMM == QualifierMangleMode::Mangle) { - std::tie(Quals, IsMember) = demangleQualifiers(MangledName); - } else if (QMM == QualifierMangleMode::Result) { - if (MangledName.consumeFront('?')) - std::tie(Quals, IsMember) = demangleQualifiers(MangledName); - } - - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - TypeNode *Ty = nullptr; - if (isTagType(MangledName)) - Ty = demangleClassType(MangledName); - else if (isPointerType(MangledName)) { - if (isMemberPointer(MangledName, Error)) - Ty = demangleMemberPointerType(MangledName); - else if (!Error) - Ty = demanglePointerType(MangledName); - else - return nullptr; - } else if (isArrayType(MangledName)) - Ty = demangleArrayType(MangledName); - else if (isFunctionType(MangledName)) { - if (MangledName.consumeFront("$$A8@@")) - Ty = demangleFunctionType(MangledName, true); - else { - assert(MangledName.startsWith("$$A6")); - MangledName.consumeFront("$$A6"); - Ty = demangleFunctionType(MangledName, false); - } - } else if (isCustomType(MangledName)) { - Ty = demangleCustomType(MangledName); - } else { - Ty = demanglePrimitiveType(MangledName); - } - - if (!Ty || Error) - return Ty; - Ty->Quals = Qualifiers(Ty->Quals | Quals); - return Ty; -} - -bool Demangler::demangleThrowSpecification(StringView &MangledName) { - if (MangledName.consumeFront("_E")) - return true; - if (MangledName.consumeFront('Z')) - return false; - - Error = true; - return false; -} - -FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, - bool HasThisQuals) { - FunctionSignatureNode *FTy = Arena.alloc<FunctionSignatureNode>(); - - if (HasThisQuals) { - FTy->Quals = demanglePointerExtQualifiers(MangledName); - FTy->RefQualifier = demangleFunctionRefQualifier(MangledName); - FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first); - } - - // Fields that appear on both member and non-member functions. - FTy->CallConvention = demangleCallingConvention(MangledName); - - // <return-type> ::= <type> - // ::= @ # structors (they have no declared return type) - bool IsStructor = MangledName.consumeFront('@'); - if (!IsStructor) - FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); - - FTy->Params = demangleFunctionParameterList(MangledName, FTy->IsVariadic); - - FTy->IsNoexcept = demangleThrowSpecification(MangledName); - - return FTy; -} - -FunctionSymbolNode * -Demangler::demangleFunctionEncoding(StringView &MangledName) { - FuncClass ExtraFlags = FC_None; - if (MangledName.consumeFront("$$J0")) - ExtraFlags = FC_ExternC; - - if (MangledName.empty()) { - Error = true; - return nullptr; - } - - FuncClass FC = demangleFunctionClass(MangledName); - FC = FuncClass(ExtraFlags | FC); - - FunctionSignatureNode *FSN = nullptr; - ThunkSignatureNode *TTN = nullptr; - if (FC & FC_StaticThisAdjust) { - TTN = Arena.alloc<ThunkSignatureNode>(); - TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); - } else if (FC & FC_VirtualThisAdjust) { - TTN = Arena.alloc<ThunkSignatureNode>(); - if (FC & FC_VirtualThisAdjustEx) { - TTN->ThisAdjust.VBPtrOffset = demangleSigned(MangledName); - TTN->ThisAdjust.VBOffsetOffset = demangleSigned(MangledName); - } - TTN->ThisAdjust.VtordispOffset = demangleSigned(MangledName); - TTN->ThisAdjust.StaticOffset = demangleSigned(MangledName); - } - - if (FC & FC_NoParameterList) { - // This is an extern "C" function whose full signature hasn't been mangled. - // This happens when we need to mangle a local symbol inside of an extern - // "C" function. - FSN = Arena.alloc<FunctionSignatureNode>(); - } else { - bool HasThisQuals = !(FC & (FC_Global | FC_Static)); - FSN = demangleFunctionType(MangledName, HasThisQuals); - } - - if (Error) - return nullptr; - - if (TTN) { - *static_cast<FunctionSignatureNode *>(TTN) = *FSN; - FSN = TTN; - } - FSN->FunctionClass = FC; - - FunctionSymbolNode *Symbol = Arena.alloc<FunctionSymbolNode>(); - Symbol->Signature = FSN; - return Symbol; -} - -CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) { - assert(MangledName.startsWith('?')); - MangledName.popFront(); - - CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>(); - CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); - if (!MangledName.consumeFront('@')) - Error = true; - if (Error) - return nullptr; - return CTN; -} - -// Reads a primitive type. -PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { - if (MangledName.consumeFront("$$T")) - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Nullptr); - - switch (MangledName.popFront()) { - case 'X': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void); - case 'D': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char); - case 'C': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Schar); - case 'E': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uchar); - case 'F': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Short); - case 'G': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ushort); - case 'H': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int); - case 'I': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint); - case 'J': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Long); - case 'K': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ulong); - case 'M': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Float); - case 'N': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Double); - case 'O': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Ldouble); - case '_': { - if (MangledName.empty()) { - Error = true; - return nullptr; - } - switch (MangledName.popFront()) { - case 'N': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool); - case 'J': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Int64); - case 'K': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64); - case 'W': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar); - case 'Q': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char8); - case 'S': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16); - case 'U': - return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char32); - } - break; - } - } - Error = true; - return nullptr; -} - -TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { - TagTypeNode *TT = nullptr; - - switch (MangledName.popFront()) { - case 'T': - TT = Arena.alloc<TagTypeNode>(TagKind::Union); - break; - case 'U': - TT = Arena.alloc<TagTypeNode>(TagKind::Struct); - break; - case 'V': - TT = Arena.alloc<TagTypeNode>(TagKind::Class); - break; - case 'W': - if (!MangledName.consumeFront('4')) { - Error = true; - return nullptr; - } - TT = Arena.alloc<TagTypeNode>(TagKind::Enum); - break; - default: - assert(false); - } - - TT->QualifiedName = demangleFullyQualifiedTypeName(MangledName); - return TT; -} - -// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type> -// # the E is required for 64-bit non-static pointers -PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) { - PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>(); - - std::tie(Pointer->Quals, Pointer->Affinity) = - demanglePointerCVQualifiers(MangledName); - - if (MangledName.consumeFront("6")) { - Pointer->Pointee = demangleFunctionType(MangledName, false); - return Pointer; - } - - Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); - Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); - - Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); - return Pointer; -} - -PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { - PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>(); - - std::tie(Pointer->Quals, Pointer->Affinity) = - demanglePointerCVQualifiers(MangledName); - assert(Pointer->Affinity == PointerAffinity::Pointer); - - Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); - Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); - - // isMemberPointer() only returns true if there is at least one character - // after the qualifiers. - if (MangledName.consumeFront("8")) { - Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); - Pointer->Pointee = demangleFunctionType(MangledName, true); - } else { - Qualifiers PointeeQuals = Q_None; - bool IsMember = false; - std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName); - assert(IsMember || Error); - Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); - - Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop); - if (Pointer->Pointee) - Pointer->Pointee->Quals = PointeeQuals; - } - - return Pointer; -} - -Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) { - Qualifiers Quals = Q_None; - if (MangledName.consumeFront('E')) - Quals = Qualifiers(Quals | Q_Pointer64); - if (MangledName.consumeFront('I')) - Quals = Qualifiers(Quals | Q_Restrict); - if (MangledName.consumeFront('F')) - Quals = Qualifiers(Quals | Q_Unaligned); - - return Quals; -} - -ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { - assert(MangledName.front() == 'Y'); - MangledName.popFront(); - - uint64_t Rank = 0; - bool IsNegative = false; - std::tie(Rank, IsNegative) = demangleNumber(MangledName); - if (IsNegative || Rank == 0) { - Error = true; - return nullptr; - } - - ArrayTypeNode *ATy = Arena.alloc<ArrayTypeNode>(); - NodeList *Head = Arena.alloc<NodeList>(); - NodeList *Tail = Head; - - for (uint64_t I = 0; I < Rank; ++I) { - uint64_t D = 0; - std::tie(D, IsNegative) = demangleNumber(MangledName); - if (Error || IsNegative) { - Error = true; - return nullptr; - } - Tail->N = Arena.alloc<IntegerLiteralNode>(D, IsNegative); - if (I + 1 < Rank) { - Tail->Next = Arena.alloc<NodeList>(); - Tail = Tail->Next; - } - } - ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank); - - if (MangledName.consumeFront("$$C")) { - bool IsMember = false; - std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName); - if (IsMember) { - Error = true; - return nullptr; - } - } - - ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop); - return ATy; -} - -// Reads a function's parameters. -NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, - bool &IsVariadic) { - // Empty parameter list. - if (MangledName.consumeFront('X')) - return nullptr; - - NodeList *Head = Arena.alloc<NodeList>(); - NodeList **Current = &Head; - size_t Count = 0; - while (!Error && !MangledName.startsWith('@') && - !MangledName.startsWith('Z')) { - ++Count; - - if (startsWithDigit(MangledName)) { - size_t N = MangledName[0] - '0'; - if (N >= Backrefs.FunctionParamCount) { - Error = true; - return nullptr; - } - MangledName = MangledName.dropFront(); - - *Current = Arena.alloc<NodeList>(); - (*Current)->N = Backrefs.FunctionParams[N]; - Current = &(*Current)->Next; - continue; - } - - size_t OldSize = MangledName.size(); - - *Current = Arena.alloc<NodeList>(); - TypeNode *TN = demangleType(MangledName, QualifierMangleMode::Drop); - if (!TN || Error) - return nullptr; - - (*Current)->N = TN; - - size_t CharsConsumed = OldSize - MangledName.size(); - assert(CharsConsumed != 0); - - // Single-letter types are ignored for backreferences because memorizing - // them doesn't save anything. - if (Backrefs.FunctionParamCount <= 9 && CharsConsumed > 1) - Backrefs.FunctionParams[Backrefs.FunctionParamCount++] = TN; - - Current = &(*Current)->Next; - } - - if (Error) - return nullptr; - - NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count); - // A non-empty parameter list is terminated by either 'Z' (variadic) parameter - // list or '@' (non variadic). Careful not to consume "@Z", as in that case - // the following Z could be a throw specifier. - if (MangledName.consumeFront('@')) - return NA; - - if (MangledName.consumeFront('Z')) { - IsVariadic = true; - return NA; - } - - DEMANGLE_UNREACHABLE; -} - -NodeArrayNode * -Demangler::demangleTemplateParameterList(StringView &MangledName) { - NodeList *Head = nullptr; - NodeList **Current = &Head; - size_t Count = 0; - - while (!MangledName.startsWith('@')) { - if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || - MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) { - // parameter pack separator - continue; - } - - ++Count; - - // Template parameter lists don't participate in back-referencing. - *Current = Arena.alloc<NodeList>(); - - NodeList &TP = **Current; - - TemplateParameterReferenceNode *TPRN = nullptr; - if (MangledName.consumeFront("$$Y")) { - // Template alias - TP.N = demangleFullyQualifiedTypeName(MangledName); - } else if (MangledName.consumeFront("$$B")) { - // Array - TP.N = demangleType(MangledName, QualifierMangleMode::Drop); - } else if (MangledName.consumeFront("$$C")) { - // Type has qualifiers. - TP.N = demangleType(MangledName, QualifierMangleMode::Mangle); - } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") || - MangledName.startsWith("$I") || MangledName.startsWith("$J")) { - // Pointer to member - TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); - TPRN->IsMemberPointer = true; - - MangledName = MangledName.dropFront(); - // 1 - single inheritance <name> - // H - multiple inheritance <name> <number> - // I - virtual inheritance <name> <number> <number> - // J - unspecified inheritance <name> <number> <number> <number> - char InheritanceSpecifier = MangledName.popFront(); - SymbolNode *S = nullptr; - if (MangledName.startsWith('?')) { - S = parse(MangledName); - if (Error || !S->Name) { - Error = true; - return nullptr; - } - memorizeIdentifier(S->Name->getUnqualifiedIdentifier()); - } - - switch (InheritanceSpecifier) { - case 'J': - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - DEMANGLE_FALLTHROUGH; - case 'I': - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - DEMANGLE_FALLTHROUGH; - case 'H': - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - DEMANGLE_FALLTHROUGH; - case '1': - break; - default: - DEMANGLE_UNREACHABLE; - } - TPRN->Affinity = PointerAffinity::Pointer; - TPRN->Symbol = S; - } else if (MangledName.startsWith("$E?")) { - MangledName.consumeFront("$E"); - // Reference to symbol - TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); - TPRN->Symbol = parse(MangledName); - TPRN->Affinity = PointerAffinity::Reference; - } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) { - TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>(); - - // Data member pointer. - MangledName = MangledName.dropFront(); - char InheritanceSpecifier = MangledName.popFront(); - - switch (InheritanceSpecifier) { - case 'G': - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - DEMANGLE_FALLTHROUGH; - case 'F': - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] = - demangleSigned(MangledName); - break; - default: - DEMANGLE_UNREACHABLE; - } - TPRN->IsMemberPointer = true; - - } else if (MangledName.consumeFront("$0")) { - // Integral non-type template parameter - bool IsNegative = false; - uint64_t Value = 0; - std::tie(Value, IsNegative) = demangleNumber(MangledName); - - TP.N = Arena.alloc<IntegerLiteralNode>(Value, IsNegative); - } else { - TP.N = demangleType(MangledName, QualifierMangleMode::Drop); - } - if (Error) - return nullptr; - - Current = &TP.Next; - } - - // The loop above returns nullptr on Error. - assert(!Error); - - // Template parameter lists cannot be variadic, so it can only be terminated - // by @ (as opposed to 'Z' in the function parameter case). - assert(MangledName.startsWith('@')); // The above loop exits only on '@'. - MangledName.consumeFront('@'); - return nodeListToNodeArray(Arena, Head, Count); -} - -void Demangler::dumpBackReferences() { - std::printf("%d function parameter backreferences\n", - (int)Backrefs.FunctionParamCount); - - // Create an output stream so we can render each type. - OutputBuffer OB; - for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { - OB.setCurrentPosition(0); - - TypeNode *T = Backrefs.FunctionParams[I]; - T->output(OB, OF_Default); - - StringView B = OB; - std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin()); - } - std::free(OB.getBuffer()); - - if (Backrefs.FunctionParamCount > 0) - std::printf("\n"); - std::printf("%d name backreferences\n", (int)Backrefs.NamesCount); - for (size_t I = 0; I < Backrefs.NamesCount; ++I) { - std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(), - Backrefs.Names[I]->Name.begin()); - } - if (Backrefs.NamesCount > 0) - std::printf("\n"); -} - -char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, - char *Buf, size_t *N, - int *Status, MSDemangleFlags Flags) { - Demangler D; - - StringView Name{MangledName}; - SymbolNode *AST = D.parse(Name); - if (!D.Error && NMangled) - *NMangled = Name.begin() - MangledName; - - if (Flags & MSDF_DumpBackrefs) - D.dumpBackReferences(); - - OutputFlags OF = OF_Default; - if (Flags & MSDF_NoCallingConvention) - OF = OutputFlags(OF | OF_NoCallingConvention); - if (Flags & MSDF_NoAccessSpecifier) - OF = OutputFlags(OF | OF_NoAccessSpecifier); - if (Flags & MSDF_NoReturnType) - OF = OutputFlags(OF | OF_NoReturnType); - if (Flags & MSDF_NoMemberType) - OF = OutputFlags(OF | OF_NoMemberType); - if (Flags & MSDF_NoVariableType) - OF = OutputFlags(OF | OF_NoVariableType); - - int InternalStatus = demangle_success; - if (D.Error) - InternalStatus = demangle_invalid_mangled_name; - else { - OutputBuffer OB(Buf, N); - AST->output(OB, OF); - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - Buf = OB.getBuffer(); - } - - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; -} diff --git a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp deleted file mode 100644 index 975649f2..00000000 --- a/demangle/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp +++ /dev/null @@ -1,658 +0,0 @@ -//===- MicrosoftDemangle.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a demangler for MSVC-style mangled symbols. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Demangle/MicrosoftDemangleNodes.h" -#include "llvm/Demangle/Utility.h" -#include <cctype> -#include <string> - -using namespace llvm; -using namespace ms_demangle; - -#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ - case Enum::Value: \ - OB << Desc; \ - break; - -// Writes a space if the last token does not end with a punctuation. -static void outputSpaceIfNecessary(OutputBuffer &OB) { - if (OB.empty()) - return; - - char C = OB.back(); - if (std::isalnum(C) || C == '>') - OB << " "; -} - -static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) { - switch (Q) { - case Q_Const: - OB << "const"; - break; - case Q_Volatile: - OB << "volatile"; - break; - case Q_Restrict: - OB << "__restrict"; - break; - default: - break; - } -} - -static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, - Qualifiers Mask, bool NeedSpace) { - if (!(Q & Mask)) - return NeedSpace; - - if (NeedSpace) - OB << " "; - - outputSingleQualifier(OB, Mask); - return true; -} - -static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, - bool SpaceAfter) { - if (Q == Q_None) - return; - - size_t Pos1 = OB.getCurrentPosition(); - SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore); - size_t Pos2 = OB.getCurrentPosition(); - if (SpaceAfter && Pos2 > Pos1) - OB << " "; -} - -static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { - outputSpaceIfNecessary(OB); - - switch (CC) { - case CallingConv::Cdecl: - OB << "__cdecl"; - break; - case CallingConv::Fastcall: - OB << "__fastcall"; - break; - case CallingConv::Pascal: - OB << "__pascal"; - break; - case CallingConv::Regcall: - OB << "__regcall"; - break; - case CallingConv::Stdcall: - OB << "__stdcall"; - break; - case CallingConv::Thiscall: - OB << "__thiscall"; - break; - case CallingConv::Eabi: - OB << "__eabi"; - break; - case CallingConv::Vectorcall: - OB << "__vectorcall"; - break; - case CallingConv::Clrcall: - OB << "__clrcall"; - break; - case CallingConv::Swift: - OB << "__attribute__((__swiftcall__)) "; - break; - case CallingConv::SwiftAsync: - OB << "__attribute__((__swiftasynccall__)) "; - break; - default: - break; - } -} - -std::string Node::toString(OutputFlags Flags) const { - OutputBuffer OB; - this->output(OB, Flags); - StringView SV = OB; - std::string Owned(SV.begin(), SV.end()); - std::free(OB.getBuffer()); - return Owned; -} - -void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - switch (PrimKind) { - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); - OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); - } - outputQualifiers(OB, Quals, true, false); -} - -void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { - output(OB, Flags, ", "); -} - -void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, - StringView Separator) const { - if (Count == 0) - return; - if (Nodes[0]) - Nodes[0]->output(OB, Flags); - for (size_t I = 1; I < Count; ++I) { - OB << Separator; - Nodes[I]->output(OB, Flags); - } -} - -void EncodedStringLiteralNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - switch (Char) { - case CharKind::Wchar: - OB << "L\""; - break; - case CharKind::Char: - OB << "\""; - break; - case CharKind::Char16: - OB << "u\""; - break; - case CharKind::Char32: - OB << "U\""; - break; - } - OB << DecodedString << "\""; - if (IsTruncated) - OB << "..."; -} - -void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { - if (IsNegative) - OB << '-'; - OB << Value; -} - -void TemplateParameterReferenceNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - if (ThunkOffsetCount > 0) - OB << "{"; - else if (Affinity == PointerAffinity::Pointer) - OB << "&"; - - if (Symbol) { - Symbol->output(OB, Flags); - if (ThunkOffsetCount > 0) - OB << ", "; - } - - if (ThunkOffsetCount > 0) - OB << ThunkOffsets[0]; - for (int I = 1; I < ThunkOffsetCount; ++I) { - OB << ", " << ThunkOffsets[I]; - } - if (ThunkOffsetCount > 0) - OB << "}"; -} - -void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, - OutputFlags Flags) const { - if (!TemplateParams) - return; - OB << "<"; - TemplateParams->output(OB, Flags); - OB << ">"; -} - -void DynamicStructorIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - if (IsDestructor) - OB << "`dynamic atexit destructor for "; - else - OB << "`dynamic initializer for "; - - if (Variable) { - OB << "`"; - Variable->output(OB, Flags); - OB << "''"; - } else { - OB << "'"; - Name->output(OB, Flags); - OB << "''"; - } -} - -void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OB << Name; - outputTemplateParameters(OB, Flags); -} - -void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - switch (Operator) { - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator=="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, - "operator[]"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, - "operator->*"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, - "operator>="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, - "operator&="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, - "operator|="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, - "operator^="); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, - "`vector deleting dtor'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, - "`default ctor closure'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, - "`scalar deleting dtor'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, - "`vector ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, - "`vector dtor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, - "`vector vbase ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, - "`virtual displacement map'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, - "`eh vector ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, - "`eh vector dtor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, - "`eh vector vbase ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, - "`copy ctor closure'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, - "`local vftable ctor closure'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, - "operator delete[]"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, - "`managed vector ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, - "`managed vector dtor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, - "`EH vector copy ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, - "`EH vector vbase copy ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, - "`vector copy ctor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, - "`vector vbase copy constructor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, - "`managed vector vbase copy constructor iterator'"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, - "operator co_await"); - OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); - case IntrinsicFunctionKind::MaxIntrinsic: - case IntrinsicFunctionKind::None: - break; - } - outputTemplateParameters(OB, Flags); -} - -void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - if (IsThread) - OB << "`local static thread guard'"; - else - OB << "`local static guard'"; - if (ScopeIndex > 0) - OB << "{" << ScopeIndex << "}"; -} - -void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - OB << "operator"; - outputTemplateParameters(OB, Flags); - OB << " "; - TargetType->output(OB, Flags); -} - -void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - if (IsDestructor) - OB << "~"; - Class->output(OB, Flags); - outputTemplateParameters(OB, Flags); -} - -void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - OB << "operator \"\"" << Name; - outputTemplateParameters(OB, Flags); -} - -void FunctionSignatureNode::outputPre(OutputBuffer &OB, - OutputFlags Flags) const { - if (!(Flags & OF_NoAccessSpecifier)) { - if (FunctionClass & FC_Public) - OB << "public: "; - if (FunctionClass & FC_Protected) - OB << "protected: "; - if (FunctionClass & FC_Private) - OB << "private: "; - } - - if (!(Flags & OF_NoMemberType)) { - if (!(FunctionClass & FC_Global)) { - if (FunctionClass & FC_Static) - OB << "static "; - } - if (FunctionClass & FC_Virtual) - OB << "virtual "; - - if (FunctionClass & FC_ExternC) - OB << "extern \"C\" "; - } - - if (!(Flags & OF_NoReturnType) && ReturnType) { - ReturnType->outputPre(OB, Flags); - OB << " "; - } - - if (!(Flags & OF_NoCallingConvention)) - outputCallingConvention(OB, CallConvention); -} - -void FunctionSignatureNode::outputPost(OutputBuffer &OB, - OutputFlags Flags) const { - if (!(FunctionClass & FC_NoParameterList)) { - OB << "("; - if (Params) - Params->output(OB, Flags); - else - OB << "void"; - - if (IsVariadic) { - if (OB.back() != '(') - OB << ", "; - OB << "..."; - } - OB << ")"; - } - - if (Quals & Q_Const) - OB << " const"; - if (Quals & Q_Volatile) - OB << " volatile"; - if (Quals & Q_Restrict) - OB << " __restrict"; - if (Quals & Q_Unaligned) - OB << " __unaligned"; - - if (IsNoexcept) - OB << " noexcept"; - - if (RefQualifier == FunctionRefQualifier::Reference) - OB << " &"; - else if (RefQualifier == FunctionRefQualifier::RValueReference) - OB << " &&"; - - if (!(Flags & OF_NoReturnType) && ReturnType) - ReturnType->outputPost(OB, Flags); -} - -void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - OB << "[thunk]: "; - - FunctionSignatureNode::outputPre(OB, Flags); -} - -void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { - if (FunctionClass & FC_StaticThisAdjust) { - OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; - } else if (FunctionClass & FC_VirtualThisAdjust) { - if (FunctionClass & FC_VirtualThisAdjustEx) { - OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " - << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset - << ", " << ThisAdjust.StaticOffset << "}'"; - } else { - OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " - << ThisAdjust.StaticOffset << "}'"; - } - } - - FunctionSignatureNode::outputPost(OB, Flags); -} - -void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - if (Pointee->kind() == NodeKind::FunctionSignature) { - // If this is a pointer to a function, don't output the calling convention. - // It needs to go inside the parentheses. - const FunctionSignatureNode *Sig = - static_cast<const FunctionSignatureNode *>(Pointee); - Sig->outputPre(OB, OF_NoCallingConvention); - } else - Pointee->outputPre(OB, Flags); - - outputSpaceIfNecessary(OB); - - if (Quals & Q_Unaligned) - OB << "__unaligned "; - - if (Pointee->kind() == NodeKind::ArrayType) { - OB << "("; - } else if (Pointee->kind() == NodeKind::FunctionSignature) { - OB << "("; - const FunctionSignatureNode *Sig = - static_cast<const FunctionSignatureNode *>(Pointee); - outputCallingConvention(OB, Sig->CallConvention); - OB << " "; - } - - if (ClassParent) { - ClassParent->output(OB, Flags); - OB << "::"; - } - - switch (Affinity) { - case PointerAffinity::Pointer: - OB << "*"; - break; - case PointerAffinity::Reference: - OB << "&"; - break; - case PointerAffinity::RValueReference: - OB << "&&"; - break; - default: - assert(false); - } - outputQualifiers(OB, Quals, false, false); -} - -void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { - if (Pointee->kind() == NodeKind::ArrayType || - Pointee->kind() == NodeKind::FunctionSignature) - OB << ")"; - - Pointee->outputPost(OB, Flags); -} - -void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - if (!(Flags & OF_NoTagSpecifier)) { - switch (Tag) { - OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); - OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct"); - OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); - OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); - } - OB << " "; - } - QualifiedName->output(OB, Flags); - outputQualifiers(OB, Quals, true, false); -} - -void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} - -void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - ElementType->outputPre(OB, Flags); - outputQualifiers(OB, Quals, true, false); -} - -void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, - Node *N) const { - assert(N->kind() == NodeKind::IntegerLiteral); - IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); - if (ILN->Value != 0) - ILN->output(OB, Flags); -} - -void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, - OutputFlags Flags) const { - if (Dimensions->Count == 0) - return; - - outputOneDimension(OB, Flags, Dimensions->Nodes[0]); - for (size_t I = 1; I < Dimensions->Count; ++I) { - OB << "]["; - outputOneDimension(OB, Flags, Dimensions->Nodes[I]); - } -} - -void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { - OB << "["; - outputDimensionsImpl(OB, Flags); - OB << "]"; - - ElementType->outputPost(OB, Flags); -} - -void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { - Name->output(OB, Flags); -} - -void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { - Signature->outputPre(OB, Flags); - outputSpaceIfNecessary(OB); - Name->output(OB, Flags); - Signature->outputPost(OB, Flags); -} - -void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { - const char *AccessSpec = nullptr; - bool IsStatic = true; - switch (SC) { - case StorageClass::PrivateStatic: - AccessSpec = "private"; - break; - case StorageClass::PublicStatic: - AccessSpec = "public"; - break; - case StorageClass::ProtectedStatic: - AccessSpec = "protected"; - break; - default: - IsStatic = false; - break; - } - if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) - OB << AccessSpec << ": "; - if (!(Flags & OF_NoMemberType) && IsStatic) - OB << "static "; - - if (!(Flags & OF_NoVariableType) && Type) { - Type->outputPre(OB, Flags); - outputSpaceIfNecessary(OB); - } - Name->output(OB, Flags); - if (!(Flags & OF_NoVariableType) && Type) - Type->outputPost(OB, Flags); -} - -void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { - Identifier->output(OB, Flags); -} -void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} - -void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { - Components->output(OB, Flags, "::"); -} - -void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - OB << "`RTTI Base Class Descriptor at ("; - OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " - << this->Flags; - OB << ")'"; -} - -void LocalStaticGuardVariableNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - Name->output(OB, Flags); -} - -void VcallThunkIdentifierNode::output(OutputBuffer &OB, - OutputFlags Flags) const { - OB << "`vcall'{" << OffsetInVTable << ", {flat}}"; -} - -void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { - outputQualifiers(OB, Quals, false, true); - Name->output(OB, Flags); - if (TargetName) { - OB << "{for `"; - TargetName->output(OB, Flags); - OB << "'}"; - } -} |