From 0192c791ce03f07d4f45b7b7386edec81dfbbe08 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 9 Aug 2022 13:51:03 +0200 Subject: [PATCH] sys: Updated llvm demangler, now supports D-Lang and Rust symbols --- lib/external/llvm-demangle/CMakeLists.txt | 15 + lib/external/llvm-demangle/LICENSE.TXT | 279 ++ .../include/llvm/Demangle/Demangle.h | 17 +- .../include/llvm/Demangle/DemangleConfig.h | 4 +- .../include/llvm/Demangle/ItaniumDemangle.h | 3614 ++++++++--------- .../include/llvm/Demangle/ItaniumNodes.def | 95 + .../include/llvm/Demangle/MicrosoftDemangle.h | 8 +- .../llvm/Demangle/MicrosoftDemangleNodes.h | 102 +- .../include/llvm/Demangle/README.txt | 61 + .../include/llvm/Demangle/StringView.h | 36 +- .../include/llvm/Demangle/Utility.h | 218 + .../llvm-demangle/source/DLangDemangle.cpp | 578 +++ .../llvm-demangle/source/Demangle.cpp | 64 + .../source}/ItaniumDemangle.cpp | 128 +- .../source}/MicrosoftDemangle.cpp | 125 +- .../source}/MicrosoftDemangleNodes.cpp | 412 +- .../llvm-demangle/source/RustDemangle.cpp | 1265 ++++++ lib/external/llvm/CMakeLists.txt | 13 - lib/external/llvm/Demangle/Demangle.cpp | 36 - .../llvm/include/llvm/Demangle/Utility.h | 191 - lib/libimhex/CMakeLists.txt | 6 +- plugins/builtin/CMakeLists.txt | 2 +- .../builtin/source/content/tools_entries.cpp | 18 +- plugins/builtin/source/lang/de_DE.cpp | 2 +- plugins/builtin/source/lang/en_US.cpp | 2 +- plugins/builtin/source/lang/it_IT.cpp | 2 +- plugins/builtin/source/lang/ja_JP.cpp | 2 +- plugins/builtin/source/lang/pt_BR.cpp | 2 +- plugins/builtin/source/lang/zh_CN.cpp | 2 +- plugins/builtin/source/lang/zh_TW.cpp | 2 +- 30 files changed, 4807 insertions(+), 2494 deletions(-) create mode 100644 lib/external/llvm-demangle/CMakeLists.txt create mode 100644 lib/external/llvm-demangle/LICENSE.TXT rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/Demangle.h (92%) rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/DemangleConfig.h (97%) rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/ItaniumDemangle.h (67%) create mode 100644 lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/MicrosoftDemangle.h (98%) rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/MicrosoftDemangleNodes.h (83%) create mode 100644 lib/external/llvm-demangle/include/llvm/Demangle/README.txt rename lib/external/{llvm => llvm-demangle}/include/llvm/Demangle/StringView.h (76%) create mode 100644 lib/external/llvm-demangle/include/llvm/Demangle/Utility.h create mode 100644 lib/external/llvm-demangle/source/DLangDemangle.cpp create mode 100644 lib/external/llvm-demangle/source/Demangle.cpp rename lib/external/{llvm/Demangle => llvm-demangle/source}/ItaniumDemangle.cpp (84%) rename lib/external/{llvm/Demangle => llvm-demangle/source}/MicrosoftDemangle.cpp (97%) rename lib/external/{llvm/Demangle => llvm-demangle/source}/MicrosoftDemangleNodes.cpp (66%) create mode 100644 lib/external/llvm-demangle/source/RustDemangle.cpp delete mode 100644 lib/external/llvm/CMakeLists.txt delete mode 100644 lib/external/llvm/Demangle/Demangle.cpp delete mode 100644 lib/external/llvm/include/llvm/Demangle/Utility.h diff --git a/lib/external/llvm-demangle/CMakeLists.txt b/lib/external/llvm-demangle/CMakeLists.txt new file mode 100644 index 000000000..56760c24e --- /dev/null +++ b/lib/external/llvm-demangle/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16) +project(llvm-demangle) + +set(CMAKE_CXX_STANDARD 17) + +add_library(llvm-demangle STATIC + source/Demangle.cpp + source/DLangDemangle.cpp + source/ItaniumDemangle.cpp + source/MicrosoftDemangle.cpp + source/MicrosoftDemangleNodes.cpp + source/RustDemangle.cpp +) + +target_include_directories(llvm-demangle PUBLIC include) diff --git a/lib/external/llvm-demangle/LICENSE.TXT b/lib/external/llvm-demangle/LICENSE.TXT new file mode 100644 index 000000000..fa6ac5400 --- /dev/null +++ b/lib/external/llvm-demangle/LICENSE.TXT @@ -0,0 +1,279 @@ +============================================================================== +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/lib/external/llvm/include/llvm/Demangle/Demangle.h b/lib/external/llvm-demangle/include/llvm/Demangle/Demangle.h similarity index 92% rename from lib/external/llvm/include/llvm/Demangle/Demangle.h rename to lib/external/llvm-demangle/include/llvm/Demangle/Demangle.h index b4006a067..6133d0b95 100644 --- a/lib/external/llvm/include/llvm/Demangle/Demangle.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/Demangle.h @@ -31,7 +31,6 @@ enum : int { char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, int *status); - enum MSDemangleFlags { MSDF_None = 0, MSDF_DumpBackrefs = 1 << 0, @@ -39,6 +38,7 @@ enum MSDemangleFlags { 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. @@ -53,9 +53,15 @@ enum MSDemangleFlags { /// 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); +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. @@ -64,6 +70,8 @@ char *microsoftDemangle(const char *mangled_name, size_t *n_read, /// 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. @@ -115,6 +123,7 @@ struct ItaniumPartialDemangler { bool isSpecialName() const; ~ItaniumPartialDemangler(); + private: void *RootNode; void *Context; diff --git a/lib/external/llvm/include/llvm/Demangle/DemangleConfig.h b/lib/external/llvm-demangle/include/llvm/Demangle/DemangleConfig.h similarity index 97% rename from lib/external/llvm/include/llvm/Demangle/DemangleConfig.h rename to lib/external/llvm-demangle/include/llvm/Demangle/DemangleConfig.h index b7b7dbd24..2ff95dd8d 100644 --- a/lib/external/llvm/include/llvm/Demangle/DemangleConfig.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/DemangleConfig.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_COMPILER_H -#define LLVM_DEMANGLE_COMPILER_H +#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H +#define LLVM_DEMANGLE_DEMANGLECONFIG_H #ifndef __has_feature #define __has_feature(x) 0 diff --git a/lib/external/llvm/include/llvm/Demangle/ItaniumDemangle.h b/lib/external/llvm-demangle/include/llvm/Demangle/ItaniumDemangle.h similarity index 67% rename from lib/external/llvm/include/llvm/Demangle/ItaniumDemangle.h rename to lib/external/llvm-demangle/include/llvm/Demangle/ItaniumDemangle.h index 6ab873218..796e979f4 100644 --- a/lib/external/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/ItaniumDemangle.h @@ -1,149 +1,222 @@ -//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// -// +//===--- 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. This file has two byte-per-byte identical -// copies in the source tree, one in libcxxabi, and the other in llvm. +// 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 - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS +#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H +#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include #include #include #include #include #include -#include +#include #include -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(SyntheticTemplateParamName) \ - X(TypeTemplateParamDecl) \ - X(NonTypeTemplateParamDecl) \ - X(TemplateTemplateParamDecl) \ - X(TemplateParamPackDecl) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(UUIDOfExpr) \ - X(BoolExpr) \ - X(StringLiteral) \ - X(LambdaExpr) \ - X(EnumLiteral) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - DEMANGLE_NAMESPACE_BEGIN +template class PODSmallVector { + static_assert(std::is_pod::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(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast(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(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 ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR +#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; + Cache RHSComponentCache : 2; /// Track if this node is a (possibly qualified) array type. This can affect /// how we format the output string. - Cache ArrayCache; + Cache ArrayCache : 2; /// Track if this node is a (possibly qualified) function type. This can /// affect how we format the output string. - Cache FunctionCache; + Cache FunctionCache : 2; public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} + 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 void visit(Fn F) const; @@ -154,50 +227,63 @@ public: // would construct an equivalent node. //template void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + 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(OutputStream &) const { - return this; + 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(OutputStream &S) const { - printLeft(S); + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // 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(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -226,19 +312,19 @@ public: Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + 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 == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -253,9 +339,7 @@ struct NodeArrayNode : Node { template void match(Fn F) const { F(Array); } - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } + void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { @@ -268,28 +352,35 @@ public: template void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + 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_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - template void match(Fn F) const { F(Ty, Ext); } + const Node *getTy() const { return Ty; } + StringView getExt() const { return Ext; } + const Node *getTA() const { return TA; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + template 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); } }; @@ -315,13 +406,13 @@ protected: const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -330,24 +421,27 @@ public: Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} + Qualifiers getQuals() const { return Quals; } + const Node *getChild() const { return Child; } + template void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -359,9 +453,9 @@ public: template void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; @@ -370,14 +464,14 @@ class PostfixQualifiedType final : public Node { const StringView Postfix; public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) + PostfixQualifiedType(const Node *Ty_, StringView Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; @@ -392,7 +486,27 @@ public: StringView getName() const { return Name; } StringView getBaseName() const override { return Name; } - void printLeft(OutputStream &s) const override { s += 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 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 { @@ -404,10 +518,10 @@ public: template void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; @@ -422,11 +536,11 @@ struct AbiTagAttr : Node { template void match(Fn F) const { F(Base, Tag); } - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Base->printLeft(OB); + OB += "[abi:"; + OB += Tag; + OB += "]"; } }; @@ -438,10 +552,10 @@ public: template void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; @@ -462,11 +576,11 @@ public: static_cast(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -478,36 +592,38 @@ public: : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} + const Node *getPointee() const { return Pointee; } + template void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -527,15 +643,30 @@ class ReferenceType : public Node { // 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. - std::pair collapse(OutputStream &S) const { + // + // 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 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 Prev; for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); + const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast(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; } @@ -547,31 +678,35 @@ public: template void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + ScopedOverride SavePrinting(Printing, true); + std::pair 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 += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + ScopedOverride SavePrinting(Printing, true); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -586,24 +721,24 @@ public: template void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; + OB += " "; + ClassType->print(OB); + OB += "::*"; } - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; @@ -620,19 +755,19 @@ public: template void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; if (Dimension) - Dimension->print(S); - S += "]"; - Base->printRight(S); + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -656,8 +791,8 @@ public: F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + 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: @@ -666,32 +801,32 @@ public: // 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(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -703,10 +838,11 @@ public: template void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept"; + OB.printOpen(); + E->printAsOperand(OB); + OB.printClose(); } }; @@ -718,10 +854,11 @@ public: template void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw"; + OB.printOpen(); + Types.printWithComma(OB); + OB.printClose(); } }; @@ -752,41 +889,41 @@ public: NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -799,9 +936,9 @@ public: template void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; @@ -815,9 +952,9 @@ public: template void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -832,11 +969,11 @@ public: template void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -851,10 +988,50 @@ struct NestedName : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + 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 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 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); } }; @@ -867,10 +1044,10 @@ struct LocalName : Node { template void match(Fn F) const { F(Encoding, Entity); } - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); + void printLeft(OutputBuffer &OB) const override { + Encoding->print(OB); + OB += "::"; + Entity->print(OB); } }; @@ -887,10 +1064,10 @@ public: StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -899,18 +1076,20 @@ class VectorType final : public Node { const Node *Dimension; public: - VectorType(const Node *BaseType_, Node *Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} + 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 void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; if (Dimension) - Dimension->print(S); - S += "]"; + Dimension->print(OB); + OB += "]"; } }; @@ -923,11 +1102,26 @@ public: template void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - Dimension->print(S); - S += "]"; + 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 void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -949,20 +1143,20 @@ public: template void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -976,13 +1170,9 @@ public: template void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -996,15 +1186,15 @@ public: template void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1021,15 +1211,14 @@ public: template void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1042,14 +1231,12 @@ public: template void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1063,11 +1250,12 @@ public: class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits::max()) { - S.CurrentPackMax = static_cast(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits::max()) { + OB.CurrentPackMax = static_cast(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1090,38 +1278,38 @@ public: template void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + 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(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1140,8 +1328,8 @@ public: NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1158,35 +1346,35 @@ public: const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + ScopedOverride SavePackIdx(OB.CurrentPackIndex, Max); + ScopedOverride 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(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1201,12 +1389,11 @@ public: NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + Params.printWithComma(OB); + OB += ">"; } }; @@ -1248,42 +1435,42 @@ struct ForwardTemplateReference : Node { // special handling. template void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; - SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); + ScopedOverride SavePrinting(Printing, true); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); + ScopedOverride SavePrinting(Printing, true); + Ref->printRight(OB); } }; @@ -1299,9 +1486,9 @@ struct NameWithTemplateArgs : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + TemplateArgs->print(OB); } }; @@ -1316,24 +1503,9 @@ public: StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1346,15 +1518,25 @@ enum class SpecialSubKind { iostream, }; -class ExpandedSpecialSubstitution final : public Node { +class SpecialSubstitution; +class ExpandedSpecialSubstitution : public Node { +protected: SpecialSubKind SSK; + ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) + : Node(K_), SSK(SSK_) {} public: ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} + inline ExpandedSpecialSubstitution(SpecialSubstitution const *); template 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: @@ -1373,82 +1555,44 @@ public: DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream >"; - break; +private: + void printLeft(OutputBuffer &OB) const override { + OB << "std::" << getBaseName(); + if (isInstantiation()) { + OB << ""; + if (SSK == SpecialSubKind::string) + OB << ", std::allocator"; + OB << ">"; } } }; -class SpecialSubstitution final : public Node { +class SpecialSubstitution final : public ExpandedSpecialSubstitution { public: - SpecialSubKind SSK; - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} template void match(Fn F) const { F(SSK); } 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("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); + 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); } - DEMANGLE_UNREACHABLE; + return SV; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::string"; - break; - case SpecialSubKind::istream: - S += "std::istream"; - break; - case SpecialSubKind::ostream: - S += "std::ostream"; - break; - case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } + 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; @@ -1461,10 +1605,10 @@ public: template void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1476,9 +1620,9 @@ public: template void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; @@ -1490,10 +1634,10 @@ public: template void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; @@ -1512,22 +1656,23 @@ public: F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1539,10 +1684,10 @@ public: template void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen('['); + Bindings.printWithComma(OB); + OB.printClose(']'); } }; @@ -1554,28 +1699,31 @@ class BinaryExpr : public Node { const Node *RHS; public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { + BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_, + Prec Prec_) + : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), + RHS(RHS_) {} + + template void match(Fn F) const { + F(LHS, InfixOperator, RHS, getPrecedence()); } - template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; + 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(); } }; @@ -1584,17 +1732,18 @@ class ArraySubscriptExpr : public Node { const Node *Op2; public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) + : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} - template void match(Fn F) const { F(Op1, Op2); } + template void match(Fn F) const { + F(Op1, Op2, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Op1->printAsOperand(OB, getPrecedence()); + OB.printOpen('['); + Op2->printAsOperand(OB); + OB.printClose(']'); } }; @@ -1603,16 +1752,16 @@ class PostfixExpr : public Node { const StringView Operator; public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_) + : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} - template void match(Fn F) const { F(Child, Operator); } + template void match(Fn F) const { + F(Child, Operator, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + Child->printAsOperand(OB, getPrecedence(), true); + OB += Operator; } }; @@ -1622,19 +1771,20 @@ class ConditionalExpr : public Node { const Node *Else; public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, + Prec Prec_) + : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} - template void match(Fn F) const { F(Cond, Then, Else); } + template void match(Fn F) const { + F(Cond, Then, Else, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Cond->printAsOperand(OB, getPrecedence()); + OB += " ? "; + Then->printAsOperand(OB); + OB += " : "; + Else->printAsOperand(OB, Prec::Assign, true); } }; @@ -1644,15 +1794,51 @@ class MemberExpr : public Node { const Node *RHS; public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_) + : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - template void match(Fn F) const { F(LHS, Kind, RHS); } + template void match(Fn F) const { + F(LHS, Kind, RHS, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + 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 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 += ">"; } }; @@ -1662,16 +1848,20 @@ class EnclosingExpr : public Node { const StringView Postfix; public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} + EnclosingExpr(StringView Prefix_, const Node *Infix_, + Prec Prec_ = Prec::Primary) + : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} - template void match(Fn F) const { F(Prefix, Infix, Postfix); } + template void match(Fn F) const { + F(Prefix, Infix, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB.printOpen(); + Infix->print(OB); + OB.printClose(); + OB += Postfix; } }; @@ -1682,18 +1872,24 @@ class CastExpr : public Node { const Node *From; public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_) - : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} + CastExpr(StringView CastKind_, const Node *To_, const Node *From_, Prec Prec_) + : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} - template void match(Fn F) const { F(CastKind, To, From); } + template void match(Fn F) const { + F(CastKind, To, From, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + To->printLeft(OB); + OB += ">"; + } + OB.printOpen(); + From->printAsOperand(OB); + OB.printClose(); } }; @@ -1706,11 +1902,12 @@ public: template void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof..."; + OB.printOpen(); ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB.printClose(); } }; @@ -1719,16 +1916,18 @@ class CallExpr : public Node { NodeArray Args; public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) + : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} - template void match(Fn F) const { F(Callee, Args); } + template void match(Fn F) const { + F(Callee, Args, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB.printOpen(); + Args.printWithComma(OB); + OB.printClose(); } }; @@ -1741,33 +1940,32 @@ class NewExpr : public Node { bool IsArray; // new[] ? public: NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} + bool IsArray_, Prec Prec_) + : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), + InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); + F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::"; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB.printOpen(); + ExprList.printWithComma(OB); + OB.printClose(); } - Type->print(S); + OB += " "; + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB.printOpen(); + InitList.printWithComma(OB); + OB.printClose(); } - } }; @@ -1777,18 +1975,22 @@ class DeleteExpr : public Node { bool IsArray; public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) + : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} - template void match(Fn F) const { F(Op, IsGlobal, IsArray); } + template void match(Fn F) const { + F(Op, IsGlobal, IsArray, getPrecedence()); + } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[]"; + OB += ' '; + Op->print(OB); } }; @@ -1797,16 +1999,16 @@ class PrefixExpr : public Node { Node *Child; public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_) + : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} - template void match(Fn F) const { F(Prefix, Child); } + template void match(Fn F) const { + F(Prefix, Child, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Child->printAsOperand(OB, getPrecedence()); } }; @@ -1818,9 +2020,9 @@ public: template void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1829,17 +2031,45 @@ class ConversionExpr : public Node { NodeArray Expressions; public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) + : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} - template void match(Fn F) const { F(Type, Expressions); } + template void match(Fn F) const { + F(Type, Expressions, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + 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 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(); } }; @@ -1852,12 +2082,12 @@ public: template void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1871,18 +2101,18 @@ public: template void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1896,15 +2126,15 @@ public: template void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1923,43 +2153,35 @@ public: F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB.printOpen(); + ParameterPackExpansion(Pack).print(OB); + OB.printClose(); }; - S += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } + 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 << " "; } - S += ')'; + OB << "..."; + if (IsLeftFold || Init != nullptr) { + // ' op (init|pack)' + OB << " " << OperatorName << " "; + if (IsLeftFold) + PrintPack(); + else + Init->printAsOperand(OB, Prec::Cast, true); + } + OB.printClose(); } }; @@ -1971,24 +2193,9 @@ public: template void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -// MSVC __uuidof extension, generated by clang in -fms-extensions mode. -class UUIDOfExpr : public Node { - Node *Operand; -public: - UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {} - - template void match(Fn F) const { F(Operand); } - - void printLeft(OutputStream &S) const override { - S << "__uuidof("; - Operand->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2000,8 +2207,8 @@ public: template void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? StringView("true") : StringView("false"); } }; @@ -2013,10 +2220,10 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2028,11 +2235,11 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast(Type)->printDeclarator(S); - S += "{...}"; + static_cast(Type)->printDeclarator(OB); + OB += "{...}"; } }; @@ -2047,15 +2254,15 @@ public: template void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S << "("; - Ty->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Ty->print(OB); + OB.printClose(); if (Integer[0] == 'n') - S << "-" << Integer.dropFront(1); + OB << "-" << Integer.dropFront(1); else - S << Integer; + OB << Integer; } }; @@ -2069,21 +2276,21 @@ public: template void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB.printOpen(); + OB += Type; + OB.printClose(); } if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); + OB += '-'; + OB += Value.dropFront(1); } else - S += Value; + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2113,7 +2320,7 @@ public: template void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { const char *first = Contents.begin(); const char *last = Contents.end() + 1; @@ -2139,7 +2346,7 @@ public: #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); + OB += StringView(num, num + n); } } }; @@ -2153,143 +2360,22 @@ using LongDoubleLiteral = FloatLiteralImpl; template void Node::visit(Fn F) const { switch (K) { -#define CASE(X) case K ## X: return F(static_cast(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE +#define NODE(X) \ + case K##X: \ + return F(static_cast(this)); +#include "ItaniumNodes.def" } assert(0 && "unknown mangling node kind"); } /// Determine the kind of a node from its type. template struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ +#define NODE(X) \ + template <> struct NodeKind { \ + static constexpr Node::Kind Kind = Node::K##X; \ + static constexpr const char *name() { return #X; } \ }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef SPECIALIZATION - -#undef FOR_EACH_NODE_KIND - -template -class PODSmallVector { - static_assert(std::is_pod::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(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast(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; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - 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(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); - } -}; +#include "ItaniumNodes.def" template struct AbstractManglingParser { const char *First; @@ -2313,9 +2399,9 @@ template struct AbstractManglingParser { TemplateParamList Params; public: - ScopedTemplateParamList(AbstractManglingParser *Parser) - : Parser(Parser), - OldNumTemplateParamLists(Parser->TemplateParams.size()) { + ScopedTemplateParamList(AbstractManglingParser *TheParser) + : Parser(TheParser), + OldNumTemplateParamLists(TheParser->TemplateParams.size()) { Parser->TemplateParams.push_back(&Params); } ~ScopedTemplateParamList() { @@ -2405,7 +2491,7 @@ template struct AbstractManglingParser { char consume() { return First != Last ? *First++ : '\0'; } - char look(unsigned Lookahead = 0) { + char look(unsigned Lookahead = 0) const { if (static_cast(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; @@ -2427,16 +2513,17 @@ template struct AbstractManglingParser { /// Parse the production. Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); + Node *parsePrefixExpr(StringView Kind, Node::Prec Prec); + Node *parseBinaryExpr(StringView Kind, Node::Prec Prec); Node *parseIntegerLiteral(StringView Lit); Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); - Node *parseNewExpr(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); + Node *parsePointerToMemberConversionExpr(Node::Prec Prec); + Node *parseSubobjectExpr(); /// Parse the production. Node *parseType(); @@ -2483,17 +2570,80 @@ template struct AbstractManglingParser { Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(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); + 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, @(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 production. - Node *parseUnresolvedName(); + Node *parseUnresolvedName(bool Global); Node *parseSimpleId(); Node *parseBaseUnresolvedName(); Node *parseUnresolvedType(); @@ -2514,41 +2664,35 @@ const char* parse_discriminator(const char* first, const char* last); // ::= template Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') return getDerived().parseLocalName(State); - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; + Node *Result = nullptr; + bool IsSubst = false; + + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) + return nullptr; + + if (look() == 'I') { + // ::= + 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; - return make(S, TA); + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by . + return nullptr; } - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= - if (look() == 'I') { - Subs.push_back(N); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); - } - // ::= - return N; + return Result; } // := Z E [] @@ -2589,34 +2733,63 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { // ::= // ::= St # ::std:: -// extension ::= StL +// [*] extension template Node * -AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) +AbstractManglingParser::parseUnscopedName(NameState *State, + bool *IsSubst) { + + Node *Std = nullptr; + if (consumeIf("St")) { + Std = make("std"); + if (Std == nullptr) return nullptr; - return make(R); } - return getDerived().parseUnqualifiedName(State); + + 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(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; } -// ::= [abi-tags] -// ::= -// ::= -// ::= -// ::= DC + E # structured binding declaration +// ::= [] L? [] +// ::= [] [] +// ::= [] L? [] +// ::= [] L? [] +// # structured binding declaration +// ::= [] L? DC + E template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State) { - // s are special-cased in parseNestedName(). +Node *AbstractManglingParser::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + + consumeIf('L'); + Node *Result; - if (look() == 'U') - Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } 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); @@ -2625,13 +2798,46 @@ AbstractManglingParser::parseUnqualifiedName(NameState *State) { Names.push_back(Binding); } while (!consumeIf('E')); Result = make(popTrailingNodeArray(BindingsBegin)); - } else + } else if (look() == 'C' || look() == 'D') { + // A . + if (Scope == nullptr || Module != nullptr) + return nullptr; + Result = getDerived().parseCtorDtorName(Scope, State); + } else { Result = getDerived().parseOperatorName(State); + } + + if (Result != nullptr && Module != nullptr) + Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); + if (Result != nullptr && Scope != nullptr) + Result = make(Scope, Result); + return Result; } +// ::= +// ::= +// ::= # passed in by caller +// ::= W +// ::= W P +template +bool AbstractManglingParser::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast(make(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // ::= Ut [] _ // ::= // @@ -2653,7 +2859,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { return make(Count); } if (consumeIf("Ul")) { - SwapAndRestore SwapParams(ParsingLambdaParamsAtLevel, + ScopedOverride SwapParams(ParsingLambdaParamsAtLevel, TemplateParams.size()); ScopedTemplateParamList LambdaTemplateParams(this); @@ -2731,97 +2937,124 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return make(Name); } -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= +// Operator encodings +template +const typename AbstractManglingParser< + Derived, Alloc>::OperatorInfo AbstractManglingParser::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 +const size_t AbstractManglingParser::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 +const typename AbstractManglingParser::OperatorInfo * +AbstractManglingParser::parseOperatorEncoding() { + if (numLeft() < 2) + return nullptr; + + auto Op = std::lower_bound( + &Ops[0], &Ops[NumOps], First, + [](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; }); + if (Op == &Ops[NumOps] || *Op != First) + return nullptr; + + First += 2; + return Op; +} + +// ::= See parseOperatorEncoding() // ::= li # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v # vendor extended operator +// ::= v # vendor extended operator template Node * AbstractManglingParser::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make("operator&&"); - case 'd': - case 'n': - First += 2; - return make("operator&"); - case 'N': - First += 2; - return make("operator&="); - case 'S': - First += 2; - return make("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make("operator()"); - case 'm': - First += 2; - return make("operator,"); - case 'o': - First += 2; - return make("operator~"); - // ::= cv # (cast) - case 'v': { - First += 2; - SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); + if (const auto *Op = parseOperatorEncoding()) { + if (Op->getKind() == OperatorInfo::CCast) { + // ::= cv # (cast) + ScopedOverride SaveTemplate(TryToParseTemplateArgs, false); // If we're parsing an encoding, State != nullptr and the conversion // operators' could have a that refers to some // s further ahead in the mangled name. - SwapAndRestore SavePermit(PermitForwardTemplateReferences, + ScopedOverride SavePermit(PermitForwardTemplateReferences, PermitForwardTemplateReferences || State != nullptr); Node *Ty = getDerived().parseType(); @@ -2830,185 +3063,29 @@ AbstractManglingParser::parseOperatorName(NameState *State) { if (State) State->CtorDtorConversion = true; return make(Ty); } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make("operator delete[]"); - case 'e': - First += 2; - return make("operator*"); - case 'l': - First += 2; - return make("operator delete"); - case 'v': - First += 2; - return make("operator/"); - case 'V': - First += 2; - return make("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make("operator^"); - case 'O': - First += 2; - return make("operator^="); - case 'q': - First += 2; - return make("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make("operator>="); - case 't': - First += 2; - return make("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make("operator<="); + + 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(Op->getName()); + } + + if (consumeIf("li")) { // ::= li # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make(SN); - } - case 's': - First += 2; - return make("operator<<"); - case 'S': - First += 2; - return make("operator<<="); - case 't': - First += 2; - return make("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make("operator-"); - case 'I': - First += 2; - return make("operator-="); - case 'l': - First += 2; - return make("operator*"); - case 'L': - First += 2; - return make("operator*="); - case 'm': - First += 2; - return make("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make("operator new[]"); - case 'e': - First += 2; - return make("operator!="); - case 'g': - First += 2; - return make("operator-"); - case 't': - First += 2; - return make("operator!"); - case 'w': - First += 2; - return make("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make("operator||"); - case 'r': - First += 2; - return make("operator|"); - case 'R': - First += 2; - return make("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make("operator->*"); - case 'l': - First += 2; - return make("operator+"); - case 'L': - First += 2; - return make("operator+="); - case 'p': - First += 2; - return make("operator++"); - case 's': - First += 2; - return make("operator+"); - case 't': - First += 2; - return make("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make("operator%"); - case 'M': - First += 2; - return make("operator%="); - case 's': - First += 2; - return make("operator>>"); - case 'S': - First += 2; - return make("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make("operator<=>"); - } - return nullptr; - // ::= v # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; + Node *SN = getDerived().parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make(SN); + } + + if (consumeIf('v')) { + // ::= v # vendor extended operator + if (look() >= '0' && look() <= '9') { + First++; Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; @@ -3016,6 +3093,7 @@ AbstractManglingParser::parseOperatorName(NameState *State) { } return nullptr; } + return nullptr; } @@ -3034,19 +3112,11 @@ Node * AbstractManglingParser::parseCtorDtorName(Node *&SoFar, NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } + // Expand the special substitution. + SoFar = make( + static_cast(SoFar)); + if (!SoFar) + return nullptr; } if (consumeIf('C')) { @@ -3075,8 +3145,10 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, return nullptr; } -// ::= N [] [] E -// ::= N [] [] E +// ::= N [] [] +// E +// ::= N [] [] +// E // // ::= // ::= @@ -3085,7 +3157,7 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, // ::= # empty // ::= // ::= -// extension ::= L +// [*] extension // // := [] M // @@ -3105,90 +3177,76 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { - consumeIf('L'); // extension + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // := [] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } - - // ::= if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'I') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) + if (TA == nullptr) return nullptr; + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically 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(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else { + ModuleName *Module = nullptr; + + if (look() == 'S') { + // ::= + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast(S); + } else if (SoFar != nullptr) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } + + // ::= [] + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } - // ::= - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) - return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } - - // Parse an thats actually a . - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); + + // No longer used. + // := [] M + consumeIf('M'); } if (SoFar == nullptr || Subs.empty()) @@ -3283,6 +3341,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // ::= [gs] # x or (with "gs") ::x // ::= [gs] sr + E // # A::x, N::y, A::z; "gs" means leading "::" +// [gs] has been parsed by caller. // ::= sr # T::x / decltype(p)::x // extension ::= sr // # T::N::x /decltype(p)::N::x @@ -3290,7 +3349,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // // ::= template -Node *AbstractManglingParser::parseUnresolvedName() { +Node *AbstractManglingParser::parseUnresolvedName(bool Global) { Node *SoFar = nullptr; // srN [] * E @@ -3324,8 +3383,6 @@ Node *AbstractManglingParser::parseUnresolvedName() { return make(SoFar, Base); } - bool Global = consumeIf("gs"); - // [gs] # x or (with "gs") ::x if (!consumeIf("sr")) { SoFar = getDerived().parseBaseUnresolvedName(); @@ -3555,7 +3612,7 @@ Node *AbstractManglingParser::parseDecltype() { return nullptr; if (!consumeIf('E')) return nullptr; - return make("decltype(", E, ")"); + return make("decltype", E); } // ::= A _ @@ -3636,15 +3693,13 @@ Node *AbstractManglingParser::parseQualifiedType() { if (Qual.empty()) return nullptr; - // FIXME parse the optional here! - // extension ::= U # objc-type if (Qual.startsWith("objcproto")) { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); StringView Proto; { - SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); + ScopedOverride SaveFirst(First, ProtoSourceName.begin()), + SaveLast(Last, ProtoSourceName.end()); Proto = parseBareSourceName(); } if (Proto.empty()) @@ -3655,10 +3710,17 @@ Node *AbstractManglingParser::parseQualifiedType() { return make(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(Child, Qual); + return make(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); @@ -3831,7 +3893,33 @@ Node *AbstractManglingParser::parseType() { // ::= Dh # IEEE 754r half-precision floating point (16 bits) case 'h': First += 2; - return make("decimal16"); + return make("half"); + // ::= DF _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(DimensionNumber); + } + // ::= DB _ # C23 signed _BitInt(N) + // ::= DB _ # C23 signed _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + case 'B': + case 'U': { + bool Signed = look(1) == 'B'; + First += 2; + Node *Size = std::isdigit(look()) ? make(parseNumber()) + : getDerived().parseExpr(); + if (!Size) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(Size, Signed); + } // ::= Di # char32_t case 'i': First += 2; @@ -3979,9 +4067,10 @@ Node *AbstractManglingParser::parseType() { } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -3994,17 +4083,19 @@ Node *AbstractManglingParser::parseType() { // If this is followed by some , and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else if (IsSubst) { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } @@ -4024,22 +4115,24 @@ Node *AbstractManglingParser::parseType() { } template -Node *AbstractManglingParser::parsePrefixExpr(StringView Kind) { +Node *AbstractManglingParser::parsePrefixExpr(StringView Kind, + Node::Prec Prec) { Node *E = getDerived().parseExpr(); if (E == nullptr) return nullptr; - return make(Kind, E); + return make(Kind, E, Prec); } template -Node *AbstractManglingParser::parseBinaryExpr(StringView Kind) { +Node *AbstractManglingParser::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(LHS, Kind, RHS); + return make(LHS, Kind, RHS, Prec); } template @@ -4094,43 +4187,6 @@ Node *AbstractManglingParser::parseFunctionParam() { return nullptr; } -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization -template -Node *AbstractManglingParser::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - 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 Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make(ExprList, Ty, NodeArray(), Global, IsArray); -} - // cv # conversion with one argument // cv _ * E # conversion with a different number of arguments template @@ -4139,7 +4195,7 @@ Node *AbstractManglingParser::parseConversionExpr() { return nullptr; Node *Ty; { - SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); Ty = getDerived().parseType(); } @@ -4256,7 +4312,7 @@ Node *AbstractManglingParser::parseExprPrimary() { return nullptr; } case 'D': - if (consumeIf("DnE")) + if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E'))) return make("nullptr"); return nullptr; case 'T': @@ -4343,55 +4399,38 @@ Node *AbstractManglingParser::parseFoldExpr() { if (!consumeIf('f')) return nullptr; - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else + 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; - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; + 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(), *Init = nullptr; + Node *Pack = getDerived().parseExpr(); if (Pack == nullptr) return nullptr; + + Node *Init = nullptr; if (HasInitializer) { Init = getDerived().parseExpr(); if (Init == nullptr) @@ -4401,7 +4440,53 @@ Node *AbstractManglingParser::parseFoldExpr() { if (IsLeftFold && Init) std::swap(Pack, Init); - return make(IsLeftFold, OperatorName, Pack, Init); + return make(IsLeftFold, Op->getSymbol(), Pack, Init); +} + +// ::= mc [] E +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node * +AbstractManglingParser::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(Ty, Expr, Offset, Prec); +} + +// ::= so [] * [p] E +// ::= _ [] +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::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(parseNumber()); + if (!Selector) + return nullptr; + Names.push_back(Selector); + } + bool OnePastTheEnd = consumeIf('p'); + if (!consumeIf('E')) + return nullptr; + return make( + Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); } // ::= @@ -4451,313 +4536,127 @@ Node *AbstractManglingParser::parseFoldExpr() { template Node *AbstractManglingParser::parseExpr() { bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - switch (*First) { - case 'L': - return getDerived().parseExprPrimary(); - case 'T': - return getDerived().parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a . - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return getDerived().parseBinaryExpr("&&"); - case 'd': - First += 2; - return getDerived().parsePrefixExpr("&"); - case 'n': - First += 2; - return getDerived().parseBinaryExpr("&"); - case 'N': - First += 2; - return getDerived().parseBinaryExpr("&="); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ty = getDerived().parseExpr(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc # const_cast(expression) - case 'c': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; + 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 Ex; - return make("const_cast", Ty, Ex); - } - // cl + E # call - case 'l': { - First += 2; - Node *Callee = getDerived().parseExpr(); - if (Callee == nullptr) - return Callee; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - return make(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr(","); - case 'o': - First += 2; - return getDerived().parsePrefixExpr("~"); - case 'v': - return getDerived().parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return getDerived().parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - return make(E, Global, /*is_array=*/false); - } - case 'n': - return getDerived().parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make(LHS, ".*", RHS); + return make(Ex, Sym, Op->getPrecedence()); } - case 't': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make(LHS, ".", RHS); - } - case 'v': - First += 2; - return getDerived().parseBinaryExpr("/"); - case 'V': - First += 2; - return getDerived().parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return getDerived().parseBinaryExpr("^"); - case 'O': - First += 2; - return getDerived().parseBinaryExpr("^="); - case 'q': - First += 2; - return getDerived().parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr(">="); - case 't': - First += 2; - return getDerived().parseBinaryExpr(">"); - } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; + case OperatorInfo::Array: { + // Array Index: lhs [ rhs ] Node *Base = getDerived().parseExpr(); if (Base == nullptr) return nullptr; Node *Index = getDerived().parseExpr(); if (Index == nullptr) - return Index; - return make(Base, Index); + return nullptr; + return make(Base, Index, Op->getPrecedence()); } - case 'l': { - First += 2; + 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(LHS, Sym, RHS, Op->getPrecedence()); + } + case OperatorInfo::New: { + // New + // # new (expr-list) type [(init)] + // [gs] nw * _ [pi *] E + // # new[] (expr-list) type [(init)] + // [gs] na * _ [pi *] 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')) { - Node *E = getDerived().parseBracedExpr(); + if (!HaveInits) + return nullptr; + Node *Init = getDerived().parseExpr(); + if (Init == nullptr) + return Init; + Names.push_back(Init); + } + NodeArray Inits = popTrailingNodeArray(InitsBegin); + return make(ExprList, Ty, Inits, Global, + /*IsArray=*/Op->getFlag(), Op->getPrecedence()); + } + case OperatorInfo::Del: { + // Delete + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(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(nullptr, popTrailingNodeArray(InitsBegin)); + return make(Callee, popTrailingNodeArray(ExprsBegin), + Op->getPrecedence()); } - } - return nullptr; - case 'l': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr("<="); - case 's': - First += 2; - return getDerived().parseBinaryExpr("<<"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("<<="); - case 't': - First += 2; - return getDerived().parseBinaryExpr("<"); - } - return nullptr; - case 'm': - switch (First[1]) { - case 'i': - First += 2; - return getDerived().parseBinaryExpr("-"); - case 'I': - First += 2; - return getDerived().parseBinaryExpr("-="); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("*"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("*="); - case 'm': - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("--"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) + case OperatorInfo::CCast: { + // C Cast: (type)expr + Node *Ty; + { + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); + Ty = getDerived().parseType(); + } + if (Ty == nullptr) return nullptr; - return make(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return getDerived().parseNewExpr(); - case 'e': - First += 2; - return getDerived().parseBinaryExpr("!="); - case 'g': - First += 2; - return getDerived().parsePrefixExpr("-"); - case 't': - First += 2; - return getDerived().parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("noexcept (", Ex, ")"); - } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return getDerived().parseUnresolvedName(); - case 'o': - First += 2; - return getDerived().parseBinaryExpr("||"); - case 'r': - First += 2; - return getDerived().parseBinaryExpr("|"); - case 'R': - First += 2; - return getDerived().parseBinaryExpr("|="); - } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return getDerived().parseBinaryExpr("->*"); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("+"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("++"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, "++"); - } - case 's': - First += 2; - return getDerived().parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = getDerived().parseExpr(); - if (L == 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; - Node *R = getDerived().parseExpr(); - if (R == nullptr) - return nullptr; - return make(L, "->", R); + return make(Ty, Exprs, Op->getPrecedence()); } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; + case OperatorInfo::Conditional: { + // Conditional operator: expr ? expr : expr Node *Cond = getDerived().parseExpr(); if (Cond == nullptr) return nullptr; @@ -4767,169 +4666,158 @@ Node *AbstractManglingParser::parseExpr() { Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(Cond, LHS, RHS); + return make(Cond, LHS, RHS, Op->getPrecedence()); } - return nullptr; - case 'r': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("reinterpret_cast", T, Ex); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr("%"); - case 'M': - First += 2; - return getDerived().parseBinaryExpr("%="); - case 's': - First += 2; - return getDerived().parseBinaryExpr(">>"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("static_cast", T, Ex); - } - case 'p': { - First += 2; - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make(Child); - } - case 'r': - return getDerived().parseUnresolvedName(); - case 't': { - First += 2; + case OperatorInfo::NamedCast: { + // Named cast operation, @(expr) Node *Ty = getDerived().parseType(); if (Ty == nullptr) - return Ty; - return make("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; + return nullptr; Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make("sizeof (", Ex, ")"); + return nullptr; + return make(Sym, Ty, Ex, Op->getPrecedence()); } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make(R); - } else if (look() == 'f') { - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make("sizeof... (", FP, ")"); - } + case OperatorInfo::OfIdOp: { + // [sizeof/alignof/typeid] ( | ) + Node *Arg = + Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); + if (!Arg) + return nullptr; + return make(Sym, Arg, Op->getPrecedence()); + } + case OperatorInfo::NameOnly: { + // Not valid as an expression operand. return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make(popTrailingNodeArray(ArgsBegin)); - if (!Pack) - return nullptr; - return make("sizeof... (", Pack, ")"); } } + DEMANGLE_UNREACHABLE; + } + + if (numLeft() < 2) return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("typeid (", Ex, ")"); - } - case 'i': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make("typeid (", Ty, ")"); - } - case 'l': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + + if (look() == 'L') + return getDerived().parseExprPrimary(); + if (look() == 'T') + return getDerived().parseTemplateParam(); + if (look() == 'f') { + // Disambiguate a fold expression from a . + 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; - size_t InitsBegin = Names.size(); + Names.push_back(E); + } + return make(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("noexcept ", Ex, Node::Prec::Unary); + } + if (consumeIf("so")) + return parseSubobjectExpr(); + if (consumeIf("sp")) { + Node *Child = getDerived().parseExpr(); + if (Child == nullptr) + return nullptr; + return make(Child); + } + if (consumeIf("sZ")) { + if (look() == 'T') { + Node *R = getDerived().parseTemplateParam(); + if (R == nullptr) + return nullptr; + return make(R); + } + Node *FP = getDerived().parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make("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(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make("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(Ty, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("tr")) + return make("throw"); + if (consumeIf("tw")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(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 , and would be otherwise be + // interpreted as 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().parseBracedExpr(); + Node *E = getDerived().parseTemplateArg(); if (E == nullptr) - return nullptr; + return E; Names.push_back(E); } - return make(Ty, popTrailingNodeArray(InitsBegin)); } - case 'r': - First += 2; - return make("throw"); - case 'w': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make(Ex); - } - } - return nullptr; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return getDerived().parseUnresolvedName(); + return make(Name, popTrailingNodeArray(ExprsBegin), + Node::Prec::Postfix); } - if (consumeIf("u8__uuidoft")) { - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - return make(Ty); - } - - if (consumeIf("u8__uuidofz")) { - Node *Ex = getDerived().parseExpr(); - if (!Ex) - return nullptr; - return make(Ex); - } - - return nullptr; + // Only unresolved names remain. + return getDerived().parseUnresolvedName(Global); } // ::= h _ @@ -4962,19 +4850,32 @@ bool AbstractManglingParser::parseCallOffset() { // # second call-offset is result adjustment // ::= T // # base is the nominal target function of thunk -// ::= GV # Guard variable for one-time initialization +// # Guard variable for one-time initialization +// ::= GV // # No // ::= TW # Thread-local wrapper // ::= TH # Thread-local initialization // ::= GR _ # First temporary // ::= GR _ # Subsequent temporaries -// extension ::= TC _ # construction vtable for second-in-first +// # construction vtable for second-in-first +// extension ::= TC _ // extension ::= GR # reference temporary for object +// extension ::= GI # module global initializer template Node *AbstractManglingParser::parseSpecialName() { switch (look()) { case 'T': switch (look(1)) { + // TA # 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("template parameter object for ", Arg); + } // TV # virtual table case 'V': { First += 2; @@ -5086,6 +4987,16 @@ Node *AbstractManglingParser::parseSpecialName() { return nullptr; return make("reference temporary for ", Name); } + // GI v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make("initializer for module ", Module); + } } } return nullptr; @@ -5101,14 +5012,18 @@ Node *AbstractManglingParser::parseEncoding() { class SaveTemplateParams { AbstractManglingParser *Parser; decltype(TemplateParams) OldParams; + decltype(OuterTemplateParams) OldOuterParams; public: - SaveTemplateParams(AbstractManglingParser *Parser) : Parser(Parser) { + 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); @@ -5196,14 +5111,19 @@ template <> struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) + 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 - static const size_t max_demangled_size = 40; + // `-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"; }; @@ -5256,43 +5176,41 @@ bool AbstractManglingParser::parseSeqId(size_t *Out) { // ::= Si # ::std::basic_istream > // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > +// The St case is handled specially in parseNestedName. template Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S')) return nullptr; - if (std::islower(look())) { - Node *SpecialSub; + if (look() >= 'a' && look() <= 'z') { + SpecialSubKind Kind; switch (look()) { case 'a': - ++First; - SpecialSub = make(SpecialSubKind::allocator); + Kind = SpecialSubKind::allocator; break; case 'b': - ++First; - SpecialSub = make(SpecialSubKind::basic_string); - break; - case 's': - ++First; - SpecialSub = make(SpecialSubKind::string); - break; - case 'i': - ++First; - SpecialSub = make(SpecialSubKind::istream); - break; - case 'o': - ++First; - SpecialSub = make(SpecialSubKind::ostream); + Kind = SpecialSubKind::basic_string; break; case 'd': - ++First; - SpecialSub = make(SpecialSubKind::iostream); + 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(Kind); if (!SpecialSub) return nullptr; + // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. @@ -5571,4 +5489,4 @@ struct ManglingParser : AbstractManglingParser, Alloc> { DEMANGLE_NAMESPACE_END -#endif // DEMANGLE_ITANIUMDEMANGLE_H +#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H diff --git a/lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def b/lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def new file mode 100644 index 000000000..c0e277d55 --- /dev/null +++ b/lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def @@ -0,0 +1,95 @@ +//===--- 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/lib/external/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangle.h similarity index 98% rename from lib/external/llvm/include/llvm/Demangle/MicrosoftDemangle.h rename to lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangle.h index c6f26061b..6f2d04169 100644 --- a/lib/external/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangle.h @@ -6,13 +6,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H -#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H +#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H +#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/MicrosoftDemangleNodes.h" #include "llvm/Demangle/StringView.h" -#include "llvm/Demangle/Utility.h" #include @@ -275,4 +273,4 @@ private: } // namespace ms_demangle } // namespace llvm -#endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H +#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H diff --git a/lib/external/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangleNodes.h similarity index 83% rename from lib/external/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h rename to lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangleNodes.h index 62e0f4765..8ad247236 100644 --- a/lib/external/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/MicrosoftDemangleNodes.h @@ -10,10 +10,9 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H -#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H +#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H +#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/StringView.h" #include #include @@ -21,11 +20,11 @@ namespace llvm { namespace itanium_demangle { -class OutputStream; +class OutputBuffer; } } -using llvm::itanium_demangle::OutputStream; +using llvm::itanium_demangle::OutputBuffer; using llvm::itanium_demangle::StringView; namespace llvm { @@ -67,6 +66,8 @@ enum class CallingConv : uint8_t { Eabi, Vectorcall, Regcall, + Swift, // Clang-only + SwiftAsync, // Clang-only }; enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef }; @@ -78,6 +79,7 @@ enum OutputFlags { OF_NoAccessSpecifier = 4, OF_NoMemberType = 8, OF_NoReturnType = 16, + OF_NoVariableType = 32, }; // Types @@ -259,7 +261,7 @@ struct Node { NodeKind kind() const { return Kind; } - virtual void output(OutputStream &OS, OutputFlags Flags) const = 0; + virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0; std::string toString(OutputFlags Flags = OF_Default) const; @@ -280,9 +282,7 @@ struct StructorIdentifierNode; struct ThunkSignatureNode; struct PointerTypeNode; struct ArrayTypeNode; -struct CustomNode; struct TagTypeNode; -struct IntrinsicTypeNode; struct NodeArrayNode; struct QualifiedNameNode; struct TemplateParameterReferenceNode; @@ -298,12 +298,12 @@ struct SpecialTableSymbolNode; struct TypeNode : public Node { explicit TypeNode(NodeKind K) : Node(K) {} - virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0; - virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0; + virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0; + virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0; - void output(OutputStream &OS, OutputFlags Flags) const override { - outputPre(OS, Flags); - outputPost(OS, Flags); + void output(OutputBuffer &OB, OutputFlags Flags) const override { + outputPre(OB, Flags); + outputPost(OB, Flags); } Qualifiers Quals = Q_None; @@ -313,8 +313,8 @@ struct PrimitiveTypeNode : public TypeNode { explicit PrimitiveTypeNode(PrimitiveKind K) : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override {} + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {} PrimitiveKind PrimKind; }; @@ -323,8 +323,8 @@ struct FunctionSignatureNode : public TypeNode { explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {} FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + 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. @@ -357,13 +357,13 @@ struct IdentifierNode : public Node { NodeArrayNode *TemplateParams = nullptr; protected: - void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const; + void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const; }; struct VcallThunkIdentifierNode : public IdentifierNode { VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint64_t OffsetInVTable = 0; }; @@ -372,7 +372,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode { DynamicStructorIdentifierNode() : IdentifierNode(NodeKind::DynamicStructorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; VariableSymbolNode *Variable = nullptr; QualifiedNameNode *Name = nullptr; @@ -382,7 +382,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode { struct NamedIdentifierNode : public IdentifierNode { NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView Name; }; @@ -392,7 +392,7 @@ struct IntrinsicFunctionIdentifierNode : public IdentifierNode { : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier), Operator(Operator) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; IntrinsicFunctionKind Operator; }; @@ -401,7 +401,7 @@ struct LiteralOperatorIdentifierNode : public IdentifierNode { LiteralOperatorIdentifierNode() : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView Name; }; @@ -410,7 +410,7 @@ struct LocalStaticGuardIdentifierNode : public IdentifierNode { LocalStaticGuardIdentifierNode() : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; bool IsThread = false; uint32_t ScopeIndex = 0; @@ -420,7 +420,7 @@ struct ConversionOperatorIdentifierNode : public IdentifierNode { ConversionOperatorIdentifierNode() : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; // The type that this operator converts too. TypeNode *TargetType = nullptr; @@ -432,7 +432,7 @@ struct StructorIdentifierNode : public IdentifierNode { : IdentifierNode(NodeKind::StructorIdentifier), IsDestructor(IsDestructor) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; // The name of the class that this is a structor of. IdentifierNode *Class = nullptr; @@ -442,8 +442,8 @@ struct StructorIdentifierNode : public IdentifierNode { struct ThunkSignatureNode : public FunctionSignatureNode { ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; struct ThisAdjustor { uint32_t StaticOffset = 0; @@ -457,8 +457,8 @@ struct ThunkSignatureNode : public FunctionSignatureNode { struct PointerTypeNode : public TypeNode { PointerTypeNode() : TypeNode(NodeKind::PointerType) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + 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; @@ -474,8 +474,8 @@ struct PointerTypeNode : public TypeNode { struct TagTypeNode : public TypeNode { explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *QualifiedName = nullptr; TagKind Tag; @@ -484,11 +484,11 @@ struct TagTypeNode : public TypeNode { struct ArrayTypeNode : public TypeNode { ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const; - void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const; + 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; @@ -499,14 +499,14 @@ struct ArrayTypeNode : public TypeNode { struct IntrinsicNode : public TypeNode { IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {} - void output(OutputStream &OS, OutputFlags Flags) const override {} + void output(OutputBuffer &OB, OutputFlags Flags) const override {} }; struct CustomTypeNode : public TypeNode { CustomTypeNode() : TypeNode(NodeKind::Custom) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; IdentifierNode *Identifier = nullptr; }; @@ -514,9 +514,9 @@ struct CustomTypeNode : public TypeNode { struct NodeArrayNode : public Node { NodeArrayNode() : Node(NodeKind::NodeArray) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; - void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const; + void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const; Node **Nodes = nullptr; size_t Count = 0; @@ -525,7 +525,7 @@ struct NodeArrayNode : public Node { struct QualifiedNameNode : public Node { QualifiedNameNode() : Node(NodeKind::QualifiedName) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; NodeArrayNode *Components = nullptr; @@ -539,7 +539,7 @@ struct TemplateParameterReferenceNode : public Node { TemplateParameterReferenceNode() : Node(NodeKind::TemplateParameterReference) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; SymbolNode *Symbol = nullptr; @@ -554,7 +554,7 @@ struct IntegerLiteralNode : public Node { IntegerLiteralNode(uint64_t Value, bool IsNegative) : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint64_t Value = 0; bool IsNegative = false; @@ -564,7 +564,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode { RttiBaseClassDescriptorNode() : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint32_t NVOffset = 0; int32_t VBPtrOffset = 0; @@ -574,7 +574,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode { struct SymbolNode : public Node { explicit SymbolNode(NodeKind K) : Node(K) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *Name = nullptr; }; @@ -582,7 +582,7 @@ struct SpecialTableSymbolNode : public SymbolNode { explicit SpecialTableSymbolNode() : SymbolNode(NodeKind::SpecialTableSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *TargetName = nullptr; Qualifiers Quals = Qualifiers::Q_None; }; @@ -591,7 +591,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode { LocalStaticGuardVariableNode() : SymbolNode(NodeKind::LocalStaticGuardVariable) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; bool IsVisible = false; }; @@ -599,7 +599,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode { struct EncodedStringLiteralNode : public SymbolNode { EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView DecodedString; bool IsTruncated = false; @@ -609,7 +609,7 @@ struct EncodedStringLiteralNode : public SymbolNode { struct VariableSymbolNode : public SymbolNode { VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StorageClass SC = StorageClass::None; TypeNode *Type = nullptr; @@ -618,7 +618,7 @@ struct VariableSymbolNode : public SymbolNode { struct FunctionSymbolNode : public SymbolNode { FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; FunctionSignatureNode *Signature = nullptr; }; diff --git a/lib/external/llvm-demangle/include/llvm/Demangle/README.txt b/lib/external/llvm-demangle/include/llvm/Demangle/README.txt new file mode 100644 index 000000000..76470f61f --- /dev/null +++ b/lib/external/llvm-demangle/include/llvm/Demangle/README.txt @@ -0,0 +1,61 @@ +Itanium Name Demangler Library +============================== + +Introduction +------------ + +This directory contains the generic itanium name demangler +library. The main purpose of the library is to demangle C++ symbols, +i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP +base ManglingParser to perform some simple analysis on the mangled +name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the +demangled AST. + +Why are there multiple copies of the this library in the source tree? +--------------------------------------------------------------------- + +The canonical sources are in libcxxabi/src/demangle and some of the +files are copied to llvm/include/llvm/Demangle. The simple reason for +this comes from before the monorepo, and both [sub]projects need to +demangle symbols, but neither can depend on each other. + +* libcxxabi needs the demangler to implement __cxa_demangle, which is + part of the itanium ABI spec. + +* LLVM needs a copy for a bunch of places, and cannot rely on the + system's __cxa_demangle because it a) might not be available (i.e., + on Windows), and b) may not be up-to-date on the latest language + features. + +The copy of the demangler in LLVM has some extra stuff that aren't +needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), +which depend on the shared generic components. Despite these +differences, we want to keep the "core" generic demangling library +identical between both copies to simplify development and testing. + +If you're working on the generic library, then do the work first in +libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This +script takes as an optional argument the path to llvm, and copies the +changes you made to libcxxabi over. Note that this script just +blindly overwrites all changes to the generic library in llvm, so be +careful. + +Because the core demangler needs to work in libcxxabi, everything +needs to be declared in an anonymous namespace (see +DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that +depends on the libcxx dylib. + +FIXME: Now that LLVM is a monorepo, it should be possible to +de-duplicate this code, and have both LLVM and libcxxabi depend on a +shared demangler library. + +Testing +------- + +The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and +llvm/unittest/Demangle. The llvm directory should only get tests for stuff not +included in the core library. In the future though, we should probably move all +the tests to LLVM. + +It is also a really good idea to run libFuzzer after non-trivial changes, see +libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html. diff --git a/lib/external/llvm/include/llvm/Demangle/StringView.h b/lib/external/llvm-demangle/include/llvm/Demangle/StringView.h similarity index 76% rename from lib/external/llvm/include/llvm/Demangle/StringView.h rename to lib/external/llvm-demangle/include/llvm/Demangle/StringView.h index ceb6c7958..30580af28 100644 --- a/lib/external/llvm/include/llvm/Demangle/StringView.h +++ b/lib/external/llvm-demangle/include/llvm/Demangle/StringView.h @@ -1,5 +1,5 @@ -//===--- StringView.h -------------------------------------------*- C++ -*-===// -// +//===--- 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 @@ -7,14 +7,16 @@ //===----------------------------------------------------------------------===// // // 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 +#ifndef LLVM_DEMANGLE_STRINGVIEW_H +#define LLVM_DEMANGLE_STRINGVIEW_H #include "DemangleConfig.h" -#include #include #include @@ -36,29 +38,23 @@ public: StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} StringView() : First(nullptr), Last(nullptr) {} - StringView substr(size_t From) const { - return StringView(begin() + From, size() - From); + 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 { - size_t FindBegin = std::min(From, size()); // Avoid calling memchr with nullptr. - if (FindBegin < size()) { + if (From < size()) { // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) + if (const void *P = ::memchr(First + From, C, size() - From)) return size_t(static_cast(P) - First); } return npos; } - StringView substr(size_t From, size_t To) const { - if (To >= size()) - To = size() - 1; - if (From >= size()) - From = size() - 1; - return StringView(First + From, First + To); - } - StringView dropFront(size_t N = 1) const { if (N >= size()) N = size(); @@ -105,7 +101,7 @@ public: bool startsWith(StringView Str) const { if (Str.size() > size()) return false; - return std::equal(Str.begin(), Str.end(), begin()); + return std::strncmp(Str.begin(), begin(), Str.size()) == 0; } const char &operator[](size_t Idx) const { return *(begin() + Idx); } @@ -118,7 +114,7 @@ public: inline bool operator==(const StringView &LHS, const StringView &RHS) { return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); + std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; } DEMANGLE_NAMESPACE_END diff --git a/lib/external/llvm-demangle/include/llvm/Demangle/Utility.h b/lib/external/llvm-demangle/include/llvm/Demangle/Utility.h new file mode 100644 index 000000000..691c34067 --- /dev/null +++ b/lib/external/llvm-demangle/include/llvm/Demangle/Utility.h @@ -0,0 +1,218 @@ +//===--- 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 LLVM_DEMANGLE_UTILITY_H +#define LLVM_DEMANGLE_UTILITY_H + +#include "StringView.h" +#include +#include +#include +#include +#include +#include + +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(std::realloc(Buffer, BufferCapacity)); + if (Buffer == nullptr) + std::terminate(); + } + } + + OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { + std::array 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), CurrentPosition(0), BufferCapacity(Size) {} + OutputBuffer() = default; + // Non-copyable + OutputBuffer(const OutputBuffer &) = delete; + OutputBuffer &operator=(const OutputBuffer &) = delete; + + operator StringView() const { return StringView(Buffer, CurrentPosition); } + + void reset(char *Buffer_, size_t BufferCapacity_) { + CurrentPosition = 0; + Buffer = Buffer_; + BufferCapacity = BufferCapacity_; + } + + /// If a ParameterPackExpansion (or similar type) is encountered, the offset + /// into the pack that we're currently printing. + unsigned CurrentPackIndex = std::numeric_limits::max(); + unsigned CurrentPackMax = std::numeric_limits::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(std::abs(N)), N < 0); + } + + OutputBuffer &operator<<(unsigned long long N) { + return writeUnsigned(N, false); + } + + OutputBuffer &operator<<(long N) { + return this->operator<<(static_cast(N)); + } + + OutputBuffer &operator<<(unsigned long N) { + return this->operator<<(static_cast(N)); + } + + OutputBuffer &operator<<(int N) { + return this->operator<<(static_cast(N)); + } + + OutputBuffer &operator<<(unsigned int N) { + return this->operator<<(static_cast(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 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; +}; + +inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, + size_t InitSize) { + size_t BufferSize; + if (Buf == nullptr) { + Buf = static_cast(std::malloc(InitSize)); + if (Buf == nullptr) + return false; + BufferSize = InitSize; + } else + BufferSize = *N; + + OB.reset(Buf, BufferSize); + return true; +} + +DEMANGLE_NAMESPACE_END + +#endif diff --git a/lib/external/llvm-demangle/source/DLangDemangle.cpp b/lib/external/llvm-demangle/source/DLangDemangle.cpp new file mode 100644 index 000000000..7cecd8007 --- /dev/null +++ b/lib/external/llvm-demangle/source/DLangDemangle.cpp @@ -0,0 +1,578 @@ +//===--- DLangDemangle.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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a demangler for the D programming language as specified +/// in the ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/Utility.h" + +#include +#include +#include + +using namespace llvm; +using llvm::itanium_demangle::OutputBuffer; +using llvm::itanium_demangle::StringView; + +namespace { + +/// Demangle information structure. +struct Demangler { + /// Initialize the information structure we use to pass around information. + /// + /// \param Mangled String to demangle. + Demangler(const char *Mangled); + + /// Extract and demangle the mangled symbol and append it to the output + /// string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#name_mangling . + /// \see https://dlang.org/spec/abi.html#MangledName . + const char *parseMangle(OutputBuffer *Demangled); + +private: + /// Extract and demangle a given mangled symbol and append it to the output + /// string. + /// + /// \param Demangled output buffer to write the demangled name. + /// \param Mangled mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#name_mangling . + /// \see https://dlang.org/spec/abi.html#MangledName . + const char *parseMangle(OutputBuffer *Demangled, const char *Mangled); + + /// Extract the number from a given string. + /// + /// \param Mangled string to extract the number. + /// \param Ret assigned result value. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \note A result larger than UINT_MAX is considered a failure. + /// + /// \see https://dlang.org/spec/abi.html#Number . + const char *decodeNumber(const char *Mangled, unsigned long &Ret); + + /// Extract the back reference position from a given string. + /// + /// \param Mangled string to extract the back reference position. + /// \param Ret assigned result value. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \note Ret is always >= 0 on success, and unspecified on failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#NumberBackRef . + const char *decodeBackrefPos(const char *Mangled, long &Ret); + + /// Extract the symbol pointed by the back reference form a given string. + /// + /// \param Mangled string to extract the back reference position. + /// \param Ret assigned result value. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + const char *decodeBackref(const char *Mangled, const char *&Ret); + + /// Extract and demangle backreferenced symbol from a given mangled symbol + /// and append it to the output string. + /// + /// \param Demangled output buffer to write the demangled name. + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#IdentifierBackRef . + const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle backreferenced type from a given mangled symbol + /// and append it to the output string. + /// + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#TypeBackRef . + const char *parseTypeBackref(const char *Mangled); + + /// Check whether it is the beginning of a symbol name. + /// + /// \param Mangled string to extract the symbol name. + /// + /// \return true on success, false otherwise. + /// + /// \see https://dlang.org/spec/abi.html#SymbolName . + bool isSymbolName(const char *Mangled); + + /// Extract and demangle an identifier from a given mangled symbol append it + /// to the output string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#SymbolName . + const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle the plain identifier from a given mangled symbol and + /// prepend/append it to the output string, with a special treatment for some + /// magic compiler generated symbols. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// \param Len Length of the mangled symbol name. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#LName . + const char *parseLName(OutputBuffer *Demangled, const char *Mangled, + unsigned long Len); + + /// Extract and demangle the qualified symbol from a given mangled symbol + /// append it to the output string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#QualifiedName . + const char *parseQualified(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle a type from a given mangled symbol append it to + /// the output string. + /// + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#Type . + const char *parseType(const char *Mangled); + + /// The string we are demangling. + const char *Str; + /// The index of the last back reference. + int LastBackref; +}; + +} // namespace + +const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) { + // Return nullptr if trying to extract something that isn't a digit. + if (Mangled == nullptr || !std::isdigit(*Mangled)) + return nullptr; + + unsigned long Val = 0; + + do { + unsigned long Digit = Mangled[0] - '0'; + + // Check for overflow. + if (Val > (std::numeric_limits::max() - Digit) / 10) + return nullptr; + + Val = Val * 10 + Digit; + ++Mangled; + } while (std::isdigit(*Mangled)); + + if (*Mangled == '\0') + return nullptr; + + Ret = Val; + return Mangled; +} + +const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { + // Return nullptr if trying to extract something that isn't a digit + if (Mangled == nullptr || !std::isalpha(*Mangled)) + return nullptr; + + // Any identifier or non-basic type that has been emitted to the mangled + // symbol before will not be emitted again, but is referenced by a special + // sequence encoding the relative position of the original occurrence in the + // mangled symbol name. + // Numbers in back references are encoded with base 26 by upper case letters + // A-Z for higher digits but lower case letters a-z for the last digit. + // NumberBackRef: + // [a-z] + // [A-Z] NumberBackRef + // ^ + unsigned long Val = 0; + + while (std::isalpha(*Mangled)) { + // Check for overflow + if (Val > (std::numeric_limits::max() - 25) / 26) + break; + + Val *= 26; + + if (Mangled[0] >= 'a' && Mangled[0] <= 'z') { + Val += Mangled[0] - 'a'; + if ((long)Val <= 0) + break; + Ret = Val; + return Mangled + 1; + } + + Val += Mangled[0] - 'A'; + ++Mangled; + } + + return nullptr; +} + +const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) { + assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!"); + Ret = nullptr; + + // Position of 'Q' + const char *Qpos = Mangled; + long RefPos; + ++Mangled; + + Mangled = decodeBackrefPos(Mangled, RefPos); + if (Mangled == nullptr) + return nullptr; + + if (RefPos > Qpos - Str) + return nullptr; + + // Set the position of the back reference. + Ret = Qpos - RefPos; + + return Mangled; +} + +const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled, + const char *Mangled) { + // An identifier back reference always points to a digit 0 to 9. + // IdentifierBackRef: + // Q NumberBackRef + // ^ + const char *Backref; + unsigned long Len; + + // Get position of the back reference + Mangled = decodeBackref(Mangled, Backref); + + // Must point to a simple identifier + Backref = decodeNumber(Backref, Len); + if (Backref == nullptr || strlen(Backref) < Len) + return nullptr; + + Backref = parseLName(Demangled, Backref, Len); + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +const char *Demangler::parseTypeBackref(const char *Mangled) { + // A type back reference always points to a letter. + // TypeBackRef: + // Q NumberBackRef + // ^ + const char *Backref; + + // If we appear to be moving backwards through the mangle string, then + // bail as this may be a recursive back reference. + if (Mangled - Str >= LastBackref) + return nullptr; + + int SaveRefPos = LastBackref; + LastBackref = Mangled - Str; + + // Get position of the back reference. + Mangled = decodeBackref(Mangled, Backref); + + // Can't decode back reference. + if (Backref == nullptr) + return nullptr; + + // TODO: Add support for function type back references. + Backref = parseType(Backref); + + LastBackref = SaveRefPos; + + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +bool Demangler::isSymbolName(const char *Mangled) { + long Ret; + const char *Qref = Mangled; + + if (std::isdigit(*Mangled)) + return true; + + // TODO: Handle template instances. + + if (*Mangled != 'Q') + return false; + + Mangled = decodeBackrefPos(Mangled + 1, Ret); + if (Mangled == nullptr || Ret > Qref - Str) + return false; + + return std::isdigit(Qref[-Ret]); +} + +const char *Demangler::parseMangle(OutputBuffer *Demangled, + const char *Mangled) { + // A D mangled symbol is comprised of both scope and type information. + // MangleName: + // _D QualifiedName Type + // _D QualifiedName Z + // ^ + // The caller should have guaranteed that the start pointer is at the + // above location. + // Note that type is never a function type, but only the return type of + // a function or the type of a variable. + Mangled += 2; + + Mangled = parseQualified(Demangled, Mangled); + + if (Mangled != nullptr) { + // Artificial symbols end with 'Z' and have no type. + if (*Mangled == 'Z') + ++Mangled; + else { + Mangled = parseType(Mangled); + } + } + + return Mangled; +} + +const char *Demangler::parseQualified(OutputBuffer *Demangled, + const char *Mangled) { + // Qualified names are identifiers separated by their encoded length. + // Nested functions also encode their argument types without specifying + // what they return. + // QualifiedName: + // SymbolFunctionName + // SymbolFunctionName QualifiedName + // ^ + // SymbolFunctionName: + // SymbolName + // SymbolName TypeFunctionNoReturn + // SymbolName M TypeFunctionNoReturn + // SymbolName M TypeModifiers TypeFunctionNoReturn + // The start pointer should be at the above location. + + // Whether it has more than one symbol + size_t NotFirst = false; + do { + // Skip over anonymous symbols. + if (*Mangled == '0') { + do + ++Mangled; + while (*Mangled == '0'); + + continue; + } + + if (NotFirst) + *Demangled << '.'; + NotFirst = true; + + Mangled = parseIdentifier(Demangled, Mangled); + + } while (Mangled && isSymbolName(Mangled)); + + return Mangled; +} + +const char *Demangler::parseIdentifier(OutputBuffer *Demangled, + const char *Mangled) { + unsigned long Len; + + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + if (*Mangled == 'Q') + return parseSymbolBackref(Demangled, Mangled); + + // TODO: Parse lengthless template instances. + + const char *Endptr = decodeNumber(Mangled, Len); + + if (Endptr == nullptr || Len == 0) + return nullptr; + + if (strlen(Endptr) < Len) + return nullptr; + + Mangled = Endptr; + + // TODO: Parse template instances with a length prefix. + + // There can be multiple different declarations in the same function that + // have the same mangled name. To make the mangled names unique, a fake + // parent in the form `__Sddd' is added to the symbol. + if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { + const char *NumPtr = Mangled + 3; + while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) + ++NumPtr; + + if (Mangled + Len == NumPtr) { + // Skip over the fake parent. + Mangled += Len; + return parseIdentifier(Demangled, Mangled); + } + + // Else demangle it as a plain identifier. + } + + return parseLName(Demangled, Mangled, Len); +} + +const char *Demangler::parseType(const char *Mangled) { + if (*Mangled == '\0') + return nullptr; + + switch (*Mangled) { + // TODO: Parse type qualifiers. + // TODO: Parse function types. + // TODO: Parse compound types. + // TODO: Parse delegate types. + // TODO: Parse tuple types. + + // Basic types. + case 'i': + ++Mangled; + // TODO: Add type name dumping + return Mangled; + + // TODO: Add support for the rest of the basic types. + + // Back referenced type. + case 'Q': + return parseTypeBackref(Mangled); + + default: // unhandled. + return nullptr; + } +} + +const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled, + unsigned long Len) { + switch (Len) { + case 6: + if (strncmp(Mangled, "__initZ", Len + 1) == 0) { + // The static initializer for a given symbol. + Demangled->prepend("initializer for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { + // The vtable symbol for a given class. + Demangled->prepend("vtable for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 7: + if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { + // The classinfo symbol for a given class. + Demangled->prepend("ClassInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 11: + if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { + // The interface symbol for a given class. + Demangled->prepend("Interface for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 12: + if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { + // The ModuleInfo symbol for a given module. + Demangled->prepend("ModuleInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + } + + *Demangled << StringView(Mangled, Len); + Mangled += Len; + + return Mangled; +} + +Demangler::Demangler(const char *Mangled) + : Str(Mangled), LastBackref(strlen(Mangled)) {} + +const char *Demangler::parseMangle(OutputBuffer *Demangled) { + return parseMangle(Demangled, this->Str); +} + +char *llvm::dlangDemangle(const char *MangledName) { + if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + OutputBuffer Demangled; + if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024)) + return nullptr; + + if (strcmp(MangledName, "_Dmain") == 0) { + Demangled << "D main"; + } else { + + Demangler D = Demangler(MangledName); + MangledName = D.parseMangle(&Demangled); + + // Check that the entire symbol was successfully demangled. + if (MangledName == nullptr || *MangledName != '\0') { + std::free(Demangled.getBuffer()); + return nullptr; + } + } + + // OutputBuffer's internal buffer is not null terminated and therefore we need + // to add it to comply with C null terminated strings. + if (Demangled.getCurrentPosition() > 0) { + Demangled << '\0'; + Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1); + return Demangled.getBuffer(); + } + + std::free(Demangled.getBuffer()); + return nullptr; +} diff --git a/lib/external/llvm-demangle/source/Demangle.cpp b/lib/external/llvm-demangle/source/Demangle.cpp new file mode 100644 index 000000000..9d128424c --- /dev/null +++ b/lib/external/llvm-demangle/source/Demangle.cpp @@ -0,0 +1,64 @@ +//===-- 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 +#include + +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; +} + +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'; +} + +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); + else if (isRustEncoding(MangledName)) + Demangled = rustDemangle(MangledName); + else if (isDLangEncoding(MangledName)) + Demangled = dlangDemangle(MangledName); + + if (!Demangled) + return false; + + Result = Demangled; + std::free(Demangled); + return true; +} diff --git a/lib/external/llvm/Demangle/ItaniumDemangle.cpp b/lib/external/llvm-demangle/source/ItaniumDemangle.cpp similarity index 84% rename from lib/external/llvm/Demangle/ItaniumDemangle.cpp rename to lib/external/llvm-demangle/source/ItaniumDemangle.cpp index fad9b6b7b..1c9209d8f 100644 --- a/lib/external/llvm/Demangle/ItaniumDemangle.cpp +++ b/lib/external/llvm-demangle/source/ItaniumDemangle.cpp @@ -19,9 +19,7 @@ #include #include #include -#include #include -#include using namespace llvm; using namespace llvm::itanium_demangle; @@ -174,6 +172,50 @@ struct DumpVisitor { 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"); @@ -333,21 +375,21 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf, int InternalStatus = demangle_success; Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; + OutputBuffer OB; Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, OB, 1024)) InternalStatus = demangle_memory_alloc_failure; else { assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; + AST->print(OB); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = OB.getCurrentPosition(); + Buf = OB.getBuffer(); } if (Status) @@ -385,14 +427,14 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { } static char *printNode(const Node *RootNode, char *Buf, size_t *N) { - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; - RootNode->print(S); - S += '\0'; + RootNode->print(OB); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { @@ -406,8 +448,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { case Node::KAbiTagAttr: Name = static_cast(Name)->Base; continue; - case Node::KStdQualifiedName: - Name = static_cast(Name)->Child; + case Node::KModuleEntity: + Name = static_cast(Name)->Name; continue; case Node::KNestedName: Name = static_cast(Name)->Name; @@ -430,8 +472,8 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, return nullptr; const Node *Name = static_cast(RootNode)->getName(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; KeepGoingLocalFunction: @@ -447,27 +489,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, break; } + if (Name->getKind() == Node::KModuleEntity) + Name = static_cast(Name)->Name; + switch (Name->getKind()) { - case Node::KStdQualifiedName: - S += "std"; - break; case Node::KNestedName: - static_cast(Name)->Qual->print(S); + static_cast(Name)->Qual->print(OB); break; case Node::KLocalName: { auto *LN = static_cast(Name); - LN->Encoding->print(S); - S += "::"; + LN->Encoding->print(OB); + OB += "::"; Name = LN->Entity; goto KeepGoingLocalFunction; } default: break; } - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { @@ -483,17 +525,17 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, return nullptr; NodeArray Params = static_cast(RootNode)->getParams(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; - S += '('; - Params.printWithComma(S); - S += ')'; - S += '\0'; + OB += '('; + Params.printWithComma(OB); + OB += ')'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionReturnType( @@ -501,18 +543,18 @@ char *ItaniumPartialDemangler::getFunctionReturnType( if (!isFunction()) return nullptr; - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; if (const Node *Ret = static_cast(RootNode)->getReturnType()) - Ret->print(S); + Ret->print(OB); - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { @@ -552,8 +594,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { case Node::KNestedName: N = static_cast(N)->Name; break; - case Node::KStdQualifiedName: - N = static_cast(N)->Child; + case Node::KModuleEntity: + N = static_cast(N)->Name; break; } } diff --git a/lib/external/llvm/Demangle/MicrosoftDemangle.cpp b/lib/external/llvm-demangle/source/MicrosoftDemangle.cpp similarity index 97% rename from lib/external/llvm/Demangle/MicrosoftDemangle.cpp rename to lib/external/llvm-demangle/source/MicrosoftDemangle.cpp index 16074314a..b4e98a20f 100644 --- a/lib/external/llvm/Demangle/MicrosoftDemangle.cpp +++ b/lib/external/llvm-demangle/source/MicrosoftDemangle.cpp @@ -245,8 +245,8 @@ demanglePointerCVQualifiers(StringView &MangledName) { } StringView Demangler::copyString(StringView Borrowed) { - char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); - std::strcpy(Stable, Borrowed.begin()); + char *Stable = Arena.allocUnalignedBuffer(Borrowed.size()); + std::memcpy(Stable, Borrowed.begin(), Borrowed.size()); return {Stable, Borrowed.size()}; } @@ -823,11 +823,15 @@ SymbolNode *Demangler::parse(StringView &MangledName) { } TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) { - if (!MangledName.consumeFront(".?A")) + if (!MangledName.consumeFront(".?A")) { + Error = true; return nullptr; + } MangledName.consumeFront(".?A"); - if (MangledName.empty()) + if (MangledName.empty()) { + Error = true; return nullptr; + } return demangleClassType(MangledName); } @@ -965,17 +969,14 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { 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. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); - Identifier->output(OS, OF_Default); - OS << '\0'; - char *Name = OS.getBuffer(); - - StringView Owned = copyString(Name); + Identifier->output(OB, OF_Default); + StringView Owned = copyString(OB); memorizeString(Owned); - std::free(Name); + std::free(OB.getBuffer()); } IdentifierNode * @@ -1107,7 +1108,7 @@ static void writeHexDigit(char *Buffer, uint8_t Digit) { *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10); } -static void outputHex(OutputStream &OS, unsigned C) { +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 @@ -1130,43 +1131,43 @@ static void outputHex(OutputStream &OS, unsigned C) { TempBuffer[Pos--] = 'x'; assert(Pos >= 0); TempBuffer[Pos--] = '\\'; - OS << StringView(&TempBuffer[Pos + 1]); + OB << StringView(&TempBuffer[Pos + 1]); } -static void outputEscapedChar(OutputStream &OS, unsigned C) { +static void outputEscapedChar(OutputBuffer &OB, unsigned C) { switch (C) { case '\0': // nul - OS << "\\0"; + OB << "\\0"; return; case '\'': // single quote - OS << "\\\'"; + OB << "\\\'"; return; case '\"': // double quote - OS << "\\\""; + OB << "\\\""; return; case '\\': // backslash - OS << "\\\\"; + OB << "\\\\"; return; case '\a': // bell - OS << "\\a"; + OB << "\\a"; return; case '\b': // backspace - OS << "\\b"; + OB << "\\b"; return; case '\f': // form feed - OS << "\\f"; + OB << "\\f"; return; case '\n': // new line - OS << "\\n"; + OB << "\\n"; return; case '\r': // carriage return - OS << "\\r"; + OB << "\\r"; return; case '\t': // tab - OS << "\\t"; + OB << "\\t"; return; case '\v': // vertical tab - OS << "\\v"; + OB << "\\v"; return; default: break; @@ -1174,11 +1175,11 @@ static void outputEscapedChar(OutputStream &OS, unsigned C) { if (C > 0x1F && C < 0x7F) { // Standard ascii char. - OS << (char)C; + OB << (char)C; return; } - outputHex(OS, C); + outputHex(OB, C); } static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { @@ -1273,18 +1274,17 @@ FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { EncodedStringLiteralNode * Demangler::demangleStringLiteral(StringView &MangledName) { // This function uses goto, so declare all variables up front. - OutputStream OS; + OutputBuffer OB; StringView CRC; uint64_t StringByteSize; bool IsWcharT = false; bool IsNegative = false; size_t CrcEndPos = 0; - char *ResultBuffer = nullptr; EncodedStringLiteralNode *Result = Arena.alloc(); // Must happen before the first `goto StringLiteralError`. - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); @@ -1329,7 +1329,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) { goto StringLiteralError; wchar_t W = demangleWcharLiteral(MangledName); if (StringByteSize != 2 || Result->IsTruncated) - outputEscapedChar(OS, W); + outputEscapedChar(OB, W); StringByteSize -= 2; if (Error) goto StringLiteralError; @@ -1371,19 +1371,17 @@ Demangler::demangleStringLiteral(StringView &MangledName) { unsigned NextChar = decodeMultiByteChar(StringBytes, CharIndex, CharBytes); if (CharIndex + 1 < NumChars || Result->IsTruncated) - outputEscapedChar(OS, NextChar); + outputEscapedChar(OB, NextChar); } } - OS << '\0'; - ResultBuffer = OS.getBuffer(); - Result->DecodedString = copyString(ResultBuffer); - std::free(ResultBuffer); + Result->DecodedString = copyString(OB); + std::free(OB.getBuffer()); return Result; StringLiteralError: Error = true; - std::free(OS.getBuffer()); + std::free(OB.getBuffer()); return nullptr; } @@ -1447,18 +1445,17 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { return nullptr; // Render the parent symbol's name into a buffer. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); - OS << '`'; - Scope->output(OS, OF_Default); - OS << '\''; - OS << "::`" << Number << "'"; - OS << '\0'; - char *Result = OS.getBuffer(); - Identifier->Name = copyString(Result); - std::free(Result); + OB << '`'; + Scope->output(OB, OF_Default); + OB << '\''; + OB << "::`" << Number << "'"; + + Identifier->Name = copyString(OB); + std::free(OB.getBuffer()); return Identifier; } @@ -1711,6 +1708,10 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { return CallingConv::Eabi; case 'Q': return CallingConv::Vectorcall; + case 'S': + return CallingConv::Swift; + case 'W': + return CallingConv::SwiftAsync; } return CallingConv::None; @@ -2309,19 +2310,19 @@ void Demangler::dumpBackReferences() { (int)Backrefs.FunctionParamCount); // Create an output stream so we can render each type. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) std::terminate(); for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { - OS.setCurrentPosition(0); + OB.setCurrentPosition(0); TypeNode *T = Backrefs.FunctionParams[I]; - T->output(OS, OF_Default); + T->output(OB, OF_Default); - std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(), - OS.getBuffer()); + StringView B = OB; + std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin()); } - std::free(OS.getBuffer()); + std::free(OB.getBuffer()); if (Backrefs.FunctionParamCount > 0) std::printf("\n"); @@ -2338,7 +2339,7 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, char *Buf, size_t *N, int *Status, MSDemangleFlags Flags) { Demangler D; - OutputStream S; + OutputBuffer OB; StringView Name{MangledName}; SymbolNode *AST = D.parse(Name); @@ -2357,18 +2358,20 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, 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 if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, OB, 1024)) InternalStatus = demangle_memory_alloc_failure; else { - AST->output(S, OF); - S += '\0'; + AST->output(OB, OF); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = OB.getCurrentPosition(); + Buf = OB.getBuffer(); } if (Status) diff --git a/lib/external/llvm/Demangle/MicrosoftDemangleNodes.cpp b/lib/external/llvm-demangle/source/MicrosoftDemangleNodes.cpp similarity index 66% rename from lib/external/llvm/Demangle/MicrosoftDemangleNodes.cpp rename to lib/external/llvm-demangle/source/MicrosoftDemangleNodes.cpp index 9cee97523..494cdabad 100644 --- a/lib/external/llvm/Demangle/MicrosoftDemangleNodes.cpp +++ b/lib/external/llvm-demangle/source/MicrosoftDemangleNodes.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/MicrosoftDemangleNodes.h" -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/Utility.h" #include #include @@ -21,91 +20,97 @@ using namespace ms_demangle; #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ case Enum::Value: \ - OS << Desc; \ + OB << Desc; \ break; // Writes a space if the last token does not end with a punctuation. -static void outputSpaceIfNecessary(OutputStream &OS) { - if (OS.empty()) +static void outputSpaceIfNecessary(OutputBuffer &OB) { + if (OB.empty()) return; - char C = OS.back(); + char C = OB.back(); if (std::isalnum(C) || C == '>') - OS << " "; + OB << " "; } -static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { +static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) { switch (Q) { case Q_Const: - OS << "const"; + OB << "const"; break; case Q_Volatile: - OS << "volatile"; + OB << "volatile"; break; case Q_Restrict: - OS << "__restrict"; + OB << "__restrict"; break; default: break; } } -static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, +static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, Qualifiers Mask, bool NeedSpace) { if (!(Q & Mask)) return NeedSpace; if (NeedSpace) - OS << " "; + OB << " "; - outputSingleQualifier(OS, Mask); + outputSingleQualifier(OB, Mask); return true; } -static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, +static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, bool SpaceAfter) { if (Q == Q_None) return; - size_t Pos1 = OS.getCurrentPosition(); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); - size_t Pos2 = OS.getCurrentPosition(); + 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) - OS << " "; + OB << " "; } -static void outputCallingConvention(OutputStream &OS, CallingConv CC) { - outputSpaceIfNecessary(OS); +static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { + outputSpaceIfNecessary(OB); switch (CC) { case CallingConv::Cdecl: - OS << "__cdecl"; + OB << "__cdecl"; break; case CallingConv::Fastcall: - OS << "__fastcall"; + OB << "__fastcall"; break; case CallingConv::Pascal: - OS << "__pascal"; + OB << "__pascal"; break; case CallingConv::Regcall: - OS << "__regcall"; + OB << "__regcall"; break; case CallingConv::Stdcall: - OS << "__stdcall"; + OB << "__stdcall"; break; case CallingConv::Thiscall: - OS << "__thiscall"; + OB << "__thiscall"; break; case CallingConv::Eabi: - OS << "__eabi"; + OB << "__eabi"; break; case CallingConv::Vectorcall: - OS << "__vectorcall"; + OB << "__vectorcall"; break; case CallingConv::Clrcall: - OS << "__clrcall"; + OB << "__clrcall"; + break; + case CallingConv::Swift: + OB << "__attribute__((__swiftcall__)) "; + break; + case CallingConv::SwiftAsync: + OB << "__attribute__((__swiftasynccall__)) "; break; default: break; @@ -113,14 +118,16 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) { } std::string Node::toString(OutputFlags Flags) const { - OutputStream OS; - initializeOutputStream(nullptr, nullptr, OS, 1024); - this->output(OS, Flags); - OS << '\0'; - return {OS.getBuffer()}; + OutputBuffer OB; + initializeOutputBuffer(nullptr, nullptr, OB, 1024); + this->output(OB, Flags); + StringView SV = OB; + std::string Owned(SV.begin(), SV.end()); + std::free(OB.getBuffer()); + return Owned; } -void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { switch (PrimKind) { OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); @@ -144,107 +151,107 @@ void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); } - outputQualifiers(OS, Quals, true, false); + outputQualifiers(OB, Quals, true, false); } -void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { - output(OS, Flags, ", "); +void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { + output(OB, Flags, ", "); } -void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, +void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const { if (Count == 0) return; if (Nodes[0]) - Nodes[0]->output(OS, Flags); + Nodes[0]->output(OB, Flags); for (size_t I = 1; I < Count; ++I) { - OS << Separator; - Nodes[I]->output(OS, Flags); + OB << Separator; + Nodes[I]->output(OB, Flags); } } -void EncodedStringLiteralNode::output(OutputStream &OS, +void EncodedStringLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { switch (Char) { case CharKind::Wchar: - OS << "L\""; + OB << "L\""; break; case CharKind::Char: - OS << "\""; + OB << "\""; break; case CharKind::Char16: - OS << "u\""; + OB << "u\""; break; case CharKind::Char32: - OS << "U\""; + OB << "U\""; break; } - OS << DecodedString << "\""; + OB << DecodedString << "\""; if (IsTruncated) - OS << "..."; + OB << "..."; } -void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { +void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsNegative) - OS << '-'; - OS << Value; + OB << '-'; + OB << Value; } -void TemplateParameterReferenceNode::output(OutputStream &OS, +void TemplateParameterReferenceNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (ThunkOffsetCount > 0) - OS << "{"; + OB << "{"; else if (Affinity == PointerAffinity::Pointer) - OS << "&"; + OB << "&"; if (Symbol) { - Symbol->output(OS, Flags); + Symbol->output(OB, Flags); if (ThunkOffsetCount > 0) - OS << ", "; + OB << ", "; } if (ThunkOffsetCount > 0) - OS << ThunkOffsets[0]; + OB << ThunkOffsets[0]; for (int I = 1; I < ThunkOffsetCount; ++I) { - OS << ", " << ThunkOffsets[I]; + OB << ", " << ThunkOffsets[I]; } if (ThunkOffsetCount > 0) - OS << "}"; + OB << "}"; } -void IdentifierNode::outputTemplateParameters(OutputStream &OS, +void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const { if (!TemplateParams) return; - OS << "<"; - TemplateParams->output(OS, Flags); - OS << ">"; + OB << "<"; + TemplateParams->output(OB, Flags); + OB << ">"; } -void DynamicStructorIdentifierNode::output(OutputStream &OS, +void DynamicStructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsDestructor) - OS << "`dynamic atexit destructor for "; + OB << "`dynamic atexit destructor for "; else - OS << "`dynamic initializer for "; + OB << "`dynamic initializer for "; if (Variable) { - OS << "`"; - Variable->output(OS, Flags); - OS << "''"; + OB << "`"; + Variable->output(OB, Flags); + OB << "''"; } else { - OS << "'"; - Name->output(OS, Flags); - OS << "''"; + OB << "'"; + Name->output(OB, Flags); + OB << "''"; } } -void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { - OS << Name; - outputTemplateParameters(OS, Flags); +void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { + OB << Name; + outputTemplateParameters(OB, Flags); } -void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, +void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { switch (Operator) { OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); @@ -342,188 +349,188 @@ void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, case IntrinsicFunctionKind::None: break; } - outputTemplateParameters(OS, Flags); + outputTemplateParameters(OB, Flags); } -void LocalStaticGuardIdentifierNode::output(OutputStream &OS, +void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsThread) - OS << "`local static thread guard'"; + OB << "`local static thread guard'"; else - OS << "`local static guard'"; + OB << "`local static guard'"; if (ScopeIndex > 0) - OS << "{" << ScopeIndex << "}"; + OB << "{" << ScopeIndex << "}"; } -void ConversionOperatorIdentifierNode::output(OutputStream &OS, +void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "operator"; - outputTemplateParameters(OS, Flags); - OS << " "; - TargetType->output(OS, Flags); + OB << "operator"; + outputTemplateParameters(OB, Flags); + OB << " "; + TargetType->output(OB, Flags); } -void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { +void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsDestructor) - OS << "~"; - Class->output(OS, Flags); - outputTemplateParameters(OS, Flags); + OB << "~"; + Class->output(OB, Flags); + outputTemplateParameters(OB, Flags); } -void LiteralOperatorIdentifierNode::output(OutputStream &OS, +void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "operator \"\"" << Name; - outputTemplateParameters(OS, Flags); + OB << "operator \"\"" << Name; + outputTemplateParameters(OB, Flags); } -void FunctionSignatureNode::outputPre(OutputStream &OS, +void FunctionSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { if (!(Flags & OF_NoAccessSpecifier)) { if (FunctionClass & FC_Public) - OS << "public: "; + OB << "public: "; if (FunctionClass & FC_Protected) - OS << "protected: "; + OB << "protected: "; if (FunctionClass & FC_Private) - OS << "private: "; + OB << "private: "; } if (!(Flags & OF_NoMemberType)) { if (!(FunctionClass & FC_Global)) { if (FunctionClass & FC_Static) - OS << "static "; + OB << "static "; } if (FunctionClass & FC_Virtual) - OS << "virtual "; + OB << "virtual "; if (FunctionClass & FC_ExternC) - OS << "extern \"C\" "; + OB << "extern \"C\" "; } if (!(Flags & OF_NoReturnType) && ReturnType) { - ReturnType->outputPre(OS, Flags); - OS << " "; + ReturnType->outputPre(OB, Flags); + OB << " "; } if (!(Flags & OF_NoCallingConvention)) - outputCallingConvention(OS, CallConvention); + outputCallingConvention(OB, CallConvention); } -void FunctionSignatureNode::outputPost(OutputStream &OS, +void FunctionSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (!(FunctionClass & FC_NoParameterList)) { - OS << "("; + OB << "("; if (Params) - Params->output(OS, Flags); + Params->output(OB, Flags); else - OS << "void"; + OB << "void"; if (IsVariadic) { - if (OS.back() != '(') - OS << ", "; - OS << "..."; + if (OB.back() != '(') + OB << ", "; + OB << "..."; } - OS << ")"; + OB << ")"; } if (Quals & Q_Const) - OS << " const"; + OB << " const"; if (Quals & Q_Volatile) - OS << " volatile"; + OB << " volatile"; if (Quals & Q_Restrict) - OS << " __restrict"; + OB << " __restrict"; if (Quals & Q_Unaligned) - OS << " __unaligned"; + OB << " __unaligned"; if (IsNoexcept) - OS << " noexcept"; + OB << " noexcept"; if (RefQualifier == FunctionRefQualifier::Reference) - OS << " &"; + OB << " &"; else if (RefQualifier == FunctionRefQualifier::RValueReference) - OS << " &&"; + OB << " &&"; if (!(Flags & OF_NoReturnType) && ReturnType) - ReturnType->outputPost(OS, Flags); + ReturnType->outputPost(OB, Flags); } -void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - OS << "[thunk]: "; +void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + OB << "[thunk]: "; - FunctionSignatureNode::outputPre(OS, Flags); + FunctionSignatureNode::outputPre(OB, Flags); } -void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { +void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (FunctionClass & FC_StaticThisAdjust) { - OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; + OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; } else if (FunctionClass & FC_VirtualThisAdjust) { if (FunctionClass & FC_VirtualThisAdjustEx) { - OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " + OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset << ", " << ThisAdjust.StaticOffset << "}'"; } else { - OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " + OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " << ThisAdjust.StaticOffset << "}'"; } } - FunctionSignatureNode::outputPost(OS, Flags); + FunctionSignatureNode::outputPost(OB, Flags); } -void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +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(Pointee); - Sig->outputPre(OS, OF_NoCallingConvention); + Sig->outputPre(OB, OF_NoCallingConvention); } else - Pointee->outputPre(OS, Flags); + Pointee->outputPre(OB, Flags); - outputSpaceIfNecessary(OS); + outputSpaceIfNecessary(OB); if (Quals & Q_Unaligned) - OS << "__unaligned "; + OB << "__unaligned "; if (Pointee->kind() == NodeKind::ArrayType) { - OS << "("; + OB << "("; } else if (Pointee->kind() == NodeKind::FunctionSignature) { - OS << "("; + OB << "("; const FunctionSignatureNode *Sig = static_cast(Pointee); - outputCallingConvention(OS, Sig->CallConvention); - OS << " "; + outputCallingConvention(OB, Sig->CallConvention); + OB << " "; } if (ClassParent) { - ClassParent->output(OS, Flags); - OS << "::"; + ClassParent->output(OB, Flags); + OB << "::"; } switch (Affinity) { case PointerAffinity::Pointer: - OS << "*"; + OB << "*"; break; case PointerAffinity::Reference: - OS << "&"; + OB << "&"; break; case PointerAffinity::RValueReference: - OS << "&&"; + OB << "&&"; break; default: assert(false); } - outputQualifiers(OS, Quals, false, false); + outputQualifiers(OB, Quals, false, false); } -void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { +void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (Pointee->kind() == NodeKind::ArrayType || Pointee->kind() == NodeKind::FunctionSignature) - OS << ")"; + OB << ")"; - Pointee->outputPost(OS, Flags); + Pointee->outputPost(OB, Flags); } -void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { if (!(Flags & OF_NoTagSpecifier)) { switch (Tag) { OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); @@ -531,59 +538,59 @@ void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); } - OS << " "; + OB << " "; } - QualifiedName->output(OS, Flags); - outputQualifiers(OS, Quals, true, false); + QualifiedName->output(OB, Flags); + outputQualifiers(OB, Quals, true, false); } -void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} +void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} -void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - ElementType->outputPre(OS, Flags); - outputQualifiers(OS, Quals, true, false); +void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + ElementType->outputPre(OB, Flags); + outputQualifiers(OB, Quals, true, false); } -void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, +void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const { assert(N->kind() == NodeKind::IntegerLiteral); IntegerLiteralNode *ILN = static_cast(N); if (ILN->Value != 0) - ILN->output(OS, Flags); + ILN->output(OB, Flags); } -void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, +void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const { if (Dimensions->Count == 0) return; - outputOneDimension(OS, Flags, Dimensions->Nodes[0]); + outputOneDimension(OB, Flags, Dimensions->Nodes[0]); for (size_t I = 1; I < Dimensions->Count; ++I) { - OS << "]["; - outputOneDimension(OS, Flags, Dimensions->Nodes[I]); + OB << "]["; + outputOneDimension(OB, Flags, Dimensions->Nodes[I]); } } -void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { - OS << "["; - outputDimensionsImpl(OS, Flags); - OS << "]"; +void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { + OB << "["; + outputDimensionsImpl(OB, Flags); + OB << "]"; - ElementType->outputPost(OS, Flags); + ElementType->outputPost(OB, Flags); } -void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - Name->output(OS, Flags); +void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { + Name->output(OB, Flags); } -void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - Signature->outputPre(OS, Flags); - outputSpaceIfNecessary(OS); - Name->output(OS, Flags); - Signature->outputPost(OS, 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(OutputStream &OS, OutputFlags Flags) const { +void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { const char *AccessSpec = nullptr; bool IsStatic = true; switch (SC) { @@ -601,53 +608,52 @@ void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { break; } if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) - OS << AccessSpec << ": "; + OB << AccessSpec << ": "; if (!(Flags & OF_NoMemberType) && IsStatic) - OS << "static "; + OB << "static "; - if (Type) { - Type->outputPre(OS, Flags); - outputSpaceIfNecessary(OS); + if (!(Flags & OF_NoVariableType) && Type) { + Type->outputPre(OB, Flags); + outputSpaceIfNecessary(OB); } - Name->output(OS, Flags); - if (Type) - Type->outputPost(OS, Flags); + Name->output(OB, Flags); + if (!(Flags & OF_NoVariableType) && Type) + Type->outputPost(OB, Flags); } -void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - Identifier->output(OS, Flags); +void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + Identifier->output(OB, Flags); } -void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} +void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} -void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { - Components->output(OS, Flags, "::"); +void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { + Components->output(OB, Flags, "::"); } -void RttiBaseClassDescriptorNode::output(OutputStream &OS, +void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "`RTTI Base Class Descriptor at ("; - OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " + OB << "`RTTI Base Class Descriptor at ("; + OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " << this->Flags; - OS << ")'"; + OB << ")'"; } -void LocalStaticGuardVariableNode::output(OutputStream &OS, +void LocalStaticGuardVariableNode::output(OutputBuffer &OB, OutputFlags Flags) const { - Name->output(OS, Flags); + Name->output(OB, Flags); } -void VcallThunkIdentifierNode::output(OutputStream &OS, +void VcallThunkIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; + OB << "`vcall'{" << OffsetInVTable << ", {flat}}"; } -void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - outputQualifiers(OS, Quals, false, true); - Name->output(OS, Flags); +void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { + outputQualifiers(OB, Quals, false, true); + Name->output(OB, Flags); if (TargetName) { - OS << "{for `"; - TargetName->output(OS, Flags); - OS << "'}"; + OB << "{for `"; + TargetName->output(OB, Flags); + OB << "'}"; } - return; } diff --git a/lib/external/llvm-demangle/source/RustDemangle.cpp b/lib/external/llvm-demangle/source/RustDemangle.cpp new file mode 100644 index 000000000..32b10db2a --- /dev/null +++ b/lib/external/llvm-demangle/source/RustDemangle.cpp @@ -0,0 +1,1265 @@ +//===--- RustDemangle.cpp ---------------------------------------*- 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 a demangler for Rust v0 mangled symbols as specified in +// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/Utility.h" + +#include +#include +#include +#include +#include + +using namespace llvm; + +using llvm::itanium_demangle::OutputBuffer; +using llvm::itanium_demangle::ScopedOverride; +using llvm::itanium_demangle::StringView; + +namespace { + +struct Identifier { + StringView Name; + bool Punycode; + + bool empty() const { return Name.empty(); } +}; + +enum class BasicType { + Bool, + Char, + I8, + I16, + I32, + I64, + I128, + ISize, + U8, + U16, + U32, + U64, + U128, + USize, + F32, + F64, + Str, + Placeholder, + Unit, + Variadic, + Never, +}; + +enum class IsInType { + No, + Yes, +}; + +enum class LeaveGenericsOpen { + No, + Yes, +}; + +class Demangler { + // Maximum recursion level. Used to avoid stack overflow. + size_t MaxRecursionLevel; + // Current recursion level. + size_t RecursionLevel; + size_t BoundLifetimes; + // Input string that is being demangled with "_R" prefix removed. + StringView Input; + // Position in the input string. + size_t Position; + // When true, print methods append the output to the stream. + // When false, the output is suppressed. + bool Print; + // True if an error occurred. + bool Error; + +public: + // Demangled output. + OutputBuffer Output; + + Demangler(size_t MaxRecursionLevel = 500); + + bool demangle(StringView MangledName); + +private: + bool demanglePath(IsInType Type, + LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No); + void demangleImplPath(IsInType InType); + void demangleGenericArg(); + void demangleType(); + void demangleFnSig(); + void demangleDynBounds(); + void demangleDynTrait(); + void demangleOptionalBinder(); + void demangleConst(); + void demangleConstInt(); + void demangleConstBool(); + void demangleConstChar(); + + template void demangleBackref(Callable Demangler) { + uint64_t Backref = parseBase62Number(); + if (Error || Backref >= Position) { + Error = true; + return; + } + + if (!Print) + return; + + ScopedOverride SavePosition(Position, Position); + Position = Backref; + Demangler(); + } + + Identifier parseIdentifier(); + uint64_t parseOptionalBase62Number(char Tag); + uint64_t parseBase62Number(); + uint64_t parseDecimalNumber(); + uint64_t parseHexNumber(StringView &HexDigits); + + void print(char C); + void print(StringView S); + void printDecimalNumber(uint64_t N); + void printBasicType(BasicType); + void printLifetime(uint64_t Index); + void printIdentifier(Identifier Ident); + + char look() const; + char consume(); + bool consumeIf(char Prefix); + + bool addAssign(uint64_t &A, uint64_t B); + bool mulAssign(uint64_t &A, uint64_t B); +}; + +} // namespace + +char *llvm::rustDemangle(const char *MangledName) { + if (MangledName == nullptr) + return nullptr; + + // Return early if mangled name doesn't look like a Rust symbol. + StringView Mangled(MangledName); + if (!Mangled.startsWith("_R")) + return nullptr; + + Demangler D; + if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024)) + return nullptr; + + if (!D.demangle(Mangled)) { + std::free(D.Output.getBuffer()); + return nullptr; + } + + D.Output += '\0'; + + return D.Output.getBuffer(); +} + +Demangler::Demangler(size_t MaxRecursionLevel) + : MaxRecursionLevel(MaxRecursionLevel) {} + +static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; } + +static inline bool isHexDigit(const char C) { + return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f'); +} + +static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; } + +static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; } + +/// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. +static inline bool isValid(const char C) { + return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; +} + +// Demangles Rust v0 mangled symbol. Returns true when successful, and false +// otherwise. The demangled symbol is stored in Output field. It is +// responsibility of the caller to free the memory behind the output stream. +// +// = "_R" [] +bool Demangler::demangle(StringView Mangled) { + Position = 0; + Error = false; + Print = true; + RecursionLevel = 0; + BoundLifetimes = 0; + + if (!Mangled.consumeFront("_R")) { + Error = true; + return false; + } + size_t Dot = Mangled.find('.'); + Input = Mangled.substr(0, Dot); + StringView Suffix = Mangled.dropFront(Dot); + + demanglePath(IsInType::No); + + if (Position != Input.size()) { + ScopedOverride SavePrint(Print, false); + demanglePath(IsInType::No); + } + + if (Position != Input.size()) + Error = true; + + if (!Suffix.empty()) { + print(" ("); + print(Suffix); + print(")"); + } + + return !Error; +} + +// Demangles a path. InType indicates whether a path is inside a type. When +// LeaveOpen is true, a closing `>` after generic arguments is omitted from the +// output. Return value indicates whether generics arguments have been left +// open. +// +// = "C" // crate root +// | "M" // (inherent impl) +// | "X" // (trait impl) +// | "Y" // (trait definition) +// | "N" // ...::ident (nested path) +// | "I" {} "E" // ... (generic args) +// | +// = [] +// = "C" // closure +// | "S" // shim +// | // other special namespaces +// | // internal namespaces +bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return false; + } + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + switch (consume()) { + case 'C': { + parseOptionalBase62Number('s'); + printIdentifier(parseIdentifier()); + break; + } + case 'M': { + demangleImplPath(InType); + print("<"); + demangleType(); + print(">"); + break; + } + case 'X': { + demangleImplPath(InType); + print("<"); + demangleType(); + print(" as "); + demanglePath(IsInType::Yes); + print(">"); + break; + } + case 'Y': { + print("<"); + demangleType(); + print(" as "); + demanglePath(IsInType::Yes); + print(">"); + break; + } + case 'N': { + char NS = consume(); + if (!isLower(NS) && !isUpper(NS)) { + Error = true; + break; + } + demanglePath(InType); + + uint64_t Disambiguator = parseOptionalBase62Number('s'); + Identifier Ident = parseIdentifier(); + + if (isUpper(NS)) { + // Special namespaces + print("::{"); + if (NS == 'C') + print("closure"); + else if (NS == 'S') + print("shim"); + else + print(NS); + if (!Ident.empty()) { + print(":"); + printIdentifier(Ident); + } + print('#'); + printDecimalNumber(Disambiguator); + print('}'); + } else { + // Implementation internal namespaces. + if (!Ident.empty()) { + print("::"); + printIdentifier(Ident); + } + } + break; + } + case 'I': { + demanglePath(InType); + // Omit "::" when in a type, where it is optional. + if (InType == IsInType::No) + print("::"); + print("<"); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleGenericArg(); + } + if (LeaveOpen == LeaveGenericsOpen::Yes) + return true; + else + print(">"); + break; + } + case 'B': { + bool IsOpen = false; + demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); }); + return IsOpen; + } + default: + Error = true; + break; + } + + return false; +} + +// = [] +// = "s" +void Demangler::demangleImplPath(IsInType InType) { + ScopedOverride SavePrint(Print, false); + parseOptionalBase62Number('s'); + demanglePath(InType); +} + +// = +// | +// | "K" +// = "L" +void Demangler::demangleGenericArg() { + if (consumeIf('L')) + printLifetime(parseBase62Number()); + else if (consumeIf('K')) + demangleConst(); + else + demangleType(); +} + +// = "a" // i8 +// | "b" // bool +// | "c" // char +// | "d" // f64 +// | "e" // str +// | "f" // f32 +// | "h" // u8 +// | "i" // isize +// | "j" // usize +// | "l" // i32 +// | "m" // u32 +// | "n" // i128 +// | "o" // u128 +// | "s" // i16 +// | "t" // u16 +// | "u" // () +// | "v" // ... +// | "x" // i64 +// | "y" // u64 +// | "z" // ! +// | "p" // placeholder (e.g. for generic params), shown as _ +static bool parseBasicType(char C, BasicType &Type) { + switch (C) { + case 'a': + Type = BasicType::I8; + return true; + case 'b': + Type = BasicType::Bool; + return true; + case 'c': + Type = BasicType::Char; + return true; + case 'd': + Type = BasicType::F64; + return true; + case 'e': + Type = BasicType::Str; + return true; + case 'f': + Type = BasicType::F32; + return true; + case 'h': + Type = BasicType::U8; + return true; + case 'i': + Type = BasicType::ISize; + return true; + case 'j': + Type = BasicType::USize; + return true; + case 'l': + Type = BasicType::I32; + return true; + case 'm': + Type = BasicType::U32; + return true; + case 'n': + Type = BasicType::I128; + return true; + case 'o': + Type = BasicType::U128; + return true; + case 'p': + Type = BasicType::Placeholder; + return true; + case 's': + Type = BasicType::I16; + return true; + case 't': + Type = BasicType::U16; + return true; + case 'u': + Type = BasicType::Unit; + return true; + case 'v': + Type = BasicType::Variadic; + return true; + case 'x': + Type = BasicType::I64; + return true; + case 'y': + Type = BasicType::U64; + return true; + case 'z': + Type = BasicType::Never; + return true; + default: + return false; + } +} + +void Demangler::printBasicType(BasicType Type) { + switch (Type) { + case BasicType::Bool: + print("bool"); + break; + case BasicType::Char: + print("char"); + break; + case BasicType::I8: + print("i8"); + break; + case BasicType::I16: + print("i16"); + break; + case BasicType::I32: + print("i32"); + break; + case BasicType::I64: + print("i64"); + break; + case BasicType::I128: + print("i128"); + break; + case BasicType::ISize: + print("isize"); + break; + case BasicType::U8: + print("u8"); + break; + case BasicType::U16: + print("u16"); + break; + case BasicType::U32: + print("u32"); + break; + case BasicType::U64: + print("u64"); + break; + case BasicType::U128: + print("u128"); + break; + case BasicType::USize: + print("usize"); + break; + case BasicType::F32: + print("f32"); + break; + case BasicType::F64: + print("f64"); + break; + case BasicType::Str: + print("str"); + break; + case BasicType::Placeholder: + print("_"); + break; + case BasicType::Unit: + print("()"); + break; + case BasicType::Variadic: + print("..."); + break; + case BasicType::Never: + print("!"); + break; + } +} + +// = | +// | // named type +// | "A" // [T; N] +// | "S" // [T] +// | "T" {} "E" // (T1, T2, T3, ...) +// | "R" [] // &T +// | "Q" [] // &mut T +// | "P" // *const T +// | "O" // *mut T +// | "F" // fn(...) -> ... +// | "D" // dyn Trait + Send + 'a +// | // backref +void Demangler::demangleType() { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return; + } + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + size_t Start = Position; + char C = consume(); + BasicType Type; + if (parseBasicType(C, Type)) + return printBasicType(Type); + + switch (C) { + case 'A': + print("["); + demangleType(); + print("; "); + demangleConst(); + print("]"); + break; + case 'S': + print("["); + demangleType(); + print("]"); + break; + case 'T': { + print("("); + size_t I = 0; + for (; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleType(); + } + if (I == 1) + print(","); + print(")"); + break; + } + case 'R': + case 'Q': + print('&'); + if (consumeIf('L')) { + if (auto Lifetime = parseBase62Number()) { + printLifetime(Lifetime); + print(' '); + } + } + if (C == 'Q') + print("mut "); + demangleType(); + break; + case 'P': + print("*const "); + demangleType(); + break; + case 'O': + print("*mut "); + demangleType(); + break; + case 'F': + demangleFnSig(); + break; + case 'D': + demangleDynBounds(); + if (consumeIf('L')) { + if (auto Lifetime = parseBase62Number()) { + print(" + "); + printLifetime(Lifetime); + } + } else { + Error = true; + } + break; + case 'B': + demangleBackref([&] { demangleType(); }); + break; + default: + Position = Start; + demanglePath(IsInType::Yes); + break; + } +} + +// := [] ["U"] ["K" ] {} "E" +// = "C" +// | +void Demangler::demangleFnSig() { + ScopedOverride SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + demangleOptionalBinder(); + + if (consumeIf('U')) + print("unsafe "); + + if (consumeIf('K')) { + print("extern \""); + if (consumeIf('C')) { + print("C"); + } else { + Identifier Ident = parseIdentifier(); + if (Ident.Punycode) + Error = true; + for (char C : Ident.Name) { + // When mangling ABI string, the "-" is replaced with "_". + if (C == '_') + C = '-'; + print(C); + } + } + print("\" "); + } + + print("fn("); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleType(); + } + print(")"); + + if (consumeIf('u')) { + // Skip the unit type from the output. + } else { + print(" -> "); + demangleType(); + } +} + +// = [] {} "E" +void Demangler::demangleDynBounds() { + ScopedOverride SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + print("dyn "); + demangleOptionalBinder(); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(" + "); + demangleDynTrait(); + } +} + +// = {} +// = "p" +void Demangler::demangleDynTrait() { + bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes); + while (!Error && consumeIf('p')) { + if (!IsOpen) { + IsOpen = true; + print('<'); + } else { + print(", "); + } + print(parseIdentifier().Name); + print(" = "); + demangleType(); + } + if (IsOpen) + print(">"); +} + +// Demangles optional binder and updates the number of bound lifetimes. +// +// = "G" +void Demangler::demangleOptionalBinder() { + uint64_t Binder = parseOptionalBase62Number('G'); + if (Error || Binder == 0) + return; + + // In valid inputs each bound lifetime is referenced later. Referencing a + // lifetime requires at least one byte of input. Reject inputs that are too + // short to reference all bound lifetimes. Otherwise demangling of invalid + // binders could generate excessive amounts of output. + if (Binder >= Input.size() - BoundLifetimes) { + Error = true; + return; + } + + print("for<"); + for (size_t I = 0; I != Binder; ++I) { + BoundLifetimes += 1; + if (I > 0) + print(", "); + printLifetime(1); + } + print("> "); +} + +// = +// | "p" // placeholder +// | +void Demangler::demangleConst() { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return; + } + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + char C = consume(); + BasicType Type; + if (parseBasicType(C, Type)) { + switch (Type) { + case BasicType::I8: + case BasicType::I16: + case BasicType::I32: + case BasicType::I64: + case BasicType::I128: + case BasicType::ISize: + case BasicType::U8: + case BasicType::U16: + case BasicType::U32: + case BasicType::U64: + case BasicType::U128: + case BasicType::USize: + demangleConstInt(); + break; + case BasicType::Bool: + demangleConstBool(); + break; + case BasicType::Char: + demangleConstChar(); + break; + case BasicType::Placeholder: + print('_'); + break; + default: + Error = true; + break; + } + } else if (C == 'B') { + demangleBackref([&] { demangleConst(); }); + } else { + Error = true; + } +} + +// = ["n"] +void Demangler::demangleConstInt() { + if (consumeIf('n')) + print('-'); + + StringView HexDigits; + uint64_t Value = parseHexNumber(HexDigits); + if (HexDigits.size() <= 16) { + printDecimalNumber(Value); + } else { + print("0x"); + print(HexDigits); + } +} + +// = "0_" // false +// | "1_" // true +void Demangler::demangleConstBool() { + StringView HexDigits; + parseHexNumber(HexDigits); + if (HexDigits == "0") + print("false"); + else if (HexDigits == "1") + print("true"); + else + Error = true; +} + +/// Returns true if CodePoint represents a printable ASCII character. +static bool isAsciiPrintable(uint64_t CodePoint) { + return 0x20 <= CodePoint && CodePoint <= 0x7e; +} + +// = +void Demangler::demangleConstChar() { + StringView HexDigits; + uint64_t CodePoint = parseHexNumber(HexDigits); + if (Error || HexDigits.size() > 6) { + Error = true; + return; + } + + print("'"); + switch (CodePoint) { + case '\t': + print(R"(\t)"); + break; + case '\r': + print(R"(\r)"); + break; + case '\n': + print(R"(\n)"); + break; + case '\\': + print(R"(\\)"); + break; + case '"': + print(R"(")"); + break; + case '\'': + print(R"(\')"); + break; + default: + if (isAsciiPrintable(CodePoint)) { + char C = CodePoint; + print(C); + } else { + print(R"(\u{)"); + print(HexDigits); + print('}'); + } + break; + } + print('\''); +} + +// = ["u"] ["_"] +Identifier Demangler::parseIdentifier() { + bool Punycode = consumeIf('u'); + uint64_t Bytes = parseDecimalNumber(); + + // Underscore resolves the ambiguity when identifier starts with a decimal + // digit or another underscore. + consumeIf('_'); + + if (Error || Bytes > Input.size() - Position) { + Error = true; + return {}; + } + StringView S = Input.substr(Position, Bytes); + Position += Bytes; + + if (!std::all_of(S.begin(), S.end(), isValid)) { + Error = true; + return {}; + } + + return {S, Punycode}; +} + +// Parses optional base 62 number. The presence of a number is determined using +// Tag. Returns 0 when tag is absent and parsed value + 1 otherwise +// +// This function is indended for parsing disambiguators and binders which when +// not present have their value interpreted as 0, and otherwise as decoded +// value + 1. For example for binders, value for "G_" is 1, for "G0_" value is +// 2. When "G" is absent value is 0. +uint64_t Demangler::parseOptionalBase62Number(char Tag) { + if (!consumeIf(Tag)) + return 0; + + uint64_t N = parseBase62Number(); + if (Error || !addAssign(N, 1)) + return 0; + + return N; +} + +// Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by +// "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, +// "1_" encodes 2, etc. +// +// = {<0-9a-zA-Z>} "_" +uint64_t Demangler::parseBase62Number() { + if (consumeIf('_')) + return 0; + + uint64_t Value = 0; + + while (true) { + uint64_t Digit; + char C = consume(); + + if (C == '_') { + break; + } else if (isDigit(C)) { + Digit = C - '0'; + } else if (isLower(C)) { + Digit = 10 + (C - 'a'); + } else if (isUpper(C)) { + Digit = 10 + 26 + (C - 'A'); + } else { + Error = true; + return 0; + } + + if (!mulAssign(Value, 62)) + return 0; + + if (!addAssign(Value, Digit)) + return 0; + } + + if (!addAssign(Value, 1)) + return 0; + + return Value; +} + +// Parses a decimal number that had been encoded without any leading zeros. +// +// = "0" +// | <1-9> {<0-9>} +uint64_t Demangler::parseDecimalNumber() { + char C = look(); + if (!isDigit(C)) { + Error = true; + return 0; + } + + if (C == '0') { + consume(); + return 0; + } + + uint64_t Value = 0; + + while (isDigit(look())) { + if (!mulAssign(Value, 10)) { + Error = true; + return 0; + } + + uint64_t D = consume() - '0'; + if (!addAssign(Value, D)) + return 0; + } + + return Value; +} + +// Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed +// value and stores hex digits in HexDigits. The return value is unspecified if +// HexDigits.size() > 16. +// +// = "0_" +// | <1-9a-f> {<0-9a-f>} "_" +uint64_t Demangler::parseHexNumber(StringView &HexDigits) { + size_t Start = Position; + uint64_t Value = 0; + + if (!isHexDigit(look())) + Error = true; + + if (consumeIf('0')) { + if (!consumeIf('_')) + Error = true; + } else { + while (!Error && !consumeIf('_')) { + char C = consume(); + Value *= 16; + if (isDigit(C)) + Value += C - '0'; + else if ('a' <= C && C <= 'f') + Value += 10 + (C - 'a'); + else + Error = true; + } + } + + if (Error) { + HexDigits = StringView(); + return 0; + } + + size_t End = Position - 1; + assert(Start < End); + HexDigits = Input.substr(Start, End - Start); + return Value; +} + +void Demangler::print(char C) { + if (Error || !Print) + return; + + Output += C; +} + +void Demangler::print(StringView S) { + if (Error || !Print) + return; + + Output += S; +} + +void Demangler::printDecimalNumber(uint64_t N) { + if (Error || !Print) + return; + + Output << N; +} + +// Prints a lifetime. An index 0 always represents an erased lifetime. Indices +// starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes +// bound by one of the enclosing binders. +void Demangler::printLifetime(uint64_t Index) { + if (Index == 0) { + print("'_"); + return; + } + + if (Index - 1 >= BoundLifetimes) { + Error = true; + return; + } + + uint64_t Depth = BoundLifetimes - Index; + print('\''); + if (Depth < 26) { + char C = 'a' + Depth; + print(C); + } else { + print('z'); + printDecimalNumber(Depth - 26 + 1); + } +} + +static inline bool decodePunycodeDigit(char C, size_t &Value) { + if (isLower(C)) { + Value = C - 'a'; + return true; + } + + if (isDigit(C)) { + Value = 26 + (C - '0'); + return true; + } + + return false; +} + +static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) { + char *Buffer = Output.getBuffer(); + char *Start = Buffer + StartIdx; + char *End = Buffer + Output.getCurrentPosition(); + Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer); +} + +// Encodes code point as UTF-8 and stores results in Output. Returns false if +// CodePoint is not a valid unicode scalar value. +static inline bool encodeUTF8(size_t CodePoint, char *Output) { + if (0xD800 <= CodePoint && CodePoint <= 0xDFFF) + return false; + + if (CodePoint <= 0x7F) { + Output[0] = CodePoint; + return true; + } + + if (CodePoint <= 0x7FF) { + Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F); + Output[1] = 0x80 | (CodePoint & 0x3F); + return true; + } + + if (CodePoint <= 0xFFFF) { + Output[0] = 0xE0 | (CodePoint >> 12); + Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F); + Output[2] = 0x80 | (CodePoint & 0x3F); + return true; + } + + if (CodePoint <= 0x10FFFF) { + Output[0] = 0xF0 | (CodePoint >> 18); + Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F); + Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F); + Output[3] = 0x80 | (CodePoint & 0x3F); + return true; + } + + return false; +} + +// Decodes string encoded using punycode and appends results to Output. +// Returns true if decoding was successful. +static bool decodePunycode(StringView Input, OutputBuffer &Output) { + size_t OutputSize = Output.getCurrentPosition(); + size_t InputIdx = 0; + + // Rust uses an underscore as a delimiter. + size_t DelimiterPos = StringView::npos; + for (size_t I = 0; I != Input.size(); ++I) + if (Input[I] == '_') + DelimiterPos = I; + + if (DelimiterPos != StringView::npos) { + // Copy basic code points before the last delimiter to the output. + for (; InputIdx != DelimiterPos; ++InputIdx) { + char C = Input[InputIdx]; + if (!isValid(C)) + return false; + // Code points are padded with zeros while decoding is in progress. + char UTF8[4] = {C}; + Output += StringView(UTF8, UTF8 + 4); + } + // Skip over the delimiter. + ++InputIdx; + } + + size_t Base = 36; + size_t Skew = 38; + size_t Bias = 72; + size_t N = 0x80; + size_t TMin = 1; + size_t TMax = 26; + size_t Damp = 700; + + auto Adapt = [&](size_t Delta, size_t NumPoints) { + Delta /= Damp; + Delta += Delta / NumPoints; + Damp = 2; + + size_t K = 0; + while (Delta > (Base - TMin) * TMax / 2) { + Delta /= Base - TMin; + K += Base; + } + return K + (((Base - TMin + 1) * Delta) / (Delta + Skew)); + }; + + // Main decoding loop. + for (size_t I = 0; InputIdx != Input.size(); I += 1) { + size_t OldI = I; + size_t W = 1; + size_t Max = std::numeric_limits::max(); + for (size_t K = Base; true; K += Base) { + if (InputIdx == Input.size()) + return false; + char C = Input[InputIdx++]; + size_t Digit = 0; + if (!decodePunycodeDigit(C, Digit)) + return false; + + if (Digit > (Max - I) / W) + return false; + I += Digit * W; + + size_t T; + if (K <= Bias) + T = TMin; + else if (K >= Bias + TMax) + T = TMax; + else + T = K - Bias; + + if (Digit < T) + break; + + if (W > Max / (Base - T)) + return false; + W *= (Base - T); + } + size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1; + Bias = Adapt(I - OldI, NumPoints); + + if (I / NumPoints > Max - N) + return false; + N += I / NumPoints; + I = I % NumPoints; + + // Insert N at position I in the output. + char UTF8[4] = {}; + if (!encodeUTF8(N, UTF8)) + return false; + Output.insert(OutputSize + I * 4, UTF8, 4); + } + + removeNullBytes(Output, OutputSize); + return true; +} + +void Demangler::printIdentifier(Identifier Ident) { + if (Error || !Print) + return; + + if (Ident.Punycode) { + if (!decodePunycode(Ident.Name, Output)) + Error = true; + } else { + print(Ident.Name); + } +} + +char Demangler::look() const { + if (Error || Position >= Input.size()) + return 0; + + return Input[Position]; +} + +char Demangler::consume() { + if (Error || Position >= Input.size()) { + Error = true; + return 0; + } + + return Input[Position++]; +} + +bool Demangler::consumeIf(char Prefix) { + if (Error || Position >= Input.size() || Input[Position] != Prefix) + return false; + + Position += 1; + return true; +} + +/// Computes A + B. When computation wraps around sets the error and returns +/// false. Otherwise assigns the result to A and returns true. +bool Demangler::addAssign(uint64_t &A, uint64_t B) { + if (A > std::numeric_limits::max() - B) { + Error = true; + return false; + } + + A += B; + return true; +} + +/// Computes A * B. When computation wraps around sets the error and returns +/// false. Otherwise assigns the result to A and returns true. +bool Demangler::mulAssign(uint64_t &A, uint64_t B) { + if (B != 0 && A > std::numeric_limits::max() / B) { + Error = true; + return false; + } + + A *= B; + return true; +} diff --git a/lib/external/llvm/CMakeLists.txt b/lib/external/llvm/CMakeLists.txt deleted file mode 100644 index 6a38926c3..000000000 --- a/lib/external/llvm/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(LLVMDemangle) - -set(CMAKE_CXX_STANDARD 17) - -add_library(LLVMDemangle STATIC - Demangle/Demangle.cpp - Demangle/ItaniumDemangle.cpp - Demangle/MicrosoftDemangle.cpp - Demangle/MicrosoftDemangleNodes.cpp -) - -target_include_directories(LLVMDemangle PUBLIC include) diff --git a/lib/external/llvm/Demangle/Demangle.cpp b/lib/external/llvm/Demangle/Demangle.cpp deleted file mode 100644 index 71dafa0b2..000000000 --- a/lib/external/llvm/Demangle/Demangle.cpp +++ /dev/null @@ -1,36 +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 - -static bool isItaniumEncoding(const std::string &MangledName) { - size_t Pos = MangledName.find_first_not_of('_'); - // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'. - return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z'; -} - -std::string llvm::demangle(const std::string &MangledName) { - char *Demangled; - if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); - else - Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, - nullptr, nullptr); - - if (!Demangled) - return MangledName; - - std::string Ret = Demangled; - free(Demangled); - return Ret; -} diff --git a/lib/external/llvm/include/llvm/Demangle/Utility.h b/lib/external/llvm/include/llvm/Demangle/Utility.h deleted file mode 100644 index 04e1936eb..000000000 --- a/lib/external/llvm/include/llvm/Demangle/Utility.h +++ /dev/null @@ -1,191 +0,0 @@ -//===--- Utility.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 -// -//===----------------------------------------------------------------------===// -// -// Provide some utility classes for use in the demangler(s). -// -//===----------------------------------------------------------------------===// - -#ifndef DEMANGLE_UTILITY_H -#define DEMANGLE_UTILITY_H - -#include "StringView.h" -#include -#include -#include -#include -#include - -DEMANGLE_NAMESPACE_BEGIN - -// Stream that AST nodes write their string representation into after the AST -// has been parsed. -class OutputStream { - char *Buffer = nullptr; - size_t CurrentPosition = 0; - size_t BufferCapacity = 0; - - // Ensure there is at least n more positions in buffer. - void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { - BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; - Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); - if (Buffer == nullptr) - std::terminate(); - } - } - - void writeUnsigned(uint64_t N, bool isNeg = false) { - // Handle special case... - if (N == 0) { - *this << '0'; - return; - } - - char Temp[21]; - char *TempPtr = std::end(Temp); - - while (N) { - *--TempPtr = '0' + char(N % 10); - N /= 10; - } - - // Add negative sign... - if (isNeg) - *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); - } - -public: - OutputStream(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; - void reset(char *Buffer_, size_t BufferCapacity_) { - CurrentPosition = 0; - Buffer = Buffer_; - BufferCapacity = BufferCapacity_; - } - - /// If a ParameterPackExpansion (or similar type) is encountered, the offset - /// into the pack that we're currently printing. - unsigned CurrentPackIndex = std::numeric_limits::max(); - unsigned CurrentPackMax = std::numeric_limits::max(); - - OutputStream &operator+=(StringView R) { - size_t Size = R.size(); - if (Size == 0) - return *this; - grow(Size); - std::memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; - return *this; - } - - OutputStream &operator+=(char C) { - grow(1); - Buffer[CurrentPosition++] = C; - return *this; - } - - OutputStream &operator<<(StringView R) { return (*this += R); } - - OutputStream &operator<<(char C) { return (*this += C); } - - OutputStream &operator<<(long long N) { - if (N < 0) - writeUnsigned(static_cast(-N), true); - else - writeUnsigned(static_cast(N)); - return *this; - } - - OutputStream &operator<<(unsigned long long N) { - writeUnsigned(N, false); - return *this; - } - - OutputStream &operator<<(long N) { - return this->operator<<(static_cast(N)); - } - - OutputStream &operator<<(unsigned long N) { - return this->operator<<(static_cast(N)); - } - - OutputStream &operator<<(int N) { - return this->operator<<(static_cast(N)); - } - - OutputStream &operator<<(unsigned int N) { - return this->operator<<(static_cast(N)); - } - - size_t getCurrentPosition() const { return CurrentPosition; } - void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } - - char back() const { - return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; - } - - bool empty() const { return CurrentPosition == 0; } - - char *getBuffer() { return Buffer; } - char *getBufferEnd() { return Buffer + CurrentPosition - 1; } - size_t getBufferCapacity() const { return BufferCapacity; } -}; - -template class SwapAndRestore { - T &Restore; - T OriginalValue; - bool ShouldRestore = true; - -public: - SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} - - SwapAndRestore(T &Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); - } - ~SwapAndRestore() { - if (ShouldRestore) - Restore = std::move(OriginalValue); - } - - void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } - - void restoreNow(bool Force) { - if (!Force && !ShouldRestore) - return; - - Restore = std::move(OriginalValue); - ShouldRestore = false; - } - - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; -}; - -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, - size_t InitSize) { - size_t BufferSize; - if (Buf == nullptr) { - Buf = static_cast(std::malloc(InitSize)); - if (Buf == nullptr) - return false; - BufferSize = InitSize; - } else - BufferSize = *N; - - S.reset(Buf, BufferSize); - return true; -} - -DEMANGLE_NAMESPACE_END - -#endif diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index fdec2a9b1..988cb3141 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -53,8 +53,8 @@ else() endif() if (NOT USE_SYSTEM_LLVM) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL) - set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm-demangle ${CMAKE_CURRENT_BINARY_DIR}/external/llvm-demangle EXCLUDE_FROM_ALL) + set_target_properties(llvm-demangle PROPERTIES POSITION_INDEPENDENT_CODE ON) else() find_package(LLVM REQUIRED Demangle) endif() @@ -163,4 +163,4 @@ if (APPLE) target_link_libraries(libimhex PUBLIC ${FOUNDATION}) endif () -target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl) +target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} llvm-demangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl) diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 35ce7d5f9..97cebaf76 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -67,7 +67,7 @@ add_library(${PROJECT_NAME} SHARED target_include_directories(${PROJECT_NAME} PRIVATE include) # Add additional libraries here # -target_link_libraries(${PROJECT_NAME} PRIVATE libimhex LLVMDemangle) +target_link_libraries(${PROJECT_NAME} PRIVATE libimhex llvm-demangle) # ---- No need to change anything from here downwards unless you know what you're doing ---- # diff --git a/plugins/builtin/source/content/tools_entries.cpp b/plugins/builtin/source/content/tools_entries.cpp index 91aaf4bf7..79843ce1e 100644 --- a/plugins/builtin/source/content/tools_entries.cpp +++ b/plugins/builtin/source/content/tools_entries.cpp @@ -37,15 +37,21 @@ namespace hex::plugin::builtin { using namespace hex::literals; void drawDemangler() { - static std::vector mangledBuffer(0xF'FFFF, 0x00); - static std::string demangledName; + static std::string mangledName, demangledName; - if (ImGui::InputText("hex.builtin.tools.demangler.mangled"_lang, mangledBuffer.data(), 0xF'FFFF)) { - demangledName = llvm::demangle(mangledBuffer.data()); + if (ImGui::InputTextWithHint("hex.builtin.tools.demangler.mangled"_lang, "Itanium, MSVC, Dlang & Rust", mangledName)) { + demangledName = llvm::demangle(mangledName); + + if (demangledName == mangledName) { + demangledName = "???"; + } } - ImGui::InputText("hex.builtin.tools.demangler.demangled"_lang, demangledName.data(), demangledName.size(), ImGuiInputTextFlags_ReadOnly); - ImGui::NewLine(); + ImGui::Header("hex.builtin.tools.demangler.demangled"_lang); + if (ImGui::BeginChild("demangled", ImVec2(0, 200_scaled), true)) { + ImGui::TextFormattedWrapped("{}", demangledName); + } + ImGui::EndChild(); } void drawASCIITable() { diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 1e06db8e5..109bc0cb0 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -594,7 +594,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "Byteverteilung" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC demangler" }, + { "hex.builtin.tools.demangler", "LLVM Demangler" }, { "hex.builtin.tools.demangler.mangled", "Mangled Namen" }, { "hex.builtin.tools.demangler.demangled", "Demangled Namen" }, { "hex.builtin.tools.ascii_table", "ASCII Tabelle" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 0b581aefa..49223f57f 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -598,7 +598,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC demangler" }, + { "hex.builtin.tools.demangler", "LLVM Demangler" }, { "hex.builtin.tools.demangler.mangled", "Mangled name" }, { "hex.builtin.tools.demangler.demangled", "Demangled name" }, { "hex.builtin.tools.ascii_table", "ASCII table" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 63e8fa29a..392604f32 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -602,7 +602,7 @@ namespace hex::plugin::builtin { //{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC demangler" }, + { "hex.builtin.tools.demangler", "LLVM Demangler" }, { "hex.builtin.tools.demangler.mangled", "Nome Mangled" }, { "hex.builtin.tools.demangler.demangled", "Nome Demangled" }, { "hex.builtin.tools.ascii_table", "Tavola ASCII" }, diff --git a/plugins/builtin/source/lang/ja_JP.cpp b/plugins/builtin/source/lang/ja_JP.cpp index 45c8defb0..cf1ce5ef6 100644 --- a/plugins/builtin/source/lang/ja_JP.cpp +++ b/plugins/builtin/source/lang/ja_JP.cpp @@ -599,7 +599,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "バイト分布" }, - { "hex.builtin.tools.demangler", "Itanium/MSVCデマングラー" }, + { "hex.builtin.tools.demangler", "LLVMデマングラー" }, { "hex.builtin.tools.demangler.mangled", "マングリング名" }, { "hex.builtin.tools.demangler.demangled", "デマングリング名" }, { "hex.builtin.tools.ascii_table", "ASCIIテーブル" }, diff --git a/plugins/builtin/source/lang/pt_BR.cpp b/plugins/builtin/source/lang/pt_BR.cpp index da6cbd5ce..c4c6c26f5 100644 --- a/plugins/builtin/source/lang/pt_BR.cpp +++ b/plugins/builtin/source/lang/pt_BR.cpp @@ -594,7 +594,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC demangler" }, + { "hex.builtin.tools.demangler", "LLVM Demangler" }, { "hex.builtin.tools.demangler.mangled", "Mangled name" }, { "hex.builtin.tools.demangler.demangled", "Demangled name" }, { "hex.builtin.tools.ascii_table", "ASCII table" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index 427b6840a..e483a889e 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -599,7 +599,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "字节分布" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC 名还原" }, + { "hex.builtin.tools.demangler", "LLVM 名还原" }, { "hex.builtin.tools.demangler.mangled", "修饰名" }, { "hex.builtin.tools.demangler.demangled", "还原名" }, { "hex.builtin.tools.ascii_table", "ASCII 表" }, diff --git a/plugins/builtin/source/lang/zh_TW.cpp b/plugins/builtin/source/lang/zh_TW.cpp index 6f6414ea0..813a9ba41 100644 --- a/plugins/builtin/source/lang/zh_TW.cpp +++ b/plugins/builtin/source/lang/zh_TW.cpp @@ -595,7 +595,7 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" }, - { "hex.builtin.tools.demangler", "Itanium/MSVC demangler" }, + { "hex.builtin.tools.demangler", "LLVM Demangler" }, { "hex.builtin.tools.demangler.mangled", "Mangled name" }, { "hex.builtin.tools.demangler.demangled", "Demangled name" }, { "hex.builtin.tools.ascii_table", "ASCII 表" },