diff options
| -rw-r--r-- | LICENSES/LLVM-exception.txt | 279 | ||||
| -rw-r--r-- | externals/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | externals/demangle/Demangle.h | 104 | ||||
| -rw-r--r-- | externals/demangle/DemangleConfig.h | 93 | ||||
| -rw-r--r-- | externals/demangle/ItaniumDemangle.cpp | 588 | ||||
| -rw-r--r-- | externals/demangle/ItaniumDemangle.h | 5582 | ||||
| -rw-r--r-- | externals/demangle/LICENSE.TXT | 279 | ||||
| -rw-r--r-- | externals/demangle/StringView.h | 127 | ||||
| -rw-r--r-- | externals/demangle/Utility.h | 192 | ||||
| -rw-r--r-- | src/common/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/common/demangle.h | 33 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 18 | 
12 files changed, 7287 insertions, 15 deletions
| diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt new file mode 100644 index 000000000..fa6ac5400 --- /dev/null +++ b/LICENSES/LLVM-exception.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/externals/CMakeLists.txt b/externals/CMakeLists.txt index dfd40cba6..89a381587 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -154,3 +154,7 @@ endif()  if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)      add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)  endif() + +add_library(demangle STATIC) +target_include_directories(demangle PUBLIC ./demangle) +target_sources(demangle PRIVATE demangle/ItaniumDemangle.cpp) diff --git a/externals/demangle/Demangle.h b/externals/demangle/Demangle.h new file mode 100644 index 000000000..3b76b49ca --- /dev/null +++ b/externals/demangle/Demangle.h @@ -0,0 +1,104 @@ +//===--- Demangle.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEMANGLE_DEMANGLE_H +#define LLVM_DEMANGLE_DEMANGLE_H + +#include <cstddef> +#include <string> + +namespace llvm { +/// This is a llvm local version of __cxa_demangle. Other than the name and +/// being in the llvm namespace it is identical. +/// +/// The mangled_name is demangled into buf and returned. If the buffer is not +/// large enough, realloc is used to expand it. +/// +/// The *status will be set to a value from the following enumeration +enum : int { +  demangle_unknown_error = -4, +  demangle_invalid_args = -3, +  demangle_invalid_mangled_name = -2, +  demangle_memory_alloc_failure = -1, +  demangle_success = 0, +}; + +char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, +                      int *status); + + +enum MSDemangleFlags { +  MSDF_None = 0, +  MSDF_DumpBackrefs = 1 << 0, +  MSDF_NoAccessSpecifier = 1 << 1, +  MSDF_NoCallingConvention = 1 << 2, +  MSDF_NoReturnType = 1 << 3, +  MSDF_NoMemberType = 1 << 4, +}; +char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n, +                        int *status, MSDemangleFlags Flags = MSDF_None); + +/// "Partial" demangler. This supports demangling a string into an AST +/// (typically an intermediate stage in itaniumDemangle) and querying certain +/// properties or partially printing the demangled name. +struct ItaniumPartialDemangler { +  ItaniumPartialDemangler(); + +  ItaniumPartialDemangler(ItaniumPartialDemangler &&Other); +  ItaniumPartialDemangler &operator=(ItaniumPartialDemangler &&Other); + +  /// Demangle into an AST. Subsequent calls to the rest of the member functions +  /// implicitly operate on the AST this produces. +  /// \return true on error, false otherwise +  bool partialDemangle(const char *MangledName); + +  /// Just print the entire mangled name into Buf. Buf and N behave like the +  /// second and third parameters to itaniumDemangle. +  char *finishDemangle(char *Buf, size_t *N) const; + +  /// Get the base name of a function. This doesn't include trailing template +  /// arguments, ie for "a::b<int>" this function returns "b". +  char *getFunctionBaseName(char *Buf, size_t *N) const; + +  /// Get the context name for a function. For "a::b::c", this function returns +  /// "a::b". +  char *getFunctionDeclContextName(char *Buf, size_t *N) const; + +  /// Get the entire name of this function. +  char *getFunctionName(char *Buf, size_t *N) const; + +  /// Get the parameters for this function. +  char *getFunctionParameters(char *Buf, size_t *N) const; +  char *getFunctionReturnType(char *Buf, size_t *N) const; + +  /// If this function has any any cv or reference qualifiers. These imply that +  /// the function is a non-static member function. +  bool hasFunctionQualifiers() const; + +  /// If this symbol describes a constructor or destructor. +  bool isCtorOrDtor() const; + +  /// If this symbol describes a function. +  bool isFunction() const; + +  /// If this symbol describes a variable. +  bool isData() const; + +  /// If this symbol is a <special-name>. These are generally implicitly +  /// generated by the implementation, such as vtables and typeinfo names. +  bool isSpecialName() const; + +  ~ItaniumPartialDemangler(); +private: +  void *RootNode; +  void *Context; +}; +} // namespace llvm + +#endif diff --git a/externals/demangle/DemangleConfig.h b/externals/demangle/DemangleConfig.h new file mode 100644 index 000000000..f155f69fa --- /dev/null +++ b/externals/demangle/DemangleConfig.h @@ -0,0 +1,93 @@ +//===--- DemangleConfig.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains a variety of feature test macros copied from +// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take +// a dependency on LLVMSupport. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEMANGLE_COMPILER_H +#define LLVM_DEMANGLE_COMPILER_H + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef DEMANGLE_GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define DEMANGLE_GNUC_PREREQ(maj, min, patch)                           \ +  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >=          \ +   ((maj) << 20) + ((min) << 10) + (patch)) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) +#define DEMANGLE_GNUC_PREREQ(maj, min, patch)                           \ +  ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +#else +#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0 +#endif +#endif + +#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0) +#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__)) +#else +#define DEMANGLE_ATTRIBUTE_USED +#endif + +#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0) +#define DEMANGLE_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define DEMANGLE_UNREACHABLE __assume(false) +#else +#define DEMANGLE_UNREACHABLE +#endif + +#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0) +#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define DEMANGLE_ATTRIBUTE_NOINLINE +#endif + +#if !defined(NDEBUG) +#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED +#else +#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE +#endif + +#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough) +#define DEMANGLE_FALLTHROUGH [[fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]] +#elif !__cplusplus +// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious +// error when __has_cpp_attribute is given a scoped attribute in C mode. +#define DEMANGLE_FALLTHROUGH +#elif __has_cpp_attribute(clang::fallthrough) +#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]] +#else +#define DEMANGLE_FALLTHROUGH +#endif + +#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle { +#define DEMANGLE_NAMESPACE_END } } + +#endif diff --git a/externals/demangle/ItaniumDemangle.cpp b/externals/demangle/ItaniumDemangle.cpp new file mode 100644 index 000000000..3a3cbda18 --- /dev/null +++ b/externals/demangle/ItaniumDemangle.cpp @@ -0,0 +1,588 @@ +//===------------------------- ItaniumDemangle.cpp ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// FIXME: (possibly) incomplete list of features that clang mangles that this +// file does not yet support: +//   - C++ modules TS + +#include "Demangle.h" +#include "ItaniumDemangle.h" + +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <functional> +#include <numeric> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace llvm::itanium_demangle; + +constexpr const char *itanium_demangle::FloatData<float>::spec; +constexpr const char *itanium_demangle::FloatData<double>::spec; +constexpr const char *itanium_demangle::FloatData<long double>::spec; + +// <discriminator> := _ <non-negative number>      # when number < 10 +//                 := __ <non-negative number> _   # when number >= 10 +//  extension      := decimal-digit+               # at the end of string +const char *itanium_demangle::parse_discriminator(const char *first, +                                                  const char *last) { +  // parse but ignore discriminator +  if (first != last) { +    if (*first == '_') { +      const char *t1 = first + 1; +      if (t1 != last) { +        if (std::isdigit(*t1)) +          first = t1 + 1; +        else if (*t1 == '_') { +          for (++t1; t1 != last && std::isdigit(*t1); ++t1) +            ; +          if (t1 != last && *t1 == '_') +            first = t1 + 1; +        } +      } +    } else if (std::isdigit(*first)) { +      const char *t1 = first + 1; +      for (; t1 != last && std::isdigit(*t1); ++t1) +        ; +      if (t1 == last) +        first = last; +    } +  } +  return first; +} + +#ifndef NDEBUG +namespace { +struct DumpVisitor { +  unsigned Depth = 0; +  bool PendingNewline = false; + +  template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { +    return true; +  } +  static bool wantsNewline(NodeArray A) { return !A.empty(); } +  static constexpr bool wantsNewline(...) { return false; } + +  template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { +    for (bool B : {wantsNewline(Vs)...}) +      if (B) +        return true; +    return false; +  } + +  void printStr(const char *S) { fprintf(stderr, "%s", S); } +  void print(StringView SV) { +    fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); +  } +  void print(const Node *N) { +    if (N) +      N->visit(std::ref(*this)); +    else +      printStr("<null>"); +  } +  void print(NodeOrString NS) { +    if (NS.isNode()) +      print(NS.asNode()); +    else if (NS.isString()) +      print(NS.asString()); +    else +      printStr("NodeOrString()"); +  } +  void print(NodeArray A) { +    ++Depth; +    printStr("{"); +    bool First = true; +    for (const Node *N : A) { +      if (First) +        print(N); +      else +        printWithComma(N); +      First = false; +    } +    printStr("}"); +    --Depth; +  } + +  // Overload used when T is exactly 'bool', not merely convertible to 'bool'. +  void print(bool B) { printStr(B ? "true" : "false"); } + +  template <class T> +  typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) { +    fprintf(stderr, "%llu", (unsigned long long)N); +  } + +  template <class T> +  typename std::enable_if<std::is_signed<T>::value>::type print(T N) { +    fprintf(stderr, "%lld", (long long)N); +  } + +  void print(ReferenceKind RK) { +    switch (RK) { +    case ReferenceKind::LValue: +      return printStr("ReferenceKind::LValue"); +    case ReferenceKind::RValue: +      return printStr("ReferenceKind::RValue"); +    } +  } +  void print(FunctionRefQual RQ) { +    switch (RQ) { +    case FunctionRefQual::FrefQualNone: +      return printStr("FunctionRefQual::FrefQualNone"); +    case FunctionRefQual::FrefQualLValue: +      return printStr("FunctionRefQual::FrefQualLValue"); +    case FunctionRefQual::FrefQualRValue: +      return printStr("FunctionRefQual::FrefQualRValue"); +    } +  } +  void print(Qualifiers Qs) { +    if (!Qs) return printStr("QualNone"); +    struct QualName { Qualifiers Q; const char *Name; } Names[] = { +      {QualConst, "QualConst"}, +      {QualVolatile, "QualVolatile"}, +      {QualRestrict, "QualRestrict"}, +    }; +    for (QualName Name : Names) { +      if (Qs & Name.Q) { +        printStr(Name.Name); +        Qs = Qualifiers(Qs & ~Name.Q); +        if (Qs) printStr(" | "); +      } +    } +  } +  void print(SpecialSubKind SSK) { +    switch (SSK) { +    case SpecialSubKind::allocator: +      return printStr("SpecialSubKind::allocator"); +    case SpecialSubKind::basic_string: +      return printStr("SpecialSubKind::basic_string"); +    case SpecialSubKind::string: +      return printStr("SpecialSubKind::string"); +    case SpecialSubKind::istream: +      return printStr("SpecialSubKind::istream"); +    case SpecialSubKind::ostream: +      return printStr("SpecialSubKind::ostream"); +    case SpecialSubKind::iostream: +      return printStr("SpecialSubKind::iostream"); +    } +  } +  void print(TemplateParamKind TPK) { +    switch (TPK) { +    case TemplateParamKind::Type: +      return printStr("TemplateParamKind::Type"); +    case TemplateParamKind::NonType: +      return printStr("TemplateParamKind::NonType"); +    case TemplateParamKind::Template: +      return printStr("TemplateParamKind::Template"); +    } +  } + +  void newLine() { +    printStr("\n"); +    for (unsigned I = 0; I != Depth; ++I) +      printStr(" "); +    PendingNewline = false; +  } + +  template<typename T> void printWithPendingNewline(T V) { +    print(V); +    if (wantsNewline(V)) +      PendingNewline = true; +  } + +  template<typename T> void printWithComma(T V) { +    if (PendingNewline || wantsNewline(V)) { +      printStr(","); +      newLine(); +    } else { +      printStr(", "); +    } + +    printWithPendingNewline(V); +  } + +  struct CtorArgPrinter { +    DumpVisitor &Visitor; + +    template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { +      if (Visitor.anyWantNewline(V, Vs...)) +        Visitor.newLine(); +      Visitor.printWithPendingNewline(V); +      int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; +      (void)PrintInOrder; +    } +  }; + +  template<typename NodeT> void operator()(const NodeT *Node) { +    Depth += 2; +    fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); +    Node->match(CtorArgPrinter{*this}); +    fprintf(stderr, ")"); +    Depth -= 2; +  } + +  void operator()(const ForwardTemplateReference *Node) { +    Depth += 2; +    fprintf(stderr, "ForwardTemplateReference("); +    if (Node->Ref && !Node->Printing) { +      Node->Printing = true; +      CtorArgPrinter{*this}(Node->Ref); +      Node->Printing = false; +    } else { +      CtorArgPrinter{*this}(Node->Index); +    } +    fprintf(stderr, ")"); +    Depth -= 2; +  } +}; +} + +void itanium_demangle::Node::dump() const { +  DumpVisitor V; +  visit(std::ref(V)); +  V.newLine(); +} +#endif + +namespace { +class BumpPointerAllocator { +  struct BlockMeta { +    BlockMeta* Next; +    size_t Current; +  }; + +  static constexpr size_t AllocSize = 4096; +  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); + +  alignas(long double) char InitialBuffer[AllocSize]; +  BlockMeta* BlockList = nullptr; + +  void grow() { +    char* NewMeta = static_cast<char *>(std::malloc(AllocSize)); +    if (NewMeta == nullptr) +      std::terminate(); +    BlockList = new (NewMeta) BlockMeta{BlockList, 0}; +  } + +  void* allocateMassive(size_t NBytes) { +    NBytes += sizeof(BlockMeta); +    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes)); +    if (NewMeta == nullptr) +      std::terminate(); +    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; +    return static_cast<void*>(NewMeta + 1); +  } + +public: +  BumpPointerAllocator() +      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} + +  void* allocate(size_t N) { +    N = (N + 15u) & ~15u; +    if (N + BlockList->Current >= UsableAllocSize) { +      if (N > UsableAllocSize) +        return allocateMassive(N); +      grow(); +    } +    BlockList->Current += N; +    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + +                              BlockList->Current - N); +  } + +  void reset() { +    while (BlockList) { +      BlockMeta* Tmp = BlockList; +      BlockList = BlockList->Next; +      if (reinterpret_cast<char*>(Tmp) != InitialBuffer) +        std::free(Tmp); +    } +    BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; +  } + +  ~BumpPointerAllocator() { reset(); } +}; + +class DefaultAllocator { +  BumpPointerAllocator Alloc; + +public: +  void reset() { Alloc.reset(); } + +  template<typename T, typename ...Args> T *makeNode(Args &&...args) { +    return new (Alloc.allocate(sizeof(T))) +        T(std::forward<Args>(args)...); +  } + +  void *allocateNodeArray(size_t sz) { +    return Alloc.allocate(sizeof(Node *) * sz); +  } +}; +}  // unnamed namespace + +//===----------------------------------------------------------------------===// +// Code beyond this point should not be synchronized with libc++abi. +//===----------------------------------------------------------------------===// + +using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; + +char *llvm::itaniumDemangle(const char *MangledName, char *Buf, +                            size_t *N, int *Status) { +  if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { +    if (Status) +      *Status = demangle_invalid_args; +    return nullptr; +  } + +  int InternalStatus = demangle_success; +  Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); +  OutputStream S; + +  Node *AST = Parser.parse(); + +  if (AST == nullptr) +    InternalStatus = demangle_invalid_mangled_name; +  else if (!initializeOutputStream(Buf, N, S, 1024)) +    InternalStatus = demangle_memory_alloc_failure; +  else { +    assert(Parser.ForwardTemplateRefs.empty()); +    AST->print(S); +    S += '\0'; +    if (N != nullptr) +      *N = S.getCurrentPosition(); +    Buf = S.getBuffer(); +  } + +  if (Status) +    *Status = InternalStatus; +  return InternalStatus == demangle_success ? Buf : nullptr; +} + +ItaniumPartialDemangler::ItaniumPartialDemangler() +    : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} + +ItaniumPartialDemangler::~ItaniumPartialDemangler() { +  delete static_cast<Demangler *>(Context); +} + +ItaniumPartialDemangler::ItaniumPartialDemangler( +    ItaniumPartialDemangler &&Other) +    : RootNode(Other.RootNode), Context(Other.Context) { +  Other.Context = Other.RootNode = nullptr; +} + +ItaniumPartialDemangler &ItaniumPartialDemangler:: +operator=(ItaniumPartialDemangler &&Other) { +  std::swap(RootNode, Other.RootNode); +  std::swap(Context, Other.Context); +  return *this; +} + +// Demangle MangledName into an AST, storing it into this->RootNode. +bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { +  Demangler *Parser = static_cast<Demangler *>(Context); +  size_t Len = std::strlen(MangledName); +  Parser->reset(MangledName, MangledName + Len); +  RootNode = Parser->parse(); +  return RootNode == nullptr; +} + +static char *printNode(const Node *RootNode, char *Buf, size_t *N) { +  OutputStream S; +  if (!initializeOutputStream(Buf, N, S, 128)) +    return nullptr; +  RootNode->print(S); +  S += '\0'; +  if (N != nullptr) +    *N = S.getCurrentPosition(); +  return S.getBuffer(); +} + +char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { +  if (!isFunction()) +    return nullptr; + +  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); + +  while (true) { +    switch (Name->getKind()) { +    case Node::KAbiTagAttr: +      Name = static_cast<const AbiTagAttr *>(Name)->Base; +      continue; +    case Node::KStdQualifiedName: +      Name = static_cast<const StdQualifiedName *>(Name)->Child; +      continue; +    case Node::KNestedName: +      Name = static_cast<const NestedName *>(Name)->Name; +      continue; +    case Node::KLocalName: +      Name = static_cast<const LocalName *>(Name)->Entity; +      continue; +    case Node::KNameWithTemplateArgs: +      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; +      continue; +    default: +      return printNode(Name, Buf, N); +    } +  } +} + +char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, +                                                          size_t *N) const { +  if (!isFunction()) +    return nullptr; +  const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); + +  OutputStream S; +  if (!initializeOutputStream(Buf, N, S, 128)) +    return nullptr; + + KeepGoingLocalFunction: +  while (true) { +    if (Name->getKind() == Node::KAbiTagAttr) { +      Name = static_cast<const AbiTagAttr *>(Name)->Base; +      continue; +    } +    if (Name->getKind() == Node::KNameWithTemplateArgs) { +      Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; +      continue; +    } +    break; +  } + +  switch (Name->getKind()) { +  case Node::KStdQualifiedName: +    S += "std"; +    break; +  case Node::KNestedName: +    static_cast<const NestedName *>(Name)->Qual->print(S); +    break; +  case Node::KLocalName: { +    auto *LN = static_cast<const LocalName *>(Name); +    LN->Encoding->print(S); +    S += "::"; +    Name = LN->Entity; +    goto KeepGoingLocalFunction; +  } +  default: +    break; +  } +  S += '\0'; +  if (N != nullptr) +    *N = S.getCurrentPosition(); +  return S.getBuffer(); +} + +char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { +  if (!isFunction()) +    return nullptr; +  auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); +  return printNode(Name, Buf, N); +} + +char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, +                                                     size_t *N) const { +  if (!isFunction()) +    return nullptr; +  NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); + +  OutputStream S; +  if (!initializeOutputStream(Buf, N, S, 128)) +    return nullptr; + +  S += '('; +  Params.printWithComma(S); +  S += ')'; +  S += '\0'; +  if (N != nullptr) +    *N = S.getCurrentPosition(); +  return S.getBuffer(); +} + +char *ItaniumPartialDemangler::getFunctionReturnType( +    char *Buf, size_t *N) const { +  if (!isFunction()) +    return nullptr; + +  OutputStream S; +  if (!initializeOutputStream(Buf, N, S, 128)) +    return nullptr; + +  if (const Node *Ret = +          static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) +    Ret->print(S); + +  S += '\0'; +  if (N != nullptr) +    *N = S.getCurrentPosition(); +  return S.getBuffer(); +} + +char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { +  assert(RootNode != nullptr && "must call partialDemangle()"); +  return printNode(static_cast<Node *>(RootNode), Buf, N); +} + +bool ItaniumPartialDemangler::hasFunctionQualifiers() const { +  assert(RootNode != nullptr && "must call partialDemangle()"); +  if (!isFunction()) +    return false; +  auto *E = static_cast<const FunctionEncoding *>(RootNode); +  return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; +} + +bool ItaniumPartialDemangler::isCtorOrDtor() const { +  const Node *N = static_cast<const Node *>(RootNode); +  while (N) { +    switch (N->getKind()) { +    default: +      return false; +    case Node::KCtorDtorName: +      return true; + +    case Node::KAbiTagAttr: +      N = static_cast<const AbiTagAttr *>(N)->Base; +      break; +    case Node::KFunctionEncoding: +      N = static_cast<const FunctionEncoding *>(N)->getName(); +      break; +    case Node::KLocalName: +      N = static_cast<const LocalName *>(N)->Entity; +      break; +    case Node::KNameWithTemplateArgs: +      N = static_cast<const NameWithTemplateArgs *>(N)->Name; +      break; +    case Node::KNestedName: +      N = static_cast<const NestedName *>(N)->Name; +      break; +    case Node::KStdQualifiedName: +      N = static_cast<const StdQualifiedName *>(N)->Child; +      break; +    } +  } +  return false; +} + +bool ItaniumPartialDemangler::isFunction() const { +  assert(RootNode != nullptr && "must call partialDemangle()"); +  return static_cast<const Node *>(RootNode)->getKind() == +         Node::KFunctionEncoding; +} + +bool ItaniumPartialDemangler::isSpecialName() const { +  assert(RootNode != nullptr && "must call partialDemangle()"); +  auto K = static_cast<const Node *>(RootNode)->getKind(); +  return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; +} + +bool ItaniumPartialDemangler::isData() const { +  return !isFunction() && !isSpecialName(); +} diff --git a/externals/demangle/ItaniumDemangle.h b/externals/demangle/ItaniumDemangle.h new file mode 100644 index 000000000..44ba428a5 --- /dev/null +++ b/externals/demangle/ItaniumDemangle.h @@ -0,0 +1,5582 @@ +//===------------------------- ItaniumDemangle.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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// 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. +// +//===----------------------------------------------------------------------===// + +#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 + +#include "DemangleConfig.h" +#include "StringView.h" +#include "Utility.h" +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <numeric> +#include <utility> + +#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(IntegerCastExpr) \ +    X(IntegerLiteral) \ +    X(FloatLiteral) \ +    X(DoubleLiteral) \ +    X(LongDoubleLiteral) \ +    X(BracedExpr) \ +    X(BracedRangeExpr) + +DEMANGLE_NAMESPACE_BEGIN + +// 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 +  }; + +  /// 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, }; + +private: +  Kind K; + +  // 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; + +  /// Track if this node is a (possibly qualified) array type. This can affect +  /// how we format the output string. +  Cache ArrayCache; + +  /// Track if this node is a (possibly qualified) function type. This can +  /// affect how we format the output string. +  Cache FunctionCache; + +public: +  Node(Kind K_, Cache RHSComponentCache_ = Cache::No, +       Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) +      : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), +        FunctionCache(FunctionCache_) {} + +  /// Visit the most-derived object corresponding to this object. +  template<typename Fn> void visit(Fn F) const; + +  // The following function is provided by all derived classes: +  // +  // Call F with arguments that, when passed to the constructor of this node, +  // would construct an equivalent node. +  //template<typename Fn> void match(Fn F) const; + +  bool hasRHSComponent(OutputStream &S) const { +    if (RHSComponentCache != Cache::Unknown) +      return RHSComponentCache == Cache::Yes; +    return hasRHSComponentSlow(S); +  } + +  bool hasArray(OutputStream &S) const { +    if (ArrayCache != Cache::Unknown) +      return ArrayCache == Cache::Yes; +    return hasArraySlow(S); +  } + +  bool hasFunction(OutputStream &S) const { +    if (FunctionCache != Cache::Unknown) +      return FunctionCache == Cache::Yes; +    return hasFunctionSlow(S); +  } + +  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; } + +  // 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; +  } + +  void print(OutputStream &S) const { +    printLeft(S); +    if (RHSComponentCache != Cache::No) +      printRight(S); +  } + +  // Print the "left" side of this Node into OutputStream. +  virtual void printLeft(OutputStream &) 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 StringView getBaseName() const { return StringView(); } + +  // Silence compiler warnings, this dtor will never be called. +  virtual ~Node() = default; + +#ifndef NDEBUG +  DEMANGLE_DUMP_METHOD void dump() const; +#endif +}; + +class NodeArray { +  Node **Elements; +  size_t NumElements; + +public: +  NodeArray() : Elements(nullptr), NumElements(0) {} +  NodeArray(Node **Elements_, size_t NumElements_) +      : Elements(Elements_), NumElements(NumElements_) {} + +  bool empty() const { return NumElements == 0; } +  size_t size() const { return NumElements; } + +  Node **begin() const { return Elements; } +  Node **end() const { return Elements + NumElements; } + +  Node *operator[](size_t Idx) const { return Elements[Idx]; } + +  void printWithComma(OutputStream &S) const { +    bool FirstElement = true; +    for (size_t Idx = 0; Idx != NumElements; ++Idx) { +      size_t BeforeComma = S.getCurrentPosition(); +      if (!FirstElement) +        S += ", "; +      size_t AfterComma = S.getCurrentPosition(); +      Elements[Idx]->print(S); + +      // Elements[Idx] is an empty parameter pack expansion, we should erase the +      // comma we just printed. +      if (AfterComma == S.getCurrentPosition()) { +        S.setCurrentPosition(BeforeComma); +        continue; +      } + +      FirstElement = false; +    } +  } +}; + +struct NodeArrayNode : Node { +  NodeArray Array; +  NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} + +  template<typename Fn> void match(Fn F) const { F(Array); } + +  void printLeft(OutputStream &S) const override { +    Array.printWithComma(S); +  } +}; + +class DotSuffix final : public Node { +  const Node *Prefix; +  const StringView Suffix; + +public: +  DotSuffix(const Node *Prefix_, StringView Suffix_) +      : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} + +  template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); } + +  void printLeft(OutputStream &s) const override { +    Prefix->print(s); +    s += " ("; +    s += Suffix; +    s += ")"; +  } +}; + +class VendorExtQualType final : public Node { +  const Node *Ty; +  StringView Ext; + +public: +  VendorExtQualType(const Node *Ty_, StringView Ext_) +      : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty, Ext); } + +  void printLeft(OutputStream &S) const override { +    Ty->print(S); +    S += " "; +    S += Ext; +  } +}; + +enum FunctionRefQual : unsigned char { +  FrefQualNone, +  FrefQualLValue, +  FrefQualRValue, +}; + +enum Qualifiers { +  QualNone = 0, +  QualConst = 0x1, +  QualVolatile = 0x2, +  QualRestrict = 0x4, +}; + +inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { +  return Q1 = static_cast<Qualifiers>(Q1 | Q2); +} + +class QualType final : public Node { +protected: +  const Qualifiers Quals; +  const Node *Child; + +  void printQuals(OutputStream &S) const { +    if (Quals & QualConst) +      S += " const"; +    if (Quals & QualVolatile) +      S += " volatile"; +    if (Quals & QualRestrict) +      S += " restrict"; +  } + +public: +  QualType(const Node *Child_, Qualifiers Quals_) +      : Node(KQualType, Child_->RHSComponentCache, +             Child_->ArrayCache, Child_->FunctionCache), +        Quals(Quals_), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Child, Quals); } + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    return Child->hasRHSComponent(S); +  } +  bool hasArraySlow(OutputStream &S) const override { +    return Child->hasArray(S); +  } +  bool hasFunctionSlow(OutputStream &S) const override { +    return Child->hasFunction(S); +  } + +  void printLeft(OutputStream &S) const override { +    Child->printLeft(S); +    printQuals(S); +  } + +  void printRight(OutputStream &S) const override { Child->printRight(S); } +}; + +class ConversionOperatorType final : public Node { +  const Node *Ty; + +public: +  ConversionOperatorType(const Node *Ty_) +      : Node(KConversionOperatorType), Ty(Ty_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty); } + +  void printLeft(OutputStream &S) const override { +    S += "operator "; +    Ty->print(S); +  } +}; + +class PostfixQualifiedType final : public Node { +  const Node *Ty; +  const StringView Postfix; + +public: +  PostfixQualifiedType(Node *Ty_, StringView Postfix_) +      : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty, Postfix); } + +  void printLeft(OutputStream &s) const override { +    Ty->printLeft(s); +    s += Postfix; +  } +}; + +class NameType final : public Node { +  const StringView Name; + +public: +  NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + +  template<typename Fn> void match(Fn F) const { F(Name); } + +  StringView getName() const { return Name; } +  StringView getBaseName() const override { return Name; } + +  void printLeft(OutputStream &s) const override { s += Name; } +}; + +class ElaboratedTypeSpefType : public Node { +  StringView Kind; +  Node *Child; +public: +  ElaboratedTypeSpefType(StringView Kind_, Node *Child_) +      : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Kind, Child); } + +  void printLeft(OutputStream &S) const override { +    S += Kind; +    S += ' '; +    Child->print(S); +  } +}; + +struct AbiTagAttr : Node { +  Node *Base; +  StringView Tag; + +  AbiTagAttr(Node* Base_, StringView Tag_) +      : Node(KAbiTagAttr, Base_->RHSComponentCache, +             Base_->ArrayCache, Base_->FunctionCache), +        Base(Base_), Tag(Tag_) {} + +  template<typename Fn> void match(Fn F) const { F(Base, Tag); } + +  void printLeft(OutputStream &S) const override { +    Base->printLeft(S); +    S += "[abi:"; +    S += Tag; +    S += "]"; +  } +}; + +class EnableIfAttr : public Node { +  NodeArray Conditions; +public: +  EnableIfAttr(NodeArray Conditions_) +      : Node(KEnableIfAttr), Conditions(Conditions_) {} + +  template<typename Fn> void match(Fn F) const { F(Conditions); } + +  void printLeft(OutputStream &S) const override { +    S += " [enable_if:"; +    Conditions.printWithComma(S); +    S += ']'; +  } +}; + +class ObjCProtoName : public Node { +  const Node *Ty; +  StringView Protocol; + +  friend class PointerType; + +public: +  ObjCProtoName(const Node *Ty_, StringView Protocol_) +      : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } + +  bool isObjCObject() const { +    return Ty->getKind() == KNameType && +           static_cast<const NameType *>(Ty)->getName() == "objc_object"; +  } + +  void printLeft(OutputStream &S) const override { +    Ty->print(S); +    S += "<"; +    S += Protocol; +    S += ">"; +  } +}; + +class PointerType final : public Node { +  const Node *Pointee; + +public: +  PointerType(const Node *Pointee_) +      : Node(KPointerType, Pointee_->RHSComponentCache), +        Pointee(Pointee_) {} + +  template<typename Fn> void match(Fn F) const { F(Pointee); } + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    return Pointee->hasRHSComponent(S); +  } + +  void printLeft(OutputStream &s) const override { +    // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. +    if (Pointee->getKind() != KObjCProtoName || +        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { +      Pointee->printLeft(s); +      if (Pointee->hasArray(s)) +        s += " "; +      if (Pointee->hasArray(s) || Pointee->hasFunction(s)) +        s += "("; +      s += "*"; +    } else { +      const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); +      s += "id<"; +      s += objcProto->Protocol; +      s += ">"; +    } +  } + +  void printRight(OutputStream &s) const override { +    if (Pointee->getKind() != KObjCProtoName || +        !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { +      if (Pointee->hasArray(s) || Pointee->hasFunction(s)) +        s += ")"; +      Pointee->printRight(s); +    } +  } +}; + +enum class ReferenceKind { +  LValue, +  RValue, +}; + +// Represents either a LValue or an RValue reference type. +class ReferenceType : public Node { +  const Node *Pointee; +  ReferenceKind RK; + +  mutable bool Printing = false; + +  // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The +  // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any +  // other combination collapses to a lvalue ref. +  std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const { +    auto SoFar = std::make_pair(RK, Pointee); +    for (;;) { +      const Node *SN = SoFar.second->getSyntaxNode(S); +      if (SN->getKind() != KReferenceType) +        break; +      auto *RT = static_cast<const ReferenceType *>(SN); +      SoFar.second = RT->Pointee; +      SoFar.first = std::min(SoFar.first, RT->RK); +    } +    return SoFar; +  } + +public: +  ReferenceType(const Node *Pointee_, ReferenceKind RK_) +      : Node(KReferenceType, Pointee_->RHSComponentCache), +        Pointee(Pointee_), RK(RK_) {} + +  template<typename Fn> void match(Fn F) const { F(Pointee, RK); } + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    return Pointee->hasRHSComponent(S); +  } + +  void printLeft(OutputStream &s) const override { +    if (Printing) +      return; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); +    Collapsed.second->printLeft(s); +    if (Collapsed.second->hasArray(s)) +      s += " "; +    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) +      s += "("; + +    s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); +  } +  void printRight(OutputStream &s) const override { +    if (Printing) +      return; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); +    if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) +      s += ")"; +    Collapsed.second->printRight(s); +  } +}; + +class PointerToMemberType final : public Node { +  const Node *ClassType; +  const Node *MemberType; + +public: +  PointerToMemberType(const Node *ClassType_, const Node *MemberType_) +      : Node(KPointerToMemberType, MemberType_->RHSComponentCache), +        ClassType(ClassType_), MemberType(MemberType_) {} + +  template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); } + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    return MemberType->hasRHSComponent(S); +  } + +  void printLeft(OutputStream &s) const override { +    MemberType->printLeft(s); +    if (MemberType->hasArray(s) || MemberType->hasFunction(s)) +      s += "("; +    else +      s += " "; +    ClassType->print(s); +    s += "::*"; +  } + +  void printRight(OutputStream &s) const override { +    if (MemberType->hasArray(s) || MemberType->hasFunction(s)) +      s += ")"; +    MemberType->printRight(s); +  } +}; + +class NodeOrString { +  const void *First; +  const void *Second; + +public: +  /* implicit */ NodeOrString(StringView Str) { +    const char *FirstChar = Str.begin(); +    const char *SecondChar = Str.end(); +    if (SecondChar == nullptr) { +      assert(FirstChar == SecondChar); +      ++FirstChar, ++SecondChar; +    } +    First = static_cast<const void *>(FirstChar); +    Second = static_cast<const void *>(SecondChar); +  } + +  /* implicit */ NodeOrString(Node *N) +      : First(static_cast<const void *>(N)), Second(nullptr) {} +  NodeOrString() : First(nullptr), Second(nullptr) {} + +  bool isString() const { return Second && First; } +  bool isNode() const { return First && !Second; } +  bool isEmpty() const { return !First && !Second; } + +  StringView asString() const { +    assert(isString()); +    return StringView(static_cast<const char *>(First), +                      static_cast<const char *>(Second)); +  } + +  const Node *asNode() const { +    assert(isNode()); +    return static_cast<const Node *>(First); +  } +}; + +class ArrayType final : public Node { +  const Node *Base; +  NodeOrString Dimension; + +public: +  ArrayType(const Node *Base_, NodeOrString Dimension_) +      : Node(KArrayType, +             /*RHSComponentCache=*/Cache::Yes, +             /*ArrayCache=*/Cache::Yes), +        Base(Base_), Dimension(Dimension_) {} + +  template<typename Fn> void match(Fn F) const { F(Base, Dimension); } + +  bool hasRHSComponentSlow(OutputStream &) const override { return true; } +  bool hasArraySlow(OutputStream &) const override { return true; } + +  void printLeft(OutputStream &S) const override { Base->printLeft(S); } + +  void printRight(OutputStream &S) const override { +    if (S.back() != ']') +      S += " "; +    S += "["; +    if (Dimension.isString()) +      S += Dimension.asString(); +    else if (Dimension.isNode()) +      Dimension.asNode()->print(S); +    S += "]"; +    Base->printRight(S); +  } +}; + +class FunctionType final : public Node { +  const Node *Ret; +  NodeArray Params; +  Qualifiers CVQuals; +  FunctionRefQual RefQual; +  const Node *ExceptionSpec; + +public: +  FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, +               FunctionRefQual RefQual_, const Node *ExceptionSpec_) +      : Node(KFunctionType, +             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, +             /*FunctionCache=*/Cache::Yes), +        Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), +        ExceptionSpec(ExceptionSpec_) {} + +  template<typename Fn> void match(Fn F) const { +    F(Ret, Params, CVQuals, RefQual, ExceptionSpec); +  } + +  bool hasRHSComponentSlow(OutputStream &) const override { return true; } +  bool hasFunctionSlow(OutputStream &) const override { return true; } + +  // Handle C++'s ... quirky decl grammar by using the left & right +  // distinction. Consider: +  //   int (*f(float))(char) {} +  // f is a function that takes a float and returns a pointer to a function +  // that takes a char and returns an int. If we're trying to print f, start +  // by printing out the return types's left, then print our parameters, then +  // finally print right of the return type. +  void printLeft(OutputStream &S) const override { +    Ret->printLeft(S); +    S += " "; +  } + +  void printRight(OutputStream &S) const override { +    S += "("; +    Params.printWithComma(S); +    S += ")"; +    Ret->printRight(S); + +    if (CVQuals & QualConst) +      S += " const"; +    if (CVQuals & QualVolatile) +      S += " volatile"; +    if (CVQuals & QualRestrict) +      S += " restrict"; + +    if (RefQual == FrefQualLValue) +      S += " &"; +    else if (RefQual == FrefQualRValue) +      S += " &&"; + +    if (ExceptionSpec != nullptr) { +      S += ' '; +      ExceptionSpec->print(S); +    } +  } +}; + +class NoexceptSpec : public Node { +  const Node *E; +public: +  NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} + +  template<typename Fn> void match(Fn F) const { F(E); } + +  void printLeft(OutputStream &S) const override { +    S += "noexcept("; +    E->print(S); +    S += ")"; +  } +}; + +class DynamicExceptionSpec : public Node { +  NodeArray Types; +public: +  DynamicExceptionSpec(NodeArray Types_) +      : Node(KDynamicExceptionSpec), Types(Types_) {} + +  template<typename Fn> void match(Fn F) const { F(Types); } + +  void printLeft(OutputStream &S) const override { +    S += "throw("; +    Types.printWithComma(S); +    S += ')'; +  } +}; + +class FunctionEncoding final : public Node { +  const Node *Ret; +  const Node *Name; +  NodeArray Params; +  const Node *Attrs; +  Qualifiers CVQuals; +  FunctionRefQual RefQual; + +public: +  FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, +                   const Node *Attrs_, Qualifiers CVQuals_, +                   FunctionRefQual RefQual_) +      : Node(KFunctionEncoding, +             /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, +             /*FunctionCache=*/Cache::Yes), +        Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), +        CVQuals(CVQuals_), RefQual(RefQual_) {} + +  template<typename Fn> void match(Fn F) const { +    F(Ret, Name, Params, Attrs, CVQuals, RefQual); +  } + +  Qualifiers getCVQuals() const { return CVQuals; } +  FunctionRefQual getRefQual() const { return RefQual; } +  NodeArray getParams() const { return Params; } +  const Node *getReturnType() const { return Ret; } + +  bool hasRHSComponentSlow(OutputStream &) const override { return true; } +  bool hasFunctionSlow(OutputStream &) const override { return true; } + +  const Node *getName() const { return Name; } + +  void printLeft(OutputStream &S) const override { +    if (Ret) { +      Ret->printLeft(S); +      if (!Ret->hasRHSComponent(S)) +        S += " "; +    } +    Name->print(S); +  } + +  void printRight(OutputStream &S) const override { +    S += "("; +    Params.printWithComma(S); +    S += ")"; +    if (Ret) +      Ret->printRight(S); + +    if (CVQuals & QualConst) +      S += " const"; +    if (CVQuals & QualVolatile) +      S += " volatile"; +    if (CVQuals & QualRestrict) +      S += " restrict"; + +    if (RefQual == FrefQualLValue) +      S += " &"; +    else if (RefQual == FrefQualRValue) +      S += " &&"; + +    if (Attrs != nullptr) +      Attrs->print(S); +  } +}; + +class LiteralOperator : public Node { +  const Node *OpName; + +public: +  LiteralOperator(const Node *OpName_) +      : Node(KLiteralOperator), OpName(OpName_) {} + +  template<typename Fn> void match(Fn F) const { F(OpName); } + +  void printLeft(OutputStream &S) const override { +    S += "operator\"\" "; +    OpName->print(S); +  } +}; + +class SpecialName final : public Node { +  const StringView Special; +  const Node *Child; + +public: +  SpecialName(StringView Special_, const Node *Child_) +      : Node(KSpecialName), Special(Special_), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Special, Child); } + +  void printLeft(OutputStream &S) const override { +    S += Special; +    Child->print(S); +  } +}; + +class CtorVtableSpecialName final : public Node { +  const Node *FirstType; +  const Node *SecondType; + +public: +  CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) +      : Node(KCtorVtableSpecialName), +        FirstType(FirstType_), SecondType(SecondType_) {} + +  template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } + +  void printLeft(OutputStream &S) const override { +    S += "construction vtable for "; +    FirstType->print(S); +    S += "-in-"; +    SecondType->print(S); +  } +}; + +struct NestedName : Node { +  Node *Qual; +  Node *Name; + +  NestedName(Node *Qual_, Node *Name_) +      : Node(KNestedName), Qual(Qual_), Name(Name_) {} + +  template<typename Fn> void match(Fn F) const { F(Qual, Name); } + +  StringView getBaseName() const override { return Name->getBaseName(); } + +  void printLeft(OutputStream &S) const override { +    Qual->print(S); +    S += "::"; +    Name->print(S); +  } +}; + +struct LocalName : Node { +  Node *Encoding; +  Node *Entity; + +  LocalName(Node *Encoding_, Node *Entity_) +      : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} + +  template<typename Fn> void match(Fn F) const { F(Encoding, Entity); } + +  void printLeft(OutputStream &S) const override { +    Encoding->print(S); +    S += "::"; +    Entity->print(S); +  } +}; + +class QualifiedName final : public Node { +  // qualifier::name +  const Node *Qualifier; +  const Node *Name; + +public: +  QualifiedName(const Node *Qualifier_, const Node *Name_) +      : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} + +  template<typename Fn> void match(Fn F) const { F(Qualifier, Name); } + +  StringView getBaseName() const override { return Name->getBaseName(); } + +  void printLeft(OutputStream &S) const override { +    Qualifier->print(S); +    S += "::"; +    Name->print(S); +  } +}; + +class VectorType final : public Node { +  const Node *BaseType; +  const NodeOrString Dimension; + +public: +  VectorType(const Node *BaseType_, NodeOrString Dimension_) +      : Node(KVectorType), BaseType(BaseType_), +        Dimension(Dimension_) {} + +  template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } + +  void printLeft(OutputStream &S) const override { +    BaseType->print(S); +    S += " vector["; +    if (Dimension.isNode()) +      Dimension.asNode()->print(S); +    else if (Dimension.isString()) +      S += Dimension.asString(); +    S += "]"; +  } +}; + +class PixelVectorType final : public Node { +  const NodeOrString Dimension; + +public: +  PixelVectorType(NodeOrString Dimension_) +      : Node(KPixelVectorType), Dimension(Dimension_) {} + +  template<typename Fn> void match(Fn F) const { F(Dimension); } + +  void printLeft(OutputStream &S) const override { +    // FIXME: This should demangle as "vector pixel". +    S += "pixel vector["; +    S += Dimension.asString(); +    S += "]"; +  } +}; + +enum class TemplateParamKind { Type, NonType, Template }; + +/// An invented name for a template parameter for which we don't have a +/// corresponding template argument. +/// +/// This node is created when parsing the <lambda-sig> for a lambda with +/// explicit template arguments, which might be referenced in the parameter +/// types appearing later in the <lambda-sig>. +class SyntheticTemplateParamName final : public Node { +  TemplateParamKind Kind; +  unsigned Index; + +public: +  SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_) +      : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {} + +  template<typename Fn> void match(Fn F) const { F(Kind, Index); } + +  void printLeft(OutputStream &S) const override { +    switch (Kind) { +    case TemplateParamKind::Type: +      S += "$T"; +      break; +    case TemplateParamKind::NonType: +      S += "$N"; +      break; +    case TemplateParamKind::Template: +      S += "$TT"; +      break; +    } +    if (Index > 0) +      S << Index - 1; +  } +}; + +/// A template type parameter declaration, 'typename T'. +class TypeTemplateParamDecl final : public Node { +  Node *Name; + +public: +  TypeTemplateParamDecl(Node *Name_) +      : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {} + +  template<typename Fn> void match(Fn F) const { F(Name); } + +  void printLeft(OutputStream &S) const override { +    S += "typename "; +  } + +  void printRight(OutputStream &S) const override { +    Name->print(S); +  } +}; + +/// A non-type template parameter declaration, 'int N'. +class NonTypeTemplateParamDecl final : public Node { +  Node *Name; +  Node *Type; + +public: +  NonTypeTemplateParamDecl(Node *Name_, Node *Type_) +      : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {} + +  template<typename Fn> void match(Fn F) const { F(Name, Type); } + +  void printLeft(OutputStream &S) const override { +    Type->printLeft(S); +    if (!Type->hasRHSComponent(S)) +      S += " "; +  } + +  void printRight(OutputStream &S) const override { +    Name->print(S); +    Type->printRight(S); +  } +}; + +/// A template template parameter declaration, +/// 'template<typename T> typename N'. +class TemplateTemplateParamDecl final : public Node { +  Node *Name; +  NodeArray Params; + +public: +  TemplateTemplateParamDecl(Node *Name_, NodeArray Params_) +      : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_), +        Params(Params_) {} + +  template<typename Fn> void match(Fn F) const { F(Name, Params); } + +  void printLeft(OutputStream &S) const override { +    S += "template<"; +    Params.printWithComma(S); +    S += "> typename "; +  } + +  void printRight(OutputStream &S) const override { +    Name->print(S); +  } +}; + +/// A template parameter pack declaration, 'typename ...T'. +class TemplateParamPackDecl final : public Node { +  Node *Param; + +public: +  TemplateParamPackDecl(Node *Param_) +      : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {} + +  template<typename Fn> void match(Fn F) const { F(Param); } + +  void printLeft(OutputStream &S) const override { +    Param->printLeft(S); +    S += "..."; +  } + +  void printRight(OutputStream &S) const override { +    Param->printRight(S); +  } +}; + +/// An unexpanded parameter pack (either in the expression or type context). If +/// this AST is correct, this node will have a ParameterPackExpansion node above +/// it. +/// +/// This node is created when some <template-args> are found that apply to an +/// <encoding>, and is stored in the TemplateParams table. In order for this to +/// appear in the final AST, it has to referenced via a <template-param> (ie, +/// T_). +class ParameterPack final : public Node { +  NodeArray Data; + +  // Setup OutputStream for a pack expansion unless we're already expanding one. +  void initializePackExpansion(OutputStream &S) const { +    if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) { +      S.CurrentPackMax = static_cast<unsigned>(Data.size()); +      S.CurrentPackIndex = 0; +    } +  } + +public: +  ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { +    ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; +    if (std::all_of(Data.begin(), Data.end(), [](Node* P) { +          return P->ArrayCache == Cache::No; +        })) +      ArrayCache = Cache::No; +    if (std::all_of(Data.begin(), Data.end(), [](Node* P) { +          return P->FunctionCache == Cache::No; +        })) +      FunctionCache = Cache::No; +    if (std::all_of(Data.begin(), Data.end(), [](Node* P) { +          return P->RHSComponentCache == Cache::No; +        })) +      RHSComponentCache = Cache::No; +  } + +  template<typename Fn> void match(Fn F) const { F(Data); } + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); +  } +  bool hasArraySlow(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    return Idx < Data.size() && Data[Idx]->hasArray(S); +  } +  bool hasFunctionSlow(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    return Idx < Data.size() && Data[Idx]->hasFunction(S); +  } +  const Node *getSyntaxNode(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; +  } + +  void printLeft(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    if (Idx < Data.size()) +      Data[Idx]->printLeft(S); +  } +  void printRight(OutputStream &S) const override { +    initializePackExpansion(S); +    size_t Idx = S.CurrentPackIndex; +    if (Idx < Data.size()) +      Data[Idx]->printRight(S); +  } +}; + +/// A variadic template argument. This node represents an occurrence of +/// J<something>E in some <template-args>. It isn't itself unexpanded, unless +/// one of it's Elements is. The parser inserts a ParameterPack into the +/// TemplateParams table if the <template-args> this pack belongs to apply to an +/// <encoding>. +class TemplateArgumentPack final : public Node { +  NodeArray Elements; +public: +  TemplateArgumentPack(NodeArray Elements_) +      : Node(KTemplateArgumentPack), Elements(Elements_) {} + +  template<typename Fn> void match(Fn F) const { F(Elements); } + +  NodeArray getElements() const { return Elements; } + +  void printLeft(OutputStream &S) const override { +    Elements.printWithComma(S); +  } +}; + +/// A pack expansion. Below this node, there are some unexpanded ParameterPacks +/// which each have Child->ParameterPackSize elements. +class ParameterPackExpansion final : public Node { +  const Node *Child; + +public: +  ParameterPackExpansion(const Node *Child_) +      : Node(KParameterPackExpansion), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Child); } + +  const Node *getChild() const { return Child; } + +  void printLeft(OutputStream &S) const override { +    constexpr unsigned Max = std::numeric_limits<unsigned>::max(); +    SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max); +    SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max); +    size_t StreamPos = S.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); + +    // No ParameterPack was found in Child. This can occur if we've found a pack +    // expansion on a <function-param>. +    if (S.CurrentPackMax == Max) { +      S += "..."; +      return; +    } + +    // We found a ParameterPack, but it has no elements. Erase whatever we may +    // of printed. +    if (S.CurrentPackMax == 0) { +      S.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); +    } +  } +}; + +class TemplateArgs final : public Node { +  NodeArray Params; + +public: +  TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} + +  template<typename Fn> void match(Fn F) const { F(Params); } + +  NodeArray getParams() { return Params; } + +  void printLeft(OutputStream &S) const override { +    S += "<"; +    Params.printWithComma(S); +    if (S.back() == '>') +      S += " "; +    S += ">"; +  } +}; + +/// A forward-reference to a template argument that was not known at the point +/// where the template parameter name was parsed in a mangling. +/// +/// This is created when demangling the name of a specialization of a +/// conversion function template: +/// +/// \code +/// struct A { +///   template<typename T> operator T*(); +/// }; +/// \endcode +/// +/// When demangling a specialization of the conversion function template, we +/// encounter the name of the template (including the \c T) before we reach +/// the template argument list, so we cannot substitute the parameter name +/// for the corresponding argument while parsing. Instead, we create a +/// \c ForwardTemplateReference node that is resolved after we parse the +/// template arguments. +struct ForwardTemplateReference : Node { +  size_t Index; +  Node *Ref = nullptr; + +  // If we're currently printing this node. It is possible (though invalid) for +  // a forward template reference to refer to itself via a substitution. This +  // creates a cyclic AST, which will stack overflow printing. To fix this, bail +  // out if more than one print* function is active. +  mutable bool Printing = false; + +  ForwardTemplateReference(size_t Index_) +      : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, +             Cache::Unknown), +        Index(Index_) {} + +  // We don't provide a matcher for these, because the value of the node is +  // not determined by its construction parameters, and it generally needs +  // special handling. +  template<typename Fn> void match(Fn F) const = delete; + +  bool hasRHSComponentSlow(OutputStream &S) const override { +    if (Printing) +      return false; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    return Ref->hasRHSComponent(S); +  } +  bool hasArraySlow(OutputStream &S) const override { +    if (Printing) +      return false; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    return Ref->hasArray(S); +  } +  bool hasFunctionSlow(OutputStream &S) const override { +    if (Printing) +      return false; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    return Ref->hasFunction(S); +  } +  const Node *getSyntaxNode(OutputStream &S) const override { +    if (Printing) +      return this; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    return Ref->getSyntaxNode(S); +  } + +  void printLeft(OutputStream &S) const override { +    if (Printing) +      return; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    Ref->printLeft(S); +  } +  void printRight(OutputStream &S) const override { +    if (Printing) +      return; +    SwapAndRestore<bool> SavePrinting(Printing, true); +    Ref->printRight(S); +  } +}; + +struct NameWithTemplateArgs : Node { +  // name<template_args> +  Node *Name; +  Node *TemplateArgs; + +  NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) +      : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} + +  template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); } + +  StringView getBaseName() const override { return Name->getBaseName(); } + +  void printLeft(OutputStream &S) const override { +    Name->print(S); +    TemplateArgs->print(S); +  } +}; + +class GlobalQualifiedName final : public Node { +  Node *Child; + +public: +  GlobalQualifiedName(Node* Child_) +      : Node(KGlobalQualifiedName), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Child); } + +  StringView getBaseName() const override { return Child->getBaseName(); } + +  void printLeft(OutputStream &S) const override { +    S += "::"; +    Child->print(S); +  } +}; + +struct StdQualifiedName : Node { +  Node *Child; + +  StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} + +  template<typename Fn> 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); +  } +}; + +enum class SpecialSubKind { +  allocator, +  basic_string, +  string, +  istream, +  ostream, +  iostream, +}; + +class ExpandedSpecialSubstitution final : public Node { +  SpecialSubKind SSK; + +public: +  ExpandedSpecialSubstitution(SpecialSubKind SSK_) +      : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + +  template<typename Fn> 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("basic_string"); +    case SpecialSubKind::istream: +      return StringView("basic_istream"); +    case SpecialSubKind::ostream: +      return StringView("basic_ostream"); +    case SpecialSubKind::iostream: +      return StringView("basic_iostream"); +    } +    DEMANGLE_UNREACHABLE; +  } + +  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<char, std::char_traits<char>, " +           "std::allocator<char> >"; +      break; +    case SpecialSubKind::istream: +      S += "std::basic_istream<char, std::char_traits<char> >"; +      break; +    case SpecialSubKind::ostream: +      S += "std::basic_ostream<char, std::char_traits<char> >"; +      break; +    case SpecialSubKind::iostream: +      S += "std::basic_iostream<char, std::char_traits<char> >"; +      break; +    } +  } +}; + +class SpecialSubstitution final : public Node { +public: +  SpecialSubKind SSK; + +  SpecialSubstitution(SpecialSubKind SSK_) +      : Node(KSpecialSubstitution), SSK(SSK_) {} + +  template<typename Fn> 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"); +    } +    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::string"; +      break; +    case SpecialSubKind::istream: +      S += "std::istream"; +      break; +    case SpecialSubKind::ostream: +      S += "std::ostream"; +      break; +    case SpecialSubKind::iostream: +      S += "std::iostream"; +      break; +    } +  } +}; + +class CtorDtorName final : public Node { +  const Node *Basename; +  const bool IsDtor; +  const int Variant; + +public: +  CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) +      : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), +        Variant(Variant_) {} + +  template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } + +  void printLeft(OutputStream &S) const override { +    if (IsDtor) +      S += "~"; +    S += Basename->getBaseName(); +  } +}; + +class DtorName : public Node { +  const Node *Base; + +public: +  DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} + +  template<typename Fn> void match(Fn F) const { F(Base); } + +  void printLeft(OutputStream &S) const override { +    S += "~"; +    Base->printLeft(S); +  } +}; + +class UnnamedTypeName : public Node { +  const StringView Count; + +public: +  UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + +  template<typename Fn> void match(Fn F) const { F(Count); } + +  void printLeft(OutputStream &S) const override { +    S += "'unnamed"; +    S += Count; +    S += "\'"; +  } +}; + +class ClosureTypeName : public Node { +  NodeArray TemplateParams; +  NodeArray Params; +  StringView Count; + +public: +  ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, +                  StringView Count_) +      : Node(KClosureTypeName), TemplateParams(TemplateParams_), +        Params(Params_), Count(Count_) {} + +  template<typename Fn> void match(Fn F) const { +    F(TemplateParams, Params, Count); +  } + +  void printDeclarator(OutputStream &S) const { +    if (!TemplateParams.empty()) { +      S += "<"; +      TemplateParams.printWithComma(S); +      S += ">"; +    } +    S += "("; +    Params.printWithComma(S); +    S += ")"; +  } + +  void printLeft(OutputStream &S) const override { +    S += "\'lambda"; +    S += Count; +    S += "\'"; +    printDeclarator(S); +  } +}; + +class StructuredBindingName : public Node { +  NodeArray Bindings; +public: +  StructuredBindingName(NodeArray Bindings_) +      : Node(KStructuredBindingName), Bindings(Bindings_) {} + +  template<typename Fn> void match(Fn F) const { F(Bindings); } + +  void printLeft(OutputStream &S) const override { +    S += '['; +    Bindings.printWithComma(S); +    S += ']'; +  } +}; + +// -- Expression Nodes -- + +class BinaryExpr : public Node { +  const Node *LHS; +  const StringView InfixOperator; +  const Node *RHS; + +public: +  BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) +      : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { +  } + +  template<typename Fn> 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 += ")"; +  } +}; + +class ArraySubscriptExpr : public Node { +  const Node *Op1; +  const Node *Op2; + +public: +  ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) +      : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + +  template<typename Fn> void match(Fn F) const { F(Op1, Op2); } + +  void printLeft(OutputStream &S) const override { +    S += "("; +    Op1->print(S); +    S += ")["; +    Op2->print(S); +    S += "]"; +  } +}; + +class PostfixExpr : public Node { +  const Node *Child; +  const StringView Operator; + +public: +  PostfixExpr(const Node *Child_, StringView Operator_) +      : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + +  template<typename Fn> void match(Fn F) const { F(Child, Operator); } + +  void printLeft(OutputStream &S) const override { +    S += "("; +    Child->print(S); +    S += ")"; +    S += Operator; +  } +}; + +class ConditionalExpr : public Node { +  const Node *Cond; +  const Node *Then; +  const Node *Else; + +public: +  ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) +      : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + +  template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); } + +  void printLeft(OutputStream &S) const override { +    S += "("; +    Cond->print(S); +    S += ") ? ("; +    Then->print(S); +    S += ") : ("; +    Else->print(S); +    S += ")"; +  } +}; + +class MemberExpr : public Node { +  const Node *LHS; +  const StringView Kind; +  const Node *RHS; + +public: +  MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) +      : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + +  template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); } + +  void printLeft(OutputStream &S) const override { +    LHS->print(S); +    S += Kind; +    RHS->print(S); +  } +}; + +class EnclosingExpr : public Node { +  const StringView Prefix; +  const Node *Infix; +  const StringView Postfix; + +public: +  EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) +      : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), +        Postfix(Postfix_) {} + +  template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); } + +  void printLeft(OutputStream &S) const override { +    S += Prefix; +    Infix->print(S); +    S += Postfix; +  } +}; + +class CastExpr : public Node { +  // cast_kind<to>(from) +  const StringView CastKind; +  const Node *To; +  const Node *From; + +public: +  CastExpr(StringView CastKind_, const Node *To_, const Node *From_) +      : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} + +  template<typename Fn> void match(Fn F) const { F(CastKind, To, From); } + +  void printLeft(OutputStream &S) const override { +    S += CastKind; +    S += "<"; +    To->printLeft(S); +    S += ">("; +    From->printLeft(S); +    S += ")"; +  } +}; + +class SizeofParamPackExpr : public Node { +  const Node *Pack; + +public: +  SizeofParamPackExpr(const Node *Pack_) +      : Node(KSizeofParamPackExpr), Pack(Pack_) {} + +  template<typename Fn> void match(Fn F) const { F(Pack); } + +  void printLeft(OutputStream &S) const override { +    S += "sizeof...("; +    ParameterPackExpansion PPE(Pack); +    PPE.printLeft(S); +    S += ")"; +  } +}; + +class CallExpr : public Node { +  const Node *Callee; +  NodeArray Args; + +public: +  CallExpr(const Node *Callee_, NodeArray Args_) +      : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + +  template<typename Fn> void match(Fn F) const { F(Callee, Args); } + +  void printLeft(OutputStream &S) const override { +    Callee->print(S); +    S += "("; +    Args.printWithComma(S); +    S += ")"; +  } +}; + +class NewExpr : public Node { +  // new (expr_list) type(init_list) +  NodeArray ExprList; +  Node *Type; +  NodeArray InitList; +  bool IsGlobal; // ::operator new ? +  bool IsArray;  // new[] ? +public: +  NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, +          bool IsArray_) +      : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), +        IsGlobal(IsGlobal_), IsArray(IsArray_) {} + +  template<typename Fn> void match(Fn F) const { +    F(ExprList, Type, InitList, IsGlobal, IsArray); +  } + +  void printLeft(OutputStream &S) const override { +    if (IsGlobal) +      S += "::operator "; +    S += "new"; +    if (IsArray) +      S += "[]"; +    S += ' '; +    if (!ExprList.empty()) { +      S += "("; +      ExprList.printWithComma(S); +      S += ")"; +    } +    Type->print(S); +    if (!InitList.empty()) { +      S += "("; +      InitList.printWithComma(S); +      S += ")"; +    } + +  } +}; + +class DeleteExpr : public Node { +  Node *Op; +  bool IsGlobal; +  bool IsArray; + +public: +  DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) +      : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + +  template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); } + +  void printLeft(OutputStream &S) const override { +    if (IsGlobal) +      S += "::"; +    S += "delete"; +    if (IsArray) +      S += "[] "; +    Op->print(S); +  } +}; + +class PrefixExpr : public Node { +  StringView Prefix; +  Node *Child; + +public: +  PrefixExpr(StringView Prefix_, Node *Child_) +      : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + +  template<typename Fn> void match(Fn F) const { F(Prefix, Child); } + +  void printLeft(OutputStream &S) const override { +    S += Prefix; +    S += "("; +    Child->print(S); +    S += ")"; +  } +}; + +class FunctionParam : public Node { +  StringView Number; + +public: +  FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} + +  template<typename Fn> void match(Fn F) const { F(Number); } + +  void printLeft(OutputStream &S) const override { +    S += "fp"; +    S += Number; +  } +}; + +class ConversionExpr : public Node { +  const Node *Type; +  NodeArray Expressions; + +public: +  ConversionExpr(const Node *Type_, NodeArray Expressions_) +      : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + +  template<typename Fn> void match(Fn F) const { F(Type, Expressions); } + +  void printLeft(OutputStream &S) const override { +    S += "("; +    Type->print(S); +    S += ")("; +    Expressions.printWithComma(S); +    S += ")"; +  } +}; + +class InitListExpr : public Node { +  const Node *Ty; +  NodeArray Inits; +public: +  InitListExpr(const Node *Ty_, NodeArray Inits_) +      : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty, Inits); } + +  void printLeft(OutputStream &S) const override { +    if (Ty) +      Ty->print(S); +    S += '{'; +    Inits.printWithComma(S); +    S += '}'; +  } +}; + +class BracedExpr : public Node { +  const Node *Elem; +  const Node *Init; +  bool IsArray; +public: +  BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) +      : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} + +  template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } + +  void printLeft(OutputStream &S) const override { +    if (IsArray) { +      S += '['; +      Elem->print(S); +      S += ']'; +    } else { +      S += '.'; +      Elem->print(S); +    } +    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) +      S += " = "; +    Init->print(S); +  } +}; + +class BracedRangeExpr : public Node { +  const Node *First; +  const Node *Last; +  const Node *Init; +public: +  BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) +      : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} + +  template<typename Fn> void match(Fn F) const { F(First, Last, Init); } + +  void printLeft(OutputStream &S) const override { +    S += '['; +    First->print(S); +    S += " ... "; +    Last->print(S); +    S += ']'; +    if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) +      S += " = "; +    Init->print(S); +  } +}; + +class FoldExpr : public Node { +  const Node *Pack, *Init; +  StringView OperatorName; +  bool IsLeftFold; + +public: +  FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, +           const Node *Init_) +      : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), +        IsLeftFold(IsLeftFold_) {} + +  template<typename Fn> void match(Fn F) const { +    F(IsLeftFold, OperatorName, Pack, Init); +  } + +  void printLeft(OutputStream &S) const override { +    auto PrintPack = [&] { +      S += '('; +      ParameterPackExpansion(Pack).print(S); +      S += ')'; +    }; + +    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); +      } +    } +    S += ')'; +  } +}; + +class ThrowExpr : public Node { +  const Node *Op; + +public: +  ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} + +  template<typename Fn> void match(Fn F) const { F(Op); } + +  void printLeft(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<typename Fn> void match(Fn F) const { F(Operand); } + +  void printLeft(OutputStream &S) const override { +    S << "__uuidof("; +    Operand->print(S); +    S << ")"; +  } +}; + +class BoolExpr : public Node { +  bool Value; + +public: +  BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} + +  template<typename Fn> void match(Fn F) const { F(Value); } + +  void printLeft(OutputStream &S) const override { +    S += Value ? StringView("true") : StringView("false"); +  } +}; + +class StringLiteral : public Node { +  const Node *Type; + +public: +  StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {} + +  template<typename Fn> void match(Fn F) const { F(Type); } + +  void printLeft(OutputStream &S) const override { +    S += "\"<"; +    Type->print(S); +    S += ">\""; +  } +}; + +class LambdaExpr : public Node { +  const Node *Type; + +public: +  LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {} + +  template<typename Fn> void match(Fn F) const { F(Type); } + +  void printLeft(OutputStream &S) const override { +    S += "[]"; +    if (Type->getKind() == KClosureTypeName) +      static_cast<const ClosureTypeName *>(Type)->printDeclarator(S); +    S += "{...}"; +  } +}; + +class IntegerCastExpr : public Node { +  // ty(integer) +  const Node *Ty; +  StringView Integer; + +public: +  IntegerCastExpr(const Node *Ty_, StringView Integer_) +      : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} + +  template<typename Fn> void match(Fn F) const { F(Ty, Integer); } + +  void printLeft(OutputStream &S) const override { +    S += "("; +    Ty->print(S); +    S += ")"; +    S += Integer; +  } +}; + +class IntegerLiteral : public Node { +  StringView Type; +  StringView Value; + +public: +  IntegerLiteral(StringView Type_, StringView Value_) +      : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} + +  template<typename Fn> void match(Fn F) const { F(Type, Value); } + +  void printLeft(OutputStream &S) const override { +    if (Type.size() > 3) { +      S += "("; +      S += Type; +      S += ")"; +    } + +    if (Value[0] == 'n') { +      S += "-"; +      S += Value.dropFront(1); +    } else +      S += Value; + +    if (Type.size() <= 3) +      S += Type; +  } +}; + +template <class Float> struct FloatData; + +namespace float_literal_impl { +constexpr Node::Kind getFloatLiteralKind(float *) { +  return Node::KFloatLiteral; +} +constexpr Node::Kind getFloatLiteralKind(double *) { +  return Node::KDoubleLiteral; +} +constexpr Node::Kind getFloatLiteralKind(long double *) { +  return Node::KLongDoubleLiteral; +} +} + +template <class Float> class FloatLiteralImpl : public Node { +  const StringView Contents; + +  static constexpr Kind KindForClass = +      float_literal_impl::getFloatLiteralKind((Float *)nullptr); + +public: +  FloatLiteralImpl(StringView Contents_) +      : Node(KindForClass), Contents(Contents_) {} + +  template<typename Fn> void match(Fn F) const { F(Contents); } + +  void printLeft(OutputStream &s) const override { +    const char *first = Contents.begin(); +    const char *last = Contents.end() + 1; + +    const size_t N = FloatData<Float>::mangled_size; +    if (static_cast<std::size_t>(last - first) > N) { +      last = first + N; +      union { +        Float value; +        char buf[sizeof(Float)]; +      }; +      const char *t = first; +      char *e = buf; +      for (; t != last; ++t, ++e) { +        unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') +                                  : static_cast<unsigned>(*t - 'a' + 10); +        ++t; +        unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') +                                  : static_cast<unsigned>(*t - 'a' + 10); +        *e = static_cast<char>((d1 << 4) + d0); +      } +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +      std::reverse(buf, e); +#endif +      char num[FloatData<Float>::max_demangled_size] = {0}; +      int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); +      s += StringView(num, num + n); +    } +  } +}; + +using FloatLiteral = FloatLiteralImpl<float>; +using DoubleLiteral = FloatLiteralImpl<double>; +using LongDoubleLiteral = FloatLiteralImpl<long double>; + +/// Visit the node. Calls \c F(P), where \c P is the node cast to the +/// appropriate derived class. +template<typename Fn> +void Node::visit(Fn F) const { +  switch (K) { +#define CASE(X) case K ## X: return F(static_cast<const X*>(this)); +    FOR_EACH_NODE_KIND(CASE) +#undef CASE +  } +  assert(0 && "unknown mangling node kind"); +} + +/// Determine the kind of a node from its type. +template<typename NodeT> struct NodeKind; +#define SPECIALIZATION(X) \ +  template<> struct NodeKind<X> { \ +    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 T, size_t N> +class PODSmallVector { +  static_assert(std::is_pod<T>::value, +                "T is required to be a plain old data type"); + +  T* First; +  T* Last; +  T* Cap; +  T Inline[N]; + +  bool isInline() const { return First == Inline; } + +  void clearInline() { +    First = Inline; +    Last = Inline; +    Cap = Inline + N; +  } + +  void reserve(size_t NewCap) { +    size_t S = size(); +    if (isInline()) { +      auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T))); +      if (Tmp == nullptr) +        std::terminate(); +      std::copy(First, Last, Tmp); +      First = Tmp; +    } else { +      First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); +      if (First == nullptr) +        std::terminate(); +    } +    Last = First + S; +    Cap = First + NewCap; +  } + +public: +  PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + +  PODSmallVector(const PODSmallVector&) = delete; +  PODSmallVector& operator=(const PODSmallVector&) = delete; + +  PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { +    if (Other.isInline()) { +      std::copy(Other.begin(), Other.end(), First); +      Last = First + Other.size(); +      Other.clear(); +      return; +    } + +    First = Other.First; +    Last = Other.Last; +    Cap = Other.Cap; +    Other.clearInline(); +  } + +  PODSmallVector& operator=(PODSmallVector&& Other) { +    if (Other.isInline()) { +      if (!isInline()) { +        std::free(First); +        clearInline(); +      } +      std::copy(Other.begin(), Other.end(), First); +      Last = First + Other.size(); +      Other.clear(); +      return *this; +    } + +    if (isInline()) { +      First = Other.First; +      Last = Other.Last; +      Cap = Other.Cap; +      Other.clearInline(); +      return *this; +    } + +    std::swap(First, Other.First); +    std::swap(Last, Other.Last); +    std::swap(Cap, Other.Cap); +    Other.clear(); +    return *this; +  } + +  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<size_t>(Last - First); } +  T& back() { +    assert(Last != First && "Calling back() on empty vector!"); +    return *(Last - 1); +  } +  T& operator[](size_t Index) { +    assert(Index < size() && "Invalid access!"); +    return *(begin() + Index); +  } +  void clear() { Last = First; } + +  ~PODSmallVector() { +    if (!isInline()) +      std::free(First); +  } +}; + +template <typename Derived, typename Alloc> struct AbstractManglingParser { +  const char *First; +  const char *Last; + +  // Name stack, this is used by the parser to hold temporary names that were +  // parsed. The parser collapses multiple names into new nodes to construct +  // the AST. Once the parser is finished, names.size() == 1. +  PODSmallVector<Node *, 32> Names; + +  // Substitution table. Itanium supports name substitutions as a means of +  // compression. The string "S42_" refers to the 44nd entry (base-36) in this +  // table. +  PODSmallVector<Node *, 32> Subs; + +  using TemplateParamList = PODSmallVector<Node *, 8>; + +  class ScopedTemplateParamList { +    AbstractManglingParser *Parser; +    size_t OldNumTemplateParamLists; +    TemplateParamList Params; + +  public: +    ScopedTemplateParamList(AbstractManglingParser *Parser) +        : Parser(Parser), +          OldNumTemplateParamLists(Parser->TemplateParams.size()) { +      Parser->TemplateParams.push_back(&Params); +    } +    ~ScopedTemplateParamList() { +      assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists); +      Parser->TemplateParams.dropBack(OldNumTemplateParamLists); +    } +  }; + +  // Template parameter table. Like the above, but referenced like "T42_". +  // This has a smaller size compared to Subs and Names because it can be +  // stored on the stack. +  TemplateParamList OuterTemplateParams; + +  // Lists of template parameters indexed by template parameter depth, +  // referenced like "TL2_4_". If nonempty, element 0 is always +  // OuterTemplateParams; inner elements are always template parameter lists of +  // lambda expressions. For a generic lambda with no explicit template +  // parameter list, the corresponding parameter list pointer will be null. +  PODSmallVector<TemplateParamList *, 4> TemplateParams; + +  // Set of unresolved forward <template-param> references. These can occur in a +  // conversion operator's type, and are resolved in the enclosing <encoding>. +  PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; + +  bool TryToParseTemplateArgs = true; +  bool PermitForwardTemplateReferences = false; +  size_t ParsingLambdaParamsAtLevel = (size_t)-1; + +  unsigned NumSyntheticTemplateParameters[3] = {}; + +  Alloc ASTAllocator; + +  AbstractManglingParser(const char *First_, const char *Last_) +      : First(First_), Last(Last_) {} + +  Derived &getDerived() { return static_cast<Derived &>(*this); } + +  void reset(const char *First_, const char *Last_) { +    First = First_; +    Last = Last_; +    Names.clear(); +    Subs.clear(); +    TemplateParams.clear(); +    ParsingLambdaParamsAtLevel = (size_t)-1; +    TryToParseTemplateArgs = true; +    PermitForwardTemplateReferences = false; +    for (int I = 0; I != 3; ++I) +      NumSyntheticTemplateParameters[I] = 0; +    ASTAllocator.reset(); +  } + +  template <class T, class... Args> Node *make(Args &&... args) { +    return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...); +  } + +  template <class It> NodeArray makeNodeArray(It begin, It end) { +    size_t sz = static_cast<size_t>(end - begin); +    void *mem = ASTAllocator.allocateNodeArray(sz); +    Node **data = new (mem) Node *[sz]; +    std::copy(begin, end, data); +    return NodeArray(data, sz); +  } + +  NodeArray popTrailingNodeArray(size_t FromPosition) { +    assert(FromPosition <= Names.size()); +    NodeArray res = +        makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); +    Names.dropBack(FromPosition); +    return res; +  } + +  bool consumeIf(StringView S) { +    if (StringView(First, Last).startsWith(S)) { +      First += S.size(); +      return true; +    } +    return false; +  } + +  bool consumeIf(char C) { +    if (First != Last && *First == C) { +      ++First; +      return true; +    } +    return false; +  } + +  char consume() { return First != Last ? *First++ : '\0'; } + +  char look(unsigned Lookahead = 0) { +    if (static_cast<size_t>(Last - First) <= Lookahead) +      return '\0'; +    return First[Lookahead]; +  } + +  size_t numLeft() const { return static_cast<size_t>(Last - First); } + +  StringView parseNumber(bool AllowNegative = false); +  Qualifiers parseCVQualifiers(); +  bool parsePositiveInteger(size_t *Out); +  StringView parseBareSourceName(); + +  bool parseSeqId(size_t *Out); +  Node *parseSubstitution(); +  Node *parseTemplateParam(); +  Node *parseTemplateParamDecl(); +  Node *parseTemplateArgs(bool TagTemplates = false); +  Node *parseTemplateArg(); + +  /// Parse the <expr> production. +  Node *parseExpr(); +  Node *parsePrefixExpr(StringView Kind); +  Node *parseBinaryExpr(StringView Kind); +  Node *parseIntegerLiteral(StringView Lit); +  Node *parseExprPrimary(); +  template <class Float> Node *parseFloatingLiteral(); +  Node *parseFunctionParam(); +  Node *parseNewExpr(); +  Node *parseConversionExpr(); +  Node *parseBracedExpr(); +  Node *parseFoldExpr(); + +  /// Parse the <type> production. +  Node *parseType(); +  Node *parseFunctionType(); +  Node *parseVectorType(); +  Node *parseDecltype(); +  Node *parseArrayType(); +  Node *parsePointerToMemberType(); +  Node *parseClassEnumType(); +  Node *parseQualifiedType(); + +  Node *parseEncoding(); +  bool parseCallOffset(); +  Node *parseSpecialName(); + +  /// Holds some extra information about a <name> that is being parsed. This +  /// information is only pertinent if the <name> refers to an <encoding>. +  struct NameState { +    bool CtorDtorConversion = false; +    bool EndsWithTemplateArgs = false; +    Qualifiers CVQualifiers = QualNone; +    FunctionRefQual ReferenceQualifier = FrefQualNone; +    size_t ForwardTemplateRefsBegin; + +    NameState(AbstractManglingParser *Enclosing) +        : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} +  }; + +  bool resolveForwardTemplateRefs(NameState &State) { +    size_t I = State.ForwardTemplateRefsBegin; +    size_t E = ForwardTemplateRefs.size(); +    for (; I < E; ++I) { +      size_t Idx = ForwardTemplateRefs[I]->Index; +      if (TemplateParams.empty() || !TemplateParams[0] || +          Idx >= TemplateParams[0]->size()) +        return true; +      ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx]; +    } +    ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); +    return false; +  } + +  /// Parse the <name> production> +  Node *parseName(NameState *State = nullptr); +  Node *parseLocalName(NameState *State); +  Node *parseOperatorName(NameState *State); +  Node *parseUnqualifiedName(NameState *State); +  Node *parseUnnamedTypeName(NameState *State); +  Node *parseSourceName(NameState *State); +  Node *parseUnscopedName(NameState *State); +  Node *parseNestedName(NameState *State); +  Node *parseCtorDtorName(Node *&SoFar, NameState *State); + +  Node *parseAbiTags(Node *N); + +  /// Parse the <unresolved-name> production. +  Node *parseUnresolvedName(); +  Node *parseSimpleId(); +  Node *parseBaseUnresolvedName(); +  Node *parseUnresolvedType(); +  Node *parseDestructorName(); + +  /// Top-level entry point into the parser. +  Node *parse(); +}; + +const char* parse_discriminator(const char* first, const char* last); + +// <name> ::= <nested-name> // N +//        ::= <local-name> # See Scope Encoding below  // Z +//        ::= <unscoped-template-name> <template-args> +//        ::= <unscoped-name> +// +// <unscoped-template-name> ::= <unscoped-name> +//                          ::= <substitution> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { +  consumeIf('L'); // extension + +  if (look() == 'N') +    return getDerived().parseNestedName(State); +  if (look() == 'Z') +    return getDerived().parseLocalName(State); + +  //        ::= <unscoped-template-name> <template-args> +  if (look() == 'S' && look(1) != 't') { +    Node *S = getDerived().parseSubstitution(); +    if (S == nullptr) +      return nullptr; +    if (look() != 'I') +      return nullptr; +    Node *TA = getDerived().parseTemplateArgs(State != nullptr); +    if (TA == nullptr) +      return nullptr; +    if (State) State->EndsWithTemplateArgs = true; +    return make<NameWithTemplateArgs>(S, TA); +  } + +  Node *N = getDerived().parseUnscopedName(State); +  if (N == nullptr) +    return nullptr; +  //        ::= <unscoped-template-name> <template-args> +  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<NameWithTemplateArgs>(N, TA); +  } +  //        ::= <unscoped-name> +  return N; +} + +// <local-name> := Z <function encoding> E <entity name> [<discriminator>] +//              := Z <function encoding> E s [<discriminator>] +//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) { +  if (!consumeIf('Z')) +    return nullptr; +  Node *Encoding = getDerived().parseEncoding(); +  if (Encoding == nullptr || !consumeIf('E')) +    return nullptr; + +  if (consumeIf('s')) { +    First = parse_discriminator(First, Last); +    auto *StringLitName = make<NameType>("string literal"); +    if (!StringLitName) +      return nullptr; +    return make<LocalName>(Encoding, StringLitName); +  } + +  if (consumeIf('d')) { +    parseNumber(true); +    if (!consumeIf('_')) +      return nullptr; +    Node *N = getDerived().parseName(State); +    if (N == nullptr) +      return nullptr; +    return make<LocalName>(Encoding, N); +  } + +  Node *Entity = getDerived().parseName(State); +  if (Entity == nullptr) +    return nullptr; +  First = parse_discriminator(First, Last); +  return make<LocalName>(Encoding, Entity); +} + +// <unscoped-name> ::= <unqualified-name> +//                 ::= St <unqualified-name>   # ::std:: +// extension       ::= StL<unqualified-name> +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) { +  if (consumeIf("StL") || consumeIf("St")) { +    Node *R = getDerived().parseUnqualifiedName(State); +    if (R == nullptr) +      return nullptr; +    return make<StdQualifiedName>(R); +  } +  return getDerived().parseUnqualifiedName(State); +} + +// <unqualified-name> ::= <operator-name> [abi-tags] +//                    ::= <ctor-dtor-name> +//                    ::= <source-name> +//                    ::= <unnamed-type-name> +//                    ::= DC <source-name>+ E      # structured binding declaration +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { +  // <ctor-dtor-name>s are special-cased in parseNestedName(). +  Node *Result; +  if (look() == 'U') +    Result = getDerived().parseUnnamedTypeName(State); +  else if (look() >= '1' && look() <= '9') +    Result = getDerived().parseSourceName(State); +  else if (consumeIf("DC")) { +    size_t BindingsBegin = Names.size(); +    do { +      Node *Binding = getDerived().parseSourceName(State); +      if (Binding == nullptr) +        return nullptr; +      Names.push_back(Binding); +    } while (!consumeIf('E')); +    Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); +  } else +    Result = getDerived().parseOperatorName(State); +  if (Result != nullptr) +    Result = getDerived().parseAbiTags(Result); +  return Result; +} + +// <unnamed-type-name> ::= Ut [<nonnegative number>] _ +//                     ::= <closure-type-name> +// +// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ +// +// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { +  // <template-params> refer to the innermost <template-args>. Clear out any +  // outer args that we may have inserted into TemplateParams. +  if (State != nullptr) +    TemplateParams.clear(); + +  if (consumeIf("Ut")) { +    StringView Count = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    return make<UnnamedTypeName>(Count); +  } +  if (consumeIf("Ul")) { +    SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel, +                                      TemplateParams.size()); +    ScopedTemplateParamList LambdaTemplateParams(this); + +    size_t ParamsBegin = Names.size(); +    while (look() == 'T' && +           StringView("yptn").find(look(1)) != StringView::npos) { +      Node *T = parseTemplateParamDecl(); +      if (!T) +        return nullptr; +      Names.push_back(T); +    } +    NodeArray TempParams = popTrailingNodeArray(ParamsBegin); + +    // FIXME: If TempParams is empty and none of the function parameters +    // includes 'auto', we should remove LambdaTemplateParams from the +    // TemplateParams list. Unfortunately, we don't find out whether there are +    // any 'auto' parameters until too late in an example such as: +    // +    //   template<typename T> void f( +    //       decltype([](decltype([]<typename T>(T v) {}), +    //                   auto) {})) {} +    //   template<typename T> void f( +    //       decltype([](decltype([]<typename T>(T w) {}), +    //                   int) {})) {} +    // +    // Here, the type of v is at level 2 but the type of w is at level 1. We +    // don't find this out until we encounter the type of the next parameter. +    // +    // However, compilers can't actually cope with the former example in +    // practice, and it's likely to be made ill-formed in future, so we don't +    // need to support it here. +    // +    // If we encounter an 'auto' in the function parameter types, we will +    // recreate a template parameter scope for it, but any intervening lambdas +    // will be parsed in the 'wrong' template parameter depth. +    if (TempParams.empty()) +      TemplateParams.pop_back(); + +    if (!consumeIf("vE")) { +      do { +        Node *P = getDerived().parseType(); +        if (P == nullptr) +          return nullptr; +        Names.push_back(P); +      } while (!consumeIf('E')); +    } +    NodeArray Params = popTrailingNodeArray(ParamsBegin); + +    StringView Count = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    return make<ClosureTypeName>(TempParams, Params, Count); +  } +  if (consumeIf("Ub")) { +    (void)parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    return make<NameType>("'block-literal'"); +  } +  return nullptr; +} + +// <source-name> ::= <positive length number> <identifier> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) { +  size_t Length = 0; +  if (parsePositiveInteger(&Length)) +    return nullptr; +  if (numLeft() < Length || Length == 0) +    return nullptr; +  StringView Name(First, First + Length); +  First += Length; +  if (Name.startsWith("_GLOBAL__N")) +    return make<NameType>("(anonymous namespace)"); +  return make<NameType>(Name); +} + +//   <operator-name> ::= aa    # && +//                   ::= ad    # & (unary) +//                   ::= an    # & +//                   ::= aN    # &= +//                   ::= aS    # = +//                   ::= cl    # () +//                   ::= cm    # , +//                   ::= co    # ~ +//                   ::= cv <type>    # (cast) +//                   ::= da    # delete[] +//                   ::= de    # * (unary) +//                   ::= dl    # delete +//                   ::= dv    # / +//                   ::= dV    # /= +//                   ::= eo    # ^ +//                   ::= eO    # ^= +//                   ::= eq    # == +//                   ::= ge    # >= +//                   ::= gt    # > +//                   ::= ix    # [] +//                   ::= le    # <= +//                   ::= li <source-name>  # operator "" +//                   ::= ls    # << +//                   ::= lS    # <<= +//                   ::= lt    # < +//                   ::= mi    # - +//                   ::= mI    # -= +//                   ::= ml    # * +//                   ::= mL    # *= +//                   ::= mm    # -- (postfix in <expression> context) +//                   ::= na    # new[] +//                   ::= ne    # != +//                   ::= ng    # - (unary) +//                   ::= nt    # ! +//                   ::= nw    # new +//                   ::= oo    # || +//                   ::= or    # | +//                   ::= oR    # |= +//                   ::= pm    # ->* +//                   ::= pl    # + +//                   ::= pL    # += +//                   ::= pp    # ++ (postfix in <expression> context) +//                   ::= ps    # + (unary) +//                   ::= pt    # -> +//                   ::= qu    # ? +//                   ::= rm    # % +//                   ::= rM    # %= +//                   ::= rs    # >> +//                   ::= rS    # >>= +//                   ::= ss    # <=> C++2a +//                   ::= v <digit> <source-name>        # vendor extended operator +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { +  switch (look()) { +  case 'a': +    switch (look(1)) { +    case 'a': +      First += 2; +      return make<NameType>("operator&&"); +    case 'd': +    case 'n': +      First += 2; +      return make<NameType>("operator&"); +    case 'N': +      First += 2; +      return make<NameType>("operator&="); +    case 'S': +      First += 2; +      return make<NameType>("operator="); +    } +    return nullptr; +  case 'c': +    switch (look(1)) { +    case 'l': +      First += 2; +      return make<NameType>("operator()"); +    case 'm': +      First += 2; +      return make<NameType>("operator,"); +    case 'o': +      First += 2; +      return make<NameType>("operator~"); +    //                   ::= cv <type>    # (cast) +    case 'v': { +      First += 2; +      SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); +      // If we're parsing an encoding, State != nullptr and the conversion +      // operators' <type> could have a <template-param> that refers to some +      // <template-arg>s further ahead in the mangled name. +      SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, +                                      PermitForwardTemplateReferences || +                                          State != nullptr); +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      if (State) State->CtorDtorConversion = true; +      return make<ConversionOperatorType>(Ty); +    } +    } +    return nullptr; +  case 'd': +    switch (look(1)) { +    case 'a': +      First += 2; +      return make<NameType>("operator delete[]"); +    case 'e': +      First += 2; +      return make<NameType>("operator*"); +    case 'l': +      First += 2; +      return make<NameType>("operator delete"); +    case 'v': +      First += 2; +      return make<NameType>("operator/"); +    case 'V': +      First += 2; +      return make<NameType>("operator/="); +    } +    return nullptr; +  case 'e': +    switch (look(1)) { +    case 'o': +      First += 2; +      return make<NameType>("operator^"); +    case 'O': +      First += 2; +      return make<NameType>("operator^="); +    case 'q': +      First += 2; +      return make<NameType>("operator=="); +    } +    return nullptr; +  case 'g': +    switch (look(1)) { +    case 'e': +      First += 2; +      return make<NameType>("operator>="); +    case 't': +      First += 2; +      return make<NameType>("operator>"); +    } +    return nullptr; +  case 'i': +    if (look(1) == 'x') { +      First += 2; +      return make<NameType>("operator[]"); +    } +    return nullptr; +  case 'l': +    switch (look(1)) { +    case 'e': +      First += 2; +      return make<NameType>("operator<="); +    //                   ::= li <source-name>  # operator "" +    case 'i': { +      First += 2; +      Node *SN = getDerived().parseSourceName(State); +      if (SN == nullptr) +        return nullptr; +      return make<LiteralOperator>(SN); +    } +    case 's': +      First += 2; +      return make<NameType>("operator<<"); +    case 'S': +      First += 2; +      return make<NameType>("operator<<="); +    case 't': +      First += 2; +      return make<NameType>("operator<"); +    } +    return nullptr; +  case 'm': +    switch (look(1)) { +    case 'i': +      First += 2; +      return make<NameType>("operator-"); +    case 'I': +      First += 2; +      return make<NameType>("operator-="); +    case 'l': +      First += 2; +      return make<NameType>("operator*"); +    case 'L': +      First += 2; +      return make<NameType>("operator*="); +    case 'm': +      First += 2; +      return make<NameType>("operator--"); +    } +    return nullptr; +  case 'n': +    switch (look(1)) { +    case 'a': +      First += 2; +      return make<NameType>("operator new[]"); +    case 'e': +      First += 2; +      return make<NameType>("operator!="); +    case 'g': +      First += 2; +      return make<NameType>("operator-"); +    case 't': +      First += 2; +      return make<NameType>("operator!"); +    case 'w': +      First += 2; +      return make<NameType>("operator new"); +    } +    return nullptr; +  case 'o': +    switch (look(1)) { +    case 'o': +      First += 2; +      return make<NameType>("operator||"); +    case 'r': +      First += 2; +      return make<NameType>("operator|"); +    case 'R': +      First += 2; +      return make<NameType>("operator|="); +    } +    return nullptr; +  case 'p': +    switch (look(1)) { +    case 'm': +      First += 2; +      return make<NameType>("operator->*"); +    case 'l': +      First += 2; +      return make<NameType>("operator+"); +    case 'L': +      First += 2; +      return make<NameType>("operator+="); +    case 'p': +      First += 2; +      return make<NameType>("operator++"); +    case 's': +      First += 2; +      return make<NameType>("operator+"); +    case 't': +      First += 2; +      return make<NameType>("operator->"); +    } +    return nullptr; +  case 'q': +    if (look(1) == 'u') { +      First += 2; +      return make<NameType>("operator?"); +    } +    return nullptr; +  case 'r': +    switch (look(1)) { +    case 'm': +      First += 2; +      return make<NameType>("operator%"); +    case 'M': +      First += 2; +      return make<NameType>("operator%="); +    case 's': +      First += 2; +      return make<NameType>("operator>>"); +    case 'S': +      First += 2; +      return make<NameType>("operator>>="); +    } +    return nullptr; +  case 's': +    if (look(1) == 's') { +      First += 2; +      return make<NameType>("operator<=>"); +    } +    return nullptr; +  // ::= v <digit> <source-name>        # vendor extended operator +  case 'v': +    if (std::isdigit(look(1))) { +      First += 2; +      Node *SN = getDerived().parseSourceName(State); +      if (SN == nullptr) +        return nullptr; +      return make<ConversionOperatorType>(SN); +    } +    return nullptr; +  } +  return nullptr; +} + +// <ctor-dtor-name> ::= C1  # complete object constructor +//                  ::= C2  # base object constructor +//                  ::= C3  # complete object allocating constructor +//   extension      ::= C4  # gcc old-style "[unified]" constructor +//   extension      ::= C5  # the COMDAT used for ctors +//                  ::= D0  # deleting destructor +//                  ::= D1  # complete object destructor +//                  ::= D2  # base object destructor +//   extension      ::= D4  # gcc old-style "[unified]" destructor +//   extension      ::= D5  # the COMDAT used for dtors +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, +                                                          NameState *State) { +  if (SoFar->getKind() == Node::KSpecialSubstitution) { +    auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK; +    switch (SSK) { +    case SpecialSubKind::string: +    case SpecialSubKind::istream: +    case SpecialSubKind::ostream: +    case SpecialSubKind::iostream: +      SoFar = make<ExpandedSpecialSubstitution>(SSK); +      if (!SoFar) +        return nullptr; +      break; +    default: +      break; +    } +  } + +  if (consumeIf('C')) { +    bool IsInherited = consumeIf('I'); +    if (look() != '1' && look() != '2' && look() != '3' && look() != '4' && +        look() != '5') +      return nullptr; +    int Variant = look() - '0'; +    ++First; +    if (State) State->CtorDtorConversion = true; +    if (IsInherited) { +      if (getDerived().parseName(State) == nullptr) +        return nullptr; +    } +    return make<CtorDtorName>(SoFar, /*IsDtor=*/false, Variant); +  } + +  if (look() == 'D' && (look(1) == '0' || look(1) == '1' || look(1) == '2' || +                        look(1) == '4' || look(1) == '5')) { +    int Variant = look(1) - '0'; +    First += 2; +    if (State) State->CtorDtorConversion = true; +    return make<CtorDtorName>(SoFar, /*IsDtor=*/true, Variant); +  } + +  return nullptr; +} + +// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E +//               ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E +// +// <prefix> ::= <prefix> <unqualified-name> +//          ::= <template-prefix> <template-args> +//          ::= <template-param> +//          ::= <decltype> +//          ::= # empty +//          ::= <substitution> +//          ::= <prefix> <data-member-prefix> +//  extension ::= L +// +// <data-member-prefix> := <member source-name> [<template-args>] M +// +// <template-prefix> ::= <prefix> <template unqualified-name> +//                   ::= <template-param> +//                   ::= <substitution> +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) { +  if (!consumeIf('N')) +    return nullptr; + +  Qualifiers CVTmp = parseCVQualifiers(); +  if (State) State->CVQualifiers = CVTmp; + +  if (consumeIf('O')) { +    if (State) State->ReferenceQualifier = FrefQualRValue; +  } else if (consumeIf('R')) { +    if (State) State->ReferenceQualifier = FrefQualLValue; +  } else +    if (State) State->ReferenceQualifier = FrefQualNone; + +  Node *SoFar = nullptr; +  auto PushComponent = [&](Node *Comp) { +    if (!Comp) return false; +    if (SoFar) SoFar = make<NestedName>(SoFar, Comp); +    else       SoFar = Comp; +    if (State) State->EndsWithTemplateArgs = false; +    return SoFar != nullptr; +  }; + +  if (consumeIf("St")) { +    SoFar = make<NameType>("std"); +    if (!SoFar) +      return nullptr; +  } + +  while (!consumeIf('E')) { +    consumeIf('L'); // extension + +    // <data-member-prefix> := <member source-name> [<template-args>] M +    if (consumeIf('M')) { +      if (SoFar == nullptr) +        return nullptr; +      continue; +    } + +    //          ::= <template-param> +    if (look() == 'T') { +      if (!PushComponent(getDerived().parseTemplateParam())) +        return nullptr; +      Subs.push_back(SoFar); +      continue; +    } + +    //          ::= <template-prefix> <template-args> +    if (look() == 'I') { +      Node *TA = getDerived().parseTemplateArgs(State != nullptr); +      if (TA == nullptr || SoFar == nullptr) +        return nullptr; +      SoFar = make<NameWithTemplateArgs>(SoFar, TA); +      if (!SoFar) +        return nullptr; +      if (State) State->EndsWithTemplateArgs = true; +      Subs.push_back(SoFar); +      continue; +    } + +    //          ::= <decltype> +    if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { +      if (!PushComponent(getDerived().parseDecltype())) +        return nullptr; +      Subs.push_back(SoFar); +      continue; +    } + +    //          ::= <substitution> +    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 <unqualified-name> thats actually a <ctor-dtor-name>. +    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; +    } + +    //          ::= <prefix> <unqualified-name> +    if (!PushComponent(getDerived().parseUnqualifiedName(State))) +      return nullptr; +    Subs.push_back(SoFar); +  } + +  if (SoFar == nullptr || Subs.empty()) +    return nullptr; + +  Subs.pop_back(); +  return SoFar; +} + +// <simple-id> ::= <source-name> [ <template-args> ] +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() { +  Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr); +  if (SN == nullptr) +    return nullptr; +  if (look() == 'I') { +    Node *TA = getDerived().parseTemplateArgs(); +    if (TA == nullptr) +      return nullptr; +    return make<NameWithTemplateArgs>(SN, TA); +  } +  return SN; +} + +// <destructor-name> ::= <unresolved-type>  # e.g., ~T or ~decltype(f()) +//                   ::= <simple-id>        # e.g., ~A<2*N> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() { +  Node *Result; +  if (std::isdigit(look())) +    Result = getDerived().parseSimpleId(); +  else +    Result = getDerived().parseUnresolvedType(); +  if (Result == nullptr) +    return nullptr; +  return make<DtorName>(Result); +} + +// <unresolved-type> ::= <template-param> +//                   ::= <decltype> +//                   ::= <substitution> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() { +  if (look() == 'T') { +    Node *TP = getDerived().parseTemplateParam(); +    if (TP == nullptr) +      return nullptr; +    Subs.push_back(TP); +    return TP; +  } +  if (look() == 'D') { +    Node *DT = getDerived().parseDecltype(); +    if (DT == nullptr) +      return nullptr; +    Subs.push_back(DT); +    return DT; +  } +  return getDerived().parseSubstitution(); +} + +// <base-unresolved-name> ::= <simple-id>                                # unresolved name +//          extension     ::= <operator-name>                            # unresolved operator-function-id +//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id +//                        ::= on <operator-name>                         # unresolved operator-function-id +//                        ::= on <operator-name> <template-args>         # unresolved operator template-id +//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor; +//                                                                         # e.g. ~X or ~X<N-1> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() { +  if (std::isdigit(look())) +    return getDerived().parseSimpleId(); + +  if (consumeIf("dn")) +    return getDerived().parseDestructorName(); + +  consumeIf("on"); + +  Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr); +  if (Oper == nullptr) +    return nullptr; +  if (look() == 'I') { +    Node *TA = getDerived().parseTemplateArgs(); +    if (TA == nullptr) +      return nullptr; +    return make<NameWithTemplateArgs>(Oper, TA); +  } +  return Oper; +} + +// <unresolved-name> +//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +//                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x +//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> +//                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::" +//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x +//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name> +//                                                                       # T::N::x /decltype(p)::N::x +//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name> +// +// <unresolved-qualifier-level> ::= <simple-id> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { +  Node *SoFar = nullptr; + +  // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +  // srN <unresolved-type>                   <unresolved-qualifier-level>+ E <base-unresolved-name> +  if (consumeIf("srN")) { +    SoFar = getDerived().parseUnresolvedType(); +    if (SoFar == nullptr) +      return nullptr; + +    if (look() == 'I') { +      Node *TA = getDerived().parseTemplateArgs(); +      if (TA == nullptr) +        return nullptr; +      SoFar = make<NameWithTemplateArgs>(SoFar, TA); +      if (!SoFar) +        return nullptr; +    } + +    while (!consumeIf('E')) { +      Node *Qual = getDerived().parseSimpleId(); +      if (Qual == nullptr) +        return nullptr; +      SoFar = make<QualifiedName>(SoFar, Qual); +      if (!SoFar) +        return nullptr; +    } + +    Node *Base = getDerived().parseBaseUnresolvedName(); +    if (Base == nullptr) +      return nullptr; +    return make<QualifiedName>(SoFar, Base); +  } + +  bool Global = consumeIf("gs"); + +  // [gs] <base-unresolved-name>                     # x or (with "gs") ::x +  if (!consumeIf("sr")) { +    SoFar = getDerived().parseBaseUnresolvedName(); +    if (SoFar == nullptr) +      return nullptr; +    if (Global) +      SoFar = make<GlobalQualifiedName>(SoFar); +    return SoFar; +  } + +  // [gs] sr <unresolved-qualifier-level>+ E   <base-unresolved-name> +  if (std::isdigit(look())) { +    do { +      Node *Qual = getDerived().parseSimpleId(); +      if (Qual == nullptr) +        return nullptr; +      if (SoFar) +        SoFar = make<QualifiedName>(SoFar, Qual); +      else if (Global) +        SoFar = make<GlobalQualifiedName>(Qual); +      else +        SoFar = Qual; +      if (!SoFar) +        return nullptr; +    } while (!consumeIf('E')); +  } +  //      sr <unresolved-type>                 <base-unresolved-name> +  //      sr <unresolved-type> <template-args> <base-unresolved-name> +  else { +    SoFar = getDerived().parseUnresolvedType(); +    if (SoFar == nullptr) +      return nullptr; + +    if (look() == 'I') { +      Node *TA = getDerived().parseTemplateArgs(); +      if (TA == nullptr) +        return nullptr; +      SoFar = make<NameWithTemplateArgs>(SoFar, TA); +      if (!SoFar) +        return nullptr; +    } +  } + +  assert(SoFar != nullptr); + +  Node *Base = getDerived().parseBaseUnresolvedName(); +  if (Base == nullptr) +    return nullptr; +  return make<QualifiedName>(SoFar, Base); +} + +// <abi-tags> ::= <abi-tag> [<abi-tags>] +// <abi-tag> ::= B <source-name> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { +  while (consumeIf('B')) { +    StringView SN = parseBareSourceName(); +    if (SN.empty()) +      return nullptr; +    N = make<AbiTagAttr>(N, SN); +    if (!N) +      return nullptr; +  } +  return N; +} + +// <number> ::= [n] <non-negative decimal integer> +template <typename Alloc, typename Derived> +StringView +AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { +  const char *Tmp = First; +  if (AllowNegative) +    consumeIf('n'); +  if (numLeft() == 0 || !std::isdigit(*First)) +    return StringView(); +  while (numLeft() != 0 && std::isdigit(*First)) +    ++First; +  return StringView(Tmp, First); +} + +// <positive length number> ::= [0-9]* +template <typename Alloc, typename Derived> +bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) { +  *Out = 0; +  if (look() < '0' || look() > '9') +    return true; +  while (look() >= '0' && look() <= '9') { +    *Out *= 10; +    *Out += static_cast<size_t>(consume() - '0'); +  } +  return false; +} + +template <typename Alloc, typename Derived> +StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { +  size_t Int = 0; +  if (parsePositiveInteger(&Int) || numLeft() < Int) +    return StringView(); +  StringView R(First, First + Int); +  First += Int; +  return R; +} + +// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E +// +// <exception-spec> ::= Do                # non-throwing exception-specification (e.g., noexcept, throw()) +//                  ::= DO <expression> E # computed (instantiation-dependent) noexcept +//                  ::= Dw <type>+ E      # dynamic exception specification with instantiation-dependent types +// +// <ref-qualifier> ::= R                   # & ref-qualifier +// <ref-qualifier> ::= O                   # && ref-qualifier +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() { +  Qualifiers CVQuals = parseCVQualifiers(); + +  Node *ExceptionSpec = nullptr; +  if (consumeIf("Do")) { +    ExceptionSpec = make<NameType>("noexcept"); +    if (!ExceptionSpec) +      return nullptr; +  } else if (consumeIf("DO")) { +    Node *E = getDerived().parseExpr(); +    if (E == nullptr || !consumeIf('E')) +      return nullptr; +    ExceptionSpec = make<NoexceptSpec>(E); +    if (!ExceptionSpec) +      return nullptr; +  } else if (consumeIf("Dw")) { +    size_t SpecsBegin = Names.size(); +    while (!consumeIf('E')) { +      Node *T = getDerived().parseType(); +      if (T == nullptr) +        return nullptr; +      Names.push_back(T); +    } +    ExceptionSpec = +      make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin)); +    if (!ExceptionSpec) +      return nullptr; +  } + +  consumeIf("Dx"); // transaction safe + +  if (!consumeIf('F')) +    return nullptr; +  consumeIf('Y'); // extern "C" +  Node *ReturnType = getDerived().parseType(); +  if (ReturnType == nullptr) +    return nullptr; + +  FunctionRefQual ReferenceQualifier = FrefQualNone; +  size_t ParamsBegin = Names.size(); +  while (true) { +    if (consumeIf('E')) +      break; +    if (consumeIf('v')) +      continue; +    if (consumeIf("RE")) { +      ReferenceQualifier = FrefQualLValue; +      break; +    } +    if (consumeIf("OE")) { +      ReferenceQualifier = FrefQualRValue; +      break; +    } +    Node *T = getDerived().parseType(); +    if (T == nullptr) +      return nullptr; +    Names.push_back(T); +  } + +  NodeArray Params = popTrailingNodeArray(ParamsBegin); +  return make<FunctionType>(ReturnType, Params, CVQuals, +                            ReferenceQualifier, ExceptionSpec); +} + +// extension: +// <vector-type>           ::= Dv <positive dimension number> _ <extended element type> +//                         ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +//                         ::= p # AltiVec vector pixel +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() { +  if (!consumeIf("Dv")) +    return nullptr; +  if (look() >= '1' && look() <= '9') { +    StringView DimensionNumber = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    if (consumeIf('p')) +      return make<PixelVectorType>(DimensionNumber); +    Node *ElemType = getDerived().parseType(); +    if (ElemType == nullptr) +      return nullptr; +    return make<VectorType>(ElemType, DimensionNumber); +  } + +  if (!consumeIf('_')) { +    Node *DimExpr = getDerived().parseExpr(); +    if (!DimExpr) +      return nullptr; +    if (!consumeIf('_')) +      return nullptr; +    Node *ElemType = getDerived().parseType(); +    if (!ElemType) +      return nullptr; +    return make<VectorType>(ElemType, DimExpr); +  } +  Node *ElemType = getDerived().parseType(); +  if (!ElemType) +    return nullptr; +  return make<VectorType>(ElemType, StringView()); +} + +// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x) +//             ::= DT <expression> E  # decltype of an expression (C++0x) +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() { +  if (!consumeIf('D')) +    return nullptr; +  if (!consumeIf('t') && !consumeIf('T')) +    return nullptr; +  Node *E = getDerived().parseExpr(); +  if (E == nullptr) +    return nullptr; +  if (!consumeIf('E')) +    return nullptr; +  return make<EnclosingExpr>("decltype(", E, ")"); +} + +// <array-type> ::= A <positive dimension number> _ <element type> +//              ::= A [<dimension expression>] _ <element type> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() { +  if (!consumeIf('A')) +    return nullptr; + +  NodeOrString Dimension; + +  if (std::isdigit(look())) { +    Dimension = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +  } else if (!consumeIf('_')) { +    Node *DimExpr = getDerived().parseExpr(); +    if (DimExpr == nullptr) +      return nullptr; +    if (!consumeIf('_')) +      return nullptr; +    Dimension = DimExpr; +  } + +  Node *Ty = getDerived().parseType(); +  if (Ty == nullptr) +    return nullptr; +  return make<ArrayType>(Ty, Dimension); +} + +// <pointer-to-member-type> ::= M <class type> <member type> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() { +  if (!consumeIf('M')) +    return nullptr; +  Node *ClassType = getDerived().parseType(); +  if (ClassType == nullptr) +    return nullptr; +  Node *MemberType = getDerived().parseType(); +  if (MemberType == nullptr) +    return nullptr; +  return make<PointerToMemberType>(ClassType, MemberType); +} + +// <class-enum-type> ::= <name>     # non-dependent type name, dependent type name, or dependent typename-specifier +//                   ::= Ts <name>  # dependent elaborated type specifier using 'struct' or 'class' +//                   ::= Tu <name>  # dependent elaborated type specifier using 'union' +//                   ::= Te <name>  # dependent elaborated type specifier using 'enum' +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { +  StringView ElabSpef; +  if (consumeIf("Ts")) +    ElabSpef = "struct"; +  else if (consumeIf("Tu")) +    ElabSpef = "union"; +  else if (consumeIf("Te")) +    ElabSpef = "enum"; + +  Node *Name = getDerived().parseName(); +  if (Name == nullptr) +    return nullptr; + +  if (!ElabSpef.empty()) +    return make<ElaboratedTypeSpefType>(ElabSpef, Name); + +  return Name; +} + +// <qualified-type>     ::= <qualifiers> <type> +// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers> +// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { +  if (consumeIf('U')) { +    StringView Qual = parseBareSourceName(); +    if (Qual.empty()) +      return nullptr; + +    // FIXME parse the optional <template-args> here! + +    // extension            ::= U <objc-name> <objc-type>  # objc-type<identifier> +    if (Qual.startsWith("objcproto")) { +      StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); +      StringView Proto; +      { +        SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()), +                                     SaveLast(Last, ProtoSourceName.end()); +        Proto = parseBareSourceName(); +      } +      if (Proto.empty()) +        return nullptr; +      Node *Child = getDerived().parseQualifiedType(); +      if (Child == nullptr) +        return nullptr; +      return make<ObjCProtoName>(Child, Proto); +    } + +    Node *Child = getDerived().parseQualifiedType(); +    if (Child == nullptr) +      return nullptr; +    return make<VendorExtQualType>(Child, Qual); +  } + +  Qualifiers Quals = parseCVQualifiers(); +  Node *Ty = getDerived().parseType(); +  if (Ty == nullptr) +    return nullptr; +  if (Quals != QualNone) +    Ty = make<QualType>(Ty, Quals); +  return Ty; +} + +// <type>      ::= <builtin-type> +//             ::= <qualified-type> +//             ::= <function-type> +//             ::= <class-enum-type> +//             ::= <array-type> +//             ::= <pointer-to-member-type> +//             ::= <template-param> +//             ::= <template-template-param> <template-args> +//             ::= <decltype> +//             ::= P <type>        # pointer +//             ::= R <type>        # l-value reference +//             ::= O <type>        # r-value reference (C++11) +//             ::= C <type>        # complex pair (C99) +//             ::= G <type>        # imaginary (C99) +//             ::= <substitution>  # See Compression below +// extension   ::= U <objc-name> <objc-type>  # objc-type<identifier> +// extension   ::= <vector-type> # <vector-type> starts with Dv +// +// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1 +// <objc-type> ::= <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseType() { +  Node *Result = nullptr; + +  switch (look()) { +  //             ::= <qualified-type> +  case 'r': +  case 'V': +  case 'K': { +    unsigned AfterQuals = 0; +    if (look(AfterQuals) == 'r') ++AfterQuals; +    if (look(AfterQuals) == 'V') ++AfterQuals; +    if (look(AfterQuals) == 'K') ++AfterQuals; + +    if (look(AfterQuals) == 'F' || +        (look(AfterQuals) == 'D' && +         (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' || +          look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) { +      Result = getDerived().parseFunctionType(); +      break; +    } +    DEMANGLE_FALLTHROUGH; +  } +  case 'U': { +    Result = getDerived().parseQualifiedType(); +    break; +  } +  // <builtin-type> ::= v    # void +  case 'v': +    ++First; +    return make<NameType>("void"); +  //                ::= w    # wchar_t +  case 'w': +    ++First; +    return make<NameType>("wchar_t"); +  //                ::= b    # bool +  case 'b': +    ++First; +    return make<NameType>("bool"); +  //                ::= c    # char +  case 'c': +    ++First; +    return make<NameType>("char"); +  //                ::= a    # signed char +  case 'a': +    ++First; +    return make<NameType>("signed char"); +  //                ::= h    # unsigned char +  case 'h': +    ++First; +    return make<NameType>("unsigned char"); +  //                ::= s    # short +  case 's': +    ++First; +    return make<NameType>("short"); +  //                ::= t    # unsigned short +  case 't': +    ++First; +    return make<NameType>("unsigned short"); +  //                ::= i    # int +  case 'i': +    ++First; +    return make<NameType>("int"); +  //                ::= j    # unsigned int +  case 'j': +    ++First; +    return make<NameType>("unsigned int"); +  //                ::= l    # long +  case 'l': +    ++First; +    return make<NameType>("long"); +  //                ::= m    # unsigned long +  case 'm': +    ++First; +    return make<NameType>("unsigned long"); +  //                ::= x    # long long, __int64 +  case 'x': +    ++First; +    return make<NameType>("long long"); +  //                ::= y    # unsigned long long, __int64 +  case 'y': +    ++First; +    return make<NameType>("unsigned long long"); +  //                ::= n    # __int128 +  case 'n': +    ++First; +    return make<NameType>("__int128"); +  //                ::= o    # unsigned __int128 +  case 'o': +    ++First; +    return make<NameType>("unsigned __int128"); +  //                ::= f    # float +  case 'f': +    ++First; +    return make<NameType>("float"); +  //                ::= d    # double +  case 'd': +    ++First; +    return make<NameType>("double"); +  //                ::= e    # long double, __float80 +  case 'e': +    ++First; +    return make<NameType>("long double"); +  //                ::= g    # __float128 +  case 'g': +    ++First; +    return make<NameType>("__float128"); +  //                ::= z    # ellipsis +  case 'z': +    ++First; +    return make<NameType>("..."); + +  // <builtin-type> ::= u <source-name>    # vendor extended type +  case 'u': { +    ++First; +    StringView Res = parseBareSourceName(); +    if (Res.empty()) +      return nullptr; +    // Typically, <builtin-type>s are not considered substitution candidates, +    // but the exception to that exception is vendor extended types (Itanium C++ +    // ABI 5.9.1). +    Result = make<NameType>(Res); +    break; +  } +  case 'D': +    switch (look(1)) { +    //                ::= Dd   # IEEE 754r decimal floating point (64 bits) +    case 'd': +      First += 2; +      return make<NameType>("decimal64"); +    //                ::= De   # IEEE 754r decimal floating point (128 bits) +    case 'e': +      First += 2; +      return make<NameType>("decimal128"); +    //                ::= Df   # IEEE 754r decimal floating point (32 bits) +    case 'f': +      First += 2; +      return make<NameType>("decimal32"); +    //                ::= Dh   # IEEE 754r half-precision floating point (16 bits) +    case 'h': +      First += 2; +      return make<NameType>("decimal16"); +    //                ::= Di   # char32_t +    case 'i': +      First += 2; +      return make<NameType>("char32_t"); +    //                ::= Ds   # char16_t +    case 's': +      First += 2; +      return make<NameType>("char16_t"); +    //                ::= Du   # char8_t (C++2a, not yet in the Itanium spec) +    case 'u': +      First += 2; +      return make<NameType>("char8_t"); +    //                ::= Da   # auto (in dependent new-expressions) +    case 'a': +      First += 2; +      return make<NameType>("auto"); +    //                ::= Dc   # decltype(auto) +    case 'c': +      First += 2; +      return make<NameType>("decltype(auto)"); +    //                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr)) +    case 'n': +      First += 2; +      return make<NameType>("std::nullptr_t"); + +    //             ::= <decltype> +    case 't': +    case 'T': { +      Result = getDerived().parseDecltype(); +      break; +    } +    // extension   ::= <vector-type> # <vector-type> starts with Dv +    case 'v': { +      Result = getDerived().parseVectorType(); +      break; +    } +    //           ::= Dp <type>       # pack expansion (C++0x) +    case 'p': { +      First += 2; +      Node *Child = getDerived().parseType(); +      if (!Child) +        return nullptr; +      Result = make<ParameterPackExpansion>(Child); +      break; +    } +    // Exception specifier on a function type. +    case 'o': +    case 'O': +    case 'w': +    // Transaction safe function type. +    case 'x': +      Result = getDerived().parseFunctionType(); +      break; +    } +    break; +  //             ::= <function-type> +  case 'F': { +    Result = getDerived().parseFunctionType(); +    break; +  } +  //             ::= <array-type> +  case 'A': { +    Result = getDerived().parseArrayType(); +    break; +  } +  //             ::= <pointer-to-member-type> +  case 'M': { +    Result = getDerived().parsePointerToMemberType(); +    break; +  } +  //             ::= <template-param> +  case 'T': { +    // This could be an elaborate type specifier on a <class-enum-type>. +    if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') { +      Result = getDerived().parseClassEnumType(); +      break; +    } + +    Result = getDerived().parseTemplateParam(); +    if (Result == nullptr) +      return nullptr; + +    // Result could be either of: +    //   <type>        ::= <template-param> +    //   <type>        ::= <template-template-param> <template-args> +    // +    //   <template-template-param> ::= <template-param> +    //                             ::= <substitution> +    // +    // If this is followed by some <template-args>, and we're permitted to +    // parse them, take the second production. + +    if (TryToParseTemplateArgs && look() == 'I') { +      Node *TA = getDerived().parseTemplateArgs(); +      if (TA == nullptr) +        return nullptr; +      Result = make<NameWithTemplateArgs>(Result, TA); +    } +    break; +  } +  //             ::= P <type>        # pointer +  case 'P': { +    ++First; +    Node *Ptr = getDerived().parseType(); +    if (Ptr == nullptr) +      return nullptr; +    Result = make<PointerType>(Ptr); +    break; +  } +  //             ::= R <type>        # l-value reference +  case 'R': { +    ++First; +    Node *Ref = getDerived().parseType(); +    if (Ref == nullptr) +      return nullptr; +    Result = make<ReferenceType>(Ref, ReferenceKind::LValue); +    break; +  } +  //             ::= O <type>        # r-value reference (C++11) +  case 'O': { +    ++First; +    Node *Ref = getDerived().parseType(); +    if (Ref == nullptr) +      return nullptr; +    Result = make<ReferenceType>(Ref, ReferenceKind::RValue); +    break; +  } +  //             ::= C <type>        # complex pair (C99) +  case 'C': { +    ++First; +    Node *P = getDerived().parseType(); +    if (P == nullptr) +      return nullptr; +    Result = make<PostfixQualifiedType>(P, " complex"); +    break; +  } +  //             ::= G <type>        # imaginary (C99) +  case 'G': { +    ++First; +    Node *P = getDerived().parseType(); +    if (P == nullptr) +      return P; +    Result = make<PostfixQualifiedType>(P, " imaginary"); +    break; +  } +  //             ::= <substitution>  # See Compression below +  case 'S': { +    if (look(1) && look(1) != 't') { +      Node *Sub = getDerived().parseSubstitution(); +      if (Sub == nullptr) +        return nullptr; + +      // Sub could be either of: +      //   <type>        ::= <substitution> +      //   <type>        ::= <template-template-param> <template-args> +      // +      //   <template-template-param> ::= <template-param> +      //                             ::= <substitution> +      // +      // If this is followed by some <template-args>, and we're permitted to +      // parse them, take the second production. + +      if (TryToParseTemplateArgs && look() == 'I') { +        Node *TA = getDerived().parseTemplateArgs(); +        if (TA == nullptr) +          return nullptr; +        Result = make<NameWithTemplateArgs>(Sub, TA); +        break; +      } + +      // If all we parsed was a substitution, don't re-insert into the +      // substitution table. +      return Sub; +    } +    DEMANGLE_FALLTHROUGH; +  } +  //        ::= <class-enum-type> +  default: { +    Result = getDerived().parseClassEnumType(); +    break; +  } +  } + +  // If we parsed a type, insert it into the substitution table. Note that all +  // <builtin-type>s and <substitution>s have already bailed out, because they +  // don't get substitutions. +  if (Result != nullptr) +    Subs.push_back(Result); +  return Result; +} + +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) { +  Node *E = getDerived().parseExpr(); +  if (E == nullptr) +    return nullptr; +  return make<PrefixExpr>(Kind, E); +} + +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) { +  Node *LHS = getDerived().parseExpr(); +  if (LHS == nullptr) +    return nullptr; +  Node *RHS = getDerived().parseExpr(); +  if (RHS == nullptr) +    return nullptr; +  return make<BinaryExpr>(LHS, Kind, RHS); +} + +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) { +  StringView Tmp = parseNumber(true); +  if (!Tmp.empty() && consumeIf('E')) +    return make<IntegerLiteral>(Lit, Tmp); +  return nullptr; +} + +// <CV-Qualifiers> ::= [r] [V] [K] +template <typename Alloc, typename Derived> +Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() { +  Qualifiers CVR = QualNone; +  if (consumeIf('r')) +    CVR |= QualRestrict; +  if (consumeIf('V')) +    CVR |= QualVolatile; +  if (consumeIf('K')) +    CVR |= QualConst; +  return CVR; +} + +// <function-param> ::= fp <top-level CV-Qualifiers> _                                     # L == 0, first parameter +//                  ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters +//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _         # L > 0, first parameter +//                  ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { +  if (consumeIf("fp")) { +    parseCVQualifiers(); +    StringView Num = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    return make<FunctionParam>(Num); +  } +  if (consumeIf("fL")) { +    if (parseNumber().empty()) +      return nullptr; +    if (!consumeIf('p')) +      return nullptr; +    parseCVQualifiers(); +    StringView Num = parseNumber(); +    if (!consumeIf('_')) +      return nullptr; +    return make<FunctionParam>(Num); +  } +  return nullptr; +} + +// [gs] nw <expression>* _ <type> E                     # new (expr-list) type +// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init) +// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type +// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init) +// <initializer> ::= pi <expression>* E                 # parenthesized initialization +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::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<NewExpr>(ExprList, Ty, Inits, Global, IsArray); +  } else if (!consumeIf('E')) +    return nullptr; +  return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray); +} + +// cv <type> <expression>                               # conversion with one argument +// cv <type> _ <expression>* E                          # conversion with a different number of arguments +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() { +  if (!consumeIf("cv")) +    return nullptr; +  Node *Ty; +  { +    SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); +    Ty = getDerived().parseType(); +  } + +  if (Ty == nullptr) +    return nullptr; + +  if (consumeIf('_')) { +    size_t ExprsBegin = Names.size(); +    while (!consumeIf('E')) { +      Node *E = getDerived().parseExpr(); +      if (E == nullptr) +        return E; +      Names.push_back(E); +    } +    NodeArray Exprs = popTrailingNodeArray(ExprsBegin); +    return make<ConversionExpr>(Ty, Exprs); +  } + +  Node *E[1] = {getDerived().parseExpr()}; +  if (E[0] == nullptr) +    return nullptr; +  return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1)); +} + +// <expr-primary> ::= L <type> <value number> E                          # integer literal +//                ::= L <type> <value float> E                           # floating literal +//                ::= L <string type> E                                  # string literal +//                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE") +//                ::= L <lambda type> E                                  # lambda expression +// FIXME:         ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000) +//                ::= L <mangled-name> E                                 # external name +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { +  if (!consumeIf('L')) +    return nullptr; +  switch (look()) { +  case 'w': +    ++First; +    return getDerived().parseIntegerLiteral("wchar_t"); +  case 'b': +    if (consumeIf("b0E")) +      return make<BoolExpr>(0); +    if (consumeIf("b1E")) +      return make<BoolExpr>(1); +    return nullptr; +  case 'c': +    ++First; +    return getDerived().parseIntegerLiteral("char"); +  case 'a': +    ++First; +    return getDerived().parseIntegerLiteral("signed char"); +  case 'h': +    ++First; +    return getDerived().parseIntegerLiteral("unsigned char"); +  case 's': +    ++First; +    return getDerived().parseIntegerLiteral("short"); +  case 't': +    ++First; +    return getDerived().parseIntegerLiteral("unsigned short"); +  case 'i': +    ++First; +    return getDerived().parseIntegerLiteral(""); +  case 'j': +    ++First; +    return getDerived().parseIntegerLiteral("u"); +  case 'l': +    ++First; +    return getDerived().parseIntegerLiteral("l"); +  case 'm': +    ++First; +    return getDerived().parseIntegerLiteral("ul"); +  case 'x': +    ++First; +    return getDerived().parseIntegerLiteral("ll"); +  case 'y': +    ++First; +    return getDerived().parseIntegerLiteral("ull"); +  case 'n': +    ++First; +    return getDerived().parseIntegerLiteral("__int128"); +  case 'o': +    ++First; +    return getDerived().parseIntegerLiteral("unsigned __int128"); +  case 'f': +    ++First; +    return getDerived().template parseFloatingLiteral<float>(); +  case 'd': +    ++First; +    return getDerived().template parseFloatingLiteral<double>(); +  case 'e': +    ++First; +    return getDerived().template parseFloatingLiteral<long double>(); +  case '_': +    if (consumeIf("_Z")) { +      Node *R = getDerived().parseEncoding(); +      if (R != nullptr && consumeIf('E')) +        return R; +    } +    return nullptr; +  case 'A': { +    Node *T = getDerived().parseType(); +    if (T == nullptr) +      return nullptr; +    // FIXME: We need to include the string contents in the mangling. +    if (consumeIf('E')) +      return make<StringLiteral>(T); +    return nullptr; +  } +  case 'D': +    if (consumeIf("DnE")) +      return make<NameType>("nullptr"); +    return nullptr; +  case 'T': +    // Invalid mangled name per +    //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html +    return nullptr; +  case 'U': { +    // FIXME: Should we support LUb... for block literals? +    if (look(1) != 'l') +      return nullptr; +    Node *T = parseUnnamedTypeName(nullptr); +    if (!T || !consumeIf('E')) +      return nullptr; +    return make<LambdaExpr>(T); +  } +  default: { +    // might be named type +    Node *T = getDerived().parseType(); +    if (T == nullptr) +      return nullptr; +    StringView N = parseNumber(); +    if (N.empty()) +      return nullptr; +    if (!consumeIf('E')) +      return nullptr; +    return make<IntegerCastExpr>(T, N); +  } +  } +} + +// <braced-expression> ::= <expression> +//                     ::= di <field source-name> <braced-expression>    # .name = expr +//                     ::= dx <index expression> <braced-expression>     # [expr] = expr +//                     ::= dX <range begin expression> <range end expression> <braced-expression> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() { +  if (look() == 'd') { +    switch (look(1)) { +    case 'i': { +      First += 2; +      Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr); +      if (Field == nullptr) +        return nullptr; +      Node *Init = getDerived().parseBracedExpr(); +      if (Init == nullptr) +        return nullptr; +      return make<BracedExpr>(Field, Init, /*isArray=*/false); +    } +    case 'x': { +      First += 2; +      Node *Index = getDerived().parseExpr(); +      if (Index == nullptr) +        return nullptr; +      Node *Init = getDerived().parseBracedExpr(); +      if (Init == nullptr) +        return nullptr; +      return make<BracedExpr>(Index, Init, /*isArray=*/true); +    } +    case 'X': { +      First += 2; +      Node *RangeBegin = getDerived().parseExpr(); +      if (RangeBegin == nullptr) +        return nullptr; +      Node *RangeEnd = getDerived().parseExpr(); +      if (RangeEnd == nullptr) +        return nullptr; +      Node *Init = getDerived().parseBracedExpr(); +      if (Init == nullptr) +        return nullptr; +      return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init); +    } +    } +  } +  return getDerived().parseExpr(); +} + +// (not yet in the spec) +// <fold-expr> ::= fL <binary-operator-name> <expression> <expression> +//             ::= fR <binary-operator-name> <expression> <expression> +//             ::= fl <binary-operator-name> <expression> +//             ::= fr <binary-operator-name> <expression> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { +  if (!consumeIf('f')) +    return nullptr; + +  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 +    return nullptr; +  ++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; + +  Node *Pack = getDerived().parseExpr(), *Init = nullptr; +  if (Pack == nullptr) +    return nullptr; +  if (HasInitializer) { +    Init = getDerived().parseExpr(); +    if (Init == nullptr) +      return nullptr; +  } + +  if (IsLeftFold && Init) +    std::swap(Pack, Init); + +  return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init); +} + +// <expression> ::= <unary operator-name> <expression> +//              ::= <binary operator-name> <expression> <expression> +//              ::= <ternary operator-name> <expression> <expression> <expression> +//              ::= cl <expression>+ E                                   # call +//              ::= cv <type> <expression>                               # conversion with one argument +//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments +//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type +//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init) +//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type +//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init) +//              ::= [gs] dl <expression>                                 # delete expression +//              ::= [gs] da <expression>                                 # delete[] expression +//              ::= pp_ <expression>                                     # prefix ++ +//              ::= mm_ <expression>                                     # prefix -- +//              ::= ti <type>                                            # typeid (type) +//              ::= te <expression>                                      # typeid (expression) +//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression) +//              ::= sc <type> <expression>                               # static_cast<type> (expression) +//              ::= cc <type> <expression>                               # const_cast<type> (expression) +//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression) +//              ::= st <type>                                            # sizeof (a type) +//              ::= sz <expression>                                      # sizeof (an expression) +//              ::= at <type>                                            # alignof (a type) +//              ::= az <expression>                                      # alignof (an expression) +//              ::= nx <expression>                                      # noexcept (expression) +//              ::= <template-param> +//              ::= <function-param> +//              ::= dt <expression> <unresolved-name>                    # expr.name +//              ::= pt <expression> <unresolved-name>                    # expr->name +//              ::= ds <expression> <expression>                         # expr.*expr +//              ::= sZ <template-param>                                  # size of a parameter pack +//              ::= sZ <function-param>                                  # size of a function parameter pack +//              ::= sP <template-arg>* E                                 # sizeof...(T), size of a captured template parameter pack from an alias template +//              ::= sp <expression>                                      # pack expansion +//              ::= tw <expression>                                      # throw expression +//              ::= tr                                                   # throw with no operand (rethrow) +//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p), +//                                                                       # freestanding dependent name (e.g., T::x), +//                                                                       # objectless nonstatic member reference +//              ::= fL <binary-operator-name> <expression> <expression> +//              ::= fR <binary-operator-name> <expression> <expression> +//              ::= fl <binary-operator-name> <expression> +//              ::= fr <binary-operator-name> <expression> +//              ::= <expr-primary> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { +  bool Global = consumeIf("gs"); +  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 <function-param>. +    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<EnclosingExpr>("alignof (", Ty, ")"); +    } +    case 'z': { +      First += 2; +      Node *Ty = getDerived().parseExpr(); +      if (Ty == nullptr) +        return nullptr; +      return make<EnclosingExpr>("alignof (", Ty, ")"); +    } +    } +    return nullptr; +  case 'c': +    switch (First[1]) { +    // cc <type> <expression>                               # const_cast<type>(expression) +    case 'c': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return Ty; +      Node *Ex = getDerived().parseExpr(); +      if (Ex == nullptr) +        return Ex; +      return make<CastExpr>("const_cast", Ty, Ex); +    } +    // cl <expression>+ 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<CallExpr>(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<DeleteExpr>(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<CastExpr>("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<DeleteExpr>(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<MemberExpr>(LHS, ".*", RHS); +    } +    case 't': { +      First += 2; +      Node *LHS = getDerived().parseExpr(); +      if (LHS == nullptr) +        return LHS; +      Node *RHS = getDerived().parseExpr(); +      if (RHS == nullptr) +        return nullptr; +      return make<MemberExpr>(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; +      Node *Base = getDerived().parseExpr(); +      if (Base == nullptr) +        return nullptr; +      Node *Index = getDerived().parseExpr(); +      if (Index == nullptr) +        return Index; +      return make<ArraySubscriptExpr>(Base, Index); +    } +    case 'l': { +      First += 2; +      size_t InitsBegin = Names.size(); +      while (!consumeIf('E')) { +        Node *E = getDerived().parseBracedExpr(); +        if (E == nullptr) +          return nullptr; +        Names.push_back(E); +      } +      return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); +    } +    } +    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) +        return nullptr; +      return make<PostfixExpr>(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<EnclosingExpr>("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<PostfixExpr>(Ex, "++"); +    } +    case 's': +      First += 2; +      return getDerived().parsePrefixExpr("+"); +    case 't': { +      First += 2; +      Node *L = getDerived().parseExpr(); +      if (L == nullptr) +        return nullptr; +      Node *R = getDerived().parseExpr(); +      if (R == nullptr) +        return nullptr; +      return make<MemberExpr>(L, "->", R); +    } +    } +    return nullptr; +  case 'q': +    if (First[1] == 'u') { +      First += 2; +      Node *Cond = getDerived().parseExpr(); +      if (Cond == nullptr) +        return nullptr; +      Node *LHS = getDerived().parseExpr(); +      if (LHS == nullptr) +        return nullptr; +      Node *RHS = getDerived().parseExpr(); +      if (RHS == nullptr) +        return nullptr; +      return make<ConditionalExpr>(Cond, LHS, RHS); +    } +    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<CastExpr>("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<CastExpr>("static_cast", T, Ex); +    } +    case 'p': { +      First += 2; +      Node *Child = getDerived().parseExpr(); +      if (Child == nullptr) +        return nullptr; +      return make<ParameterPackExpansion>(Child); +    } +    case 'r': +      return getDerived().parseUnresolvedName(); +    case 't': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return Ty; +      return make<EnclosingExpr>("sizeof (", Ty, ")"); +    } +    case 'z': { +      First += 2; +      Node *Ex = getDerived().parseExpr(); +      if (Ex == nullptr) +        return Ex; +      return make<EnclosingExpr>("sizeof (", Ex, ")"); +    } +    case 'Z': +      First += 2; +      if (look() == 'T') { +        Node *R = getDerived().parseTemplateParam(); +        if (R == nullptr) +          return nullptr; +        return make<SizeofParamPackExpr>(R); +      } else if (look() == 'f') { +        Node *FP = getDerived().parseFunctionParam(); +        if (FP == nullptr) +          return nullptr; +        return make<EnclosingExpr>("sizeof... (", FP, ")"); +      } +      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<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); +      if (!Pack) +        return nullptr; +      return make<EnclosingExpr>("sizeof... (", Pack, ")"); +    } +    } +    return nullptr; +  case 't': +    switch (First[1]) { +    case 'e': { +      First += 2; +      Node *Ex = getDerived().parseExpr(); +      if (Ex == nullptr) +        return Ex; +      return make<EnclosingExpr>("typeid (", Ex, ")"); +    } +    case 'i': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return Ty; +      return make<EnclosingExpr>("typeid (", Ty, ")"); +    } +    case 'l': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      size_t InitsBegin = Names.size(); +      while (!consumeIf('E')) { +        Node *E = getDerived().parseBracedExpr(); +        if (E == nullptr) +          return nullptr; +        Names.push_back(E); +      } +      return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); +    } +    case 'r': +      First += 2; +      return make<NameType>("throw"); +    case 'w': { +      First += 2; +      Node *Ex = getDerived().parseExpr(); +      if (Ex == nullptr) +        return nullptr; +      return make<ThrowExpr>(Ex); +    } +    } +    return nullptr; +  case '1': +  case '2': +  case '3': +  case '4': +  case '5': +  case '6': +  case '7': +  case '8': +  case '9': +    return getDerived().parseUnresolvedName(); +  } + +  if (consumeIf("u8__uuidoft")) { +    Node *Ty = getDerived().parseType(); +    if (!Ty) +      return nullptr; +    return make<UUIDOfExpr>(Ty); +  } + +  if (consumeIf("u8__uuidofz")) { +    Node *Ex = getDerived().parseExpr(); +    if (!Ex) +      return nullptr; +    return make<UUIDOfExpr>(Ex); +  } + +  return nullptr; +} + +// <call-offset> ::= h <nv-offset> _ +//               ::= v <v-offset> _ +// +// <nv-offset> ::= <offset number> +//               # non-virtual base override +// +// <v-offset>  ::= <offset number> _ <virtual offset number> +//               # virtual base override, with vcall offset +template <typename Alloc, typename Derived> +bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() { +  // Just scan through the call offset, we never add this information into the +  // output. +  if (consumeIf('h')) +    return parseNumber(true).empty() || !consumeIf('_'); +  if (consumeIf('v')) +    return parseNumber(true).empty() || !consumeIf('_') || +           parseNumber(true).empty() || !consumeIf('_'); +  return true; +} + +// <special-name> ::= TV <type>    # virtual table +//                ::= TT <type>    # VTT structure (construction vtable index) +//                ::= TI <type>    # typeinfo structure +//                ::= TS <type>    # typeinfo name (null-terminated byte string) +//                ::= Tc <call-offset> <call-offset> <base encoding> +//                    # base is the nominal target function of thunk +//                    # first call-offset is 'this' adjustment +//                    # second call-offset is result adjustment +//                ::= T <call-offset> <base encoding> +//                    # base is the nominal target function of thunk +//                ::= GV <object name> # Guard variable for one-time initialization +//                                     # No <type> +//                ::= TW <object name> # Thread-local wrapper +//                ::= TH <object name> # Thread-local initialization +//                ::= GR <object name> _             # First temporary +//                ::= GR <object name> <seq-id> _    # Subsequent temporaries +//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first +//      extension ::= GR <object name> # reference temporary for object +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { +  switch (look()) { +  case 'T': +    switch (look(1)) { +    // TV <type>    # virtual table +    case 'V': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      return make<SpecialName>("vtable for ", Ty); +    } +    // TT <type>    # VTT structure (construction vtable index) +    case 'T': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      return make<SpecialName>("VTT for ", Ty); +    } +    // TI <type>    # typeinfo structure +    case 'I': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      return make<SpecialName>("typeinfo for ", Ty); +    } +    // TS <type>    # typeinfo name (null-terminated byte string) +    case 'S': { +      First += 2; +      Node *Ty = getDerived().parseType(); +      if (Ty == nullptr) +        return nullptr; +      return make<SpecialName>("typeinfo name for ", Ty); +    } +    // Tc <call-offset> <call-offset> <base encoding> +    case 'c': { +      First += 2; +      if (parseCallOffset() || parseCallOffset()) +        return nullptr; +      Node *Encoding = getDerived().parseEncoding(); +      if (Encoding == nullptr) +        return nullptr; +      return make<SpecialName>("covariant return thunk to ", Encoding); +    } +    // extension ::= TC <first type> <number> _ <second type> +    //               # construction vtable for second-in-first +    case 'C': { +      First += 2; +      Node *FirstType = getDerived().parseType(); +      if (FirstType == nullptr) +        return nullptr; +      if (parseNumber(true).empty() || !consumeIf('_')) +        return nullptr; +      Node *SecondType = getDerived().parseType(); +      if (SecondType == nullptr) +        return nullptr; +      return make<CtorVtableSpecialName>(SecondType, FirstType); +    } +    // TW <object name> # Thread-local wrapper +    case 'W': { +      First += 2; +      Node *Name = getDerived().parseName(); +      if (Name == nullptr) +        return nullptr; +      return make<SpecialName>("thread-local wrapper routine for ", Name); +    } +    // TH <object name> # Thread-local initialization +    case 'H': { +      First += 2; +      Node *Name = getDerived().parseName(); +      if (Name == nullptr) +        return nullptr; +      return make<SpecialName>("thread-local initialization routine for ", Name); +    } +    // T <call-offset> <base encoding> +    default: { +      ++First; +      bool IsVirt = look() == 'v'; +      if (parseCallOffset()) +        return nullptr; +      Node *BaseEncoding = getDerived().parseEncoding(); +      if (BaseEncoding == nullptr) +        return nullptr; +      if (IsVirt) +        return make<SpecialName>("virtual thunk to ", BaseEncoding); +      else +        return make<SpecialName>("non-virtual thunk to ", BaseEncoding); +    } +    } +  case 'G': +    switch (look(1)) { +    // GV <object name> # Guard variable for one-time initialization +    case 'V': { +      First += 2; +      Node *Name = getDerived().parseName(); +      if (Name == nullptr) +        return nullptr; +      return make<SpecialName>("guard variable for ", Name); +    } +    // GR <object name> # reference temporary for object +    // GR <object name> _             # First temporary +    // GR <object name> <seq-id> _    # Subsequent temporaries +    case 'R': { +      First += 2; +      Node *Name = getDerived().parseName(); +      if (Name == nullptr) +        return nullptr; +      size_t Count; +      bool ParsedSeqId = !parseSeqId(&Count); +      if (!consumeIf('_') && ParsedSeqId) +        return nullptr; +      return make<SpecialName>("reference temporary for ", Name); +    } +    } +  } +  return nullptr; +} + +// <encoding> ::= <function name> <bare-function-type> +//            ::= <data name> +//            ::= <special-name> +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { +  if (look() == 'G' || look() == 'T') +    return getDerived().parseSpecialName(); + +  auto IsEndOfEncoding = [&] { +    // The set of chars that can potentially follow an <encoding> (none of which +    // can start a <type>). Enumerating these allows us to avoid speculative +    // parsing. +    return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_'; +  }; + +  NameState NameInfo(this); +  Node *Name = getDerived().parseName(&NameInfo); +  if (Name == nullptr) +    return nullptr; + +  if (resolveForwardTemplateRefs(NameInfo)) +    return nullptr; + +  if (IsEndOfEncoding()) +    return Name; + +  Node *Attrs = nullptr; +  if (consumeIf("Ua9enable_ifI")) { +    size_t BeforeArgs = Names.size(); +    while (!consumeIf('E')) { +      Node *Arg = getDerived().parseTemplateArg(); +      if (Arg == nullptr) +        return nullptr; +      Names.push_back(Arg); +    } +    Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs)); +    if (!Attrs) +      return nullptr; +  } + +  Node *ReturnType = nullptr; +  if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) { +    ReturnType = getDerived().parseType(); +    if (ReturnType == nullptr) +      return nullptr; +  } + +  if (consumeIf('v')) +    return make<FunctionEncoding>(ReturnType, Name, NodeArray(), +                                  Attrs, NameInfo.CVQualifiers, +                                  NameInfo.ReferenceQualifier); + +  size_t ParamsBegin = Names.size(); +  do { +    Node *Ty = getDerived().parseType(); +    if (Ty == nullptr) +      return nullptr; +    Names.push_back(Ty); +  } while (!IsEndOfEncoding()); + +  return make<FunctionEncoding>(ReturnType, Name, +                                popTrailingNodeArray(ParamsBegin), +                                Attrs, NameInfo.CVQualifiers, +                                NameInfo.ReferenceQualifier); +} + +template <class Float> +struct FloatData; + +template <> +struct FloatData<float> +{ +    static const size_t mangled_size = 8; +    static const size_t max_demangled_size = 24; +    static constexpr const char* spec = "%af"; +}; + +template <> +struct FloatData<double> +{ +    static const size_t mangled_size = 16; +    static const size_t max_demangled_size = 32; +    static constexpr const char* spec = "%a"; +}; + +template <> +struct FloatData<long double> +{ +#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ +    defined(__wasm__) +    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; +    static constexpr const char *spec = "%LaL"; +}; + +template <typename Alloc, typename Derived> +template <class Float> +Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() { +  const size_t N = FloatData<Float>::mangled_size; +  if (numLeft() <= N) +    return nullptr; +  StringView Data(First, First + N); +  for (char C : Data) +    if (!std::isxdigit(C)) +      return nullptr; +  First += N; +  if (!consumeIf('E')) +    return nullptr; +  return make<FloatLiteralImpl<Float>>(Data); +} + +// <seq-id> ::= <0-9A-Z>+ +template <typename Alloc, typename Derived> +bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) { +  if (!(look() >= '0' && look() <= '9') && +      !(look() >= 'A' && look() <= 'Z')) +    return true; + +  size_t Id = 0; +  while (true) { +    if (look() >= '0' && look() <= '9') { +      Id *= 36; +      Id += static_cast<size_t>(look() - '0'); +    } else if (look() >= 'A' && look() <= 'Z') { +      Id *= 36; +      Id += static_cast<size_t>(look() - 'A') + 10; +    } else { +      *Out = Id; +      return false; +    } +    ++First; +  } +} + +// <substitution> ::= S <seq-id> _ +//                ::= S_ +// <substitution> ::= Sa # ::std::allocator +// <substitution> ::= Sb # ::std::basic_string +// <substitution> ::= Ss # ::std::basic_string < char, +//                                               ::std::char_traits<char>, +//                                               ::std::allocator<char> > +// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> > +// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> > +// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { +  if (!consumeIf('S')) +    return nullptr; + +  if (std::islower(look())) { +    Node *SpecialSub; +    switch (look()) { +    case 'a': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator); +      break; +    case 'b': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string); +      break; +    case 's': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string); +      break; +    case 'i': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream); +      break; +    case 'o': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream); +      break; +    case 'd': +      ++First; +      SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream); +      break; +    default: +      return nullptr; +    } +    if (!SpecialSub) +      return nullptr; +    // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> +    // has ABI tags, the tags are appended to the substitution; the result is a +    // substitutable component. +    Node *WithTags = getDerived().parseAbiTags(SpecialSub); +    if (WithTags != SpecialSub) { +      Subs.push_back(WithTags); +      SpecialSub = WithTags; +    } +    return SpecialSub; +  } + +  //                ::= S_ +  if (consumeIf('_')) { +    if (Subs.empty()) +      return nullptr; +    return Subs[0]; +  } + +  //                ::= S <seq-id> _ +  size_t Index = 0; +  if (parseSeqId(&Index)) +    return nullptr; +  ++Index; +  if (!consumeIf('_') || Index >= Subs.size()) +    return nullptr; +  return Subs[Index]; +} + +// <template-param> ::= T_    # first template parameter +//                  ::= T <parameter-2 non-negative number> _ +//                  ::= TL <level-1> __ +//                  ::= TL <level-1> _ <parameter-2 non-negative number> _ +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { +  if (!consumeIf('T')) +    return nullptr; + +  size_t Level = 0; +  if (consumeIf('L')) { +    if (parsePositiveInteger(&Level)) +      return nullptr; +    ++Level; +    if (!consumeIf('_')) +      return nullptr; +  } + +  size_t Index = 0; +  if (!consumeIf('_')) { +    if (parsePositiveInteger(&Index)) +      return nullptr; +    ++Index; +    if (!consumeIf('_')) +      return nullptr; +  } + +  // If we're in a context where this <template-param> refers to a +  // <template-arg> further ahead in the mangled name (currently just conversion +  // operator types), then we should only look it up in the right context. +  // This can only happen at the outermost level. +  if (PermitForwardTemplateReferences && Level == 0) { +    Node *ForwardRef = make<ForwardTemplateReference>(Index); +    if (!ForwardRef) +      return nullptr; +    assert(ForwardRef->getKind() == Node::KForwardTemplateReference); +    ForwardTemplateRefs.push_back( +        static_cast<ForwardTemplateReference *>(ForwardRef)); +    return ForwardRef; +  } + +  if (Level >= TemplateParams.size() || !TemplateParams[Level] || +      Index >= TemplateParams[Level]->size()) { +    // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter +    // list are mangled as the corresponding artificial template type parameter. +    if (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) { +      // This will be popped by the ScopedTemplateParamList in +      // parseUnnamedTypeName. +      if (Level == TemplateParams.size()) +        TemplateParams.push_back(nullptr); +      return make<NameType>("auto"); +    } + +    return nullptr; +  } + +  return (*TemplateParams[Level])[Index]; +} + +// <template-param-decl> ::= Ty                          # type parameter +//                       ::= Tn <type>                   # non-type parameter +//                       ::= Tt <template-param-decl>* E # template parameter +//                       ::= Tp <template-param-decl>    # parameter pack +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { +  auto InventTemplateParamName = [&](TemplateParamKind Kind) { +    unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; +    Node *N = make<SyntheticTemplateParamName>(Kind, Index); +    if (N) TemplateParams.back()->push_back(N); +    return N; +  }; + +  if (consumeIf("Ty")) { +    Node *Name = InventTemplateParamName(TemplateParamKind::Type); +    if (!Name) +      return nullptr; +    return make<TypeTemplateParamDecl>(Name); +  } + +  if (consumeIf("Tn")) { +    Node *Name = InventTemplateParamName(TemplateParamKind::NonType); +    if (!Name) +      return nullptr; +    Node *Type = parseType(); +    if (!Type) +      return nullptr; +    return make<NonTypeTemplateParamDecl>(Name, Type); +  } + +  if (consumeIf("Tt")) { +    Node *Name = InventTemplateParamName(TemplateParamKind::Template); +    if (!Name) +      return nullptr; +    size_t ParamsBegin = Names.size(); +    ScopedTemplateParamList TemplateTemplateParamParams(this); +    while (!consumeIf("E")) { +      Node *P = parseTemplateParamDecl(); +      if (!P) +        return nullptr; +      Names.push_back(P); +    } +    NodeArray Params = popTrailingNodeArray(ParamsBegin); +    return make<TemplateTemplateParamDecl>(Name, Params); +  } + +  if (consumeIf("Tp")) { +    Node *P = parseTemplateParamDecl(); +    if (!P) +      return nullptr; +    return make<TemplateParamPackDecl>(P); +  } + +  return nullptr; +} + +// <template-arg> ::= <type>                    # type or template +//                ::= X <expression> E          # expression +//                ::= <expr-primary>            # simple expressions +//                ::= J <template-arg>* E       # argument pack +//                ::= LZ <encoding> E           # extension +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() { +  switch (look()) { +  case 'X': { +    ++First; +    Node *Arg = getDerived().parseExpr(); +    if (Arg == nullptr || !consumeIf('E')) +      return nullptr; +    return Arg; +  } +  case 'J': { +    ++First; +    size_t ArgsBegin = Names.size(); +    while (!consumeIf('E')) { +      Node *Arg = getDerived().parseTemplateArg(); +      if (Arg == nullptr) +        return nullptr; +      Names.push_back(Arg); +    } +    NodeArray Args = popTrailingNodeArray(ArgsBegin); +    return make<TemplateArgumentPack>(Args); +  } +  case 'L': { +    //                ::= LZ <encoding> E           # extension +    if (look(1) == 'Z') { +      First += 2; +      Node *Arg = getDerived().parseEncoding(); +      if (Arg == nullptr || !consumeIf('E')) +        return nullptr; +      return Arg; +    } +    //                ::= <expr-primary>            # simple expressions +    return getDerived().parseExprPrimary(); +  } +  default: +    return getDerived().parseType(); +  } +} + +// <template-args> ::= I <template-arg>* E +//     extension, the abi says <template-arg>+ +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { +  if (!consumeIf('I')) +    return nullptr; + +  // <template-params> refer to the innermost <template-args>. Clear out any +  // outer args that we may have inserted into TemplateParams. +  if (TagTemplates) { +    TemplateParams.clear(); +    TemplateParams.push_back(&OuterTemplateParams); +    OuterTemplateParams.clear(); +  } + +  size_t ArgsBegin = Names.size(); +  while (!consumeIf('E')) { +    if (TagTemplates) { +      auto OldParams = std::move(TemplateParams); +      Node *Arg = getDerived().parseTemplateArg(); +      TemplateParams = std::move(OldParams); +      if (Arg == nullptr) +        return nullptr; +      Names.push_back(Arg); +      Node *TableEntry = Arg; +      if (Arg->getKind() == Node::KTemplateArgumentPack) { +        TableEntry = make<ParameterPack>( +            static_cast<TemplateArgumentPack*>(TableEntry)->getElements()); +        if (!TableEntry) +          return nullptr; +      } +      TemplateParams.back()->push_back(TableEntry); +    } else { +      Node *Arg = getDerived().parseTemplateArg(); +      if (Arg == nullptr) +        return nullptr; +      Names.push_back(Arg); +    } +  } +  return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); +} + +// <mangled-name> ::= _Z <encoding> +//                ::= <type> +// extension      ::= ___Z <encoding> _block_invoke +// extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+ +// extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+ +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parse() { +  if (consumeIf("_Z") || consumeIf("__Z")) { +    Node *Encoding = getDerived().parseEncoding(); +    if (Encoding == nullptr) +      return nullptr; +    if (look() == '.') { +      Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); +      First = Last; +    } +    if (numLeft() != 0) +      return nullptr; +    return Encoding; +  } + +  if (consumeIf("___Z") || consumeIf("____Z")) { +    Node *Encoding = getDerived().parseEncoding(); +    if (Encoding == nullptr || !consumeIf("_block_invoke")) +      return nullptr; +    bool RequireNumber = consumeIf('_'); +    if (parseNumber().empty() && RequireNumber) +      return nullptr; +    if (look() == '.') +      First = Last; +    if (numLeft() != 0) +      return nullptr; +    return make<SpecialName>("invocation function for block in ", Encoding); +  } + +  Node *Ty = getDerived().parseType(); +  if (numLeft() != 0) +    return nullptr; +  return Ty; +} + +template <typename Alloc> +struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> { +  using AbstractManglingParser<ManglingParser<Alloc>, +                               Alloc>::AbstractManglingParser; +}; + +DEMANGLE_NAMESPACE_END + +#endif // DEMANGLE_ITANIUMDEMANGLE_H diff --git a/externals/demangle/LICENSE.TXT b/externals/demangle/LICENSE.TXT new file mode 100644 index 000000000..fa6ac5400 --- /dev/null +++ b/externals/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/externals/demangle/StringView.h b/externals/demangle/StringView.h new file mode 100644 index 000000000..c9848e46d --- /dev/null +++ b/externals/demangle/StringView.h @@ -0,0 +1,127 @@ +//===--- StringView.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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// FIXME: Use std::string_view instead when we support C++17. +// +//===----------------------------------------------------------------------===// + +#ifndef DEMANGLE_STRINGVIEW_H +#define DEMANGLE_STRINGVIEW_H + +#include "DemangleConfig.h" +#include <algorithm> +#include <cassert> +#include <cstring> + +DEMANGLE_NAMESPACE_BEGIN + +class StringView { +  const char *First; +  const char *Last; + +public: +  static const size_t npos = ~size_t(0); + +  template <size_t N> +  StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} +  StringView(const char *First_, const char *Last_) +      : First(First_), Last(Last_) {} +  StringView(const char *First_, size_t Len) +      : First(First_), Last(First_ + Len) {} +  StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} +  StringView() : First(nullptr), Last(nullptr) {} + +  StringView substr(size_t From) const { +    return StringView(begin() + From, size() - From); +  } + +  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()) { +      // Just forward to memchr, which is faster than a hand-rolled loop. +      if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) +        return size_t(static_cast<const char *>(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(); +    return StringView(First + N, Last); +  } + +  StringView dropBack(size_t N = 1) const { +    if (N >= size()) +      N = size(); +    return StringView(First, Last - N); +  } + +  char front() const { +    assert(!empty()); +    return *begin(); +  } + +  char back() const { +    assert(!empty()); +    return *(end() - 1); +  } + +  char popFront() { +    assert(!empty()); +    return *First++; +  } + +  bool consumeFront(char C) { +    if (!startsWith(C)) +      return false; +    *this = dropFront(1); +    return true; +  } + +  bool consumeFront(StringView S) { +    if (!startsWith(S)) +      return false; +    *this = dropFront(S.size()); +    return true; +  } + +  bool startsWith(char C) const { return !empty() && *begin() == C; } + +  bool startsWith(StringView Str) const { +    if (Str.size() > size()) +      return false; +    return std::equal(Str.begin(), Str.end(), begin()); +  } + +  const char &operator[](size_t Idx) const { return *(begin() + Idx); } + +  const char *begin() const { return First; } +  const char *end() const { return Last; } +  size_t size() const { return static_cast<size_t>(Last - First); } +  bool empty() const { return First == Last; } +}; + +inline bool operator==(const StringView &LHS, const StringView &RHS) { +  return LHS.size() == RHS.size() && +         std::equal(LHS.begin(), LHS.end(), RHS.begin()); +} + +DEMANGLE_NAMESPACE_END + +#endif diff --git a/externals/demangle/Utility.h b/externals/demangle/Utility.h new file mode 100644 index 000000000..d98ad5c0b --- /dev/null +++ b/externals/demangle/Utility.h @@ -0,0 +1,192 @@ +//===--- 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-FileCopyrightText: Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// 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 <cstdint> +#include <cstdlib> +#include <cstring> +#include <iterator> +#include <limits> + +DEMANGLE_NAMESPACE_BEGIN + +// Stream that AST nodes write their string representation into after the AST +// has been parsed. +class OutputStream { +  char *Buffer; +  size_t CurrentPosition; +  size_t BufferCapacity; + +  // 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<char *>(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<unsigned>::max(); +  unsigned CurrentPackMax = std::numeric_limits<unsigned>::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<unsigned long long>(-N), true); +    else +      writeUnsigned(static_cast<unsigned long long>(N)); +    return *this; +  } + +  OutputStream &operator<<(unsigned long long N) { +    writeUnsigned(N, false); +    return *this; +  } + +  OutputStream &operator<<(long N) { +    return this->operator<<(static_cast<long long>(N)); +  } + +  OutputStream &operator<<(unsigned long N) { +    return this->operator<<(static_cast<unsigned long long>(N)); +  } + +  OutputStream &operator<<(int N) { +    return this->operator<<(static_cast<long long>(N)); +  } + +  OutputStream &operator<<(unsigned int N) { +    return this->operator<<(static_cast<unsigned long long>(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() { return BufferCapacity; } +}; + +template <class T> 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<char *>(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/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 45332cf95..57eec57b5 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(common STATIC      common_precompiled_headers.h      common_types.h      concepts.h +    demangle.h      div_ceil.h      dynamic_library.cpp      dynamic_library.h @@ -175,7 +176,7 @@ endif()  create_target_directory_groups(common)  target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads) -target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd) +target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd demangle)  if (YUZU_USE_PRECOMPILED_HEADERS)      target_precompile_headers(common PRIVATE precompiled_headers.h) diff --git a/src/common/demangle.h b/src/common/demangle.h new file mode 100644 index 000000000..1c4143629 --- /dev/null +++ b/src/common/demangle.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <string> + +namespace llvm { +char* itaniumDemangle(const char* mangled_name, char* buf, size_t* n, int* status); +} + +namespace Common { +std::string DemangleSymbol(const std::string& mangled) { +    auto is_itanium = [](const std::string& name) -> bool { +        // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'. +        auto pos = name.find_first_not_of('_'); +        return pos > 0 && pos <= 4 && name[pos] == 'Z'; +    }; + +    char* demangled = nullptr; +    if (is_itanium(mangled)) { +        demangled = llvm::itaniumDemangle(mangled.c_str(), nullptr, nullptr, nullptr); +    } + +    if (!demangled) { +        return mangled; +    } + +    std::string ret = demangled; +    std::free(demangled); +    return ret; +} +} // namespace Common
\ No newline at end of file diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 2df7b0ee8..a34200539 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -7,8 +7,10 @@  #include <map>  #include <optional> +  #include "common/bit_field.h"  #include "common/common_types.h" +#include "common/demangle.h"  #include "common/logging/log.h"  #include "core/arm/arm_interface.h"  #include "core/arm/symbols.h" @@ -71,20 +73,8 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt          const auto symbol_set = symbols.find(entry.module);          if (symbol_set != symbols.end()) {              const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); -            if (symbol.has_value()) { -#ifdef _MSC_VER -                // TODO(DarkLordZach): Add demangling of symbol names. -                entry.name = *symbol; -#else -                int status{-1}; -                char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)}; -                if (status == 0 && demangled != nullptr) { -                    entry.name = demangled; -                    std::free(demangled); -                } else { -                    entry.name = *symbol; -                } -#endif +            if (symbol) { +                entry.name = Common::DemangleSymbol(*symbol);              }          }      } | 
