From 16a883200c2ec46034af4011b811df52e484b015 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 19 May 2020 16:36:04 -0400 Subject: [PATCH 01/42] tweak releasing doc and dist.py in minor ways --- RELEASING | 10 +++++----- dist.py | 16 +++++++++------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/RELEASING b/RELEASING index d799f1b..8f1c700 100644 --- a/RELEASING +++ b/RELEASING @@ -1,13 +1,13 @@ Push new release branch: 1. make sure branches 'master' and 'release' are synced up locally -2. update demumble.cc with new version (with ".git"), then +2. update kDemumbleVersion in demumble.cc with new version (with ".git"), then git commit -am 'mark this 1.0.0.git' 3. git checkout release; git merge master -4. fix version number in src/version.cc (it will likely conflict in the above) -5. commit, tag, push (don't forget to push --tags) +4. fix version number in src/version.cc (it will conflict in the above) +5. commit, tag, push (don't forget to push --tags), build binaries git commit -am v1.0.0; git push origin release git tag v1.0.0; git push --tags + ./dist.py # on the 'release' branch # Push the 1.0.0.git change on master too: git checkout master; git push origin master -6. add binaries to https://github.com/nico/demumble/releases - build them with `./dist.py` (on the release branch) +6. add demumble-{linux,mac,win}.zip to https://github.com/nico/demumble/releases diff --git a/dist.py b/dist.py index b1be851..b88b8bf 100755 --- a/dist.py +++ b/dist.py @@ -9,13 +9,13 @@ # Also needs a GN build of llvm at ~/src/llvm-project/out/gn for llvm-strip # for stripping the Linux binary. -# Doesn't run tests, so make sure to run `./demumble_test.py` on all 3 platforms -# before running this script. +# Run this in the demumble root directory while on the "release" branch. +# It'll create subcirectories "buildlinux", "buildmac", "buildwin" to build +# for each platforms, and then puts the final built products in +# demumble-{linux,mac,win}.zip. -# After this script finishes successfully, the cwd will contain -# demumble-mac.zip, demumble-linux.zip, demumble-windows.zip which each contain -# a demumble binary built for that OS, ready for releasing (assuming the script -# was run on the release branch). +# Runs demumble_test.py on mac at the end, but best make sure it passes on +# on all 3 platforms before running this script. # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/CrossCompiling has # some documentation on cross builds with cmake. @@ -58,7 +58,9 @@ def buildir(newdir): os.chdir(prevdir) subprocess.check_call(['rm', '-rf', 'buildlinux', 'buildmac', 'buildwin']) -devnull = open(os.devnull,"w") +subprocess.check_call( + ['rm', '-f', 'demumble-linux.zip', 'demumble-mac.zip', 'demumble-win.zip']) +devnull = open(os.devnull, 'w') # Linux. linux_sysroot = crsrc + '/build/linux/debian_sid_amd64-sysroot' From 819793fb1726ebcf61cf69659c0e9f1a55d4f49a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 13 Jun 2019 11:53:08 -0400 Subject: [PATCH 02/42] fix a -Wsign-compare warning --- demumble.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demumble.cc b/demumble.cc index 3d282bc..168f141 100644 --- a/demumble.cc +++ b/demumble.cc @@ -68,7 +68,7 @@ int main(int argc, char* argv[]) { ++argv; break; } else if (argv[1][0] == '-' && argv[1][1] != '-') { - for (int i = 1; i < strlen(argv[1]); ++i) + for (size_t i = 1; i < strlen(argv[1]); ++i) switch (argv[1][i]) { case 'b': print_format = "\"%s\" (%s)"; break; case 'h': return print_help(stdout); From 5ac2b708d9dbd60ef0529c5b90ef8a64a13bfbaf Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 1 Jul 2020 10:50:27 -0400 Subject: [PATCH 03/42] Update LLVM lib/Demangle from 1c1fb359 to 679d101e And update caller to match. Only change: microsoftDemangle() now has an n_read out param, which we for now set to NULL. This makes it possible to eventually fix #10. Ran: cp ~/src/llvm-project/llvm/include/llvm/Demangle/*.h third_party/llvm/include/llvm/Demangle/ cp ~/src/llvm-project/llvm/lib/Demangle/*.cpp third_party/llvm/lib/Demangle/ cp ~/src/llvm-project/llvm/LICENSE.TXT third_party/llvm/LICENSE.txt --- demumble.cc | 2 +- .../llvm/include/llvm/Demangle/Demangle.h | 16 +++++++++++++++- third_party/llvm/lib/Demangle/Demangle.cpp | 4 ++-- .../llvm/lib/Demangle/MicrosoftDemangle.cpp | 7 +++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/demumble.cc b/demumble.cc index 168f141..1cbcd9c 100644 --- a/demumble.cc +++ b/demumble.cc @@ -26,7 +26,7 @@ static void print_demangled(const char* format, const char* s) { if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) { printf(format, itanium, s); free(itanium); - } else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL)) { + } else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL, NULL)) { printf(format, ms, s); free(ms); } else { diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h index 7b85b9a..b4006a0 100644 --- a/third_party/llvm/include/llvm/Demangle/Demangle.h +++ b/third_party/llvm/include/llvm/Demangle/Demangle.h @@ -40,7 +40,21 @@ enum MSDemangleFlags { MSDF_NoReturnType = 1 << 3, MSDF_NoMemberType = 1 << 4, }; -char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n, + +/// Demangles the Microsoft symbol pointed at by mangled_name and returns it. +/// Returns a pointer to the start of a null-terminated demangled string on +/// success, or nullptr on error. +/// If n_read is non-null and demangling was successful, it receives how many +/// bytes of the input string were consumed. +/// buf can point to a *n_buf bytes large buffer where the demangled name is +/// stored. If the buffer is too small, it is grown with realloc(). If buf is +/// nullptr, then this malloc()s memory for the result. +/// *n_buf stores the size of buf on input if buf is non-nullptr, and it +/// receives the size of the demangled string on output if n_buf is not nullptr. +/// status receives one of the demangle_ enum entries above if it's not nullptr. +/// Flags controls various details of the demangled representation. +char *microsoftDemangle(const char *mangled_name, size_t *n_read, + char *buf, size_t *n_buf, int *status, MSDemangleFlags Flags = MSDF_None); /// Attempt to demangle a string using different demangling schemes. diff --git a/third_party/llvm/lib/Demangle/Demangle.cpp b/third_party/llvm/lib/Demangle/Demangle.cpp index 5f92153..71dafa0 100644 --- a/third_party/llvm/lib/Demangle/Demangle.cpp +++ b/third_party/llvm/lib/Demangle/Demangle.cpp @@ -24,8 +24,8 @@ std::string llvm::demangle(const std::string &MangledName) { if (isItaniumEncoding(MangledName)) Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); else - Demangled = - microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); + Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, + nullptr, nullptr); if (!Demangled) return MangledName; diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index c681d6e..1607431 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -2334,14 +2334,16 @@ void Demangler::dumpBackReferences() { std::printf("\n"); } -char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N, +char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, + char *Buf, size_t *N, int *Status, MSDemangleFlags Flags) { - int InternalStatus = demangle_success; Demangler D; OutputStream S; StringView Name{MangledName}; SymbolNode *AST = D.parse(Name); + if (!D.Error && NMangled) + *NMangled = Name.begin() - MangledName; if (Flags & MSDF_DumpBackrefs) D.dumpBackReferences(); @@ -2356,6 +2358,7 @@ char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N, if (Flags & MSDF_NoMemberType) OF = OutputFlags(OF | OF_NoMemberType); + int InternalStatus = demangle_success; if (D.Error) InternalStatus = demangle_invalid_mangled_name; else if (!initializeOutputStream(Buf, N, S, 1024)) From 4bbc2242b52695e87b7520638f031cf12dc4fc8b Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 1 Jul 2020 11:02:46 -0400 Subject: [PATCH 04/42] Don't silently omit suffices on ms symbols Fixes #10. --- demumble.cc | 14 +++++++++----- demumble_test.py | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/demumble.cc b/demumble.cc index 1cbcd9c..9ee19df 100644 --- a/demumble.cc +++ b/demumble.cc @@ -22,11 +22,11 @@ static int print_help(FILE* out) { return out == stdout ? 0 : 1; } -static void print_demangled(const char* format, const char* s) { +static void print_demangled(const char* format, const char* s, size_t* n_used) { if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) { printf(format, itanium, s); free(itanium); - } else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL, NULL)) { + } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL, NULL, NULL)) { printf(format, ms, s); free(ms); } else { @@ -87,8 +87,11 @@ int main(int argc, char* argv[]) { ++argv; } for (int i = 1; i < argc; ++i) { - print_demangled(print_format, argv[i]); + size_t used = strlen(argv[i]); + print_demangled(print_format, argv[i], &used); printf("\n"); + if (used < strlen(argv[i])) + printf(" unused suffix: %s\n", argv[i] + used); } if (argc == 1) { // Read stdin instead. // By default, don't demangle types. Mangled function names are unlikely @@ -127,11 +130,12 @@ int main(int argc, char* argv[]) { char tmp = cur[n_sym]; cur[n_sym] = '\0'; - print_demangled(print_format, cur); + size_t n_used = n_sym; + print_demangled(print_format, cur, &n_used); need_separator = true; cur[n_sym] = tmp; - cur += n_sym; + cur += n_used; } } } diff --git a/demumble_test.py b/demumble_test.py index 2a6d9ab..ee80153 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -40,6 +40,9 @@ ('demumble < _ZZ3fooiENK3$_0clEi', 'foo(int)::$_0::operator()(int) const\n'), ('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"), + ('demumble < asdf?x@@3HAjkl', 'asdfint xjkl\n'), + ('demumble < asdf?x@@3Hjkl', 'asdf?x@@3Hjkl\n'), + ('demumble ?x@@3HAjkl', 'int x\n unused suffix: jkl\n'), ] status = 0 From 465d9460261a93061b0d06c1035e95100e84e6b0 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 1 Jul 2020 11:05:33 -0400 Subject: [PATCH 05/42] Replace 'OS X' with 'macOS' in readme and comments --- README.md | 4 ++-- demumble_test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4e1af91..53376ab 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ It has several nice features that c++filt lacks (and lacks many of c++filt's features I never use). Smart about underscores: C++ symbols have an additional leading underscore on -OS X. `operator new` is mangled as `_Znw` on Linux but `__Znw` on Mac. OS X's +macOS. `operator new` is mangled as `_Znw` on Linux but `__Znw` on Mac. macOS's c++filt automatically strips one leading underscore, but Linux's c++filt -doesn't. So if you want to demangle a Linux symbol on OS X, you need to pass +doesn't. So if you want to demangle a Linux symbol on macOS, you need to pass `-n` to tell it to not strip the underscore, and if you want to demangle an OS X symbol on Linux you likewise need to pass `-_`. demumble just does the right thing: diff --git a/demumble_test.py b/demumble_test.py index ee80153..f3c060e 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -9,7 +9,7 @@ ('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), ('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), ('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), - ('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for OS X) + ('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for macOS) ('demumble < __Znwi', 'operator new(int)\n'), # Also from stdin ('demumble -m hi _Z1fv ho _Z1gv', 'hi\nf()\nho\ng()\n'), ('demumble -m < hi_ho _Z1fv ho _Z1gv ?hm', 'f()\ng()\n?hm\n'), From bf688e4c73dffc5b660dda3b3d843b614d7e5316 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 8 Dec 2020 15:58:52 -0500 Subject: [PATCH 06/42] build universal binary on macOS --- dist.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dist.py b/dist.py index b88b8bf..2425aa9 100755 --- a/dist.py +++ b/dist.py @@ -84,6 +84,7 @@ def buildir(newdir): print 'building mac' subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangxx, + '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64', ], stdout=devnull) subprocess.check_call(['ninja', 'demumble']) subprocess.check_call(['strip', 'demumble']) From 282b288f4e539a698f9a28c48c9fa4dc0ade9816 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 8 Dec 2020 16:00:15 -0500 Subject: [PATCH 07/42] Move to C++14 Fixes #13. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd35e5b..84c34f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,5 +37,5 @@ add_executable(demumble third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp ) -set_target_properties(demumble PROPERTIES CXX_STANDARD 11 +set_target_properties(demumble PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON) From 4573f4c3671ca48039484d80086cdac32179b93a Mon Sep 17 00:00:00 2001 From: Yifei Teng Date: Sat, 31 Jul 2021 17:58:54 -0700 Subject: [PATCH 08/42] Update LLVM lib/Demangle to 87039c048c0cbc3d8cbba86187269b006bf2f373 This adds support for demangling Rust symbols. Added two simple test cases for demangling Rust. Ran: cp ~/src/llvm-project/llvm/include/llvm/Demangle/*.h third_party/llvm/include/llvm/Demangle/ cp ~/src/llvm-project/llvm/lib/Demangle/*.cpp third_party/llvm/lib/Demangle/ cp ~/src/llvm-project/llvm/LICENSE.TXT third_party/llvm/LICENSE.txt --- CMakeLists.txt | 2 + README.md | 6 +- demumble.cc | 17 + demumble_test.py | 4 + .../llvm/include/llvm/Demangle/Compiler.h | 518 +++++++- .../llvm/include/llvm/Demangle/Demangle.h | 3 + .../include/llvm/Demangle/DemangleConfig.h | 4 +- .../include/llvm/Demangle/ItaniumDemangle.h | 249 +++- .../include/llvm/Demangle/MicrosoftDemangle.h | 6 +- .../llvm/Demangle/MicrosoftDemangleNodes.h | 18 +- .../llvm/include/llvm/Demangle/StringView.h | 17 +- .../llvm/include/llvm/Demangle/Utility.h | 6 +- third_party/llvm/lib/Demangle/Demangle.cpp | 9 +- .../llvm/lib/Demangle/MicrosoftDemangle.cpp | 4 + .../lib/Demangle/MicrosoftDemangleNodes.cpp | 11 +- .../llvm/lib/Demangle/RustDemangle.cpp | 1127 +++++++++++++++++ 16 files changed, 1891 insertions(+), 110 deletions(-) create mode 100644 third_party/llvm/lib/Demangle/RustDemangle.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 84c34f2..33b29a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,9 +33,11 @@ endif() include_directories(third_party/llvm/include) add_executable(demumble demumble.cc + third_party/llvm/lib/Demangle/Demangle.cpp third_party/llvm/lib/Demangle/ItaniumDemangle.cpp third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp + third_party/llvm/lib/Demangle/RustDemangle.cpp ) set_target_properties(demumble PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON) diff --git a/README.md b/README.md index 53376ab..ba795c5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # demumble -`demumble` demangles both Itanium and Visual Studio symbols. It runs on both -POSIX and Windows. +`demumble` demangles both Itanium, Rust, and Visual Studio symbols. It runs on +both POSIX and Windows. $ demumble _Z4funcPci func(char*, int) $ demumble '?Fx_i@@YAHP6AHH@Z@Z' int __cdecl Fx_i(int (__cdecl *)(int)) - + ## Download There are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the diff --git a/demumble.cc b/demumble.cc index 9ee19df..358efe1 100644 --- a/demumble.cc +++ b/demumble.cc @@ -26,6 +26,9 @@ static void print_demangled(const char* format, const char* s, size_t* n_used) { if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) { printf(format, itanium, s); free(itanium); + } else if (char* rust = llvm::rustDemangle(s, NULL, NULL, NULL)) { + printf(format, rust, s); + free(rust); } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL, NULL, NULL)) { printf(format, ms, s); free(ms); @@ -39,6 +42,12 @@ static bool is_mangle_char_itanium(char c) { (c >= '0' && c <= '9') || c == '_' || c == '$'; } +static bool is_mangle_char_rust(char c) { + // See https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html. + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '_'; +} + static bool is_mangle_char_win(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strchr("?_@$", c); @@ -53,6 +62,11 @@ static bool is_plausible_itanium_prefix(char* s) { return strstr(prefix, "_Z"); } +static bool is_plausible_rust_prefix(char* s) { + // Rust symbols start with "_R". + return s[0] == '_' && s[1] == 'R'; +} + static char buf[8192]; int main(int argc, char* argv[]) { enum { kPrintAll, kPrintMatching } print_mode = kPrintAll; @@ -121,6 +135,9 @@ int main(int argc, char* argv[]) { else if (is_plausible_itanium_prefix(cur)) while (cur + n_sym != end && is_mangle_char_itanium(cur[n_sym])) ++n_sym; + else if (is_plausible_rust_prefix(cur)) + while (cur + n_sym != end && is_mangle_char_rust(cur[n_sym])) + ++n_sym; else { if (print_mode == kPrintAll) printf("_"); diff --git a/demumble_test.py b/demumble_test.py index f3c060e..a7b8d83 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -6,6 +6,10 @@ ('demumble hello', 'hello\n'), ('demumble _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'), ('demumble < _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'), + ('demumble _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar', + 'std::mem::align_of::\nmylib::foo::bar\n'), + ('demumble < _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar', + 'std::mem::align_of::\nmylib::foo::bar\n'), ('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), ('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), ('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), diff --git a/third_party/llvm/include/llvm/Demangle/Compiler.h b/third_party/llvm/include/llvm/Demangle/Compiler.h index 248d6e3..c17ff4c 100644 --- a/third_party/llvm/include/llvm/Demangle/Compiler.h +++ b/third_party/llvm/include/llvm/Demangle/Compiler.h @@ -14,40 +14,125 @@ #ifndef LLVM_DEMANGLE_COMPILER_H #define LLVM_DEMANGLE_COMPILER_H -#ifdef _MSC_VER -// snprintf is implemented in VS 2015 -#if _MSC_VER < 1900 -#define snprintf _snprintf_s +#ifdef __cplusplus +#include #endif +#include + +#if defined(_MSC_VER) +#include #endif #ifndef __has_feature -#define __has_feature(x) 0 +# define __has_feature(x) 0 #endif -#ifndef __has_cpp_attribute -#define __has_cpp_attribute(x) 0 +#ifndef __has_extension +# define __has_extension(x) 0 #endif #ifndef __has_attribute -#define __has_attribute(x) 0 +# define __has_attribute(x) 0 #endif #ifndef __has_builtin -#define __has_builtin(x) 0 +# define __has_builtin(x) 0 #endif +// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in +// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid. +#ifndef LLVM_HAS_CPP_ATTRIBUTE +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define LLVM_HAS_CPP_ATTRIBUTE(x) 0 +#endif +#endif + +/// \macro LLVM_GNUC_PREREQ +/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't +/// available. #ifndef LLVM_GNUC_PREREQ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -#define LLVM_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ - ((maj) << 20) + ((min) << 10) + (patch)) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) -#define LLVM_GNUC_PREREQ(maj, min, patch) \ - ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ + ((maj) << 20) + ((min) << 10) + (patch)) +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +# else +# define LLVM_GNUC_PREREQ(maj, min, patch) 0 +# endif +#endif + +/// \macro LLVM_MSC_PREREQ +/// Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1910: VS2017, version 15.1 & 15.2 +/// * 1911: VS2017, version 15.3 & 15.4 +/// * 1912: VS2017, version 15.5 +/// * 1913: VS2017, version 15.6 +/// * 1914: VS2017, version 15.7 +/// * 1915: VS2017, version 15.8 +/// * 1916: VS2017, version 15.9 +/// * 1920: VS2019, version 16.0 +/// * 1921: VS2019, version 16.1 +#ifdef _MSC_VER +#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version)) + +// We require at least MSVC 2017. +#if !LLVM_MSC_PREREQ(1910) +#error LLVM requires at least MSVC 2017. +#endif + +#else +#define LLVM_MSC_PREREQ(version) 0 +#endif + +/// Does the compiler support ref-qualifiers for *this? +/// +/// Sadly, this is separate from just rvalue reference support because GCC +/// and MSVC implemented this later than everything else. This appears to be +/// corrected in MSVC 2019 but not MSVC 2017. +#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \ + LLVM_MSC_PREREQ(1920) +#define LLVM_HAS_RVALUE_REFERENCE_THIS 1 +#else +#define LLVM_HAS_RVALUE_REFERENCE_THIS 0 +#endif + +/// Expands to '&' if ref-qualifiers for *this are supported. +/// +/// This can be used to provide lvalue/rvalue overrides of member functions. +/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS +#if LLVM_HAS_RVALUE_REFERENCE_THIS +#define LLVM_LVALUE_FUNCTION & #else -#define LLVM_GNUC_PREREQ(maj, min, patch) 0 +#define LLVM_LVALUE_FUNCTION #endif + +/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked +/// into a shared library, then the class should be private to the library and +/// not accessible from outside it. Can also be used to mark variables and +/// functions, making them private to any shared library they are linked into. +/// On PE/COFF targets, library visibility is the default, so this isn't needed. +/// +/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with +/// this attribute will be made public and visible outside of any shared library +/// they are linked in to. +#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ + !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32) +#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) +#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default"))) +#else +#define LLVM_LIBRARY_VISIBILITY +#define LLVM_EXTERNAL_VISIBILITY +#endif + +#if defined(__GNUC__) +#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality) +#else +#define LLVM_PREFETCH(addr, rw, locality) #endif #if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0) @@ -56,12 +141,84 @@ #define LLVM_ATTRIBUTE_USED #endif -#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0) -#define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -#define LLVM_BUILTIN_UNREACHABLE __assume(false) +/// LLVM_NODISCARD - Warn if a type or return value is discarded. + +// Use the 'nodiscard' attribute in C++17 or newer mode. +#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) +#define LLVM_NODISCARD [[nodiscard]] +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result) +#define LLVM_NODISCARD [[clang::warn_unused_result]] +// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also +// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518). +// Use the 'nodiscard' attribute in C++14 mode only with GCC. +// TODO: remove this workaround when PR33518 is resolved. +#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard) +#define LLVM_NODISCARD [[nodiscard]] +#else +#define LLVM_NODISCARD +#endif + +// Indicate that a non-static, non-const C++ member function reinitializes +// the entire object to a known state, independent of the previous state of +// the object. +// +// The clang-tidy check bugprone-use-after-move recognizes this attribute as a +// marker that a moved-from object has left the indeterminate state and can be +// reused. +#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes) +#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define LLVM_ATTRIBUTE_REINITIALIZES +#endif + +// Some compilers warn about unused functions. When a function is sometimes +// used or not depending on build settings (e.g. a function only called from +// within "assert"), this attribute can be used to suppress such warnings. +// +// However, it shouldn't be used for unused *variables*, as those have a much +// more portable solution: +// (void)unused_var_name; +// Prefer cast-to-void wherever it is sufficient. +#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0) +#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define LLVM_ATTRIBUTE_UNUSED #endif +// FIXME: Provide this for PE/COFF targets. +#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \ + (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)) +#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__)) +#else +#define LLVM_ATTRIBUTE_WEAK +#endif + +// Prior to clang 3.2, clang did not accept any spelling of +// __has_attribute(const), so assume it is supported. +#if defined(__clang__) || defined(__GNUC__) +// aka 'CONST' but following LLVM Conventions. +#define LLVM_READNONE __attribute__((__const__)) +#else +#define LLVM_READNONE +#endif + +#if __has_attribute(pure) || defined(__GNUC__) +// aka 'PURE' but following LLVM Conventions. +#define LLVM_READONLY __attribute__((__pure__)) +#else +#define LLVM_READONLY +#endif + +#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0) +#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) +#else +#define LLVM_LIKELY(EXPR) (EXPR) +#define LLVM_UNLIKELY(EXPR) (EXPR) +#endif + +/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, +/// mark a method "not for inlining". #if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0) #define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) @@ -70,24 +227,323 @@ #define LLVM_ATTRIBUTE_NOINLINE #endif -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED +/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do +/// so, mark a method "always inline" because it is performance sensitive. GCC +/// 3.4 supported this but is buggy in various cases and produces unimplemented +/// errors, just use it in GCC 4.0 and later. +#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline #else -#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE +#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline #endif -#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough) +#ifdef __GNUC__ +#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define LLVM_ATTRIBUTE_NORETURN +#endif + +#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0) +#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_ +#else +#define LLVM_ATTRIBUTE_RETURNS_NONNULL +#endif + +/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a +/// pointer that does not alias any other valid pointer. +#ifdef __GNUC__ +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) +#else +#define LLVM_ATTRIBUTE_RETURNS_NOALIAS +#endif + +/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements. +#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough) #define LLVM_FALLTHROUGH [[fallthrough]] -#elif __has_cpp_attribute(gnu::fallthrough) +#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough) #define LLVM_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 LLVM_FALLTHROUGH -#elif __has_cpp_attribute(clang::fallthrough) +#elif __has_attribute(fallthrough) +#define LLVM_FALLTHROUGH __attribute__((fallthrough)) +#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough) #define LLVM_FALLTHROUGH [[clang::fallthrough]] #else #define LLVM_FALLTHROUGH #endif +/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that +/// they are constant initialized. +#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization) +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \ + [[clang::require_constant_initialization]] +#else +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION +#endif + +/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable +/// lifetime warnings. +#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner) +#define LLVM_GSL_OWNER [[gsl::Owner]] +#else +#define LLVM_GSL_OWNER +#endif + +/// LLVM_GSL_POINTER - Apply this to non-owning classes like +/// StringRef to enable lifetime warnings. +#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer) +#define LLVM_GSL_POINTER [[gsl::Pointer]] +#else +#define LLVM_GSL_POINTER +#endif + +/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress +/// pedantic diagnostics. +#ifdef __GNUC__ +#define LLVM_EXTENSION __extension__ +#else +#define LLVM_EXTENSION +#endif + +// LLVM_ATTRIBUTE_DEPRECATED(decl, "message") +// This macro will be removed. +// Use C++14's attribute instead: [[deprecated("message")]] +#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl + +/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands +/// to an expression which states that it is undefined behavior for the +/// compiler to reach this point. Otherwise is not defined. +#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0) +# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +# define LLVM_BUILTIN_UNREACHABLE __assume(false) +#endif + +/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression +/// which causes the program to exit abnormally. +#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0) +# define LLVM_BUILTIN_TRAP __builtin_trap() +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC, does not require forward +// declarations involving platform-specific typedefs (unlike RaiseException), +// results in a call to vectored exception handlers, and encodes to a short +// instruction that still causes the trapping behavior we want. +# define LLVM_BUILTIN_TRAP __debugbreak() +#else +# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0 +#endif + +/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to +/// an expression which causes the program to break while running +/// under a debugger. +#if __has_builtin(__builtin_debugtrap) +# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap() +#elif defined(_MSC_VER) +// The __debugbreak intrinsic is supported by MSVC and breaks while +// running under the debugger, and also supports invoking a debugger +// when the OS is configured appropriately. +# define LLVM_BUILTIN_DEBUGTRAP __debugbreak() +#else +// Just continue execution when built with compilers that have no +// support. This is a debugging aid and not intended to force the +// program to abort if encountered. +# define LLVM_BUILTIN_DEBUGTRAP +#endif + +/// \macro LLVM_ASSUME_ALIGNED +/// Returns a pointer with an assumed alignment. +#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0) +# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a) +#elif defined(LLVM_BUILTIN_UNREACHABLE) +# define LLVM_ASSUME_ALIGNED(p, a) \ + (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p))) +#else +# define LLVM_ASSUME_ALIGNED(p, a) (p) +#endif + +/// \macro LLVM_PACKED +/// Used to specify a packed structure. +/// LLVM_PACKED( +/// struct A { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }); +/// +/// LLVM_PACKED_START +/// struct B { +/// int i; +/// int j; +/// int k; +/// long long l; +/// }; +/// LLVM_PACKED_END +#ifdef _MSC_VER +# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop)) +# define LLVM_PACKED_START __pragma(pack(push, 1)) +# define LLVM_PACKED_END __pragma(pack(pop)) +#else +# define LLVM_PACKED(d) d __attribute__((packed)) +# define LLVM_PACKED_START _Pragma("pack(push, 1)") +# define LLVM_PACKED_END _Pragma("pack(pop)") +#endif + +/// \macro LLVM_PTR_SIZE +/// A constant integer equivalent to the value of sizeof(void*). +/// Generally used in combination with alignas or when doing computation in the +/// preprocessor. +#ifdef __SIZEOF_POINTER__ +# define LLVM_PTR_SIZE __SIZEOF_POINTER__ +#elif defined(_WIN64) +# define LLVM_PTR_SIZE 8 +#elif defined(_WIN32) +# define LLVM_PTR_SIZE 4 +#elif defined(_MSC_VER) +# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC" +#else +# define LLVM_PTR_SIZE sizeof(void *) +#endif + +/// \macro LLVM_MEMORY_SANITIZER_BUILD +/// Whether LLVM itself is built with MemorySanitizer instrumentation. +#if __has_feature(memory_sanitizer) +# define LLVM_MEMORY_SANITIZER_BUILD 1 +# include +# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory)) +#else +# define LLVM_MEMORY_SANITIZER_BUILD 0 +# define __msan_allocated_memory(p, size) +# define __msan_unpoison(p, size) +# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE +#endif + +/// \macro LLVM_ADDRESS_SANITIZER_BUILD +/// Whether LLVM itself is built with AddressSanitizer instrumentation. +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define LLVM_ADDRESS_SANITIZER_BUILD 1 +# include +#else +# define LLVM_ADDRESS_SANITIZER_BUILD 0 +# define __asan_poison_memory_region(p, size) +# define __asan_unpoison_memory_region(p, size) +#endif + +/// \macro LLVM_THREAD_SANITIZER_BUILD +/// Whether LLVM itself is built with ThreadSanitizer instrumentation. +#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +# define LLVM_THREAD_SANITIZER_BUILD 1 +#else +# define LLVM_THREAD_SANITIZER_BUILD 0 +#endif + +#if LLVM_THREAD_SANITIZER_BUILD +// Thread Sanitizer is a tool that finds races in code. +// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations . +// tsan detects these exact functions by name. +#ifdef __cplusplus +extern "C" { +#endif +void AnnotateHappensAfter(const char *file, int line, const volatile void *cv); +void AnnotateHappensBefore(const char *file, int line, const volatile void *cv); +void AnnotateIgnoreWritesBegin(const char *file, int line); +void AnnotateIgnoreWritesEnd(const char *file, int line); +#ifdef __cplusplus +} +#endif + +// This marker is used to define a happens-before arc. The race detector will +// infer an arc from the begin to the end when they share the same pointer +// argument. +# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv) + +// This marker defines the destination of a happens-before arc. +# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv) + +// Ignore any races on writes between here and the next TsanIgnoreWritesEnd. +# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__) + +// Resume checking for racy writes. +# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__) +#else +# define TsanHappensBefore(cv) +# define TsanHappensAfter(cv) +# define TsanIgnoreWritesBegin() +# define TsanIgnoreWritesEnd() +#endif + +/// \macro LLVM_NO_SANITIZE +/// Disable a particular sanitizer for a function. +#if __has_attribute(no_sanitize) +#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND))) +#else +#define LLVM_NO_SANITIZE(KIND) +#endif + +/// Mark debug helper function definitions like dump() that should not be +/// stripped from debug builds. +/// Note that you should also surround dump() functions with +/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always +/// get stripped in release builds. +// FIXME: Move this to a private config.h as it's not usable in public headers. +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED +#else +#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE +#endif + +/// \macro LLVM_PRETTY_FUNCTION +/// Gets a user-friendly looking function signature for the current scope +/// using the best available method on each platform. The exact format of the +/// resulting string is implementation specific and non-portable, so this should +/// only be used, for example, for logging or diagnostics. +#if defined(_MSC_VER) +#define LLVM_PRETTY_FUNCTION __FUNCSIG__ +#elif defined(__GNUC__) || defined(__clang__) +#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define LLVM_PRETTY_FUNCTION __func__ +#endif + +/// \macro LLVM_THREAD_LOCAL +/// A thread-local storage specifier which can be used with globals, +/// extern globals, and static globals. +/// +/// This is essentially an extremely restricted analog to C++11's thread_local +/// support. It uses thread_local if available, falling back on gcc __thread +/// if not. __thread doesn't support many of the C++11 thread_local's +/// features. You should only use this for PODs that you can statically +/// initialize to some constant value. In almost all circumstances this is most +/// appropriate for use with a pointer, integer, or small aggregation of +/// pointers and integers. +#if LLVM_ENABLE_THREADS +#if __has_feature(cxx_thread_local) || defined(_MSC_VER) +#define LLVM_THREAD_LOCAL thread_local +#else +// Clang, GCC, and other compatible compilers used __thread prior to C++11 and +// we only need the restricted functionality that provides. +#define LLVM_THREAD_LOCAL __thread +#endif +#else // !LLVM_ENABLE_THREADS +// If threading is disabled entirely, this compiles to nothing and you get +// a normal global variable. +#define LLVM_THREAD_LOCAL +#endif + +/// \macro LLVM_ENABLE_EXCEPTIONS +/// Whether LLVM is built with exception support. +#if __has_feature(cxx_exceptions) +#define LLVM_ENABLE_EXCEPTIONS 1 +#elif defined(__GNUC__) && defined(__EXCEPTIONS) +#define LLVM_ENABLE_EXCEPTIONS 1 +#elif defined(_MSC_VER) && defined(_CPPUNWIND) +#define LLVM_ENABLE_EXCEPTIONS 1 +#endif + #endif diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h index b4006a0..c396a1d 100644 --- a/third_party/llvm/include/llvm/Demangle/Demangle.h +++ b/third_party/llvm/include/llvm/Demangle/Demangle.h @@ -57,6 +57,9 @@ char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf, size_t *n_buf, int *status, MSDemangleFlags Flags = MSDF_None); +// Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. +char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); + /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. diff --git a/third_party/llvm/include/llvm/Demangle/DemangleConfig.h b/third_party/llvm/include/llvm/Demangle/DemangleConfig.h index b7b7dbd..2ff95dd 100644 --- a/third_party/llvm/include/llvm/Demangle/DemangleConfig.h +++ b/third_party/llvm/include/llvm/Demangle/DemangleConfig.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_COMPILER_H -#define LLVM_DEMANGLE_COMPILER_H +#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H +#define LLVM_DEMANGLE_DEMANGLECONFIG_H #ifndef __has_feature #define __has_feature(x) 0 diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h index dcece38..9163b71 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef DEMANGLE_ITANIUMDEMANGLE_H -#define DEMANGLE_ITANIUMDEMANGLE_H +#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H +#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H // FIXME: (possibly) incomplete list of features that clang mangles that this // file does not yet support: @@ -82,6 +82,7 @@ X(PostfixExpr) \ X(ConditionalExpr) \ X(MemberExpr) \ + X(SubobjectExpr) \ X(EnclosingExpr) \ X(CastExpr) \ X(SizeofParamPackExpr) \ @@ -91,10 +92,10 @@ X(PrefixExpr) \ X(FunctionParam) \ X(ConversionExpr) \ + X(PointerToMemberConversionExpr) \ X(InitListExpr) \ X(FoldExpr) \ X(ThrowExpr) \ - X(UUIDOfExpr) \ X(BoolExpr) \ X(StringLiteral) \ X(LambdaExpr) \ @@ -279,17 +280,20 @@ class DotSuffix final : public Node { class VendorExtQualType final : public Node { const Node *Ty; StringView Ext; + const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - template void match(Fn F) const { F(Ty, Ext); } + template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputStream &S) const override { Ty->print(S); S += " "; S += Ext; + if (TA != nullptr) + TA->print(S); } }; @@ -1656,6 +1660,40 @@ class MemberExpr : public Node { } }; +class SubobjectExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + NodeArray UnionSelectors; + bool OnePastTheEnd; + +public: + SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, + NodeArray UnionSelectors_, bool OnePastTheEnd_) + : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), + UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} + + template void match(Fn F) const { + F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); + } + + void printLeft(OutputStream &S) const override { + SubExpr->print(S); + S += ".<"; + Type->print(S); + S += " at offset "; + if (Offset.empty()) { + S += "0"; + } else if (Offset[0] == 'n') { + S += "-"; + S += Offset.dropFront(); + } else { + S += Offset; + } + S += ">"; + } +}; + class EnclosingExpr : public Node { const StringView Prefix; const Node *Infix; @@ -1843,6 +1881,28 @@ class ConversionExpr : public Node { } }; +class PointerToMemberConversionExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + +public: + PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, + StringView Offset_) + : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_), + Offset(Offset_) {} + + template void match(Fn F) const { F(Type, SubExpr, Offset); } + + void printLeft(OutputStream &S) const override { + S += "("; + Type->print(S); + S += ")("; + SubExpr->print(S); + S += ")"; + } +}; + class InitListExpr : public Node { const Node *Ty; NodeArray Inits; @@ -1977,21 +2037,6 @@ class ThrowExpr : public Node { } }; -// MSVC __uuidof extension, generated by clang in -fms-extensions mode. -class UUIDOfExpr : public Node { - Node *Operand; -public: - UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {} - - template void match(Fn F) const { F(Operand); } - - void printLeft(OutputStream &S) const override { - S << "__uuidof("; - Operand->print(S); - S << ")"; - } -}; - class BoolExpr : public Node { bool Value; @@ -2313,9 +2358,9 @@ template struct AbstractManglingParser { TemplateParamList Params; public: - ScopedTemplateParamList(AbstractManglingParser *Parser) - : Parser(Parser), - OldNumTemplateParamLists(Parser->TemplateParams.size()) { + ScopedTemplateParamList(AbstractManglingParser *TheParser) + : Parser(TheParser), + OldNumTemplateParamLists(TheParser->TemplateParams.size()) { Parser->TemplateParams.push_back(&Params); } ~ScopedTemplateParamList() { @@ -2437,6 +2482,8 @@ template struct AbstractManglingParser { Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); + Node *parsePointerToMemberConversionExpr(); + Node *parseSubobjectExpr(); /// Parse the production. Node *parseType(); @@ -3636,8 +3683,6 @@ Node *AbstractManglingParser::parseQualifiedType() { if (Qual.empty()) return nullptr; - // FIXME parse the optional here! - // extension ::= U # objc-type if (Qual.startsWith("objcproto")) { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); @@ -3655,10 +3700,17 @@ Node *AbstractManglingParser::parseQualifiedType() { return make(Child, Proto); } + Node *TA = nullptr; + if (look() == 'I') { + TA = getDerived().parseTemplateArgs(); + if (TA == nullptr) + return nullptr; + } + Node *Child = getDerived().parseQualifiedType(); if (Child == nullptr) return nullptr; - return make(Child, Qual); + return make(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); @@ -3831,7 +3883,7 @@ Node *AbstractManglingParser::parseType() { // ::= Dh # IEEE 754r half-precision floating point (16 bits) case 'h': First += 2; - return make("decimal16"); + return make("half"); // ::= Di # char32_t case 'i': First += 2; @@ -4404,6 +4456,50 @@ Node *AbstractManglingParser::parseFoldExpr() { return make(IsLeftFold, OperatorName, Pack, Init); } +// ::= mc [] E +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parsePointerToMemberConversionExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + if (!consumeIf('E')) + return nullptr; + return make(Ty, Expr, Offset); +} + +// ::= so [] * [p] E +// ::= _ [] +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parseSubobjectExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + size_t SelectorsBegin = Names.size(); + while (consumeIf('_')) { + Node *Selector = make(parseNumber()); + if (!Selector) + return nullptr; + Names.push_back(Selector); + } + bool OnePastTheEnd = consumeIf('p'); + if (!consumeIf('E')) + return nullptr; + return make( + Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); +} + // ::= // ::= // ::= @@ -4661,6 +4757,9 @@ Node *AbstractManglingParser::parseExpr() { return nullptr; case 'm': switch (First[1]) { + case 'c': + First += 2; + return parsePointerToMemberConversionExpr(); case 'i': First += 2; return getDerived().parseBinaryExpr("-"); @@ -4808,6 +4907,9 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("static_cast", T, Ex); } + case 'o': + First += 2; + return parseSubobjectExpr(); case 'p': { First += 2; Node *Child = getDerived().parseExpr(); @@ -4903,6 +5005,43 @@ Node *AbstractManglingParser::parseExpr() { } } return nullptr; + case 'u': { + ++First; + Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); + if (!Name) + return nullptr; + // Special case legacy __uuidof mangling. The 't' and 'z' appear where the + // standard encoding expects a , and would be otherwise be + // interpreted as node 'short' or 'ellipsis'. However, neither + // __uuidof(short) nor __uuidof(...) can actually appear, so there is no + // actual conflict here. + if (Name->getBaseName() == "__uuidof") { + if (numLeft() < 2) + return nullptr; + if (*First == 't') { + ++First; + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + return make(Name, makeNodeArray(&Ty, &Ty + 1)); + } + if (*First == 'z') { + ++First; + Node *Ex = getDerived().parseExpr(); + if (!Ex) + return nullptr; + return make(Name, makeNodeArray(&Ex, &Ex + 1)); + } + } + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseTemplateArg(); + if (E == nullptr) + return E; + Names.push_back(E); + } + return make(Name, popTrailingNodeArray(ExprsBegin)); + } case '1': case '2': case '3': @@ -4914,21 +5053,6 @@ Node *AbstractManglingParser::parseExpr() { case '9': return getDerived().parseUnresolvedName(); } - - if (consumeIf("u8__uuidoft")) { - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - return make(Ty); - } - - if (consumeIf("u8__uuidofz")) { - Node *Ex = getDerived().parseExpr(); - if (!Ex) - return nullptr; - return make(Ex); - } - return nullptr; } @@ -4975,6 +5099,16 @@ Node *AbstractManglingParser::parseSpecialName() { switch (look()) { case 'T': switch (look(1)) { + // TA # template parameter object + // + // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63 + case 'A': { + First += 2; + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + return make("template parameter object for ", Arg); + } // TV # virtual table case 'V': { First += 2; @@ -5096,6 +5230,26 @@ Node *AbstractManglingParser::parseSpecialName() { // ::= template Node *AbstractManglingParser::parseEncoding() { + // The template parameters of an encoding are unrelated to those of the + // enclosing context. + class SaveTemplateParams { + AbstractManglingParser *Parser; + decltype(TemplateParams) OldParams; + decltype(OuterTemplateParams) OldOuterParams; + + public: + SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { + OldParams = std::move(Parser->TemplateParams); + OldOuterParams = std::move(Parser->OuterTemplateParams); + Parser->TemplateParams.clear(); + Parser->OuterTemplateParams.clear(); + } + ~SaveTemplateParams() { + Parser->TemplateParams = std::move(OldParams); + Parser->OuterTemplateParams = std::move(OldOuterParams); + } + } SaveTemplateParams(this); + if (look() == 'G' || look() == 'T') return getDerived().parseSpecialName(); @@ -5187,7 +5341,12 @@ struct FloatData #else static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms #endif - static const size_t max_demangled_size = 40; + // `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes. + // 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits. + // Negatives are one character longer than positives. + // `0x1.` and `p` are constant, and exponents `+16383` and `-16382` are the + // same length. 1 sign bit, 112 mantissa bits, and 15 exponent bits == 128. + static const size_t max_demangled_size = 42; static constexpr const char *spec = "%LaL"; }; @@ -5555,4 +5714,4 @@ struct ManglingParser : AbstractManglingParser, Alloc> { DEMANGLE_NAMESPACE_END -#endif // DEMANGLE_ITANIUMDEMANGLE_H +#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h index c6f2606..0403136 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H -#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H +#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H +#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H #include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/MicrosoftDemangleNodes.h" @@ -275,4 +275,4 @@ class Demangler { } // namespace ms_demangle } // namespace llvm -#endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H +#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h index ec40eec..77446e9 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H -#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H +#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H +#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H #include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/StringView.h" @@ -67,6 +67,8 @@ enum class CallingConv : uint8_t { Eabi, Vectorcall, Regcall, + Swift, // Clang-only + SwiftAsync, // Clang-only }; enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef }; @@ -313,8 +315,8 @@ struct PrimitiveTypeNode : public TypeNode { explicit PrimitiveTypeNode(PrimitiveKind K) : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const; - void outputPost(OutputStream &OS, OutputFlags Flags) const {} + void outputPre(OutputStream &OS, OutputFlags Flags) const override; + void outputPost(OutputStream &OS, OutputFlags Flags) const override {} PrimitiveKind PrimKind; }; @@ -474,8 +476,8 @@ struct PointerTypeNode : public TypeNode { struct TagTypeNode : public TypeNode { explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const; - void outputPost(OutputStream &OS, OutputFlags Flags) const; + void outputPre(OutputStream &OS, OutputFlags Flags) const override; + void outputPost(OutputStream &OS, OutputFlags Flags) const override; QualifiedNameNode *QualifiedName = nullptr; TagKind Tag; @@ -484,8 +486,8 @@ struct TagTypeNode : public TypeNode { struct ArrayTypeNode : public TypeNode { ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const; - void outputPost(OutputStream &OS, OutputFlags Flags) const; + void outputPre(OutputStream &OS, OutputFlags Flags) const override; + void outputPost(OutputStream &OS, OutputFlags Flags) const override; void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const; void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const; diff --git a/third_party/llvm/include/llvm/Demangle/StringView.h b/third_party/llvm/include/llvm/Demangle/StringView.h index ceb6c79..378e853 100644 --- a/third_party/llvm/include/llvm/Demangle/StringView.h +++ b/third_party/llvm/include/llvm/Demangle/StringView.h @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#ifndef DEMANGLE_STRINGVIEW_H -#define DEMANGLE_STRINGVIEW_H +#ifndef LLVM_DEMANGLE_STRINGVIEW_H +#define LLVM_DEMANGLE_STRINGVIEW_H #include "DemangleConfig.h" #include @@ -36,8 +36,9 @@ class StringView { StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} StringView() : First(nullptr), Last(nullptr) {} - StringView substr(size_t From) const { - return StringView(begin() + From, size() - From); + StringView substr(size_t Pos, size_t Len = npos) const { + assert(Pos <= size()); + return StringView(begin() + Pos, std::min(Len, size() - Pos)); } size_t find(char C, size_t From = 0) const { @@ -51,14 +52,6 @@ class StringView { 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(); diff --git a/third_party/llvm/include/llvm/Demangle/Utility.h b/third_party/llvm/include/llvm/Demangle/Utility.h index 04e1936..04ff65a 100644 --- a/third_party/llvm/include/llvm/Demangle/Utility.h +++ b/third_party/llvm/include/llvm/Demangle/Utility.h @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#ifndef DEMANGLE_UTILITY_H -#define DEMANGLE_UTILITY_H +#ifndef LLVM_DEMANGLE_UTILITY_H +#define LLVM_DEMANGLE_UTILITY_H #include "StringView.h" #include @@ -52,7 +52,7 @@ class OutputStream { char *TempPtr = std::end(Temp); while (N) { - *--TempPtr = '0' + char(N % 10); + *--TempPtr = char('0' + N % 10); N /= 10; } diff --git a/third_party/llvm/lib/Demangle/Demangle.cpp b/third_party/llvm/lib/Demangle/Demangle.cpp index 71dafa0..1851fb7 100644 --- a/third_party/llvm/lib/Demangle/Demangle.cpp +++ b/third_party/llvm/lib/Demangle/Demangle.cpp @@ -19,10 +19,17 @@ static bool isItaniumEncoding(const std::string &MangledName) { return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z'; } +static bool isRustEncoding(const std::string &MangledName) { + return MangledName.size() >= 2 && MangledName[0] == '_' && + MangledName[1] == 'R'; +} + std::string llvm::demangle(const std::string &MangledName) { char *Demangled; if (isItaniumEncoding(MangledName)) Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); + else if (isRustEncoding(MangledName)) + Demangled = rustDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); else Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr, nullptr); @@ -31,6 +38,6 @@ std::string llvm::demangle(const std::string &MangledName) { return MangledName; std::string Ret = Demangled; - free(Demangled); + std::free(Demangled); return Ret; } diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index 1607431..3032071 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -1711,6 +1711,10 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { return CallingConv::Eabi; case 'Q': return CallingConv::Vectorcall; + case 'S': + return CallingConv::Swift; + case 'W': + return CallingConv::SwiftAsync; } return CallingConv::None; diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp index 9cee975..9fe157b 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp @@ -107,6 +107,12 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) { case CallingConv::Clrcall: OS << "__clrcall"; break; + case CallingConv::Swift: + OS << "__attribute__((__swiftcall__)) "; + break; + case CallingConv::SwiftAsync: + OS << "__attribute__((__swiftasynccall__)) "; + break; default: break; } @@ -117,7 +123,9 @@ std::string Node::toString(OutputFlags Flags) const { initializeOutputStream(nullptr, nullptr, OS, 1024); this->output(OS, Flags); OS << '\0'; - return {OS.getBuffer()}; + std::string Owned(OS.getBuffer()); + std::free(OS.getBuffer()); + return Owned; } void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { @@ -649,5 +657,4 @@ void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { TargetName->output(OS, Flags); OS << "'}"; } - return; } diff --git a/third_party/llvm/lib/Demangle/RustDemangle.cpp b/third_party/llvm/lib/Demangle/RustDemangle.cpp new file mode 100644 index 0000000..f916300 --- /dev/null +++ b/third_party/llvm/lib/Demangle/RustDemangle.cpp @@ -0,0 +1,1127 @@ +//===--- RustDemangle.cpp ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a demangler for Rust v0 mangled symbols as specified in +// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/Utility.h" + +#include +#include +#include +#include +#include + +using namespace llvm; + +using llvm::itanium_demangle::OutputStream; +using llvm::itanium_demangle::StringView; +using llvm::itanium_demangle::SwapAndRestore; + +namespace { + +struct Identifier { + StringView Name; + bool Punycode; + + bool empty() const { return Name.empty(); } +}; + +enum class BasicType { + Bool, + Char, + I8, + I16, + I32, + I64, + I128, + ISize, + U8, + U16, + U32, + U64, + U128, + USize, + F32, + F64, + Str, + Placeholder, + Unit, + Variadic, + Never, +}; + +enum class IsInType { + No, + Yes, +}; + +enum class LeaveGenericsOpen { + No, + Yes, +}; + +class Demangler { + // Maximum recursion level. Used to avoid stack overflow. + size_t MaxRecursionLevel; + // Current recursion level. + size_t RecursionLevel; + size_t BoundLifetimes; + // Input string that is being demangled with "_R" prefix removed. + StringView Input; + // Position in the input string. + size_t Position; + // When true, print methods append the output to the stream. + // When false, the output is suppressed. + bool Print; + // True if an error occurred. + bool Error; + +public: + // Demangled output. + OutputStream Output; + + Demangler(size_t MaxRecursionLevel = 500); + + bool demangle(StringView MangledName); + +private: + bool demanglePath(IsInType Type, + LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No); + void demangleImplPath(IsInType InType); + void demangleGenericArg(); + void demangleType(); + void demangleFnSig(); + void demangleDynBounds(); + void demangleDynTrait(); + void demangleOptionalBinder(); + void demangleConst(); + void demangleConstInt(); + void demangleConstBool(); + void demangleConstChar(); + + template void demangleBackref(Callable Demangler) { + uint64_t Backref = parseBase62Number(); + if (Error || Backref >= Position) { + Error = true; + return; + } + + if (!Print) + return; + + SwapAndRestore SavePosition(Position, Position); + Position = Backref; + Demangler(); + } + + Identifier parseIdentifier(); + uint64_t parseOptionalBase62Number(char Tag); + uint64_t parseBase62Number(); + uint64_t parseDecimalNumber(); + uint64_t parseHexNumber(StringView &HexDigits); + + void print(char C); + void print(StringView S); + void printDecimalNumber(uint64_t N); + void printBasicType(BasicType); + void printLifetime(uint64_t Index); + + char look() const; + char consume(); + bool consumeIf(char Prefix); + + bool addAssign(uint64_t &A, uint64_t B); + bool mulAssign(uint64_t &A, uint64_t B); +}; + +} // namespace + +char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N, + int *Status) { + if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { + if (Status != nullptr) + *Status = demangle_invalid_args; + return nullptr; + } + + // Return early if mangled name doesn't look like a Rust symbol. + StringView Mangled(MangledName); + if (!Mangled.startsWith("_R")) { + if (Status != nullptr) + *Status = demangle_invalid_mangled_name; + return nullptr; + } + + Demangler D; + if (!initializeOutputStream(nullptr, nullptr, D.Output, 1024)) { + if (Status != nullptr) + *Status = demangle_memory_alloc_failure; + return nullptr; + } + + if (!D.demangle(Mangled)) { + if (Status != nullptr) + *Status = demangle_invalid_mangled_name; + std::free(D.Output.getBuffer()); + return nullptr; + } + + D.Output += '\0'; + char *Demangled = D.Output.getBuffer(); + size_t DemangledLen = D.Output.getCurrentPosition(); + + if (Buf != nullptr) { + if (DemangledLen <= *N) { + std::memcpy(Buf, Demangled, DemangledLen); + std::free(Demangled); + Demangled = Buf; + } else { + std::free(Buf); + } + } + + if (N != nullptr) + *N = DemangledLen; + + if (Status != nullptr) + *Status = demangle_success; + + return Demangled; +} + +Demangler::Demangler(size_t MaxRecursionLevel) + : MaxRecursionLevel(MaxRecursionLevel) {} + +static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; } + +static inline bool isHexDigit(const char C) { + return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f'); +} + +static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; } + +static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; } + +/// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. +static inline bool isValid(const char C) { + return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; +} + +// Demangles Rust v0 mangled symbol. Returns true when successful, and false +// otherwise. The demangled symbol is stored in Output field. It is +// responsibility of the caller to free the memory behind the output stream. +// +// = "_R" [] +bool Demangler::demangle(StringView Mangled) { + Position = 0; + Error = false; + Print = true; + RecursionLevel = 0; + BoundLifetimes = 0; + + if (!Mangled.consumeFront("_R")) { + Error = true; + return false; + } + size_t Dot = Mangled.find('.'); + Input = Mangled.substr(0, Dot); + StringView Suffix = Mangled.dropFront(Dot); + + demanglePath(IsInType::No); + + if (Position != Input.size()) { + SwapAndRestore SavePrint(Print, false); + demanglePath(IsInType::No); + } + + if (Position != Input.size()) + Error = true; + + if (!Suffix.empty()) { + print(" ("); + print(Suffix); + print(")"); + } + + return !Error; +} + +// Demangles a path. InType indicates whether a path is inside a type. When +// LeaveOpen is true, a closing `>` after generic arguments is omitted from the +// output. Return value indicates whether generics arguments have been left +// open. +// +// = "C" // crate root +// | "M" // (inherent impl) +// | "X" // (trait impl) +// | "Y" // (trait definition) +// | "N" // ...::ident (nested path) +// | "I" {} "E" // ... (generic args) +// | +// = [] +// = "C" // closure +// | "S" // shim +// | // other special namespaces +// | // internal namespaces +bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return false; + } + SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + switch (consume()) { + case 'C': { + parseOptionalBase62Number('s'); + Identifier Ident = parseIdentifier(); + print(Ident.Name); + break; + } + case 'M': { + demangleImplPath(InType); + print("<"); + demangleType(); + print(">"); + break; + } + case 'X': { + demangleImplPath(InType); + print("<"); + demangleType(); + print(" as "); + demanglePath(IsInType::Yes); + print(">"); + break; + } + case 'Y': { + print("<"); + demangleType(); + print(" as "); + demanglePath(IsInType::Yes); + print(">"); + break; + } + case 'N': { + char NS = consume(); + if (!isLower(NS) && !isUpper(NS)) { + Error = true; + break; + } + demanglePath(InType); + + uint64_t Disambiguator = parseOptionalBase62Number('s'); + Identifier Ident = parseIdentifier(); + + if (isUpper(NS)) { + // Special namespaces + print("::{"); + if (NS == 'C') + print("closure"); + else if (NS == 'S') + print("shim"); + else + print(NS); + if (!Ident.empty()) { + print(":"); + print(Ident.Name); + } + print('#'); + printDecimalNumber(Disambiguator); + print('}'); + } else { + // Implementation internal namespaces. + if (!Ident.empty()) { + print("::"); + print(Ident.Name); + } + } + break; + } + case 'I': { + demanglePath(InType); + // Omit "::" when in a type, where it is optional. + if (InType == IsInType::No) + print("::"); + print("<"); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleGenericArg(); + } + if (LeaveOpen == LeaveGenericsOpen::Yes) + return true; + else + print(">"); + break; + } + case 'B': { + bool IsOpen = false; + demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); }); + return IsOpen; + } + default: + Error = true; + break; + } + + return false; +} + +// = [] +// = "s" +void Demangler::demangleImplPath(IsInType InType) { + SwapAndRestore SavePrint(Print, false); + parseOptionalBase62Number('s'); + demanglePath(InType); +} + +// = +// | +// | "K" +// = "L" +void Demangler::demangleGenericArg() { + if (consumeIf('L')) + printLifetime(parseBase62Number()); + else if (consumeIf('K')) + demangleConst(); + else + demangleType(); +} + +// = "a" // i8 +// | "b" // bool +// | "c" // char +// | "d" // f64 +// | "e" // str +// | "f" // f32 +// | "h" // u8 +// | "i" // isize +// | "j" // usize +// | "l" // i32 +// | "m" // u32 +// | "n" // i128 +// | "o" // u128 +// | "s" // i16 +// | "t" // u16 +// | "u" // () +// | "v" // ... +// | "x" // i64 +// | "y" // u64 +// | "z" // ! +// | "p" // placeholder (e.g. for generic params), shown as _ +static bool parseBasicType(char C, BasicType &Type) { + switch (C) { + case 'a': + Type = BasicType::I8; + return true; + case 'b': + Type = BasicType::Bool; + return true; + case 'c': + Type = BasicType::Char; + return true; + case 'd': + Type = BasicType::F64; + return true; + case 'e': + Type = BasicType::Str; + return true; + case 'f': + Type = BasicType::F32; + return true; + case 'h': + Type = BasicType::U8; + return true; + case 'i': + Type = BasicType::ISize; + return true; + case 'j': + Type = BasicType::USize; + return true; + case 'l': + Type = BasicType::I32; + return true; + case 'm': + Type = BasicType::U32; + return true; + case 'n': + Type = BasicType::I128; + return true; + case 'o': + Type = BasicType::U128; + return true; + case 'p': + Type = BasicType::Placeholder; + return true; + case 's': + Type = BasicType::I16; + return true; + case 't': + Type = BasicType::U16; + return true; + case 'u': + Type = BasicType::Unit; + return true; + case 'v': + Type = BasicType::Variadic; + return true; + case 'x': + Type = BasicType::I64; + return true; + case 'y': + Type = BasicType::U64; + return true; + case 'z': + Type = BasicType::Never; + return true; + default: + return false; + } +} + +void Demangler::printBasicType(BasicType Type) { + switch (Type) { + case BasicType::Bool: + print("bool"); + break; + case BasicType::Char: + print("char"); + break; + case BasicType::I8: + print("i8"); + break; + case BasicType::I16: + print("i16"); + break; + case BasicType::I32: + print("i32"); + break; + case BasicType::I64: + print("i64"); + break; + case BasicType::I128: + print("i128"); + break; + case BasicType::ISize: + print("isize"); + break; + case BasicType::U8: + print("u8"); + break; + case BasicType::U16: + print("u16"); + break; + case BasicType::U32: + print("u32"); + break; + case BasicType::U64: + print("u64"); + break; + case BasicType::U128: + print("u128"); + break; + case BasicType::USize: + print("usize"); + break; + case BasicType::F32: + print("f32"); + break; + case BasicType::F64: + print("f64"); + break; + case BasicType::Str: + print("str"); + break; + case BasicType::Placeholder: + print("_"); + break; + case BasicType::Unit: + print("()"); + break; + case BasicType::Variadic: + print("..."); + break; + case BasicType::Never: + print("!"); + break; + } +} + +// = | +// | // named type +// | "A" // [T; N] +// | "S" // [T] +// | "T" {} "E" // (T1, T2, T3, ...) +// | "R" [] // &T +// | "Q" [] // &mut T +// | "P" // *const T +// | "O" // *mut T +// | "F" // fn(...) -> ... +// | "D" // dyn Trait + Send + 'a +// | // backref +void Demangler::demangleType() { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return; + } + SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + size_t Start = Position; + char C = consume(); + BasicType Type; + if (parseBasicType(C, Type)) + return printBasicType(Type); + + switch (C) { + case 'A': + print("["); + demangleType(); + print("; "); + demangleConst(); + print("]"); + break; + case 'S': + print("["); + demangleType(); + print("]"); + break; + case 'T': { + print("("); + size_t I = 0; + for (; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleType(); + } + if (I == 1) + print(","); + print(")"); + break; + } + case 'R': + case 'Q': + print('&'); + if (consumeIf('L')) { + if (auto Lifetime = parseBase62Number()) { + printLifetime(Lifetime); + print(' '); + } + } + if (C == 'Q') + print("mut "); + demangleType(); + break; + case 'P': + print("*const "); + demangleType(); + break; + case 'O': + print("*mut "); + demangleType(); + break; + case 'F': + demangleFnSig(); + break; + case 'D': + demangleDynBounds(); + if (consumeIf('L')) { + if (auto Lifetime = parseBase62Number()) { + print(" + "); + printLifetime(Lifetime); + } + } else { + Error = true; + } + break; + case 'B': + demangleBackref([&] { demangleType(); }); + break; + default: + Position = Start; + demanglePath(IsInType::Yes); + break; + } +} + +// := [] ["U"] ["K" ] {} "E" +// = "C" +// | +void Demangler::demangleFnSig() { + SwapAndRestore SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + demangleOptionalBinder(); + + if (consumeIf('U')) + print("unsafe "); + + if (consumeIf('K')) { + print("extern \""); + if (consumeIf('C')) { + print("C"); + } else { + Identifier Ident = parseIdentifier(); + for (char C : Ident.Name) { + // When mangling ABI string, the "-" is replaced with "_". + if (C == '_') + C = '-'; + print(C); + } + } + print("\" "); + } + + print("fn("); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(", "); + demangleType(); + } + print(")"); + + if (consumeIf('u')) { + // Skip the unit type from the output. + } else { + print(" -> "); + demangleType(); + } +} + +// = [] {} "E" +void Demangler::demangleDynBounds() { + SwapAndRestore SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + print("dyn "); + demangleOptionalBinder(); + for (size_t I = 0; !Error && !consumeIf('E'); ++I) { + if (I > 0) + print(" + "); + demangleDynTrait(); + } +} + +// = {} +// = "p" +void Demangler::demangleDynTrait() { + bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes); + while (!Error && consumeIf('p')) { + if (!IsOpen) { + IsOpen = true; + print('<'); + } else { + print(", "); + } + print(parseIdentifier().Name); + print(" = "); + demangleType(); + } + if (IsOpen) + print(">"); +} + +// Demangles optional binder and updates the number of bound lifetimes. +// +// = "G" +void Demangler::demangleOptionalBinder() { + uint64_t Binder = parseOptionalBase62Number('G'); + if (Error || Binder == 0) + return; + + // In valid inputs each bound lifetime is referenced later. Referencing a + // lifetime requires at least one byte of input. Reject inputs that are too + // short to reference all bound lifetimes. Otherwise demangling of invalid + // binders could generate excessive amounts of output. + if (Binder >= Input.size() - BoundLifetimes) { + Error = true; + return; + } + + print("for<"); + for (size_t I = 0; I != Binder; ++I) { + BoundLifetimes += 1; + if (I > 0) + print(", "); + printLifetime(1); + } + print("> "); +} + +// = +// | "p" // placeholder +// | +void Demangler::demangleConst() { + if (Error || RecursionLevel >= MaxRecursionLevel) { + Error = true; + return; + } + SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + + char C = consume(); + BasicType Type; + if (parseBasicType(C, Type)) { + switch (Type) { + case BasicType::I8: + case BasicType::I16: + case BasicType::I32: + case BasicType::I64: + case BasicType::I128: + case BasicType::ISize: + case BasicType::U8: + case BasicType::U16: + case BasicType::U32: + case BasicType::U64: + case BasicType::U128: + case BasicType::USize: + demangleConstInt(); + break; + case BasicType::Bool: + demangleConstBool(); + break; + case BasicType::Char: + demangleConstChar(); + break; + case BasicType::Placeholder: + print('_'); + break; + default: + Error = true; + break; + } + } else if (C == 'B') { + demangleBackref([&] { demangleConst(); }); + } else { + Error = true; + } +} + +// = ["n"] +void Demangler::demangleConstInt() { + if (consumeIf('n')) + print('-'); + + StringView HexDigits; + uint64_t Value = parseHexNumber(HexDigits); + if (HexDigits.size() <= 16) { + printDecimalNumber(Value); + } else { + print("0x"); + print(HexDigits); + } +} + +// = "0_" // false +// | "1_" // true +void Demangler::demangleConstBool() { + StringView HexDigits; + parseHexNumber(HexDigits); + if (HexDigits == "0") + print("false"); + else if (HexDigits == "1") + print("true"); + else + Error = true; +} + +/// Returns true if CodePoint represents a printable ASCII character. +static bool isAsciiPrintable(uint64_t CodePoint) { + return 0x20 <= CodePoint && CodePoint <= 0x7e; +} + +// = +void Demangler::demangleConstChar() { + StringView HexDigits; + uint64_t CodePoint = parseHexNumber(HexDigits); + if (Error || HexDigits.size() > 6) { + Error = true; + return; + } + + print("'"); + switch (CodePoint) { + case '\t': + print(R"(\t)"); + break; + case '\r': + print(R"(\r)"); + break; + case '\n': + print(R"(\n)"); + break; + case '\\': + print(R"(\\)"); + break; + case '"': + print(R"(")"); + break; + case '\'': + print(R"(\')"); + break; + default: + if (isAsciiPrintable(CodePoint)) { + char C = CodePoint; + print(C); + } else { + print(R"(\u{)"); + print(HexDigits); + print('}'); + } + break; + } + print('\''); +} + +// = ["u"] ["_"] +Identifier Demangler::parseIdentifier() { + bool Punycode = consumeIf('u'); + uint64_t Bytes = parseDecimalNumber(); + + // Underscore resolves the ambiguity when identifier starts with a decimal + // digit or another underscore. + consumeIf('_'); + + if (Error || Bytes > Input.size() - Position) { + Error = true; + return {}; + } + StringView S = Input.substr(Position, Bytes); + Position += Bytes; + + if (!std::all_of(S.begin(), S.end(), isValid)) { + Error = true; + return {}; + } + + return {S, Punycode}; +} + +// Parses optional base 62 number. The presence of a number is determined using +// Tag. Returns 0 when tag is absent and parsed value + 1 otherwise +// +// This function is indended for parsing disambiguators and binders which when +// not present have their value interpreted as 0, and otherwise as decoded +// value + 1. For example for binders, value for "G_" is 1, for "G0_" value is +// 2. When "G" is absent value is 0. +uint64_t Demangler::parseOptionalBase62Number(char Tag) { + if (!consumeIf(Tag)) + return 0; + + uint64_t N = parseBase62Number(); + if (Error || !addAssign(N, 1)) + return 0; + + return N; +} + +// Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by +// "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, +// "1_" encodes 2, etc. +// +// = {<0-9a-zA-Z>} "_" +uint64_t Demangler::parseBase62Number() { + if (consumeIf('_')) + return 0; + + uint64_t Value = 0; + + while (true) { + uint64_t Digit; + char C = consume(); + + if (C == '_') { + break; + } else if (isDigit(C)) { + Digit = C - '0'; + } else if (isLower(C)) { + Digit = 10 + (C - 'a'); + } else if (isUpper(C)) { + Digit = 10 + 26 + (C - 'A'); + } else { + Error = true; + return 0; + } + + if (!mulAssign(Value, 62)) + return 0; + + if (!addAssign(Value, Digit)) + return 0; + } + + if (!addAssign(Value, 1)) + return 0; + + return Value; +} + +// Parses a decimal number that had been encoded without any leading zeros. +// +// = "0" +// | <1-9> {<0-9>} +uint64_t Demangler::parseDecimalNumber() { + char C = look(); + if (!isDigit(C)) { + Error = true; + return 0; + } + + if (C == '0') { + consume(); + return 0; + } + + uint64_t Value = 0; + + while (isDigit(look())) { + if (!mulAssign(Value, 10)) { + Error = true; + return 0; + } + + uint64_t D = consume() - '0'; + if (!addAssign(Value, D)) + return 0; + } + + return Value; +} + +// Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed +// value and stores hex digits in HexDigits. The return value is unspecified if +// HexDigits.size() > 16. +// +// = "0_" +// | <1-9a-f> {<0-9a-f>} "_" +uint64_t Demangler::parseHexNumber(StringView &HexDigits) { + size_t Start = Position; + uint64_t Value = 0; + + if (!isHexDigit(look())) + Error = true; + + if (consumeIf('0')) { + if (!consumeIf('_')) + Error = true; + } else { + while (!Error && !consumeIf('_')) { + char C = consume(); + Value *= 16; + if (isDigit(C)) + Value += C - '0'; + else if ('a' <= C && C <= 'f') + Value += 10 + (C - 'a'); + else + Error = true; + } + } + + if (Error) { + HexDigits = StringView(); + return 0; + } + + size_t End = Position - 1; + assert(Start < End); + HexDigits = Input.substr(Start, End - Start); + return Value; +} + +void Demangler::print(char C) { + if (Error || !Print) + return; + + Output += C; +} + +void Demangler::print(StringView S) { + if (Error || !Print) + return; + + Output += S; +} + +void Demangler::printDecimalNumber(uint64_t N) { + if (Error || !Print) + return; + + Output << N; +} + +// Prints a lifetime. An index 0 always represents an erased lifetime. Indices +// starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes +// bound by one of the enclosing binders. +void Demangler::printLifetime(uint64_t Index) { + if (Index == 0) { + print("'_"); + return; + } + + if (Index - 1 >= BoundLifetimes) { + Error = true; + return; + } + + uint64_t Depth = BoundLifetimes - Index; + print('\''); + if (Depth < 26) { + char C = 'a' + Depth; + print(C); + } else { + print('z'); + printDecimalNumber(Depth - 26 + 1); + } +} + +char Demangler::look() const { + if (Error || Position >= Input.size()) + return 0; + + return Input[Position]; +} + +char Demangler::consume() { + if (Error || Position >= Input.size()) { + Error = true; + return 0; + } + + return Input[Position++]; +} + +bool Demangler::consumeIf(char Prefix) { + if (Error || Position >= Input.size() || Input[Position] != Prefix) + return false; + + Position += 1; + return true; +} + +/// Computes A + B. When computation wraps around sets the error and returns +/// false. Otherwise assigns the result to A and returns true. +bool Demangler::addAssign(uint64_t &A, uint64_t B) { + if (A > std::numeric_limits::max() - B) { + Error = true; + return false; + } + + A += B; + return true; +} + +/// Computes A * B. When computation wraps around sets the error and returns +/// false. Otherwise assigns the result to A and returns true. +bool Demangler::mulAssign(uint64_t &A, uint64_t B) { + if (B != 0 && A > std::numeric_limits::max() / B) { + Error = true; + return false; + } + + A *= B; + return true; +} From f737aa9f8ffe314ba2b03aaba4a8a5d13fcec9df Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sat, 18 Sep 2021 09:57:21 -0400 Subject: [PATCH 09/42] use shorter branch name in RELEASING --- RELEASING | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASING b/RELEASING index 8f1c700..6a6e23e 100644 --- a/RELEASING +++ b/RELEASING @@ -1,13 +1,13 @@ Push new release branch: -1. make sure branches 'master' and 'release' are synced up locally +1. make sure branches 'main' and 'release' are synced up locally 2. update kDemumbleVersion in demumble.cc with new version (with ".git"), then git commit -am 'mark this 1.0.0.git' -3. git checkout release; git merge master +3. git checkout release; git merge main 4. fix version number in src/version.cc (it will conflict in the above) 5. commit, tag, push (don't forget to push --tags), build binaries git commit -am v1.0.0; git push origin release git tag v1.0.0; git push --tags ./dist.py # on the 'release' branch - # Push the 1.0.0.git change on master too: - git checkout master; git push origin master + # Push the 1.0.0.git change on main too: + git checkout main; git push origin main 6. add demumble-{linux,mac,win}.zip to https://github.com/nico/demumble/releases From dffd7ee8e95fd12af9bde6ae89dda4f75b839401 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 15 Mar 2022 09:55:19 -0400 Subject: [PATCH 10/42] dist.py: Make work with new win sysroot layout Adopts the script to work after the changes in: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2372727 https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2655836 After those, the paths in the json file are relative to the root, and the windows sdk is in "Windows Kits/10" instead of in "win_sdk". --- dist.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dist.py b/dist.py index 2425aa9..444bd49 100755 --- a/dist.py +++ b/dist.py @@ -94,13 +94,14 @@ def buildir(newdir): # Win. win_sysroot = glob.glob( crsrc + '/third_party/depot_tools/win_toolchain/vs_files/*')[0] -win_bindir = win_sysroot + '/win_sdk/bin' +win_bindir = win_sysroot + '/Windows Kits/10/bin' # This json file looks like http://codepad.org/kmfgf0UL winenv = json.load(open(win_bindir + '/SetEnv.x64.json'))['env'] for k in ['INCLUDE', 'LIB']: - winenv[k] = [os.path.join(*([win_bindir] + e)) for e in winenv[k]] -win_include = ['-imsvc' + i for i in winenv['INCLUDE']] -win_lib = ['/libpath:' + i for i in winenv['LIB']] + winenv[k] = [os.path.join(*([win_sysroot] + e)) for e in winenv[k]] +def quote(s): return '"' + s + '"' +win_include = [quote('-imsvc' + i) for i in winenv['INCLUDE']] +win_lib = [quote('/libpath:' + i) for i in winenv['LIB']] cflags = ['--target=x86_64-pc-windows'] + win_include with buildir('buildwin'): print 'building windows' From fa101f45d9691765fa01ace7a3031969a26dc540 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 15 Mar 2022 09:56:59 -0400 Subject: [PATCH 11/42] dist.py: use clang /winsysroot flag for compiling on win --- dist.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dist.py b/dist.py index 444bd49..6cfbd25 100755 --- a/dist.py +++ b/dist.py @@ -100,9 +100,8 @@ def buildir(newdir): for k in ['INCLUDE', 'LIB']: winenv[k] = [os.path.join(*([win_sysroot] + e)) for e in winenv[k]] def quote(s): return '"' + s + '"' -win_include = [quote('-imsvc' + i) for i in winenv['INCLUDE']] win_lib = [quote('/libpath:' + i) for i in winenv['LIB']] -cflags = ['--target=x86_64-pc-windows'] + win_include +cflags = ['--target=x86_64-pc-windows', '/winsysroot' + win_sysroot] with buildir('buildwin'): print 'building windows' subprocess.check_call(call_cmake + [ From aee53d03cad178ac2d7731941945eac00176e6c4 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 15 Mar 2022 09:57:57 -0400 Subject: [PATCH 12/42] dist.py: extract "ldflags" variable for win build --- dist.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dist.py b/dist.py index 6cfbd25..81507bd 100755 --- a/dist.py +++ b/dist.py @@ -102,16 +102,17 @@ def buildir(newdir): def quote(s): return '"' + s + '"' win_lib = [quote('/libpath:' + i) for i in winenv['LIB']] cflags = ['--target=x86_64-pc-windows', '/winsysroot' + win_sysroot] +# Without /manifest:no, cmake creates a default manifest file -- and +# explicitly calls mt.exe (which we don't have in a cross build). +# This also removes a dependency on rc.exe -- without this we'd also +# have to set CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY. +ldflags = ['/manifest:no'] + win_lib with buildir('buildwin'): print 'building windows' subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangcl, '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), - # Without /manifest:no, cmake creates a default manifest file -- and - # explicitly calls mt.exe (which we don't have in a cross build). - # This also removes a dependency on rc.exe -- without this we'd also - # have to set CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY. - '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(['/manifest:no'] + win_lib), + '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_LINKER=' + lldlink, '-DCMAKE_SYSTEM_NAME=Windows', ], stdout=devnull) From 787c4d0927658048489cddfa38ccf8807e07469f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 08:30:28 -0400 Subject: [PATCH 13/42] dist.py: use lld-link's new /winsysroot: flag for linking on win --- dist.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/dist.py b/dist.py index 81507bd..5661fba 100755 --- a/dist.py +++ b/dist.py @@ -94,19 +94,13 @@ def buildir(newdir): # Win. win_sysroot = glob.glob( crsrc + '/third_party/depot_tools/win_toolchain/vs_files/*')[0] -win_bindir = win_sysroot + '/Windows Kits/10/bin' -# This json file looks like http://codepad.org/kmfgf0UL -winenv = json.load(open(win_bindir + '/SetEnv.x64.json'))['env'] -for k in ['INCLUDE', 'LIB']: - winenv[k] = [os.path.join(*([win_sysroot] + e)) for e in winenv[k]] -def quote(s): return '"' + s + '"' -win_lib = [quote('/libpath:' + i) for i in winenv['LIB']] cflags = ['--target=x86_64-pc-windows', '/winsysroot' + win_sysroot] # Without /manifest:no, cmake creates a default manifest file -- and # explicitly calls mt.exe (which we don't have in a cross build). # This also removes a dependency on rc.exe -- without this we'd also # have to set CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY. -ldflags = ['/manifest:no'] + win_lib +# TODO: Remove /machine:x64 once crbug.com/1300005 is fixed. +ldflags = ['/manifest:no', '/winsysroot:' + win_sysroot, '/machine:x64'] with buildir('buildwin'): print 'building windows' subprocess.check_call(call_cmake + [ From 0f7c61eaada744bdf832cf1e5d084019ea45c8bf Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 12:10:13 -0400 Subject: [PATCH 14/42] dist.py: make test pass consistently on arm mac `cp` reuses the inode, which confuses poor macOS. rm dest file before copying, to make sure it gets a new inode. --- dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist.py b/dist.py index 5661fba..c43ca43 100755 --- a/dist.py +++ b/dist.py @@ -117,7 +117,8 @@ def buildir(newdir): # Copy over mac binary and run tests. print 'running tests (on mac)' -subprocess.check_call(['cp', 'buildmac/demumble', '.']) +# https://developer.apple.com/documentation/security/updating_mac_software +subprocess.check_call('rm -f demumble && cp buildmac/demumble .', shell=True) subprocess.check_call(['./demumble_test.py']) # Show zip files. From 9189449e1e7940bb6393f0da5dab32eb8583b2ba Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 12:10:55 -0400 Subject: [PATCH 15/42] dist.py: move to py3 --- dist.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dist.py b/dist.py index c43ca43..5a2bbec 100755 --- a/dist.py +++ b/dist.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Builds demumble for Mac, Linux, Windows. Must run on a Mac. # Needs a chromium checkout at ~/src/chrome/src that was synced with @@ -67,7 +67,7 @@ def buildir(newdir): cflags = [ '--sysroot', linux_sysroot, '--target=x86_64-linux-gnu', ] ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildlinux'): - print 'building linux' + print('building linux') subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangxx, '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), @@ -81,7 +81,7 @@ def buildir(newdir): # Mac. with buildir('buildmac'): - print 'building mac' + print('building mac') subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangxx, '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64', @@ -102,7 +102,7 @@ def buildir(newdir): # TODO: Remove /machine:x64 once crbug.com/1300005 is fixed. ldflags = ['/manifest:no', '/winsysroot:' + win_sysroot, '/machine:x64'] with buildir('buildwin'): - print 'building windows' + print('building windows') subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangcl, '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), @@ -116,7 +116,7 @@ def buildir(newdir): subprocess.check_call(['mv', 'demumble-win.zip', '..']) # Copy over mac binary and run tests. -print 'running tests (on mac)' +print('running tests (on mac)') # https://developer.apple.com/documentation/security/updating_mac_software subprocess.check_call('rm -f demumble && cp buildmac/demumble .', shell=True) subprocess.check_call(['./demumble_test.py']) From f58e0f2d779a0116c15344da736ccad57e6c3877 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 12:19:39 -0400 Subject: [PATCH 16/42] demumble_test.py: require py3 --- demumble_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/demumble_test.py b/demumble_test.py index a7b8d83..ef7bbdc 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 import os, re, subprocess, sys tests = [ @@ -62,7 +61,7 @@ else: out = subprocess.check_output(cmd, universal_newlines=True) if (out != t[1] if isinstance(t[1], str) else not t[1].match(out)): - print("`%s`: Expected '%s', got '%s'" % (t[0], t[1], out)) + print(f"`{t[0]}`: Expected '{t[1]}', got '{out}'") status = 1 print("passed" if status == 0 else "failed") sys.exit(status) From 76068f8f1fa7da472a9b46efd7c72cdb3f1fc3e3 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 12:19:59 -0400 Subject: [PATCH 17/42] demumble_test.py: make quote characters more consistent --- demumble_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demumble_test.py b/demumble_test.py index ef7bbdc..5a22948 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -63,5 +63,5 @@ if (out != t[1] if isinstance(t[1], str) else not t[1].match(out)): print(f"`{t[0]}`: Expected '{t[1]}', got '{out}'") status = 1 -print("passed" if status == 0 else "failed") +print('passed' if status == 0 else 'failed') sys.exit(status) From a727758ac2de6cd9ea4fa0c8f688f5144063d8f5 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Mar 2022 12:30:04 -0400 Subject: [PATCH 18/42] demumble_test.py: using encoding= instead of universal_newlines= now that py3 is required --- demumble_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demumble_test.py b/demumble_test.py index 5a22948..c7d6242 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -56,10 +56,10 @@ if '<' in cmd: p = subprocess.Popen(cmd[:cmd.index('<')], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - universal_newlines=True) + encoding='utf-8') out = p.communicate(input='\n'.join(cmd[cmd.index('<') + 1:]) + '\n')[0] else: - out = subprocess.check_output(cmd, universal_newlines=True) + out = subprocess.check_output(cmd, encoding='utf-8') if (out != t[1] if isinstance(t[1], str) else not t[1].match(out)): print(f"`{t[0]}`: Expected '{t[1]}', got '{out}'") status = 1 From 1eb2d84f5e4958c971c05194eda7e2ff61867bfc Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 22 Mar 2022 13:57:32 -0400 Subject: [PATCH 19/42] dist.py: on linux, use CMAKE_SYSROOT instead of passing --sysroot in cflags Close to no behavior change. It's "more correct" in that CMAKE_SYSROOT also affects `find_*` commands. Demumble doesn't use any of those, but I suppose it's still nicer. (This has the tiny side effect that the --sysroot flag is now on the rule in CMakeFiles/rules.ninja instead of in each compile's cflags in build.ninja.) --- dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist.py b/dist.py index 5a2bbec..ae58e72 100755 --- a/dist.py +++ b/dist.py @@ -64,7 +64,7 @@ def buildir(newdir): # Linux. linux_sysroot = crsrc + '/build/linux/debian_sid_amd64-sysroot' -cflags = [ '--sysroot', linux_sysroot, '--target=x86_64-linux-gnu', ] +cflags = [ '--target=x86_64-linux-gnu', ] ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildlinux'): print('building linux') @@ -72,6 +72,7 @@ def buildir(newdir): '-DCMAKE_CXX_COMPILER=' + clangxx, '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), + '-DCMAKE_SYSROOT=' + linux_sysroot, '-DCMAKE_SYSTEM_NAME=Linux', ], stdout=devnull) subprocess.check_call(['ninja', 'demumble']) From a7e76588c40db610e8d512dc3ff1d9a8bbc5c841 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 22 Mar 2022 15:06:19 -0400 Subject: [PATCH 20/42] dist.py: Make kind of runnable on linux Doesn't fully work, due to lack of `lipo`. --- dist.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/dist.py b/dist.py index ae58e72..598c5bd 100755 --- a/dist.py +++ b/dist.py @@ -37,10 +37,12 @@ # FIXME: https://chromium-review.googlesource.com/c/chromium/src/+/1214943 # has a way to build eu-strip on macOS, which is arguably a smaller dep # than llvm-strip. -linux_strip = os.path.join(os.path.expanduser('~'), - 'src/llvm-project/out/gn/bin/llvm-strip') +llvm_strip = os.path.join(os.path.expanduser('~'), + 'src/llvm-project/out/gn/bin/llvm-strip') -cmake = '/Applications/CMake.app/Contents/bin/cmake' +platform = 'mac' if sys.platform == 'darwin' else 'linux' +cmake = ('/Applications/CMake.app/Contents/bin/cmake' if platform == 'mac' else + '/usr/bin/cmake') call_cmake = [cmake, '-GNinja', '..', '-DCMAKE_BUILD_TYPE=Release'] @@ -64,7 +66,7 @@ def buildir(newdir): # Linux. linux_sysroot = crsrc + '/build/linux/debian_sid_amd64-sysroot' -cflags = [ '--target=x86_64-linux-gnu', ] +cflags = [ '--target=x86_64-linux-gnu' ] ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildlinux'): print('building linux') @@ -76,19 +78,27 @@ def buildir(newdir): '-DCMAKE_SYSTEM_NAME=Linux', ], stdout=devnull) subprocess.check_call(['ninja', 'demumble']) - subprocess.check_call([linux_strip, 'demumble']) + subprocess.check_call([llvm_strip, 'demumble']) subprocess.check_call(['zip', '-q9', 'demumble-linux.zip', 'demumble']) subprocess.check_call(['mv', 'demumble-linux.zip', '..']) # Mac. +mac_sysroot = (crsrc + '/build/mac_files/xcode_binaries/Contents/Developer' + + '/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk') +cflags = [ '--target=apple-macos', '-mmacosx-version-min=10.9' ] +ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildmac'): print('building mac') subprocess.check_call(call_cmake + [ '-DCMAKE_CXX_COMPILER=' + clangxx, + '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), + '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64', + '-DCMAKE_OSX_SYSROOT=' + mac_sysroot, + '-DCMAKE_SYSTEM_NAME=Darwin', ], stdout=devnull) subprocess.check_call(['ninja', 'demumble']) - subprocess.check_call(['strip', 'demumble']) + subprocess.check_call([llvm_strip, 'demumble']) subprocess.check_call(['zip', '-q9', 'demumble-mac.zip', 'demumble']) subprocess.check_call(['mv', 'demumble-mac.zip', '..']) @@ -116,10 +126,11 @@ def buildir(newdir): subprocess.check_call(['zip', '-q9', 'demumble-win.zip', 'demumble.exe']) subprocess.check_call(['mv', 'demumble-win.zip', '..']) -# Copy over mac binary and run tests. -print('running tests (on mac)') +# Copy over linux or mac binary and run tests. +print(f'running tests (on {platform})') # https://developer.apple.com/documentation/security/updating_mac_software -subprocess.check_call('rm -f demumble && cp buildmac/demumble .', shell=True) +subprocess.check_call(f'rm -f demumble && cp build{platform}/demumble .', + shell=True) subprocess.check_call(['./demumble_test.py']) # Show zip files. From 84b40ab0f84ee4d024d75672ecda757a2abfb109 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 22 Mar 2022 15:14:21 -0400 Subject: [PATCH 21/42] dist.py: make mac hermetic sysroot optional again when building on mac --- dist.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dist.py b/dist.py index 598c5bd..c5afd80 100755 --- a/dist.py +++ b/dist.py @@ -85,16 +85,19 @@ def buildir(newdir): # Mac. mac_sysroot = (crsrc + '/build/mac_files/xcode_binaries/Contents/Developer' + '/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk') +if platform == 'mac' and not os.path.isdir(mac_sysroot): + mac_sysroot_flag = [] +else: + mac_sysroot_flag = [ ' -DCMAKE_OSX_SYSROOT=' + mac_sysroot ] cflags = [ '--target=apple-macos', '-mmacosx-version-min=10.9' ] ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildmac'): print('building mac') - subprocess.check_call(call_cmake + [ + subprocess.check_call(call_cmake + mac_sysroot_flag + [ '-DCMAKE_CXX_COMPILER=' + clangxx, '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64', - '-DCMAKE_OSX_SYSROOT=' + mac_sysroot, '-DCMAKE_SYSTEM_NAME=Darwin', ], stdout=devnull) subprocess.check_call(['ninja', 'demumble']) From 37187de740d4c900e000d27c0fcc87556b9ae7d2 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 22 Mar 2022 16:08:09 -0400 Subject: [PATCH 22/42] dist.py: fix typo in 84b40ab0f84ee4 --- dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist.py b/dist.py index c5afd80..b842bf8 100755 --- a/dist.py +++ b/dist.py @@ -88,7 +88,7 @@ def buildir(newdir): if platform == 'mac' and not os.path.isdir(mac_sysroot): mac_sysroot_flag = [] else: - mac_sysroot_flag = [ ' -DCMAKE_OSX_SYSROOT=' + mac_sysroot ] + mac_sysroot_flag = [ '-DCMAKE_OSX_SYSROOT=' + mac_sysroot ] cflags = [ '--target=apple-macos', '-mmacosx-version-min=10.9' ] ldflags = ['-fuse-ld=lld'] + cflags with buildir('buildmac'): From df938e45c2b0e064fb5323d88b692d03b451d271 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 22 Mar 2022 16:08:26 -0400 Subject: [PATCH 23/42] Update LLVM lib/Demangle 87039c048c0cb..3de6b1ce0dd1d735 This adds support for demangling D symbols. Ran: cp ~/src/llvm-project/llvm/include/llvm/Demangle/*.h third_party/llvm/include/llvm/Demangle/ cp ~/src/llvm-project/llvm/lib/Demangle/*.cpp third_party/llvm/lib/Demangle/ cp ~/src/llvm-project/llvm/LICENSE.TXT third_party/llvm/LICENSE.txt --- CMakeLists.txt | 1 + .../llvm/include/llvm/Demangle/Demangle.h | 14 +- .../include/llvm/Demangle/ItaniumDemangle.h | 3104 ++++++++--------- .../include/llvm/Demangle/MicrosoftDemangle.h | 2 - .../llvm/Demangle/MicrosoftDemangleNodes.h | 96 +- .../llvm/include/llvm/Demangle/StringView.h | 25 +- .../llvm/include/llvm/Demangle/Utility.h | 140 +- .../llvm/lib/Demangle/DLangDemangle.cpp | 578 +++ third_party/llvm/lib/Demangle/Demangle.cpp | 51 +- .../llvm/lib/Demangle/ItaniumDemangle.cpp | 84 +- .../llvm/lib/Demangle/MicrosoftDemangle.cpp | 100 +- .../lib/Demangle/MicrosoftDemangleNodes.cpp | 409 ++- .../llvm/lib/Demangle/RustDemangle.cpp | 182 +- 13 files changed, 2661 insertions(+), 2125 deletions(-) create mode 100644 third_party/llvm/lib/Demangle/DLangDemangle.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 33b29a7..4bf3e66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(demumble demumble.cc third_party/llvm/lib/Demangle/Demangle.cpp third_party/llvm/lib/Demangle/ItaniumDemangle.cpp + third_party/llvm/lib/Demangle/DLangDemangle.cpp third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp third_party/llvm/lib/Demangle/RustDemangle.cpp diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h index c396a1d..3150e04 100644 --- a/third_party/llvm/include/llvm/Demangle/Demangle.h +++ b/third_party/llvm/include/llvm/Demangle/Demangle.h @@ -31,7 +31,6 @@ enum : int { char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, int *status); - enum MSDemangleFlags { MSDF_None = 0, MSDF_DumpBackrefs = 1 << 0, @@ -39,6 +38,7 @@ enum MSDemangleFlags { MSDF_NoCallingConvention = 1 << 2, MSDF_NoReturnType = 1 << 3, MSDF_NoMemberType = 1 << 4, + MSDF_NoVariableType = 1 << 5, }; /// Demangles the Microsoft symbol pointed at by mangled_name and returns it. @@ -53,13 +53,16 @@ enum MSDemangleFlags { /// receives the size of the demangled string on output if n_buf is not nullptr. /// status receives one of the demangle_ enum entries above if it's not nullptr. /// Flags controls various details of the demangled representation. -char *microsoftDemangle(const char *mangled_name, size_t *n_read, - char *buf, size_t *n_buf, - int *status, MSDemangleFlags Flags = MSDF_None); +char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf, + size_t *n_buf, int *status, + MSDemangleFlags Flags = MSDF_None); // Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); +// Demangles a D mangled symbol. +char *dlangDemangle(const char *MangledName); + /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. @@ -67,6 +70,8 @@ char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); /// demangling occurred. std::string demangle(const std::string &MangledName); +bool nonMicrosoftDemangle(const char *MangledName, std::string &Result); + /// "Partial" demangler. This supports demangling a string into an AST /// (typically an intermediate stage in itaniumDemangle) and querying certain /// properties or partially printing the demangled name. @@ -118,6 +123,7 @@ struct ItaniumPartialDemangler { bool isSpecialName() const; ~ItaniumPartialDemangler(); + private: void *RootNode; void *Context; diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h index 9163b71..f65d750 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -1,114 +1,235 @@ -//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// -// +//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===// +// Do not edit! See README.txt. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // -// Generic itanium demangler library. This file has two byte-per-byte identical -// copies in the source tree, one in libcxxabi, and the other in llvm. +// Generic itanium demangler library. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H -#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS +#ifndef DEMANGLE_ITANIUMDEMANGLE_H +#define DEMANGLE_ITANIUMDEMANGLE_H #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include #include #include #include #include #include -#include +#include #include -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(SyntheticTemplateParamName) \ - X(TypeTemplateParamDecl) \ - X(NonTypeTemplateParamDecl) \ - X(TemplateTemplateParamDecl) \ - X(TemplateParamPackDecl) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(SubobjectExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(PointerToMemberConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(BoolExpr) \ - X(StringLiteral) \ - X(LambdaExpr) \ - X(EnumLiteral) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) +#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(ModuleName) \ + X(ModuleEntity) \ + X(VectorType) \ + X(PixelVectorType) \ + X(BinaryFPType) \ + 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(ExpandedSpecialSubstitution) \ + X(SpecialSubstitution) \ + X(CtorDtorName) \ + X(DtorName) \ + X(UnnamedTypeName) \ + X(ClosureTypeName) \ + X(StructuredBindingName) \ + X(BinaryExpr) \ + X(ArraySubscriptExpr) \ + X(PostfixExpr) \ + X(ConditionalExpr) \ + X(MemberExpr) \ + X(SubobjectExpr) \ + X(EnclosingExpr) \ + X(CastExpr) \ + X(SizeofParamPackExpr) \ + X(CallExpr) \ + X(NewExpr) \ + X(DeleteExpr) \ + X(PrefixExpr) \ + X(FunctionParam) \ + X(ConversionExpr) \ + X(PointerToMemberConversionExpr) \ + X(InitListExpr) \ + X(FoldExpr) \ + X(ThrowExpr) \ + X(BoolExpr) \ + X(StringLiteral) \ + X(LambdaExpr) \ + X(EnumLiteral) \ + X(IntegerLiteral) \ + X(FloatLiteral) \ + X(DoubleLiteral) \ + X(LongDoubleLiteral) \ + X(BracedExpr) \ + X(BracedRangeExpr) DEMANGLE_NAMESPACE_BEGIN +template class PODSmallVector { + static_assert(std::is_pod::value, + "T is required to be a plain old data type"); + + T *First = nullptr; + T *Last = nullptr; + T *Cap = nullptr; + T Inline[N] = {0}; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto *Tmp = static_cast(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector &) = delete; + PODSmallVector &operator=(const PODSmallVector &) = delete; + + PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector &operator=(PODSmallVector &&Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void push_back(const T &Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T *begin() { return First; } + T *end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast(Last - First); } + T &back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T &operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + // Base class of all AST nodes. The AST is built by the parser, then is // traversed by the printLeft/Right functions to produce a demangled string. class Node { @@ -155,50 +276,48 @@ class Node { // would construct an equivalent node. //template void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } + virtual bool hasArraySlow(OutputBuffer &) const { return false; } + virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } + virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } - void print(OutputStream &S) const { - printLeft(S); + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // Print the "left" side of this Node into OutputBuffer. + virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. - virtual void printRight(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -227,19 +346,19 @@ class NodeArray { Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + OB += ", "; + size_t AfterComma = OB.getCurrentPosition(); + Elements[Idx]->print(OB); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -254,9 +373,7 @@ struct NodeArrayNode : Node { template void match(Fn F) const { F(Array); } - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } + void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { @@ -269,11 +386,11 @@ class DotSuffix final : public Node { template void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + void printLeft(OutputBuffer &OB) const override { + Prefix->print(OB); + OB += " ("; + OB += Suffix; + OB += ")"; } }; @@ -288,12 +405,12 @@ class VendorExtQualType final : public Node { template void match(Fn F) const { F(Ty, Ext, TA); } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += " "; + OB += Ext; if (TA != nullptr) - TA->print(S); + TA->print(OB); } }; @@ -319,13 +436,13 @@ class QualType final : public Node { const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -336,22 +453,22 @@ class QualType final : public Node { template void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -363,9 +480,9 @@ class ConversionOperatorType final : public Node { template void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; @@ -379,9 +496,9 @@ class PostfixQualifiedType final : public Node { template void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; @@ -396,7 +513,7 @@ class NameType final : public Node { StringView getName() const { return Name; } StringView getBaseName() const override { return Name; } - void printLeft(OutputStream &s) const override { s += Name; } + void printLeft(OutputBuffer &OB) const override { OB += Name; } }; class ElaboratedTypeSpefType : public Node { @@ -408,10 +525,10 @@ class ElaboratedTypeSpefType : public Node { template void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; @@ -426,11 +543,11 @@ struct AbiTagAttr : Node { template void match(Fn F) const { F(Base, Tag); } - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Base->printLeft(OB); + OB += "[abi:"; + OB += Tag; + OB += "]"; } }; @@ -442,10 +559,10 @@ class EnableIfAttr : public Node { template void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; @@ -466,11 +583,11 @@ class ObjCProtoName : public Node { static_cast(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -484,34 +601,34 @@ class PointerType final : public Node { template void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -531,15 +648,30 @@ class ReferenceType : public Node { // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any // other combination collapses to a lvalue ref. - std::pair collapse(OutputStream &S) const { + // + // A combination of a TemplateForwardReference and a back-ref Substitution + // from an ill-formed string may have created a cycle; use cycle detection to + // avoid looping forever. + std::pair collapse(OutputBuffer &OB) const { auto SoFar = std::make_pair(RK, Pointee); + // Track the chain of nodes for the Floyd's 'tortoise and hare' + // cycle-detection algorithm, since getSyntaxNode(S) is impure + PODSmallVector Prev; for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); + const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast(SN); SoFar.second = RT->Pointee; SoFar.first = std::min(SoFar.first, RT->RK); + + // The middle of Prev is the 'slow' pointer moving at half speed + Prev.push_back(SoFar.second); + if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { + // Cycle detected + SoFar.second = nullptr; + break; + } } return SoFar; } @@ -551,31 +683,35 @@ class ReferenceType : public Node { template void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + Collapsed.second->printLeft(OB); + if (Collapsed.second->hasArray(OB)) + OB += " "; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -590,24 +726,24 @@ class PointerToMemberType final : public Node { template void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; + OB += " "; + ClassType->print(OB); + OB += "::*"; } - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; @@ -624,19 +760,19 @@ class ArrayType final : public Node { template void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; if (Dimension) - Dimension->print(S); - S += "]"; - Base->printRight(S); + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -660,8 +796,8 @@ class FunctionType final : public Node { F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: @@ -670,32 +806,32 @@ class FunctionType final : public Node { // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -707,10 +843,10 @@ class NoexceptSpec : public Node { template void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept("; + E->print(OB); + OB += ")"; } }; @@ -722,10 +858,10 @@ class DynamicExceptionSpec : public Node { template void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw("; + Types.printWithComma(OB); + OB += ')'; } }; @@ -756,41 +892,41 @@ class FunctionEncoding final : public Node { NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -803,9 +939,9 @@ class LiteralOperator : public Node { template void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; @@ -819,9 +955,9 @@ class SpecialName final : public Node { template void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -836,11 +972,11 @@ class CtorVtableSpecialName final : public Node { template void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -855,10 +991,48 @@ struct NestedName : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qual->print(OB); + OB += "::"; + Name->print(OB); + } +}; + +struct ModuleName : Node { + ModuleName *Parent; + Node *Name; + bool IsPartition; + + ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) + : Node(KModuleName), Parent(Parent_), Name(Name_), + IsPartition(IsPartition_) {} + + template void match(Fn F) const { F(Parent, Name); } + + void printLeft(OutputBuffer &OB) const override { + if (Parent) + Parent->print(OB); + if (Parent || IsPartition) + OB += IsPartition ? ':' : '.'; + Name->print(OB); + } +}; + +struct ModuleEntity : Node { + ModuleName *Module; + Node *Name; + + ModuleEntity(ModuleName *Module_, Node *Name_) + : Node(KModuleEntity), Module(Module_), Name(Name_) {} + + template void match(Fn F) const { F(Module, Name); } + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + OB += '@'; + Module->print(OB); } }; @@ -871,10 +1045,10 @@ struct LocalName : Node { template void match(Fn F) const { F(Encoding, Entity); } - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); + void printLeft(OutputBuffer &OB) const override { + Encoding->print(OB); + OB += "::"; + Entity->print(OB); } }; @@ -891,10 +1065,10 @@ class QualifiedName final : public Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -909,12 +1083,12 @@ class VectorType final : public Node { template void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; if (Dimension) - Dimension->print(S); - S += "]"; + Dimension->print(OB); + OB += "]"; } }; @@ -927,11 +1101,26 @@ class PixelVectorType final : public Node { template void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - Dimension->print(S); - S += "]"; + OB += "pixel vector["; + Dimension->print(OB); + OB += "]"; + } +}; + +class BinaryFPType final : public Node { + const Node *Dimension; + +public: + BinaryFPType(const Node *Dimension_) + : Node(KBinaryFPType), Dimension(Dimension_) {} + + template void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -953,20 +1142,20 @@ class SyntheticTemplateParamName final : public Node { template void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -980,13 +1169,9 @@ class TypeTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -1000,15 +1185,15 @@ class NonTypeTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1025,15 +1210,13 @@ class TemplateTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1046,14 +1229,12 @@ class TemplateParamPackDecl final : public Node { template void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1067,11 +1248,12 @@ class TemplateParamPackDecl final : public Node { class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits::max()) { - S.CurrentPackMax = static_cast(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits::max()) { + OB.CurrentPackMax = static_cast(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1094,38 +1276,38 @@ class ParameterPack final : public Node { template void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + const Node *getSyntaxNode(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1144,8 +1326,8 @@ class TemplateArgumentPack final : public Node { NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1162,35 +1344,35 @@ class ParameterPackExpansion final : public Node { const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + SwapAndRestore SavePackIdx(OB.CurrentPackIndex, Max); + SwapAndRestore SavePackMax(OB.CurrentPackMax, Max); + size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. - Child->print(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1205,12 +1387,12 @@ class TemplateArgs final : public Node { NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + OB += "<"; + Params.printWithComma(OB); + if (OB.back() == '>') + OB += " "; + OB += ">"; } }; @@ -1252,42 +1434,42 @@ struct ForwardTemplateReference : Node { // special handling. template void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); + Ref->printRight(OB); } }; @@ -1303,9 +1485,9 @@ struct NameWithTemplateArgs : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + TemplateArgs->print(OB); } }; @@ -1320,24 +1502,9 @@ class GlobalQualifiedName final : public Node { StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1377,26 +1544,26 @@ class ExpandedSpecialSubstitution final : public Node { DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; + OB += "std::basic_string, " + "std::allocator >"; break; case SpecialSubKind::istream: - S += "std::basic_istream >"; + OB += "std::basic_istream >"; break; case SpecialSubKind::ostream: - S += "std::basic_ostream >"; + OB += "std::basic_ostream >"; break; case SpecialSubKind::iostream: - S += "std::basic_iostream >"; + OB += "std::basic_iostream >"; break; } } @@ -1429,25 +1596,25 @@ class SpecialSubstitution final : public Node { DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::string"; + OB += "std::string"; break; case SpecialSubKind::istream: - S += "std::istream"; + OB += "std::istream"; break; case SpecialSubKind::ostream: - S += "std::ostream"; + OB += "std::ostream"; break; case SpecialSubKind::iostream: - S += "std::iostream"; + OB += "std::iostream"; break; } } @@ -1465,10 +1632,10 @@ class CtorDtorName final : public Node { template void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1480,9 +1647,9 @@ class DtorName : public Node { template void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; @@ -1494,10 +1661,10 @@ class UnnamedTypeName : public Node { template void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; @@ -1516,22 +1683,22 @@ class ClosureTypeName : public Node { F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB += "("; + Params.printWithComma(OB); + OB += ")"; } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1543,10 +1710,10 @@ class StructuredBindingName : public Node { template void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + Bindings.printWithComma(OB); + OB += ']'; } }; @@ -1564,22 +1731,22 @@ class BinaryExpr : public Node { template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // might be a template argument expression, then we need to disambiguate // with parens. if (InfixOperator == ">") - S += "("; + OB += "("; - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; + OB += "("; + LHS->print(OB); + OB += ") "; + OB += InfixOperator; + OB += " ("; + RHS->print(OB); + OB += ")"; if (InfixOperator == ">") - S += ")"; + OB += ")"; } }; @@ -1593,12 +1760,12 @@ class ArraySubscriptExpr : public Node { template void match(Fn F) const { F(Op1, Op2); } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Op1->print(OB); + OB += ")["; + Op2->print(OB); + OB += "]"; } }; @@ -1612,11 +1779,11 @@ class PostfixExpr : public Node { template void match(Fn F) const { F(Child, Operator); } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Child->print(OB); + OB += ")"; + OB += Operator; } }; @@ -1631,14 +1798,14 @@ class ConditionalExpr : public Node { template 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 += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Cond->print(OB); + OB += ") ? ("; + Then->print(OB); + OB += ") : ("; + Else->print(OB); + OB += ")"; } }; @@ -1653,10 +1820,16 @@ class MemberExpr : public Node { template void match(Fn F) const { F(LHS, Kind, RHS); } - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + void printLeft(OutputBuffer &OB) const override { + LHS->print(OB); + OB += Kind; + // Parenthesize pointer-to-member deference argument. + bool IsPtr = Kind.back() == '*'; + if (IsPtr) + OB += '('; + RHS->print(OB); + if (IsPtr) + OB += ')'; } }; @@ -1677,20 +1850,20 @@ class SubobjectExpr : public Node { F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); } - void printLeft(OutputStream &S) const override { - SubExpr->print(S); - S += ".<"; - Type->print(S); - S += " at offset "; + void printLeft(OutputBuffer &OB) const override { + SubExpr->print(OB); + OB += ".<"; + Type->print(OB); + OB += " at offset "; if (Offset.empty()) { - S += "0"; + OB += "0"; } else if (Offset[0] == 'n') { - S += "-"; - S += Offset.dropFront(); + OB += "-"; + OB += Offset.dropFront(); } else { - S += Offset; + OB += Offset; } - S += ">"; + OB += ">"; } }; @@ -1706,10 +1879,10 @@ class EnclosingExpr : public Node { template void match(Fn F) const { F(Prefix, Infix, Postfix); } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Infix->print(OB); + OB += Postfix; } }; @@ -1725,13 +1898,13 @@ class CastExpr : public Node { template 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 += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + OB += "<"; + To->printLeft(OB); + OB += ">("; + From->printLeft(OB); + OB += ")"; } }; @@ -1744,11 +1917,11 @@ class SizeofParamPackExpr : public Node { template void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof...("; ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB += ")"; } }; @@ -1762,11 +1935,11 @@ class CallExpr : public Node { template void match(Fn F) const { F(Callee, Args); } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB += "("; + Args.printWithComma(OB); + OB += ")"; } }; @@ -1787,25 +1960,24 @@ class NewExpr : public Node { F(ExprList, Type, InitList, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::"; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB += "("; + ExprList.printWithComma(OB); + OB += ")"; } - Type->print(S); + OB += ' '; + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB += "("; + InitList.printWithComma(OB); + OB += ")"; } - } }; @@ -1820,13 +1992,14 @@ class DeleteExpr : public Node { template void match(Fn F) const { F(Op, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[]"; + OB += ' '; + Op->print(OB); } }; @@ -1840,11 +2013,11 @@ class PrefixExpr : public Node { template void match(Fn F) const { F(Prefix, Child); } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB += "("; + Child->print(OB); + OB += ")"; } }; @@ -1856,9 +2029,9 @@ class FunctionParam : public Node { template void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1872,12 +2045,12 @@ class ConversionExpr : public Node { template void match(Fn F) const { F(Type, Expressions); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + Expressions.printWithComma(OB); + OB += ")"; } }; @@ -1894,12 +2067,12 @@ class PointerToMemberConversionExpr : public Node { template void match(Fn F) const { F(Type, SubExpr, Offset); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - SubExpr->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + SubExpr->print(OB); + OB += ")"; } }; @@ -1912,12 +2085,12 @@ class InitListExpr : public Node { template void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1931,18 +2104,18 @@ class BracedExpr : public Node { template void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1956,15 +2129,15 @@ class BracedRangeExpr : public Node { template void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1983,43 +2156,43 @@ class FoldExpr : public Node { F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB += '('; + ParameterPackExpansion(Pack).print(OB); + OB += ')'; }; - S += '('; + OB += '('; if (IsLeftFold) { // init op ... op pack if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; + Init->print(OB); + OB += ' '; + OB += OperatorName; + OB += ' '; } // ... op pack - S += "... "; - S += OperatorName; - S += ' '; + OB += "... "; + OB += OperatorName; + OB += ' '; PrintPack(); } else { // !IsLeftFold // pack op ... PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; + OB += ' '; + OB += OperatorName; + OB += " ..."; // pack op ... op init if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); + OB += ' '; + OB += OperatorName; + OB += ' '; + Init->print(OB); } } - S += ')'; + OB += ')'; } }; @@ -2031,9 +2204,9 @@ class ThrowExpr : public Node { template void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2045,8 +2218,8 @@ class BoolExpr : public Node { template void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? StringView("true") : StringView("false"); } }; @@ -2058,10 +2231,10 @@ class StringLiteral : public Node { template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2073,11 +2246,11 @@ class LambdaExpr : public Node { template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast(Type)->printDeclarator(S); - S += "{...}"; + static_cast(Type)->printDeclarator(OB); + OB += "{...}"; } }; @@ -2092,15 +2265,15 @@ class EnumLiteral : public Node { template void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S << "("; - Ty->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB << "("; + Ty->print(OB); + OB << ")"; if (Integer[0] == 'n') - S << "-" << Integer.dropFront(1); + OB << "-" << Integer.dropFront(1); else - S << Integer; + OB << Integer; } }; @@ -2114,21 +2287,21 @@ class IntegerLiteral : public Node { template void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB += "("; + OB += Type; + OB += ")"; } if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); + OB += "-"; + OB += Value.dropFront(1); } else - S += Value; + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2158,7 +2331,7 @@ template class FloatLiteralImpl : public Node { template void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { const char *first = Contents.begin(); const char *last = Contents.end() + 1; @@ -2184,7 +2357,7 @@ template class FloatLiteralImpl : public Node { #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); + OB += StringView(num, num + n); } } }; @@ -2217,125 +2390,6 @@ FOR_EACH_NODE_KIND(SPECIALIZATION) #undef FOR_EACH_NODE_KIND -template -class PODSmallVector { - static_assert(std::is_pod::value, - "T is required to be a plain old data type"); - - T* First = nullptr; - T* Last = nullptr; - T* Cap = nullptr; - T Inline[N] = {0}; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - template struct AbstractManglingParser { const char *First; const char *Last; @@ -2450,7 +2504,7 @@ template struct AbstractManglingParser { char consume() { return First != Last ? *First++ : '\0'; } - char look(unsigned Lookahead = 0) { + char look(unsigned Lookahead = 0) const { if (static_cast(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; @@ -2478,7 +2532,6 @@ template struct AbstractManglingParser { Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); - Node *parseNewExpr(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); @@ -2530,17 +2583,75 @@ template struct AbstractManglingParser { Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); + bool parseModuleNameOpt(ModuleName *&Module); + Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); + Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); Node *parseAbiTags(Node *N); + struct OperatorInfo { + enum OIKind : unsigned char { + Prefix, // Prefix unary: @ expr + Postfix, // Postfix unary: expr @ + Binary, // Binary: lhs @ rhs + Array, // Array index: lhs [ rhs ] + Member, // Member access: lhs @ rhs + New, // New + Del, // Delete + Call, // Function call: expr (expr*) + CCast, // C cast: (type)expr + Conditional, // Conditional: expr ? expr : expr + NameOnly, // Overload only, not allowed in expression. + // Below do not have operator names + NamedCast, // Named cast, @(expr) + OfIdOp, // alignof, sizeof, typeid + + Unnameable = NamedCast, + }; + char Enc[2]; // Encoding + OIKind Kind; // Kind of operator + bool Flag : 1; // Entry-specific flag + const char *Name; // Spelling + + public: + constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, const char *N) + : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Name{N} {} + + public: + bool operator<(const OperatorInfo &Other) const { + return *this < Other.Enc; + } + bool operator<(const char *Peek) const { + return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]); + } + bool operator==(const char *Peek) const { + return Enc[0] == Peek[0] && Enc[1] == Peek[1]; + } + bool operator!=(const char *Peek) const { return !this->operator==(Peek); } + + public: + StringView getSymbol() const { + StringView Res = Name; + if (Kind < Unnameable) { + assert(Res.startsWith("operator") && + "operator name does not start with 'operator'"); + Res = Res.dropFront(sizeof("operator") - 1); + Res.consumeFront(' '); + } + return Res; + } + StringView getName() const { return Name; } + OIKind getKind() const { return Kind; } + bool getFlag() const { return Flag; } + }; + const OperatorInfo *parseOperatorEncoding(); + /// Parse the production. - Node *parseUnresolvedName(); + Node *parseUnresolvedName(bool Global); Node *parseSimpleId(); Node *parseBaseUnresolvedName(); Node *parseUnresolvedType(); @@ -2561,41 +2672,35 @@ const char* parse_discriminator(const char* first, const char* last); // ::= template Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') return getDerived().parseLocalName(State); - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); - } + Node *Result = nullptr; + bool IsSubst = false; - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) return nullptr; - // ::= + if (look() == 'I') { - Subs.push_back(N); + // ::= + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by . + return nullptr; } - // ::= - return N; + + return Result; } // := Z E [] @@ -2634,36 +2739,63 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { return make(Encoding, Entity); } -// ::= -// ::= St # ::std:: -// extension ::= StL +// ::= [L]* +// ::= St [L]* # ::std:: +// [*] extension template Node * -AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) +AbstractManglingParser::parseUnscopedName(NameState *State, + bool *IsSubst) { + + Node *Std = nullptr; + if (consumeIf("St")) { + Std = make("std"); + if (Std == nullptr) + return nullptr; + } + consumeIf('L'); + + Node *Res = nullptr; + ModuleName *Module = nullptr; + if (look() == 'S') { + Node *S = getDerived().parseSubstitution(); + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) + Module = static_cast(S); + else if (IsSubst && Std == nullptr) { + Res = S; + *IsSubst = true; + } else { return nullptr; - return make(R); + } } - return getDerived().parseUnqualifiedName(State); + + if (Res == nullptr) + Res = getDerived().parseUnqualifiedName(State, Std, Module); + + return Res; } -// ::= [abi-tags] -// ::= -// ::= -// ::= -// ::= DC + E # structured binding declaration +// ::= [] [] +// ::= [] [] +// ::= [] [] +// ::= [] [] +// # structured binding declaration +// ::= [] DC + E template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State) { - // s are special-cased in parseNestedName(). +Node *AbstractManglingParser::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + Node *Result; - if (look() == 'U') + if (look() == 'U') { Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + } else if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } else if (consumeIf("DC")) { + // Structured binding size_t BindingsBegin = Names.size(); do { Node *Binding = getDerived().parseSourceName(State); @@ -2672,13 +2804,46 @@ AbstractManglingParser::parseUnqualifiedName(NameState *State) { Names.push_back(Binding); } while (!consumeIf('E')); Result = make(popTrailingNodeArray(BindingsBegin)); - } else + } else if (look() == 'C' || look() == 'D') { + // A . + if (Scope == nullptr || Module != nullptr) + return nullptr; + Result = getDerived().parseCtorDtorName(Scope, State); + } else { Result = getDerived().parseOperatorName(State); + } + + if (Module) + Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); + if (Result != nullptr && Scope != nullptr) + Result = make(Scope, Result); + return Result; } +// ::= +// ::= +// ::= # passed in by caller +// ::= W +// ::= W P +template +bool AbstractManglingParser::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast(make(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // ::= Ut [] _ // ::= // @@ -2778,92 +2943,112 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return make(Name); } -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= +// If the next 2 chars are an operator encoding, consume them and return their +// OperatorInfo. Otherwise return nullptr. +template +const typename AbstractManglingParser::OperatorInfo * +AbstractManglingParser::parseOperatorEncoding() { + static const OperatorInfo Ops[] = { + // Keep ordered by encoding + {"aN", OperatorInfo::Binary, false, "operator&="}, + {"aS", OperatorInfo::Binary, false, "operator="}, + {"aa", OperatorInfo::Binary, false, "operator&&"}, + {"ad", OperatorInfo::Prefix, false, "operator&"}, + {"an", OperatorInfo::Binary, false, "operator&"}, + {"at", OperatorInfo::OfIdOp, /*Type*/ true, "alignof ("}, + {"aw", OperatorInfo::NameOnly, false, "operator co_await"}, + {"az", OperatorInfo::OfIdOp, /*Type*/ false, "alignof ("}, + {"cc", OperatorInfo::NamedCast, false, "const_cast"}, + {"cl", OperatorInfo::Call, false, "operator()"}, + {"cm", OperatorInfo::Binary, false, "operator,"}, + {"co", OperatorInfo::Prefix, false, "operator~"}, + {"cv", OperatorInfo::CCast, false, "operator"}, // C Cast + {"dV", OperatorInfo::Binary, false, "operator/="}, + {"da", OperatorInfo::Del, /*Ary*/ true, "operator delete[]"}, + {"dc", OperatorInfo::NamedCast, false, "dynamic_cast"}, + {"de", OperatorInfo::Prefix, false, "operator*"}, + {"dl", OperatorInfo::Del, /*Ary*/ false, "operator delete"}, + {"ds", OperatorInfo::Member, /*Named*/ false, "operator.*"}, + {"dt", OperatorInfo::Member, /*Named*/ false, "operator."}, + {"dv", OperatorInfo::Binary, false, "operator/"}, + {"eO", OperatorInfo::Binary, false, "operator^="}, + {"eo", OperatorInfo::Binary, false, "operator^"}, + {"eq", OperatorInfo::Binary, false, "operator=="}, + {"ge", OperatorInfo::Binary, false, "operator>="}, + {"gt", OperatorInfo::Binary, false, "operator>"}, + {"ix", OperatorInfo::Array, false, "operator[]"}, + {"lS", OperatorInfo::Binary, false, "operator<<="}, + {"le", OperatorInfo::Binary, false, "operator<="}, + {"ls", OperatorInfo::Binary, false, "operator<<"}, + {"lt", OperatorInfo::Binary, false, "operator<"}, + {"mI", OperatorInfo::Binary, false, "operator-="}, + {"mL", OperatorInfo::Binary, false, "operator*="}, + {"mi", OperatorInfo::Binary, false, "operator-"}, + {"ml", OperatorInfo::Binary, false, "operator*"}, + {"mm", OperatorInfo::Postfix, false, "operator--"}, + {"na", OperatorInfo::New, /*Ary*/ true, "operator new[]"}, + {"ne", OperatorInfo::Binary, false, "operator!="}, + {"ng", OperatorInfo::Prefix, false, "operator-"}, + {"nt", OperatorInfo::Prefix, false, "operator!"}, + {"nw", OperatorInfo::New, /*Ary*/ false, "operator new"}, + {"oR", OperatorInfo::Binary, false, "operator|="}, + {"oo", OperatorInfo::Binary, false, "operator||"}, + {"or", OperatorInfo::Binary, false, "operator|"}, + {"pL", OperatorInfo::Binary, false, "operator+="}, + {"pl", OperatorInfo::Binary, false, "operator+"}, + {"pm", OperatorInfo::Member, /*Named*/ false, "operator->*"}, + {"pp", OperatorInfo::Postfix, false, "operator++"}, + {"ps", OperatorInfo::Prefix, false, "operator+"}, + {"pt", OperatorInfo::Member, /*Named*/ true, "operator->"}, + {"qu", OperatorInfo::Conditional, false, "operator?"}, + {"rM", OperatorInfo::Binary, false, "operator%="}, + {"rS", OperatorInfo::Binary, false, "operator>>="}, + {"rc", OperatorInfo::NamedCast, false, "reinterpret_cast"}, + {"rm", OperatorInfo::Binary, false, "operator%"}, + {"rs", OperatorInfo::Binary, false, "operator>>"}, + {"sc", OperatorInfo::NamedCast, false, "static_cast"}, + {"ss", OperatorInfo::Binary, false, "operator<=>"}, + {"st", OperatorInfo::OfIdOp, /*Type*/ true, "sizeof ("}, + {"sz", OperatorInfo::OfIdOp, /*Type*/ false, "sizeof ("}, + {"te", OperatorInfo::OfIdOp, /*Type*/ false, "typeid ("}, + {"ti", OperatorInfo::OfIdOp, /*Type*/ true, "typeid ("}, + }; + const auto NumOps = sizeof(Ops) / sizeof(Ops[0]); + +#ifndef NDEBUG + { + // Verify table order. + static bool Done; + if (!Done) { + Done = true; + for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++) + assert(Op[0] < Op[1] && "Operator table is not ordered"); + } + } +#endif + + if (numLeft() < 2) + return nullptr; + + auto Op = std::lower_bound( + &Ops[0], &Ops[NumOps], First, + [](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; }); + if (Op == &Ops[NumOps] || *Op != First) + return nullptr; + + First += 2; + return Op; +} + +// ::= See parseOperatorEncoding() // ::= li # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v # vendor extended operator +// ::= v # vendor extended operator template Node * AbstractManglingParser::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make("operator&&"); - case 'd': - case 'n': - First += 2; - return make("operator&"); - case 'N': - First += 2; - return make("operator&="); - case 'S': - First += 2; - return make("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make("operator()"); - case 'm': - First += 2; - return make("operator,"); - case 'o': - First += 2; - return make("operator~"); - // ::= cv # (cast) - case 'v': { - First += 2; + if (const auto *Op = parseOperatorEncoding()) { + if (Op->getKind() == OperatorInfo::CCast) { + // ::= cv # (cast) SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); // If we're parsing an encoding, State != nullptr and the conversion // operators' could have a that refers to some @@ -2877,185 +3062,29 @@ AbstractManglingParser::parseOperatorName(NameState *State) { if (State) State->CtorDtorConversion = true; return make(Ty); } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make("operator delete[]"); - case 'e': - First += 2; - return make("operator*"); - case 'l': - First += 2; - return make("operator delete"); - case 'v': - First += 2; - return make("operator/"); - case 'V': - First += 2; - return make("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make("operator^"); - case 'O': - First += 2; - return make("operator^="); - case 'q': - First += 2; - return make("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make("operator>="); - case 't': - First += 2; - return make("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make("operator<="); + + if (Op->getKind() >= OperatorInfo::Unnameable) + /* Not a nameable operator. */ + return nullptr; + if (Op->getKind() == OperatorInfo::Member && !Op->getFlag()) + /* Not a nameable MemberExpr */ + return nullptr; + + return make(Op->getName()); + } + + if (consumeIf("li")) { // ::= li # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make(SN); - } - case 's': - First += 2; - return make("operator<<"); - case 'S': - First += 2; - return make("operator<<="); - case 't': - First += 2; - return make("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make("operator-"); - case 'I': - First += 2; - return make("operator-="); - case 'l': - First += 2; - return make("operator*"); - case 'L': - First += 2; - return make("operator*="); - case 'm': - First += 2; - return make("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make("operator new[]"); - case 'e': - First += 2; - return make("operator!="); - case 'g': - First += 2; - return make("operator-"); - case 't': - First += 2; - return make("operator!"); - case 'w': - First += 2; - return make("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make("operator||"); - case 'r': - First += 2; - return make("operator|"); - case 'R': - First += 2; - return make("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make("operator->*"); - case 'l': - First += 2; - return make("operator+"); - case 'L': - First += 2; - return make("operator+="); - case 'p': - First += 2; - return make("operator++"); - case 's': - First += 2; - return make("operator+"); - case 't': - First += 2; - return make("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make("operator%"); - case 'M': - First += 2; - return make("operator%="); - case 's': - First += 2; - return make("operator>>"); - case 'S': - First += 2; - return make("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make("operator<=>"); - } - return nullptr; - // ::= v # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; + Node *SN = getDerived().parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make(SN); + } + + if (consumeIf('v')) { + // ::= v # vendor extended operator + if (look() >= '0' && look() <= '9') { + First++; Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; @@ -3063,6 +3092,7 @@ AbstractManglingParser::parseOperatorName(NameState *State) { } return nullptr; } + return nullptr; } @@ -3125,14 +3155,14 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, // ::= N [] [] E // ::= N [] [] E // -// ::= +// ::= [L]* // ::= // ::= // ::= // ::= # empty // ::= // ::= -// extension ::= L +// [*] extension // // := [] M // @@ -3152,90 +3182,77 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { - consumeIf('L'); // extension - - // := [] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // ::= if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'I') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) + if (TA == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically cannot be generated by a + // C++ entity. There will always be [something like] a name between + // them. return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } + if (State) + State->EndsWithTemplateArgs = true; + SoFar = make(SoFar, TA); + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else { + ModuleName *Module = nullptr; + bool IsLocal = consumeIf('L'); // extension + + if (look() == 'S') { + // ::= + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast(S); + } else if (SoFar != nullptr || IsLocal) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } - // Parse an thats actually a . - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; + // ::= [] + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } - // ::= - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); + + // No longer used. + // := [] M + consumeIf('M'); } if (SoFar == nullptr || Subs.empty()) @@ -3330,6 +3347,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // ::= [gs] # x or (with "gs") ::x // ::= [gs] sr + E // # A::x, N::y, A::z; "gs" means leading "::" +// [gs] has been parsed by caller. // ::= sr # T::x / decltype(p)::x // extension ::= sr // # T::N::x /decltype(p)::N::x @@ -3337,7 +3355,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // // ::= template -Node *AbstractManglingParser::parseUnresolvedName() { +Node *AbstractManglingParser::parseUnresolvedName(bool Global) { Node *SoFar = nullptr; // srN [] * E @@ -3371,8 +3389,6 @@ Node *AbstractManglingParser::parseUnresolvedName() { return make(SoFar, Base); } - bool Global = consumeIf("gs"); - // [gs] # x or (with "gs") ::x if (!consumeIf("sr")) { SoFar = getDerived().parseBaseUnresolvedName(); @@ -3884,6 +3900,16 @@ Node *AbstractManglingParser::parseType() { case 'h': First += 2; return make("half"); + // ::= DF _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(DimensionNumber); + } // ::= Di # char32_t case 'i': First += 2; @@ -4031,9 +4057,10 @@ Node *AbstractManglingParser::parseType() { } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -4046,17 +4073,19 @@ Node *AbstractManglingParser::parseType() { // If this is followed by some , and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else if (IsSubst) { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } @@ -4146,43 +4175,6 @@ Node *AbstractManglingParser::parseFunctionParam() { return nullptr; } -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization -template -Node *AbstractManglingParser::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make(ExprList, Ty, NodeArray(), Global, IsArray); -} - // cv # conversion with one argument // cv _ * E # conversion with a different number of arguments template @@ -4395,55 +4387,34 @@ Node *AbstractManglingParser::parseFoldExpr() { if (!consumeIf('f')) return nullptr; - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else + bool IsLeftFold = false, HasInitializer = false; + switch (look()) { + default: return nullptr; + case 'L': + IsLeftFold = true; + HasInitializer = true; + break; + case 'R': + HasInitializer = true; + break; + case 'l': + IsLeftFold = true; + break; + case 'r': + break; + } ++First; - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; - - Node *Pack = getDerived().parseExpr(), *Init = nullptr; + const auto *Op = parseOperatorEncoding(); + if (!Op || Op->getKind() != OperatorInfo::Binary) + return nullptr; + + Node *Pack = getDerived().parseExpr(); if (Pack == nullptr) return nullptr; + + Node *Init = nullptr; if (HasInitializer) { Init = getDerived().parseExpr(); if (Init == nullptr) @@ -4453,7 +4424,7 @@ Node *AbstractManglingParser::parseFoldExpr() { if (IsLeftFold && Init) std::swap(Pack, Init); - return make(IsLeftFold, OperatorName, Pack, Init); + return make(IsLeftFold, Op->getSymbol(), Pack, Init); } // ::= mc [] E @@ -4547,316 +4518,125 @@ Node *AbstractManglingParser::parseSubobjectExpr() { template Node *AbstractManglingParser::parseExpr() { bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - switch (*First) { - case 'L': - return getDerived().parseExprPrimary(); - case 'T': - return getDerived().parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a . - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return getDerived().parseBinaryExpr("&&"); - case 'd': - First += 2; - return getDerived().parsePrefixExpr("&"); - case 'n': - First += 2; - return getDerived().parseBinaryExpr("&"); - case 'N': - First += 2; - return getDerived().parseBinaryExpr("&="); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + const auto *Op = parseOperatorEncoding(); + if (Op) { + auto Sym = Op->getSymbol(); + switch (Op->getKind()) { + case OperatorInfo::Binary: + // Binary operator: lhs @ rhs + return getDerived().parseBinaryExpr(Sym); + case OperatorInfo::Prefix: + // Prefix unary operator: @ expr + return getDerived().parsePrefixExpr(Sym); + case OperatorInfo::Postfix: { + // Postfix unary operator: expr @ + if (consumeIf('_')) + return getDerived().parsePrefixExpr(Sym); + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) return nullptr; - return make("alignof (", Ty, ")"); + return make(Ex, Sym); } - case 'z': { - First += 2; - Node *Ty = getDerived().parseExpr(); - if (Ty == nullptr) + case OperatorInfo::Array: { + // Array Index: lhs [ rhs ] + Node *Base = getDerived().parseExpr(); + if (Base == nullptr) return nullptr; - return make("alignof (", Ty, ")"); - } + Node *Index = getDerived().parseExpr(); + if (Index == nullptr) + return nullptr; + return make(Base, Index); } - return nullptr; - case 'c': - switch (First[1]) { - // cc # const_cast(expression) - case 'c': { - First += 2; + case OperatorInfo::Member: { + // Member access lhs @ rhs + Node *LHS = getDerived().parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = getDerived().parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, Sym, RHS); + } + case OperatorInfo::New: { + // New + // # new (expr-list) type [(init)] + // [gs] nw * _ [pi *] E + // # new[] (expr-list) type [(init)] + // [gs] na * _ [pi *] E + size_t Exprs = Names.size(); + while (!consumeIf('_')) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + Names.push_back(Ex); + } + NodeArray ExprList = popTrailingNodeArray(Exprs); Node *Ty = getDerived().parseType(); if (Ty == nullptr) - return Ty; + return nullptr; + bool HaveInits = consumeIf("pi"); + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + if (!HaveInits) + return nullptr; + Node *Init = getDerived().parseExpr(); + if (Init == nullptr) + return Init; + Names.push_back(Init); + } + NodeArray Inits = popTrailingNodeArray(InitsBegin); + return make(ExprList, Ty, Inits, Global, + /*IsArray=*/Op->getFlag()); + } + case OperatorInfo::Del: { + // Delete Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make("const_cast", Ty, Ex); + return nullptr; + return make(Ex, Global, /*IsArray=*/Op->getFlag()); } - // cl + E # call - case 'l': { - First += 2; + case OperatorInfo::Call: { + // Function Call Node *Callee = getDerived().parseExpr(); if (Callee == nullptr) - return Callee; + return nullptr; size_t ExprsBegin = Names.size(); while (!consumeIf('E')) { Node *E = getDerived().parseExpr(); if (E == nullptr) - return E; + return nullptr; Names.push_back(E); } return make(Callee, popTrailingNodeArray(ExprsBegin)); } - case 'm': - First += 2; - return getDerived().parseBinaryExpr(","); - case 'o': - First += 2; - return getDerived().parsePrefixExpr("~"); - case 'v': - return getDerived().parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return getDerived().parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - return make(E, Global, /*is_array=*/false); - } - case 'n': - return getDerived().parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make(LHS, ".*", RHS); - } - case 't': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make(LHS, ".", RHS); - } - case 'v': - First += 2; - return getDerived().parseBinaryExpr("/"); - case 'V': - First += 2; - return getDerived().parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return getDerived().parseBinaryExpr("^"); - case 'O': - First += 2; - return getDerived().parseBinaryExpr("^="); - case 'q': - First += 2; - return getDerived().parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr(">="); - case 't': - First += 2; - return getDerived().parseBinaryExpr(">"); - } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; - Node *Base = getDerived().parseExpr(); - if (Base == nullptr) + case OperatorInfo::CCast: { + // C Cast: (type)expr + Node *Ty; + { + SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + Ty = getDerived().parseType(); + } + if (Ty == nullptr) return nullptr; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return Index; - return make(Base, Index); - } - case 'l': { - First += 2; - size_t InitsBegin = Names.size(); + + size_t ExprsBegin = Names.size(); + bool IsMany = consumeIf('_'); while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); + Node *E = getDerived().parseExpr(); if (E == nullptr) - return nullptr; + return E; Names.push_back(E); + if (!IsMany) + break; } - return make(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 'c': - First += 2; - return parsePointerToMemberConversionExpr(); - 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) + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + if (!IsMany && Exprs.size() != 1) return nullptr; - return make(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return getDerived().parseNewExpr(); - case 'e': - First += 2; - return getDerived().parseBinaryExpr("!="); - case 'g': - First += 2; - return getDerived().parsePrefixExpr("-"); - case 't': - First += 2; - return getDerived().parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("noexcept (", Ex, ")"); + return make(Ty, Exprs); } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return getDerived().parseUnresolvedName(); - case 'o': - First += 2; - return getDerived().parseBinaryExpr("||"); - case 'r': - First += 2; - return getDerived().parseBinaryExpr("|"); - case 'R': - First += 2; - return getDerived().parseBinaryExpr("|="); - } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return getDerived().parseBinaryExpr("->*"); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("+"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("++"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, "++"); - } - case 's': - First += 2; - return getDerived().parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = getDerived().parseExpr(); - if (L == nullptr) - return nullptr; - Node *R = getDerived().parseExpr(); - if (R == nullptr) - return nullptr; - return make(L, "->", R); - } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; + case OperatorInfo::Conditional: { + // Conditional operator: expr ? expr : expr Node *Cond = getDerived().parseExpr(); if (Cond == nullptr) return nullptr; @@ -4868,145 +4648,118 @@ Node *AbstractManglingParser::parseExpr() { return nullptr; return make(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("reinterpret_cast", T, Ex); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr("%"); - case 'M': - First += 2; - return getDerived().parseBinaryExpr("%="); - case 's': - First += 2; - return getDerived().parseBinaryExpr(">>"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("static_cast", T, Ex); - } - case 'o': - First += 2; - return parseSubobjectExpr(); - case 'p': { - First += 2; - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make(Child); - } - case 'r': - return getDerived().parseUnresolvedName(); - case 't': { - First += 2; + case OperatorInfo::NamedCast: { + // Named cast operation, @(expr) Node *Ty = getDerived().parseType(); if (Ty == nullptr) - return Ty; - return make("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; + return nullptr; Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make("sizeof (", Ex, ")"); + return nullptr; + return make(Sym, Ty, Ex); } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make(R); - } else if (look() == 'f') { - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make("sizeof... (", FP, ")"); - } - return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make(popTrailingNodeArray(ArgsBegin)); - if (!Pack) + case OperatorInfo::OfIdOp: { + // [sizeof/alignof/typeid] ( | ) + Node *Arg = + Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); + if (!Arg) return nullptr; - return make("sizeof... (", Pack, ")"); + return make(Sym, Arg, ")"); } + case OperatorInfo::NameOnly: { + // Not valid as an expression operand. + return nullptr; } - return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("typeid (", Ex, ")"); } - case 'i': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make("typeid (", Ty, ")"); + DEMANGLE_UNREACHABLE; + } + + if (numLeft() < 2) + return nullptr; + + if (look() == 'L') + return getDerived().parseExprPrimary(); + if (look() == 'T') + return getDerived().parseTemplateParam(); + if (look() == 'f') { + // Disambiguate a fold expression from a . + if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) + return getDerived().parseFunctionParam(); + return getDerived().parseFoldExpr(); + } + if (consumeIf("il")) { + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); } - case 'l': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + return make(nullptr, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("mc")) + return parsePointerToMemberConversionExpr(); + if (consumeIf("nx")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return Ex; + return make("noexcept (", Ex, ")"); + } + if (consumeIf("so")) + return parseSubobjectExpr(); + if (consumeIf("sp")) { + Node *Child = getDerived().parseExpr(); + if (Child == nullptr) + return nullptr; + return make(Child); + } + if (consumeIf("sZ")) { + if (look() == 'T') { + Node *R = getDerived().parseTemplateParam(); + if (R == nullptr) return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make(Ty, popTrailingNodeArray(InitsBegin)); + return make(R); } - case 'r': - First += 2; - return make("throw"); - case 'w': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) + Node *FP = getDerived().parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make("sizeof... (", FP, ")"); + } + if (consumeIf("sP")) { + size_t ArgsBegin = Names.size(); + while (!consumeIf('E')) { + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) return nullptr; - return make(Ex); + Names.push_back(Arg); } + auto *Pack = make(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make("sizeof... (", Pack, ")"); + } + if (consumeIf("tl")) { + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) + return nullptr; + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); } - return nullptr; - case 'u': { - ++First; + return make(Ty, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("tr")) + return make("throw"); + if (consumeIf("tw")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(Ex); + } + if (consumeIf('u')) { Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); if (!Name) return nullptr; @@ -5015,45 +4768,35 @@ Node *AbstractManglingParser::parseExpr() { // interpreted as node 'short' or 'ellipsis'. However, neither // __uuidof(short) nor __uuidof(...) can actually appear, so there is no // actual conflict here. + bool IsUUID = false; + Node *UUID = nullptr; if (Name->getBaseName() == "__uuidof") { - if (numLeft() < 2) - return nullptr; - if (*First == 't') { - ++First; - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - return make(Name, makeNodeArray(&Ty, &Ty + 1)); - } - if (*First == 'z') { - ++First; - Node *Ex = getDerived().parseExpr(); - if (!Ex) - return nullptr; - return make(Name, makeNodeArray(&Ex, &Ex + 1)); + if (consumeIf('t')) { + UUID = getDerived().parseType(); + IsUUID = true; + } else if (consumeIf('z')) { + UUID = getDerived().parseExpr(); + IsUUID = true; } } size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseTemplateArg(); - if (E == nullptr) - return E; - Names.push_back(E); + if (IsUUID) { + if (UUID == nullptr) + return nullptr; + Names.push_back(UUID); + } else { + while (!consumeIf('E')) { + Node *E = getDerived().parseTemplateArg(); + if (E == nullptr) + return E; + Names.push_back(E); + } } return make(Name, popTrailingNodeArray(ExprsBegin)); } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return getDerived().parseUnresolvedName(); - } - return nullptr; + + // Only unresolved names remain. + return getDerived().parseUnresolvedName(Global); } // ::= h _ @@ -5086,14 +4829,17 @@ bool AbstractManglingParser::parseCallOffset() { // # second call-offset is result adjustment // ::= T // # base is the nominal target function of thunk -// ::= GV # Guard variable for one-time initialization +// # Guard variable for one-time initialization +// ::= GV // # No // ::= TW # Thread-local wrapper // ::= TH # Thread-local initialization // ::= GR _ # First temporary // ::= GR _ # Subsequent temporaries -// extension ::= TC _ # construction vtable for second-in-first +// # construction vtable for second-in-first +// extension ::= TC _ // extension ::= GR # reference temporary for object +// extension ::= GI # module global initializer template Node *AbstractManglingParser::parseSpecialName() { switch (look()) { @@ -5220,6 +4966,16 @@ Node *AbstractManglingParser::parseSpecialName() { return nullptr; return make("reference temporary for ", Name); } + // GI v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make("initializer for module ", Module); + } } } return nullptr; @@ -5399,43 +5155,41 @@ bool AbstractManglingParser::parseSeqId(size_t *Out) { // ::= Si # ::std::basic_istream > // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > +// The St case is handled specially in parseNestedName. template Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S')) return nullptr; - if (std::islower(look())) { - Node *SpecialSub; + if (look() >= 'a' && look() <= 'z') { + SpecialSubKind Kind; switch (look()) { case 'a': - ++First; - SpecialSub = make(SpecialSubKind::allocator); + Kind = SpecialSubKind::allocator; break; case 'b': - ++First; - SpecialSub = make(SpecialSubKind::basic_string); + Kind = SpecialSubKind::basic_string; break; - case 's': - ++First; - SpecialSub = make(SpecialSubKind::string); + case 'd': + Kind = SpecialSubKind::iostream; break; case 'i': - ++First; - SpecialSub = make(SpecialSubKind::istream); + Kind = SpecialSubKind::istream; break; case 'o': - ++First; - SpecialSub = make(SpecialSubKind::ostream); + Kind = SpecialSubKind::ostream; break; - case 'd': - ++First; - SpecialSub = make(SpecialSubKind::iostream); + case 's': + Kind = SpecialSubKind::string; break; default: return nullptr; } + ++First; + auto *SpecialSub = make(Kind); if (!SpecialSub) return nullptr; + // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. @@ -5714,4 +5468,4 @@ struct ManglingParser : AbstractManglingParser, Alloc> { DEMANGLE_NAMESPACE_END -#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H +#endif // DEMANGLE_ITANIUMDEMANGLE_H diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h index 0403136..6f2d041 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h @@ -9,10 +9,8 @@ #ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H #define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/MicrosoftDemangleNodes.h" #include "llvm/Demangle/StringView.h" -#include "llvm/Demangle/Utility.h" #include diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h index 77446e9..8ad2472 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h @@ -13,7 +13,6 @@ #ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H #define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/StringView.h" #include #include @@ -21,11 +20,11 @@ namespace llvm { namespace itanium_demangle { -class OutputStream; +class OutputBuffer; } } -using llvm::itanium_demangle::OutputStream; +using llvm::itanium_demangle::OutputBuffer; using llvm::itanium_demangle::StringView; namespace llvm { @@ -80,6 +79,7 @@ enum OutputFlags { OF_NoAccessSpecifier = 4, OF_NoMemberType = 8, OF_NoReturnType = 16, + OF_NoVariableType = 32, }; // Types @@ -261,7 +261,7 @@ struct Node { NodeKind kind() const { return Kind; } - virtual void output(OutputStream &OS, OutputFlags Flags) const = 0; + virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0; std::string toString(OutputFlags Flags = OF_Default) const; @@ -282,9 +282,7 @@ struct StructorIdentifierNode; struct ThunkSignatureNode; struct PointerTypeNode; struct ArrayTypeNode; -struct CustomNode; struct TagTypeNode; -struct IntrinsicTypeNode; struct NodeArrayNode; struct QualifiedNameNode; struct TemplateParameterReferenceNode; @@ -300,12 +298,12 @@ struct SpecialTableSymbolNode; struct TypeNode : public Node { explicit TypeNode(NodeKind K) : Node(K) {} - virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0; - virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0; + virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0; + virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0; - void output(OutputStream &OS, OutputFlags Flags) const override { - outputPre(OS, Flags); - outputPost(OS, Flags); + void output(OutputBuffer &OB, OutputFlags Flags) const override { + outputPre(OB, Flags); + outputPost(OB, Flags); } Qualifiers Quals = Q_None; @@ -315,8 +313,8 @@ struct PrimitiveTypeNode : public TypeNode { explicit PrimitiveTypeNode(PrimitiveKind K) : TypeNode(NodeKind::PrimitiveType), PrimKind(K) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override {} + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {} PrimitiveKind PrimKind; }; @@ -325,8 +323,8 @@ struct FunctionSignatureNode : public TypeNode { explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {} FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; // Valid if this FunctionTypeNode is the Pointee of a PointerType or // MemberPointerType. @@ -359,13 +357,13 @@ struct IdentifierNode : public Node { NodeArrayNode *TemplateParams = nullptr; protected: - void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const; + void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const; }; struct VcallThunkIdentifierNode : public IdentifierNode { VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint64_t OffsetInVTable = 0; }; @@ -374,7 +372,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode { DynamicStructorIdentifierNode() : IdentifierNode(NodeKind::DynamicStructorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; VariableSymbolNode *Variable = nullptr; QualifiedNameNode *Name = nullptr; @@ -384,7 +382,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode { struct NamedIdentifierNode : public IdentifierNode { NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView Name; }; @@ -394,7 +392,7 @@ struct IntrinsicFunctionIdentifierNode : public IdentifierNode { : IdentifierNode(NodeKind::IntrinsicFunctionIdentifier), Operator(Operator) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; IntrinsicFunctionKind Operator; }; @@ -403,7 +401,7 @@ struct LiteralOperatorIdentifierNode : public IdentifierNode { LiteralOperatorIdentifierNode() : IdentifierNode(NodeKind::LiteralOperatorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView Name; }; @@ -412,7 +410,7 @@ struct LocalStaticGuardIdentifierNode : public IdentifierNode { LocalStaticGuardIdentifierNode() : IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; bool IsThread = false; uint32_t ScopeIndex = 0; @@ -422,7 +420,7 @@ struct ConversionOperatorIdentifierNode : public IdentifierNode { ConversionOperatorIdentifierNode() : IdentifierNode(NodeKind::ConversionOperatorIdentifier) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; // The type that this operator converts too. TypeNode *TargetType = nullptr; @@ -434,7 +432,7 @@ struct StructorIdentifierNode : public IdentifierNode { : IdentifierNode(NodeKind::StructorIdentifier), IsDestructor(IsDestructor) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; // The name of the class that this is a structor of. IdentifierNode *Class = nullptr; @@ -444,8 +442,8 @@ struct StructorIdentifierNode : public IdentifierNode { struct ThunkSignatureNode : public FunctionSignatureNode { ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; struct ThisAdjustor { uint32_t StaticOffset = 0; @@ -459,8 +457,8 @@ struct ThunkSignatureNode : public FunctionSignatureNode { struct PointerTypeNode : public TypeNode { PointerTypeNode() : TypeNode(NodeKind::PointerType) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; // Is this a pointer, reference, or rvalue-reference? PointerAffinity Affinity = PointerAffinity::None; @@ -476,8 +474,8 @@ struct PointerTypeNode : public TypeNode { struct TagTypeNode : public TypeNode { explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *QualifiedName = nullptr; TagKind Tag; @@ -486,11 +484,11 @@ struct TagTypeNode : public TypeNode { struct ArrayTypeNode : public TypeNode { ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; - void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const; - void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const; + void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const; + void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const; // A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]` NodeArrayNode *Dimensions = nullptr; @@ -501,14 +499,14 @@ struct ArrayTypeNode : public TypeNode { struct IntrinsicNode : public TypeNode { IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {} - void output(OutputStream &OS, OutputFlags Flags) const override {} + void output(OutputBuffer &OB, OutputFlags Flags) const override {} }; struct CustomTypeNode : public TypeNode { CustomTypeNode() : TypeNode(NodeKind::Custom) {} - void outputPre(OutputStream &OS, OutputFlags Flags) const override; - void outputPost(OutputStream &OS, OutputFlags Flags) const override; + void outputPre(OutputBuffer &OB, OutputFlags Flags) const override; + void outputPost(OutputBuffer &OB, OutputFlags Flags) const override; IdentifierNode *Identifier = nullptr; }; @@ -516,9 +514,9 @@ struct CustomTypeNode : public TypeNode { struct NodeArrayNode : public Node { NodeArrayNode() : Node(NodeKind::NodeArray) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; - void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const; + void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const; Node **Nodes = nullptr; size_t Count = 0; @@ -527,7 +525,7 @@ struct NodeArrayNode : public Node { struct QualifiedNameNode : public Node { QualifiedNameNode() : Node(NodeKind::QualifiedName) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; NodeArrayNode *Components = nullptr; @@ -541,7 +539,7 @@ struct TemplateParameterReferenceNode : public Node { TemplateParameterReferenceNode() : Node(NodeKind::TemplateParameterReference) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; SymbolNode *Symbol = nullptr; @@ -556,7 +554,7 @@ struct IntegerLiteralNode : public Node { IntegerLiteralNode(uint64_t Value, bool IsNegative) : Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint64_t Value = 0; bool IsNegative = false; @@ -566,7 +564,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode { RttiBaseClassDescriptorNode() : IdentifierNode(NodeKind::RttiBaseClassDescriptor) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; uint32_t NVOffset = 0; int32_t VBPtrOffset = 0; @@ -576,7 +574,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode { struct SymbolNode : public Node { explicit SymbolNode(NodeKind K) : Node(K) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *Name = nullptr; }; @@ -584,7 +582,7 @@ struct SpecialTableSymbolNode : public SymbolNode { explicit SpecialTableSymbolNode() : SymbolNode(NodeKind::SpecialTableSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; QualifiedNameNode *TargetName = nullptr; Qualifiers Quals = Qualifiers::Q_None; }; @@ -593,7 +591,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode { LocalStaticGuardVariableNode() : SymbolNode(NodeKind::LocalStaticGuardVariable) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; bool IsVisible = false; }; @@ -601,7 +599,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode { struct EncodedStringLiteralNode : public SymbolNode { EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StringView DecodedString; bool IsTruncated = false; @@ -611,7 +609,7 @@ struct EncodedStringLiteralNode : public SymbolNode { struct VariableSymbolNode : public SymbolNode { VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; StorageClass SC = StorageClass::None; TypeNode *Type = nullptr; @@ -620,7 +618,7 @@ struct VariableSymbolNode : public SymbolNode { struct FunctionSymbolNode : public SymbolNode { FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {} - void output(OutputStream &OS, OutputFlags Flags) const override; + void output(OutputBuffer &OB, OutputFlags Flags) const override; FunctionSignatureNode *Signature = nullptr; }; diff --git a/third_party/llvm/include/llvm/Demangle/StringView.h b/third_party/llvm/include/llvm/Demangle/StringView.h index 378e853..6bbb883 100644 --- a/third_party/llvm/include/llvm/Demangle/StringView.h +++ b/third_party/llvm/include/llvm/Demangle/StringView.h @@ -1,5 +1,5 @@ -//===--- StringView.h -------------------------------------------*- C++ -*-===// -// +//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===// +// Do not edit! See README.txt. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -7,14 +7,16 @@ //===----------------------------------------------------------------------===// // // FIXME: Use std::string_view instead when we support C++17. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_STRINGVIEW_H -#define LLVM_DEMANGLE_STRINGVIEW_H +#ifndef DEMANGLE_STRINGVIEW_H +#define DEMANGLE_STRINGVIEW_H #include "DemangleConfig.h" -#include #include #include @@ -38,15 +40,16 @@ class StringView { StringView substr(size_t Pos, size_t Len = npos) const { assert(Pos <= size()); - return StringView(begin() + Pos, std::min(Len, size() - Pos)); + if (Len > size() - Pos) + Len = size() - Pos; + return StringView(begin() + Pos, Len); } size_t find(char C, size_t From = 0) const { - size_t FindBegin = std::min(From, size()); // Avoid calling memchr with nullptr. - if (FindBegin < size()) { + if (From < size()) { // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) + if (const void *P = ::memchr(First + From, C, size() - From)) return size_t(static_cast(P) - First); } return npos; @@ -98,7 +101,7 @@ class StringView { bool startsWith(StringView Str) const { if (Str.size() > size()) return false; - return std::equal(Str.begin(), Str.end(), begin()); + return std::strncmp(Str.begin(), begin(), Str.size()) == 0; } const char &operator[](size_t Idx) const { return *(begin() + Idx); } @@ -111,7 +114,7 @@ class StringView { inline bool operator==(const StringView &LHS, const StringView &RHS) { return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); + std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; } DEMANGLE_NAMESPACE_END diff --git a/third_party/llvm/include/llvm/Demangle/Utility.h b/third_party/llvm/include/llvm/Demangle/Utility.h index 04ff65a..5f012d7 100644 --- a/third_party/llvm/include/llvm/Demangle/Utility.h +++ b/third_party/llvm/include/llvm/Demangle/Utility.h @@ -1,71 +1,80 @@ -//===--- Utility.h ----------------------------------------------*- C++ -*-===// -// +//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===// +// Do not edit! See README.txt. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // -// Provide some utility classes for use in the demangler(s). +// Provide some utility classes for use in the demangler. +// There are two copies of this file in the source tree. The one in libcxxabi +// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update +// the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_UTILITY_H -#define LLVM_DEMANGLE_UTILITY_H +#ifndef DEMANGLE_UTILITY_H +#define DEMANGLE_UTILITY_H #include "StringView.h" +#include #include #include #include -#include +#include #include DEMANGLE_NAMESPACE_BEGIN // Stream that AST nodes write their string representation into after the AST // has been parsed. -class OutputStream { +class OutputBuffer { char *Buffer = nullptr; size_t CurrentPosition = 0; size_t BufferCapacity = 0; - // Ensure there is at least n more positions in buffer. + // Ensure there are at least N more positions in the buffer. void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { + size_t Need = N + CurrentPosition; + if (Need > BufferCapacity) { + // Reduce the number of reallocations, with a bit of hysteresis. The + // number here is chosen so the first allocation will more-than-likely not + // allocate more than 1K. + Need += 1024 - 32; BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; + if (BufferCapacity < Need) + BufferCapacity = Need; Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); } } - void writeUnsigned(uint64_t N, bool isNeg = false) { - // Handle special case... - if (N == 0) { - *this << '0'; - return; - } - - char Temp[21]; - char *TempPtr = std::end(Temp); + OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { + std::array Temp; + char *TempPtr = Temp.data() + Temp.size(); - while (N) { + // Output at least one character. + do { *--TempPtr = char('0' + N % 10); N /= 10; - } + } while (N); - // Add negative sign... + // Add negative sign. if (isNeg) *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); + + return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); } public: - OutputStream(char *StartBuf, size_t Size) + OutputBuffer(char *StartBuf, size_t Size) : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; + OutputBuffer() = default; + // Non-copyable + OutputBuffer(const OutputBuffer &) = delete; + OutputBuffer &operator=(const OutputBuffer &) = delete; + void reset(char *Buffer_, size_t BufferCapacity_) { CurrentPosition = 0; Buffer = Buffer_; @@ -77,55 +86,70 @@ class OutputStream { unsigned CurrentPackIndex = std::numeric_limits::max(); unsigned CurrentPackMax = std::numeric_limits::max(); - OutputStream &operator+=(StringView R) { - size_t Size = R.size(); - if (Size == 0) - return *this; - grow(Size); - std::memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; + OutputBuffer &operator+=(StringView R) { + if (size_t Size = R.size()) { + grow(Size); + std::memcpy(Buffer + CurrentPosition, R.begin(), Size); + CurrentPosition += Size; + } return *this; } - OutputStream &operator+=(char C) { + OutputBuffer &operator+=(char C) { grow(1); Buffer[CurrentPosition++] = C; return *this; } - OutputStream &operator<<(StringView R) { return (*this += R); } + OutputBuffer &prepend(StringView R) { + size_t Size = R.size(); - OutputStream &operator<<(char C) { return (*this += C); } + grow(Size); + std::memmove(Buffer + Size, Buffer, CurrentPosition); + std::memcpy(Buffer, R.begin(), Size); + CurrentPosition += Size; - OutputStream &operator<<(long long N) { - if (N < 0) - writeUnsigned(static_cast(-N), true); - else - writeUnsigned(static_cast(N)); return *this; } - OutputStream &operator<<(unsigned long long N) { - writeUnsigned(N, false); - return *this; + OutputBuffer &operator<<(StringView R) { return (*this += R); } + + OutputBuffer &operator<<(char C) { return (*this += C); } + + OutputBuffer &operator<<(long long N) { + return writeUnsigned(static_cast(std::abs(N)), N < 0); } - OutputStream &operator<<(long N) { + OutputBuffer &operator<<(unsigned long long N) { + return writeUnsigned(N, false); + } + + OutputBuffer &operator<<(long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned long N) { + OutputBuffer &operator<<(unsigned long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(int N) { + OutputBuffer &operator<<(int N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned int N) { + OutputBuffer &operator<<(unsigned int N) { return this->operator<<(static_cast(N)); } + void insert(size_t Pos, const char *S, size_t N) { + assert(Pos <= CurrentPosition); + if (N == 0) + return; + grow(N); + std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); + std::memcpy(Buffer + Pos, S, N); + CurrentPosition += N; + } + size_t getCurrentPosition() const { return CurrentPosition; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } @@ -143,7 +167,6 @@ class OutputStream { template class SwapAndRestore { T &Restore; T OriginalValue; - bool ShouldRestore = true; public: SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} @@ -152,26 +175,13 @@ template class SwapAndRestore { : 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() { Restore = std::move(OriginalValue); } SwapAndRestore(const SwapAndRestore &) = delete; SwapAndRestore &operator=(const SwapAndRestore &) = delete; }; -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, +inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, size_t InitSize) { size_t BufferSize; if (Buf == nullptr) { @@ -182,7 +192,7 @@ inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, } else BufferSize = *N; - S.reset(Buf, BufferSize); + OB.reset(Buf, BufferSize); return true; } diff --git a/third_party/llvm/lib/Demangle/DLangDemangle.cpp b/third_party/llvm/lib/Demangle/DLangDemangle.cpp new file mode 100644 index 0000000..7cecd80 --- /dev/null +++ b/third_party/llvm/lib/Demangle/DLangDemangle.cpp @@ -0,0 +1,578 @@ +//===--- DLangDemangle.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a demangler for the D programming language as specified +/// in the ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/Utility.h" + +#include +#include +#include + +using namespace llvm; +using llvm::itanium_demangle::OutputBuffer; +using llvm::itanium_demangle::StringView; + +namespace { + +/// Demangle information structure. +struct Demangler { + /// Initialize the information structure we use to pass around information. + /// + /// \param Mangled String to demangle. + Demangler(const char *Mangled); + + /// Extract and demangle the mangled symbol and append it to the output + /// string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#name_mangling . + /// \see https://dlang.org/spec/abi.html#MangledName . + const char *parseMangle(OutputBuffer *Demangled); + +private: + /// Extract and demangle a given mangled symbol and append it to the output + /// string. + /// + /// \param Demangled output buffer to write the demangled name. + /// \param Mangled mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#name_mangling . + /// \see https://dlang.org/spec/abi.html#MangledName . + const char *parseMangle(OutputBuffer *Demangled, const char *Mangled); + + /// Extract the number from a given string. + /// + /// \param Mangled string to extract the number. + /// \param Ret assigned result value. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \note A result larger than UINT_MAX is considered a failure. + /// + /// \see https://dlang.org/spec/abi.html#Number . + const char *decodeNumber(const char *Mangled, unsigned long &Ret); + + /// Extract the back reference position from a given string. + /// + /// \param Mangled string to extract the back reference position. + /// \param Ret assigned result value. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \note Ret is always >= 0 on success, and unspecified on failure + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#NumberBackRef . + const char *decodeBackrefPos(const char *Mangled, long &Ret); + + /// Extract the symbol pointed by the back reference form a given string. + /// + /// \param Mangled string to extract the back reference position. + /// \param Ret assigned result value. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + const char *decodeBackref(const char *Mangled, const char *&Ret); + + /// Extract and demangle backreferenced symbol from a given mangled symbol + /// and append it to the output string. + /// + /// \param Demangled output buffer to write the demangled name. + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#IdentifierBackRef . + const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle backreferenced type from a given mangled symbol + /// and append it to the output string. + /// + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#back_ref . + /// \see https://dlang.org/spec/abi.html#TypeBackRef . + const char *parseTypeBackref(const char *Mangled); + + /// Check whether it is the beginning of a symbol name. + /// + /// \param Mangled string to extract the symbol name. + /// + /// \return true on success, false otherwise. + /// + /// \see https://dlang.org/spec/abi.html#SymbolName . + bool isSymbolName(const char *Mangled); + + /// Extract and demangle an identifier from a given mangled symbol append it + /// to the output string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#SymbolName . + const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle the plain identifier from a given mangled symbol and + /// prepend/append it to the output string, with a special treatment for some + /// magic compiler generated symbols. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// \param Len Length of the mangled symbol name. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#LName . + const char *parseLName(OutputBuffer *Demangled, const char *Mangled, + unsigned long Len); + + /// Extract and demangle the qualified symbol from a given mangled symbol + /// append it to the output string. + /// + /// \param Demangled Output buffer to write the demangled name. + /// \param Mangled Mangled symbol to be demangled. + /// + /// \return The remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#QualifiedName . + const char *parseQualified(OutputBuffer *Demangled, const char *Mangled); + + /// Extract and demangle a type from a given mangled symbol append it to + /// the output string. + /// + /// \param Mangled mangled symbol to be demangled. + /// + /// \return the remaining string on success or nullptr on failure. + /// + /// \see https://dlang.org/spec/abi.html#Type . + const char *parseType(const char *Mangled); + + /// The string we are demangling. + const char *Str; + /// The index of the last back reference. + int LastBackref; +}; + +} // namespace + +const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) { + // Return nullptr if trying to extract something that isn't a digit. + if (Mangled == nullptr || !std::isdigit(*Mangled)) + return nullptr; + + unsigned long Val = 0; + + do { + unsigned long Digit = Mangled[0] - '0'; + + // Check for overflow. + if (Val > (std::numeric_limits::max() - Digit) / 10) + return nullptr; + + Val = Val * 10 + Digit; + ++Mangled; + } while (std::isdigit(*Mangled)); + + if (*Mangled == '\0') + return nullptr; + + Ret = Val; + return Mangled; +} + +const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { + // Return nullptr if trying to extract something that isn't a digit + if (Mangled == nullptr || !std::isalpha(*Mangled)) + return nullptr; + + // Any identifier or non-basic type that has been emitted to the mangled + // symbol before will not be emitted again, but is referenced by a special + // sequence encoding the relative position of the original occurrence in the + // mangled symbol name. + // Numbers in back references are encoded with base 26 by upper case letters + // A-Z for higher digits but lower case letters a-z for the last digit. + // NumberBackRef: + // [a-z] + // [A-Z] NumberBackRef + // ^ + unsigned long Val = 0; + + while (std::isalpha(*Mangled)) { + // Check for overflow + if (Val > (std::numeric_limits::max() - 25) / 26) + break; + + Val *= 26; + + if (Mangled[0] >= 'a' && Mangled[0] <= 'z') { + Val += Mangled[0] - 'a'; + if ((long)Val <= 0) + break; + Ret = Val; + return Mangled + 1; + } + + Val += Mangled[0] - 'A'; + ++Mangled; + } + + return nullptr; +} + +const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) { + assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!"); + Ret = nullptr; + + // Position of 'Q' + const char *Qpos = Mangled; + long RefPos; + ++Mangled; + + Mangled = decodeBackrefPos(Mangled, RefPos); + if (Mangled == nullptr) + return nullptr; + + if (RefPos > Qpos - Str) + return nullptr; + + // Set the position of the back reference. + Ret = Qpos - RefPos; + + return Mangled; +} + +const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled, + const char *Mangled) { + // An identifier back reference always points to a digit 0 to 9. + // IdentifierBackRef: + // Q NumberBackRef + // ^ + const char *Backref; + unsigned long Len; + + // Get position of the back reference + Mangled = decodeBackref(Mangled, Backref); + + // Must point to a simple identifier + Backref = decodeNumber(Backref, Len); + if (Backref == nullptr || strlen(Backref) < Len) + return nullptr; + + Backref = parseLName(Demangled, Backref, Len); + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +const char *Demangler::parseTypeBackref(const char *Mangled) { + // A type back reference always points to a letter. + // TypeBackRef: + // Q NumberBackRef + // ^ + const char *Backref; + + // If we appear to be moving backwards through the mangle string, then + // bail as this may be a recursive back reference. + if (Mangled - Str >= LastBackref) + return nullptr; + + int SaveRefPos = LastBackref; + LastBackref = Mangled - Str; + + // Get position of the back reference. + Mangled = decodeBackref(Mangled, Backref); + + // Can't decode back reference. + if (Backref == nullptr) + return nullptr; + + // TODO: Add support for function type back references. + Backref = parseType(Backref); + + LastBackref = SaveRefPos; + + if (Backref == nullptr) + return nullptr; + + return Mangled; +} + +bool Demangler::isSymbolName(const char *Mangled) { + long Ret; + const char *Qref = Mangled; + + if (std::isdigit(*Mangled)) + return true; + + // TODO: Handle template instances. + + if (*Mangled != 'Q') + return false; + + Mangled = decodeBackrefPos(Mangled + 1, Ret); + if (Mangled == nullptr || Ret > Qref - Str) + return false; + + return std::isdigit(Qref[-Ret]); +} + +const char *Demangler::parseMangle(OutputBuffer *Demangled, + const char *Mangled) { + // A D mangled symbol is comprised of both scope and type information. + // MangleName: + // _D QualifiedName Type + // _D QualifiedName Z + // ^ + // The caller should have guaranteed that the start pointer is at the + // above location. + // Note that type is never a function type, but only the return type of + // a function or the type of a variable. + Mangled += 2; + + Mangled = parseQualified(Demangled, Mangled); + + if (Mangled != nullptr) { + // Artificial symbols end with 'Z' and have no type. + if (*Mangled == 'Z') + ++Mangled; + else { + Mangled = parseType(Mangled); + } + } + + return Mangled; +} + +const char *Demangler::parseQualified(OutputBuffer *Demangled, + const char *Mangled) { + // Qualified names are identifiers separated by their encoded length. + // Nested functions also encode their argument types without specifying + // what they return. + // QualifiedName: + // SymbolFunctionName + // SymbolFunctionName QualifiedName + // ^ + // SymbolFunctionName: + // SymbolName + // SymbolName TypeFunctionNoReturn + // SymbolName M TypeFunctionNoReturn + // SymbolName M TypeModifiers TypeFunctionNoReturn + // The start pointer should be at the above location. + + // Whether it has more than one symbol + size_t NotFirst = false; + do { + // Skip over anonymous symbols. + if (*Mangled == '0') { + do + ++Mangled; + while (*Mangled == '0'); + + continue; + } + + if (NotFirst) + *Demangled << '.'; + NotFirst = true; + + Mangled = parseIdentifier(Demangled, Mangled); + + } while (Mangled && isSymbolName(Mangled)); + + return Mangled; +} + +const char *Demangler::parseIdentifier(OutputBuffer *Demangled, + const char *Mangled) { + unsigned long Len; + + if (Mangled == nullptr || *Mangled == '\0') + return nullptr; + + if (*Mangled == 'Q') + return parseSymbolBackref(Demangled, Mangled); + + // TODO: Parse lengthless template instances. + + const char *Endptr = decodeNumber(Mangled, Len); + + if (Endptr == nullptr || Len == 0) + return nullptr; + + if (strlen(Endptr) < Len) + return nullptr; + + Mangled = Endptr; + + // TODO: Parse template instances with a length prefix. + + // There can be multiple different declarations in the same function that + // have the same mangled name. To make the mangled names unique, a fake + // parent in the form `__Sddd' is added to the symbol. + if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { + const char *NumPtr = Mangled + 3; + while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) + ++NumPtr; + + if (Mangled + Len == NumPtr) { + // Skip over the fake parent. + Mangled += Len; + return parseIdentifier(Demangled, Mangled); + } + + // Else demangle it as a plain identifier. + } + + return parseLName(Demangled, Mangled, Len); +} + +const char *Demangler::parseType(const char *Mangled) { + if (*Mangled == '\0') + return nullptr; + + switch (*Mangled) { + // TODO: Parse type qualifiers. + // TODO: Parse function types. + // TODO: Parse compound types. + // TODO: Parse delegate types. + // TODO: Parse tuple types. + + // Basic types. + case 'i': + ++Mangled; + // TODO: Add type name dumping + return Mangled; + + // TODO: Add support for the rest of the basic types. + + // Back referenced type. + case 'Q': + return parseTypeBackref(Mangled); + + default: // unhandled. + return nullptr; + } +} + +const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled, + unsigned long Len) { + switch (Len) { + case 6: + if (strncmp(Mangled, "__initZ", Len + 1) == 0) { + // The static initializer for a given symbol. + Demangled->prepend("initializer for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { + // The vtable symbol for a given class. + Demangled->prepend("vtable for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 7: + if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { + // The classinfo symbol for a given class. + Demangled->prepend("ClassInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 11: + if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { + // The interface symbol for a given class. + Demangled->prepend("Interface for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + + case 12: + if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { + // The ModuleInfo symbol for a given module. + Demangled->prepend("ModuleInfo for "); + Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); + Mangled += Len; + return Mangled; + } + break; + } + + *Demangled << StringView(Mangled, Len); + Mangled += Len; + + return Mangled; +} + +Demangler::Demangler(const char *Mangled) + : Str(Mangled), LastBackref(strlen(Mangled)) {} + +const char *Demangler::parseMangle(OutputBuffer *Demangled) { + return parseMangle(Demangled, this->Str); +} + +char *llvm::dlangDemangle(const char *MangledName) { + if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + OutputBuffer Demangled; + if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024)) + return nullptr; + + if (strcmp(MangledName, "_Dmain") == 0) { + Demangled << "D main"; + } else { + + Demangler D = Demangler(MangledName); + MangledName = D.parseMangle(&Demangled); + + // Check that the entire symbol was successfully demangled. + if (MangledName == nullptr || *MangledName != '\0') { + std::free(Demangled.getBuffer()); + return nullptr; + } + } + + // OutputBuffer's internal buffer is not null terminated and therefore we need + // to add it to comply with C null terminated strings. + if (Demangled.getCurrentPosition() > 0) { + Demangled << '\0'; + Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1); + return Demangled.getBuffer(); + } + + std::free(Demangled.getBuffer()); + return nullptr; +} diff --git a/third_party/llvm/lib/Demangle/Demangle.cpp b/third_party/llvm/lib/Demangle/Demangle.cpp index 1851fb7..13aa286 100644 --- a/third_party/llvm/lib/Demangle/Demangle.cpp +++ b/third_party/llvm/lib/Demangle/Demangle.cpp @@ -12,32 +12,53 @@ #include "llvm/Demangle/Demangle.h" #include +#include -static bool isItaniumEncoding(const std::string &MangledName) { - size_t Pos = MangledName.find_first_not_of('_'); - // A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'. - return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z'; +static bool isItaniumEncoding(const char *S) { + // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'. + return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0; } -static bool isRustEncoding(const std::string &MangledName) { +static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; } + +static bool isDLangEncoding(const std::string &MangledName) { return MangledName.size() >= 2 && MangledName[0] == '_' && - MangledName[1] == 'R'; + MangledName[1] == 'D'; } std::string llvm::demangle(const std::string &MangledName) { - char *Demangled; + std::string Result; + const char *S = MangledName.c_str(); + + if (nonMicrosoftDemangle(S, Result)) + return Result; + + if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result)) + return Result; + + if (char *Demangled = + microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) { + Result = Demangled; + std::free(Demangled); + return Result; + } + + return MangledName; +} + +bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) { + char *Demangled = nullptr; if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); + Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr); else if (isRustEncoding(MangledName)) - Demangled = rustDemangle(MangledName.c_str(), nullptr, nullptr, nullptr); - else - Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr, - nullptr, nullptr); + Demangled = rustDemangle(MangledName, nullptr, nullptr, nullptr); + else if (isDLangEncoding(MangledName)) + Demangled = dlangDemangle(MangledName); if (!Demangled) - return MangledName; + return false; - std::string Ret = Demangled; + Result = Demangled; std::free(Demangled); - return Ret; + return true; } diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp index fad9b6b..5d2fb2b 100644 --- a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -19,9 +19,7 @@ #include #include #include -#include #include -#include using namespace llvm; using namespace llvm::itanium_demangle; @@ -333,21 +331,21 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf, int InternalStatus = demangle_success; Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; + OutputBuffer OB; Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, OB, 1024)) InternalStatus = demangle_memory_alloc_failure; else { assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; + AST->print(OB); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = OB.getCurrentPosition(); + Buf = OB.getBuffer(); } if (Status) @@ -385,14 +383,14 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { } static char *printNode(const Node *RootNode, char *Buf, size_t *N) { - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; - RootNode->print(S); - S += '\0'; + RootNode->print(OB); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { @@ -406,8 +404,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { case Node::KAbiTagAttr: Name = static_cast(Name)->Base; continue; - case Node::KStdQualifiedName: - Name = static_cast(Name)->Child; + case Node::KModuleEntity: + Name = static_cast(Name)->Name; continue; case Node::KNestedName: Name = static_cast(Name)->Name; @@ -430,8 +428,8 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, return nullptr; const Node *Name = static_cast(RootNode)->getName(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; KeepGoingLocalFunction: @@ -447,27 +445,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, break; } + if (Name->getKind() == Node::KModuleEntity) + Name = static_cast(Name)->Name; + switch (Name->getKind()) { - case Node::KStdQualifiedName: - S += "std"; - break; case Node::KNestedName: - static_cast(Name)->Qual->print(S); + static_cast(Name)->Qual->print(OB); break; case Node::KLocalName: { auto *LN = static_cast(Name); - LN->Encoding->print(S); - S += "::"; + LN->Encoding->print(OB); + OB += "::"; Name = LN->Entity; goto KeepGoingLocalFunction; } default: break; } - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { @@ -483,17 +481,17 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, return nullptr; NodeArray Params = static_cast(RootNode)->getParams(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; - S += '('; - Params.printWithComma(S); - S += ')'; - S += '\0'; + OB += '('; + Params.printWithComma(OB); + OB += ')'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionReturnType( @@ -501,18 +499,18 @@ char *ItaniumPartialDemangler::getFunctionReturnType( if (!isFunction()) return nullptr; - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) + OutputBuffer OB; + if (!initializeOutputBuffer(Buf, N, OB, 128)) return nullptr; if (const Node *Ret = static_cast(RootNode)->getReturnType()) - Ret->print(S); + Ret->print(OB); - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { @@ -552,8 +550,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { case Node::KNestedName: N = static_cast(N)->Name; break; - case Node::KStdQualifiedName: - N = static_cast(N)->Child; + case Node::KModuleEntity: + N = static_cast(N)->Name; break; } } diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index 3032071..d8da3b4 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -965,13 +965,13 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { void Demangler::memorizeIdentifier(IdentifierNode *Identifier) { // Render this class template name into a string buffer so that we can // memorize it for the purpose of back-referencing. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); - Identifier->output(OS, OF_Default); - OS << '\0'; - char *Name = OS.getBuffer(); + Identifier->output(OB, OF_Default); + OB << '\0'; + char *Name = OB.getBuffer(); StringView Owned = copyString(Name); memorizeString(Owned); @@ -1107,7 +1107,7 @@ static void writeHexDigit(char *Buffer, uint8_t Digit) { *Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10); } -static void outputHex(OutputStream &OS, unsigned C) { +static void outputHex(OutputBuffer &OB, unsigned C) { assert (C != 0); // It's easier to do the math if we can work from right to left, but we need @@ -1130,43 +1130,43 @@ static void outputHex(OutputStream &OS, unsigned C) { TempBuffer[Pos--] = 'x'; assert(Pos >= 0); TempBuffer[Pos--] = '\\'; - OS << StringView(&TempBuffer[Pos + 1]); + OB << StringView(&TempBuffer[Pos + 1]); } -static void outputEscapedChar(OutputStream &OS, unsigned C) { +static void outputEscapedChar(OutputBuffer &OB, unsigned C) { switch (C) { case '\0': // nul - OS << "\\0"; + OB << "\\0"; return; case '\'': // single quote - OS << "\\\'"; + OB << "\\\'"; return; case '\"': // double quote - OS << "\\\""; + OB << "\\\""; return; case '\\': // backslash - OS << "\\\\"; + OB << "\\\\"; return; case '\a': // bell - OS << "\\a"; + OB << "\\a"; return; case '\b': // backspace - OS << "\\b"; + OB << "\\b"; return; case '\f': // form feed - OS << "\\f"; + OB << "\\f"; return; case '\n': // new line - OS << "\\n"; + OB << "\\n"; return; case '\r': // carriage return - OS << "\\r"; + OB << "\\r"; return; case '\t': // tab - OS << "\\t"; + OB << "\\t"; return; case '\v': // vertical tab - OS << "\\v"; + OB << "\\v"; return; default: break; @@ -1174,11 +1174,11 @@ static void outputEscapedChar(OutputStream &OS, unsigned C) { if (C > 0x1F && C < 0x7F) { // Standard ascii char. - OS << (char)C; + OB << (char)C; return; } - outputHex(OS, C); + outputHex(OB, C); } static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { @@ -1273,7 +1273,7 @@ FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { EncodedStringLiteralNode * Demangler::demangleStringLiteral(StringView &MangledName) { // This function uses goto, so declare all variables up front. - OutputStream OS; + OutputBuffer OB; StringView CRC; uint64_t StringByteSize; bool IsWcharT = false; @@ -1284,7 +1284,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) { EncodedStringLiteralNode *Result = Arena.alloc(); // Must happen before the first `goto StringLiteralError`. - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); @@ -1329,7 +1329,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) { goto StringLiteralError; wchar_t W = demangleWcharLiteral(MangledName); if (StringByteSize != 2 || Result->IsTruncated) - outputEscapedChar(OS, W); + outputEscapedChar(OB, W); StringByteSize -= 2; if (Error) goto StringLiteralError; @@ -1371,19 +1371,19 @@ Demangler::demangleStringLiteral(StringView &MangledName) { unsigned NextChar = decodeMultiByteChar(StringBytes, CharIndex, CharBytes); if (CharIndex + 1 < NumChars || Result->IsTruncated) - outputEscapedChar(OS, NextChar); + outputEscapedChar(OB, NextChar); } } - OS << '\0'; - ResultBuffer = OS.getBuffer(); + OB << '\0'; + ResultBuffer = OB.getBuffer(); Result->DecodedString = copyString(ResultBuffer); std::free(ResultBuffer); return Result; StringLiteralError: Error = true; - std::free(OS.getBuffer()); + std::free(OB.getBuffer()); return nullptr; } @@ -1447,16 +1447,16 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { return nullptr; // Render the parent symbol's name into a buffer. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) // FIXME: Propagate out-of-memory as an error? std::terminate(); - OS << '`'; - Scope->output(OS, OF_Default); - OS << '\''; - OS << "::`" << Number << "'"; - OS << '\0'; - char *Result = OS.getBuffer(); + OB << '`'; + Scope->output(OB, OF_Default); + OB << '\''; + OB << "::`" << Number << "'"; + OB << '\0'; + char *Result = OB.getBuffer(); Identifier->Name = copyString(Result); std::free(Result); return Identifier; @@ -2313,19 +2313,19 @@ void Demangler::dumpBackReferences() { (int)Backrefs.FunctionParamCount); // Create an output stream so we can render each type. - OutputStream OS; - if (!initializeOutputStream(nullptr, nullptr, OS, 1024)) + OutputBuffer OB; + if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) std::terminate(); for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { - OS.setCurrentPosition(0); + OB.setCurrentPosition(0); TypeNode *T = Backrefs.FunctionParams[I]; - T->output(OS, OF_Default); + T->output(OB, OF_Default); - std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(), - OS.getBuffer()); + std::printf(" [%d] - %.*s\n", (int)I, (int)OB.getCurrentPosition(), + OB.getBuffer()); } - std::free(OS.getBuffer()); + std::free(OB.getBuffer()); if (Backrefs.FunctionParamCount > 0) std::printf("\n"); @@ -2342,7 +2342,7 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, char *Buf, size_t *N, int *Status, MSDemangleFlags Flags) { Demangler D; - OutputStream S; + OutputBuffer OB; StringView Name{MangledName}; SymbolNode *AST = D.parse(Name); @@ -2361,18 +2361,20 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, OF = OutputFlags(OF | OF_NoReturnType); if (Flags & MSDF_NoMemberType) OF = OutputFlags(OF | OF_NoMemberType); + if (Flags & MSDF_NoVariableType) + OF = OutputFlags(OF | OF_NoVariableType); int InternalStatus = demangle_success; if (D.Error) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, OB, 1024)) InternalStatus = demangle_memory_alloc_failure; else { - AST->output(S, OF); - S += '\0'; + AST->output(OB, OF); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = OB.getCurrentPosition(); + Buf = OB.getBuffer(); } if (Status) diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp index 9fe157b..d07d05a 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/MicrosoftDemangleNodes.h" -#include "llvm/Demangle/DemangleConfig.h" #include "llvm/Demangle/Utility.h" #include #include @@ -21,97 +20,97 @@ using namespace ms_demangle; #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ case Enum::Value: \ - OS << Desc; \ + OB << Desc; \ break; // Writes a space if the last token does not end with a punctuation. -static void outputSpaceIfNecessary(OutputStream &OS) { - if (OS.empty()) +static void outputSpaceIfNecessary(OutputBuffer &OB) { + if (OB.empty()) return; - char C = OS.back(); + char C = OB.back(); if (std::isalnum(C) || C == '>') - OS << " "; + OB << " "; } -static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { +static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) { switch (Q) { case Q_Const: - OS << "const"; + OB << "const"; break; case Q_Volatile: - OS << "volatile"; + OB << "volatile"; break; case Q_Restrict: - OS << "__restrict"; + OB << "__restrict"; break; default: break; } } -static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, +static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, Qualifiers Mask, bool NeedSpace) { if (!(Q & Mask)) return NeedSpace; if (NeedSpace) - OS << " "; + OB << " "; - outputSingleQualifier(OS, Mask); + outputSingleQualifier(OB, Mask); return true; } -static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, +static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, bool SpaceAfter) { if (Q == Q_None) return; - size_t Pos1 = OS.getCurrentPosition(); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); - SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); - size_t Pos2 = OS.getCurrentPosition(); + size_t Pos1 = OB.getCurrentPosition(); + SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore); + SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore); + SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore); + size_t Pos2 = OB.getCurrentPosition(); if (SpaceAfter && Pos2 > Pos1) - OS << " "; + OB << " "; } -static void outputCallingConvention(OutputStream &OS, CallingConv CC) { - outputSpaceIfNecessary(OS); +static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { + outputSpaceIfNecessary(OB); switch (CC) { case CallingConv::Cdecl: - OS << "__cdecl"; + OB << "__cdecl"; break; case CallingConv::Fastcall: - OS << "__fastcall"; + OB << "__fastcall"; break; case CallingConv::Pascal: - OS << "__pascal"; + OB << "__pascal"; break; case CallingConv::Regcall: - OS << "__regcall"; + OB << "__regcall"; break; case CallingConv::Stdcall: - OS << "__stdcall"; + OB << "__stdcall"; break; case CallingConv::Thiscall: - OS << "__thiscall"; + OB << "__thiscall"; break; case CallingConv::Eabi: - OS << "__eabi"; + OB << "__eabi"; break; case CallingConv::Vectorcall: - OS << "__vectorcall"; + OB << "__vectorcall"; break; case CallingConv::Clrcall: - OS << "__clrcall"; + OB << "__clrcall"; break; case CallingConv::Swift: - OS << "__attribute__((__swiftcall__)) "; + OB << "__attribute__((__swiftcall__)) "; break; case CallingConv::SwiftAsync: - OS << "__attribute__((__swiftasynccall__)) "; + OB << "__attribute__((__swiftasynccall__)) "; break; default: break; @@ -119,16 +118,16 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) { } std::string Node::toString(OutputFlags Flags) const { - OutputStream OS; - initializeOutputStream(nullptr, nullptr, OS, 1024); - this->output(OS, Flags); - OS << '\0'; - std::string Owned(OS.getBuffer()); - std::free(OS.getBuffer()); + OutputBuffer OB; + initializeOutputBuffer(nullptr, nullptr, OB, 1024); + this->output(OB, Flags); + OB << '\0'; + std::string Owned(OB.getBuffer()); + std::free(OB.getBuffer()); return Owned; } -void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { switch (PrimKind) { OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); @@ -152,107 +151,107 @@ void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); } - outputQualifiers(OS, Quals, true, false); + outputQualifiers(OB, Quals, true, false); } -void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { - output(OS, Flags, ", "); +void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { + output(OB, Flags, ", "); } -void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, +void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const { if (Count == 0) return; if (Nodes[0]) - Nodes[0]->output(OS, Flags); + Nodes[0]->output(OB, Flags); for (size_t I = 1; I < Count; ++I) { - OS << Separator; - Nodes[I]->output(OS, Flags); + OB << Separator; + Nodes[I]->output(OB, Flags); } } -void EncodedStringLiteralNode::output(OutputStream &OS, +void EncodedStringLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { switch (Char) { case CharKind::Wchar: - OS << "L\""; + OB << "L\""; break; case CharKind::Char: - OS << "\""; + OB << "\""; break; case CharKind::Char16: - OS << "u\""; + OB << "u\""; break; case CharKind::Char32: - OS << "U\""; + OB << "U\""; break; } - OS << DecodedString << "\""; + OB << DecodedString << "\""; if (IsTruncated) - OS << "..."; + OB << "..."; } -void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { +void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsNegative) - OS << '-'; - OS << Value; + OB << '-'; + OB << Value; } -void TemplateParameterReferenceNode::output(OutputStream &OS, +void TemplateParameterReferenceNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (ThunkOffsetCount > 0) - OS << "{"; + OB << "{"; else if (Affinity == PointerAffinity::Pointer) - OS << "&"; + OB << "&"; if (Symbol) { - Symbol->output(OS, Flags); + Symbol->output(OB, Flags); if (ThunkOffsetCount > 0) - OS << ", "; + OB << ", "; } if (ThunkOffsetCount > 0) - OS << ThunkOffsets[0]; + OB << ThunkOffsets[0]; for (int I = 1; I < ThunkOffsetCount; ++I) { - OS << ", " << ThunkOffsets[I]; + OB << ", " << ThunkOffsets[I]; } if (ThunkOffsetCount > 0) - OS << "}"; + OB << "}"; } -void IdentifierNode::outputTemplateParameters(OutputStream &OS, +void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const { if (!TemplateParams) return; - OS << "<"; - TemplateParams->output(OS, Flags); - OS << ">"; + OB << "<"; + TemplateParams->output(OB, Flags); + OB << ">"; } -void DynamicStructorIdentifierNode::output(OutputStream &OS, +void DynamicStructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsDestructor) - OS << "`dynamic atexit destructor for "; + OB << "`dynamic atexit destructor for "; else - OS << "`dynamic initializer for "; + OB << "`dynamic initializer for "; if (Variable) { - OS << "`"; - Variable->output(OS, Flags); - OS << "''"; + OB << "`"; + Variable->output(OB, Flags); + OB << "''"; } else { - OS << "'"; - Name->output(OS, Flags); - OS << "''"; + OB << "'"; + Name->output(OB, Flags); + OB << "''"; } } -void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { - OS << Name; - outputTemplateParameters(OS, Flags); +void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { + OB << Name; + outputTemplateParameters(OB, Flags); } -void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, +void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { switch (Operator) { OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); @@ -350,188 +349,188 @@ void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, case IntrinsicFunctionKind::None: break; } - outputTemplateParameters(OS, Flags); + outputTemplateParameters(OB, Flags); } -void LocalStaticGuardIdentifierNode::output(OutputStream &OS, +void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsThread) - OS << "`local static thread guard'"; + OB << "`local static thread guard'"; else - OS << "`local static guard'"; + OB << "`local static guard'"; if (ScopeIndex > 0) - OS << "{" << ScopeIndex << "}"; + OB << "{" << ScopeIndex << "}"; } -void ConversionOperatorIdentifierNode::output(OutputStream &OS, +void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "operator"; - outputTemplateParameters(OS, Flags); - OS << " "; - TargetType->output(OS, Flags); + OB << "operator"; + outputTemplateParameters(OB, Flags); + OB << " "; + TargetType->output(OB, Flags); } -void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { +void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { if (IsDestructor) - OS << "~"; - Class->output(OS, Flags); - outputTemplateParameters(OS, Flags); + OB << "~"; + Class->output(OB, Flags); + outputTemplateParameters(OB, Flags); } -void LiteralOperatorIdentifierNode::output(OutputStream &OS, +void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "operator \"\"" << Name; - outputTemplateParameters(OS, Flags); + OB << "operator \"\"" << Name; + outputTemplateParameters(OB, Flags); } -void FunctionSignatureNode::outputPre(OutputStream &OS, +void FunctionSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { if (!(Flags & OF_NoAccessSpecifier)) { if (FunctionClass & FC_Public) - OS << "public: "; + OB << "public: "; if (FunctionClass & FC_Protected) - OS << "protected: "; + OB << "protected: "; if (FunctionClass & FC_Private) - OS << "private: "; + OB << "private: "; } if (!(Flags & OF_NoMemberType)) { if (!(FunctionClass & FC_Global)) { if (FunctionClass & FC_Static) - OS << "static "; + OB << "static "; } if (FunctionClass & FC_Virtual) - OS << "virtual "; + OB << "virtual "; if (FunctionClass & FC_ExternC) - OS << "extern \"C\" "; + OB << "extern \"C\" "; } if (!(Flags & OF_NoReturnType) && ReturnType) { - ReturnType->outputPre(OS, Flags); - OS << " "; + ReturnType->outputPre(OB, Flags); + OB << " "; } if (!(Flags & OF_NoCallingConvention)) - outputCallingConvention(OS, CallConvention); + outputCallingConvention(OB, CallConvention); } -void FunctionSignatureNode::outputPost(OutputStream &OS, +void FunctionSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (!(FunctionClass & FC_NoParameterList)) { - OS << "("; + OB << "("; if (Params) - Params->output(OS, Flags); + Params->output(OB, Flags); else - OS << "void"; + OB << "void"; if (IsVariadic) { - if (OS.back() != '(') - OS << ", "; - OS << "..."; + if (OB.back() != '(') + OB << ", "; + OB << "..."; } - OS << ")"; + OB << ")"; } if (Quals & Q_Const) - OS << " const"; + OB << " const"; if (Quals & Q_Volatile) - OS << " volatile"; + OB << " volatile"; if (Quals & Q_Restrict) - OS << " __restrict"; + OB << " __restrict"; if (Quals & Q_Unaligned) - OS << " __unaligned"; + OB << " __unaligned"; if (IsNoexcept) - OS << " noexcept"; + OB << " noexcept"; if (RefQualifier == FunctionRefQualifier::Reference) - OS << " &"; + OB << " &"; else if (RefQualifier == FunctionRefQualifier::RValueReference) - OS << " &&"; + OB << " &&"; if (!(Flags & OF_NoReturnType) && ReturnType) - ReturnType->outputPost(OS, Flags); + ReturnType->outputPost(OB, Flags); } -void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - OS << "[thunk]: "; +void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + OB << "[thunk]: "; - FunctionSignatureNode::outputPre(OS, Flags); + FunctionSignatureNode::outputPre(OB, Flags); } -void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { +void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (FunctionClass & FC_StaticThisAdjust) { - OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; + OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; } else if (FunctionClass & FC_VirtualThisAdjust) { if (FunctionClass & FC_VirtualThisAdjustEx) { - OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " + OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset << ", " << ThisAdjust.StaticOffset << "}'"; } else { - OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " + OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " << ThisAdjust.StaticOffset << "}'"; } } - FunctionSignatureNode::outputPost(OS, Flags); + FunctionSignatureNode::outputPost(OB, Flags); } -void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { if (Pointee->kind() == NodeKind::FunctionSignature) { // If this is a pointer to a function, don't output the calling convention. // It needs to go inside the parentheses. const FunctionSignatureNode *Sig = static_cast(Pointee); - Sig->outputPre(OS, OF_NoCallingConvention); + Sig->outputPre(OB, OF_NoCallingConvention); } else - Pointee->outputPre(OS, Flags); + Pointee->outputPre(OB, Flags); - outputSpaceIfNecessary(OS); + outputSpaceIfNecessary(OB); if (Quals & Q_Unaligned) - OS << "__unaligned "; + OB << "__unaligned "; if (Pointee->kind() == NodeKind::ArrayType) { - OS << "("; + OB << "("; } else if (Pointee->kind() == NodeKind::FunctionSignature) { - OS << "("; + OB << "("; const FunctionSignatureNode *Sig = static_cast(Pointee); - outputCallingConvention(OS, Sig->CallConvention); - OS << " "; + outputCallingConvention(OB, Sig->CallConvention); + OB << " "; } if (ClassParent) { - ClassParent->output(OS, Flags); - OS << "::"; + ClassParent->output(OB, Flags); + OB << "::"; } switch (Affinity) { case PointerAffinity::Pointer: - OS << "*"; + OB << "*"; break; case PointerAffinity::Reference: - OS << "&"; + OB << "&"; break; case PointerAffinity::RValueReference: - OS << "&&"; + OB << "&&"; break; default: assert(false); } - outputQualifiers(OS, Quals, false, false); + outputQualifiers(OB, Quals, false, false); } -void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { +void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { if (Pointee->kind() == NodeKind::ArrayType || Pointee->kind() == NodeKind::FunctionSignature) - OS << ")"; + OB << ")"; - Pointee->outputPost(OS, Flags); + Pointee->outputPost(OB, Flags); } -void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { +void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { if (!(Flags & OF_NoTagSpecifier)) { switch (Tag) { OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); @@ -539,59 +538,59 @@ void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); } - OS << " "; + OB << " "; } - QualifiedName->output(OS, Flags); - outputQualifiers(OS, Quals, true, false); + QualifiedName->output(OB, Flags); + outputQualifiers(OB, Quals, true, false); } -void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} +void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} -void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - ElementType->outputPre(OS, Flags); - outputQualifiers(OS, Quals, true, false); +void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + ElementType->outputPre(OB, Flags); + outputQualifiers(OB, Quals, true, false); } -void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, +void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const { assert(N->kind() == NodeKind::IntegerLiteral); IntegerLiteralNode *ILN = static_cast(N); if (ILN->Value != 0) - ILN->output(OS, Flags); + ILN->output(OB, Flags); } -void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, +void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const { if (Dimensions->Count == 0) return; - outputOneDimension(OS, Flags, Dimensions->Nodes[0]); + outputOneDimension(OB, Flags, Dimensions->Nodes[0]); for (size_t I = 1; I < Dimensions->Count; ++I) { - OS << "]["; - outputOneDimension(OS, Flags, Dimensions->Nodes[I]); + OB << "]["; + outputOneDimension(OB, Flags, Dimensions->Nodes[I]); } } -void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { - OS << "["; - outputDimensionsImpl(OS, Flags); - OS << "]"; +void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { + OB << "["; + outputDimensionsImpl(OB, Flags); + OB << "]"; - ElementType->outputPost(OS, Flags); + ElementType->outputPost(OB, Flags); } -void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - Name->output(OS, Flags); +void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { + Name->output(OB, Flags); } -void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - Signature->outputPre(OS, Flags); - outputSpaceIfNecessary(OS); - Name->output(OS, Flags); - Signature->outputPost(OS, Flags); +void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { + Signature->outputPre(OB, Flags); + outputSpaceIfNecessary(OB); + Name->output(OB, Flags); + Signature->outputPost(OB, Flags); } -void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { +void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { const char *AccessSpec = nullptr; bool IsStatic = true; switch (SC) { @@ -609,52 +608,52 @@ void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { break; } if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) - OS << AccessSpec << ": "; + OB << AccessSpec << ": "; if (!(Flags & OF_NoMemberType) && IsStatic) - OS << "static "; + OB << "static "; - if (Type) { - Type->outputPre(OS, Flags); - outputSpaceIfNecessary(OS); + if (!(Flags & OF_NoVariableType) && Type) { + Type->outputPre(OB, Flags); + outputSpaceIfNecessary(OB); } - Name->output(OS, Flags); - if (Type) - Type->outputPost(OS, Flags); + Name->output(OB, Flags); + if (!(Flags & OF_NoVariableType) && Type) + Type->outputPost(OB, Flags); } -void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { - Identifier->output(OS, Flags); +void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { + Identifier->output(OB, Flags); } -void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} +void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} -void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { - Components->output(OS, Flags, "::"); +void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { + Components->output(OB, Flags, "::"); } -void RttiBaseClassDescriptorNode::output(OutputStream &OS, +void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "`RTTI Base Class Descriptor at ("; - OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " + OB << "`RTTI Base Class Descriptor at ("; + OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " << this->Flags; - OS << ")'"; + OB << ")'"; } -void LocalStaticGuardVariableNode::output(OutputStream &OS, +void LocalStaticGuardVariableNode::output(OutputBuffer &OB, OutputFlags Flags) const { - Name->output(OS, Flags); + Name->output(OB, Flags); } -void VcallThunkIdentifierNode::output(OutputStream &OS, +void VcallThunkIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { - OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; + OB << "`vcall'{" << OffsetInVTable << ", {flat}}"; } -void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { - outputQualifiers(OS, Quals, false, true); - Name->output(OS, Flags); +void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { + outputQualifiers(OB, Quals, false, true); + Name->output(OB, Flags); if (TargetName) { - OS << "{for `"; - TargetName->output(OS, Flags); - OS << "'}"; + OB << "{for `"; + TargetName->output(OB, Flags); + OB << "'}"; } } diff --git a/third_party/llvm/lib/Demangle/RustDemangle.cpp b/third_party/llvm/lib/Demangle/RustDemangle.cpp index f916300..dcac0bd 100644 --- a/third_party/llvm/lib/Demangle/RustDemangle.cpp +++ b/third_party/llvm/lib/Demangle/RustDemangle.cpp @@ -23,7 +23,7 @@ using namespace llvm; -using llvm::itanium_demangle::OutputStream; +using llvm::itanium_demangle::OutputBuffer; using llvm::itanium_demangle::StringView; using llvm::itanium_demangle::SwapAndRestore; @@ -88,7 +88,7 @@ class Demangler { public: // Demangled output. - OutputStream Output; + OutputBuffer Output; Demangler(size_t MaxRecursionLevel = 500); @@ -135,6 +135,7 @@ class Demangler { void printDecimalNumber(uint64_t N); void printBasicType(BasicType); void printLifetime(uint64_t Index); + void printIdentifier(Identifier Ident); char look() const; char consume(); @@ -163,7 +164,7 @@ char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N, } Demangler D; - if (!initializeOutputStream(nullptr, nullptr, D.Output, 1024)) { + if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024)) { if (Status != nullptr) *Status = demangle_memory_alloc_failure; return nullptr; @@ -283,8 +284,7 @@ bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { switch (consume()) { case 'C': { parseOptionalBase62Number('s'); - Identifier Ident = parseIdentifier(); - print(Ident.Name); + printIdentifier(parseIdentifier()); break; } case 'M': { @@ -333,7 +333,7 @@ bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { print(NS); if (!Ident.empty()) { print(":"); - print(Ident.Name); + printIdentifier(Ident); } print('#'); printDecimalNumber(Disambiguator); @@ -342,7 +342,7 @@ bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { // Implementation internal namespaces. if (!Ident.empty()) { print("::"); - print(Ident.Name); + printIdentifier(Ident); } } break; @@ -669,6 +669,8 @@ void Demangler::demangleFnSig() { print("C"); } else { Identifier Ident = parseIdentifier(); + if (Ident.Punycode) + Error = true; for (char C : Ident.Name) { // When mangling ABI string, the "-" is replaced with "_". if (C == '_') @@ -1078,6 +1080,172 @@ void Demangler::printLifetime(uint64_t Index) { } } +static inline bool decodePunycodeDigit(char C, size_t &Value) { + if (isLower(C)) { + Value = C - 'a'; + return true; + } + + if (isDigit(C)) { + Value = 26 + (C - '0'); + return true; + } + + return false; +} + +static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) { + char *Buffer = Output.getBuffer(); + char *Start = Buffer + StartIdx; + char *End = Buffer + Output.getCurrentPosition(); + Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer); +} + +// Encodes code point as UTF-8 and stores results in Output. Returns false if +// CodePoint is not a valid unicode scalar value. +static inline bool encodeUTF8(size_t CodePoint, char *Output) { + if (0xD800 <= CodePoint && CodePoint <= 0xDFFF) + return false; + + if (CodePoint <= 0x7F) { + Output[0] = CodePoint; + return true; + } + + if (CodePoint <= 0x7FF) { + Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F); + Output[1] = 0x80 | (CodePoint & 0x3F); + return true; + } + + if (CodePoint <= 0xFFFF) { + Output[0] = 0xE0 | (CodePoint >> 12); + Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F); + Output[2] = 0x80 | (CodePoint & 0x3F); + return true; + } + + if (CodePoint <= 0x10FFFF) { + Output[0] = 0xF0 | (CodePoint >> 18); + Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F); + Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F); + Output[3] = 0x80 | (CodePoint & 0x3F); + return true; + } + + return false; +} + +// Decodes string encoded using punycode and appends results to Output. +// Returns true if decoding was successful. +static bool decodePunycode(StringView Input, OutputBuffer &Output) { + size_t OutputSize = Output.getCurrentPosition(); + size_t InputIdx = 0; + + // Rust uses an underscore as a delimiter. + size_t DelimiterPos = StringView::npos; + for (size_t I = 0; I != Input.size(); ++I) + if (Input[I] == '_') + DelimiterPos = I; + + if (DelimiterPos != StringView::npos) { + // Copy basic code points before the last delimiter to the output. + for (; InputIdx != DelimiterPos; ++InputIdx) { + char C = Input[InputIdx]; + if (!isValid(C)) + return false; + // Code points are padded with zeros while decoding is in progress. + char UTF8[4] = {C}; + Output += StringView(UTF8, UTF8 + 4); + } + // Skip over the delimiter. + ++InputIdx; + } + + size_t Base = 36; + size_t Skew = 38; + size_t Bias = 72; + size_t N = 0x80; + size_t TMin = 1; + size_t TMax = 26; + size_t Damp = 700; + + auto Adapt = [&](size_t Delta, size_t NumPoints) { + Delta /= Damp; + Delta += Delta / NumPoints; + Damp = 2; + + size_t K = 0; + while (Delta > (Base - TMin) * TMax / 2) { + Delta /= Base - TMin; + K += Base; + } + return K + (((Base - TMin + 1) * Delta) / (Delta + Skew)); + }; + + // Main decoding loop. + for (size_t I = 0; InputIdx != Input.size(); I += 1) { + size_t OldI = I; + size_t W = 1; + size_t Max = std::numeric_limits::max(); + for (size_t K = Base; true; K += Base) { + if (InputIdx == Input.size()) + return false; + char C = Input[InputIdx++]; + size_t Digit = 0; + if (!decodePunycodeDigit(C, Digit)) + return false; + + if (Digit > (Max - I) / W) + return false; + I += Digit * W; + + size_t T; + if (K <= Bias) + T = TMin; + else if (K >= Bias + TMax) + T = TMax; + else + T = K - Bias; + + if (Digit < T) + break; + + if (W > Max / (Base - T)) + return false; + W *= (Base - T); + } + size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1; + Bias = Adapt(I - OldI, NumPoints); + + if (I / NumPoints > Max - N) + return false; + N += I / NumPoints; + I = I % NumPoints; + + // Insert N at position I in the output. + char UTF8[4] = {}; + if (!encodeUTF8(N, UTF8)) + return false; + Output.insert(OutputSize + I * 4, UTF8, 4); + } + + removeNullBytes(Output, OutputSize); + return true; +} + +void Demangler::printIdentifier(Identifier Ident) { + if (Error || !Print) + return; + + if (Ident.Punycode) { + if (!decodePunycode(Ident.Name, Output)) + Error = true; + } else { + print(Ident.Name); + } +} + char Demangler::look() const { if (Error || Position >= Input.size()) return 0; From afc35346e54990b1cb2572dbdac5c9b0dabd0681 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jul 2023 10:26:09 -0400 Subject: [PATCH 24/42] Update LLVM lib/Demangle 3de6b1ce0dd1d735...0cc19b564dd3a2b7ce51840d6 This adds support for demangling D symbols. Ran: cp ~/src/llvm-project/llvm/include/llvm/Demangle/*.{h,def} third_party/llvm/include/llvm/Demangle/ cp ~/src/llvm-project/llvm/lib/Demangle/*.cpp third_party/llvm/lib/Demangle/ cp ~/src/llvm-project/llvm/LICENSE.TXT third_party/llvm/LICENSE.txt And added these 2 new files: git add third_party/llvm/include/llvm/Demangle/StringViewExtras.h git add third_party/llvm/include/llvm/Demangle/ItaniumNodes.def Upstream removed a few parameters, so update demumble.cc to stop passing them. Upstream also changed the first arg to string_view, so switch to C++17 to enable that. This breaks tests due to https://github.com/llvm/llvm-project/issues/63740 Disable failing tests until that is fixed. --- CMakeLists.txt | 2 +- demumble.cc | 6 +- demumble_test.py | 11 +- .../llvm/include/llvm/Demangle/Demangle.h | 29 +- .../include/llvm/Demangle/ItaniumDemangle.h | 1235 +++++++++-------- .../include/llvm/Demangle/ItaniumNodes.def | 95 ++ .../include/llvm/Demangle/MicrosoftDemangle.h | 137 +- .../llvm/Demangle/MicrosoftDemangleNodes.h | 12 +- .../include/llvm/Demangle/StringViewExtras.h | 38 + .../llvm/include/llvm/Demangle/Utility.h | 80 +- .../llvm/lib/Demangle/DLangDemangle.cpp | 382 ++--- third_party/llvm/lib/Demangle/Demangle.cpp | 46 +- .../llvm/lib/Demangle/ItaniumDemangle.cpp | 101 +- .../llvm/lib/Demangle/MicrosoftDemangle.cpp | 615 ++++---- .../lib/Demangle/MicrosoftDemangleNodes.cpp | 7 +- .../llvm/lib/Demangle/RustDemangle.cpp | 112 +- 16 files changed, 1575 insertions(+), 1333 deletions(-) create mode 100644 third_party/llvm/include/llvm/Demangle/ItaniumNodes.def create mode 100644 third_party/llvm/include/llvm/Demangle/StringViewExtras.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bf3e66..1891592 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,5 +40,5 @@ add_executable(demumble third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp third_party/llvm/lib/Demangle/RustDemangle.cpp ) -set_target_properties(demumble PROPERTIES CXX_STANDARD 14 +set_target_properties(demumble PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) diff --git a/demumble.cc b/demumble.cc index 358efe1..a8f5cc9 100644 --- a/demumble.cc +++ b/demumble.cc @@ -23,13 +23,13 @@ static int print_help(FILE* out) { } static void print_demangled(const char* format, const char* s, size_t* n_used) { - if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) { + if (char* itanium = llvm::itaniumDemangle(s)) { printf(format, itanium, s); free(itanium); - } else if (char* rust = llvm::rustDemangle(s, NULL, NULL, NULL)) { + } else if (char* rust = llvm::rustDemangle(s)) { printf(format, rust, s); free(rust); - } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL, NULL, NULL)) { + } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL)) { printf(format, ms, s); free(ms); } else { diff --git a/demumble_test.py b/demumble_test.py index c7d6242..e72582a 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 import os, re, subprocess, sys +# FIXME: Re-enable disabled tests once +# https://github.com/llvm/llvm-project/issues/63740 is fixed. +# Don't make a release until then. tests = [ ('demumble hello', 'hello\n'), ('demumble _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'), @@ -9,9 +12,9 @@ 'std::mem::align_of::\nmylib::foo::bar\n'), ('demumble < _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar', 'std::mem::align_of::\nmylib::foo::bar\n'), - ('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), - ('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), - ('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), + #('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), + #('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), + #('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), ('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for macOS) ('demumble < __Znwi', 'operator new(int)\n'), # Also from stdin ('demumble -m hi _Z1fv ho _Z1gv', 'hi\nf()\nho\ng()\n'), @@ -42,7 +45,7 @@ ('demumble -bx < bar', re.compile(".*unrecognized option `x' in `-bx'.*")), ('demumble < _ZZ3fooiENK3$_0clEi', 'foo(int)::$_0::operator()(int) const\n'), - ('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"), + #('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"), ('demumble < asdf?x@@3HAjkl', 'asdfint xjkl\n'), ('demumble < asdf?x@@3Hjkl', 'asdf?x@@3Hjkl\n'), ('demumble ?x@@3HAjkl', 'int x\n unused suffix: jkl\n'), diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h index 3150e04..e1f73c4 100644 --- a/third_party/llvm/include/llvm/Demangle/Demangle.h +++ b/third_party/llvm/include/llvm/Demangle/Demangle.h @@ -11,6 +11,7 @@ #include #include +#include namespace llvm { /// This is a llvm local version of __cxa_demangle. Other than the name and @@ -28,8 +29,10 @@ enum : int { demangle_success = 0, }; -char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, - int *status); +/// Returns a non-NULL pointer to a NUL-terminated C style string +/// that should be explicitly freed, if successful. Otherwise, may return +/// nullptr if mangled_name is not a valid mangling or is nullptr. +char *itaniumDemangle(std::string_view mangled_name); enum MSDemangleFlags { MSDF_None = 0, @@ -46,31 +49,25 @@ enum MSDemangleFlags { /// success, or nullptr on error. /// If n_read is non-null and demangling was successful, it receives how many /// bytes of the input string were consumed. -/// buf can point to a *n_buf bytes large buffer where the demangled name is -/// stored. If the buffer is too small, it is grown with realloc(). If buf is -/// nullptr, then this malloc()s memory for the result. -/// *n_buf stores the size of buf on input if buf is non-nullptr, and it -/// receives the size of the demangled string on output if n_buf is not nullptr. /// status receives one of the demangle_ enum entries above if it's not nullptr. /// Flags controls various details of the demangled representation. -char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf, - size_t *n_buf, int *status, - MSDemangleFlags Flags = MSDF_None); +char *microsoftDemangle(std::string_view mangled_name, size_t *n_read, + int *status, MSDemangleFlags Flags = MSDF_None); -// Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. -char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); +// Demangles a Rust v0 mangled symbol. +char *rustDemangle(std::string_view MangledName); // Demangles a D mangled symbol. -char *dlangDemangle(const char *MangledName); +char *dlangDemangle(std::string_view MangledName); /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. /// \returns - the demangled string, or a copy of the input string if no /// demangling occurred. -std::string demangle(const std::string &MangledName); +std::string demangle(std::string_view MangledName); -bool nonMicrosoftDemangle(const char *MangledName, std::string &Result); +bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result); /// "Partial" demangler. This supports demangling a string into an AST /// (typically an intermediate stage in itaniumDemangle) and querying certain @@ -87,7 +84,7 @@ struct ItaniumPartialDemangler { 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. + /// second and third parameters to __cxa_demangle. char *finishDemangle(char *Buf, size_t *N) const; /// Get the base name of a function. This doesn't include trailing template diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h index f65d750..68db8c6 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -17,7 +17,7 @@ #define DEMANGLE_ITANIUMDEMANGLE_H #include "DemangleConfig.h" -#include "StringView.h" +#include "StringViewExtras.h" #include "Utility.h" #include #include @@ -26,88 +26,11 @@ #include #include #include +#include +#include +#include #include -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(ModuleName) \ - X(ModuleEntity) \ - X(VectorType) \ - X(PixelVectorType) \ - X(BinaryFPType) \ - 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(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(SubobjectExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(PointerToMemberConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(BoolExpr) \ - X(StringLiteral) \ - X(LambdaExpr) \ - X(EnumLiteral) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - DEMANGLE_NAMESPACE_BEGIN template class PODSmallVector { @@ -235,37 +158,68 @@ template class PODSmallVector { class Node { public: enum Kind : unsigned char { -#define ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR +#define NODE(NodeKind) K##NodeKind, +#include "ItaniumNodes.def" }; /// Three-way bool to track a cached value. Unknown is possible if this node /// has an unexpanded parameter pack below it that may affect this cache. enum class Cache : unsigned char { Yes, No, Unknown, }; + /// Operator precedence for expression nodes. Used to determine required + /// parens in expression emission. + enum class Prec { + Primary, + Postfix, + Unary, + Cast, + PtrMem, + Multiplicative, + Additive, + Shift, + Spaceship, + Relational, + Equality, + And, + Xor, + Ior, + AndIf, + OrIf, + Conditional, + Assign, + Comma, + Default, + }; + private: Kind K; + Prec Precedence : 6; + // FIXME: Make these protected. public: /// Tracks if this node has a component on its right side, in which case we /// need to call printRight. - Cache RHSComponentCache; + Cache RHSComponentCache : 2; /// Track if this node is a (possibly qualified) array type. This can affect /// how we format the output string. - Cache ArrayCache; + Cache ArrayCache : 2; /// Track if this node is a (possibly qualified) function type. This can /// affect how we format the output string. - Cache FunctionCache; + Cache FunctionCache : 2; public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} + Node(Kind K_, Prec Precedence_ = Prec::Primary, + Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_), + ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {} + Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_, + FunctionCache_) {} /// Visit the most-derived object corresponding to this object. template void visit(Fn F) const; @@ -296,6 +250,8 @@ class Node { Kind getKind() const { return K; } + Prec getPrecedence() const { return Precedence; } + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } virtual bool hasArraySlow(OutputBuffer &) const { return false; } virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } @@ -304,6 +260,19 @@ class Node { // get at a node that actually represents some concrete syntax. virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } + // Print this node as an expression operand, surrounding it in parentheses if + // its precedence is [Strictly] weaker than P. + void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default, + bool StrictlyWorse = false) const { + bool Paren = + unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse); + if (Paren) + OB.printOpen(); + print(OB); + if (Paren) + OB.printClose(); + } + void print(OutputBuffer &OB) const { printLeft(OB); if (RHSComponentCache != Cache::No) @@ -319,7 +288,7 @@ class Node { // implementation. virtual void printRight(OutputBuffer &) const {} - virtual StringView getBaseName() const { return StringView(); } + virtual std::string_view getBaseName() const { return {}; } // Silence compiler warnings, this dtor will never be called. virtual ~Node() = default; @@ -353,7 +322,7 @@ class NodeArray { if (!FirstElement) OB += ", "; size_t AfterComma = OB.getCurrentPosition(); - Elements[Idx]->print(OB); + Elements[Idx]->printAsOperand(OB, Node::Prec::Comma); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. @@ -378,10 +347,10 @@ struct NodeArrayNode : Node { class DotSuffix final : public Node { const Node *Prefix; - const StringView Suffix; + const std::string_view Suffix; public: - DotSuffix(const Node *Prefix_, StringView Suffix_) + DotSuffix(const Node *Prefix_, std::string_view Suffix_) : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} template void match(Fn F) const { F(Prefix, Suffix); } @@ -396,13 +365,17 @@ class DotSuffix final : public Node { class VendorExtQualType final : public Node { const Node *Ty; - StringView Ext; + std::string_view Ext; const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_) : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} + const Node *getTy() const { return Ty; } + std::string_view getExt() const { return Ext; } + const Node *getTA() const { return TA; } + template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputBuffer &OB) const override { @@ -451,6 +424,9 @@ class QualType final : public Node { Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} + Qualifiers getQuals() const { return Quals; } + const Node *getChild() const { return Child; } + template void match(Fn F) const { F(Child, Quals); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { @@ -488,10 +464,10 @@ class ConversionOperatorType final : public Node { class PostfixQualifiedType final : public Node { const Node *Ty; - const StringView Postfix; + const std::string_view Postfix; public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) + PostfixQualifiedType(const Node *Ty_, std::string_view Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template void match(Fn F) const { F(Ty, Postfix); } @@ -503,24 +479,44 @@ class PostfixQualifiedType final : public Node { }; class NameType final : public Node { - const StringView Name; + const std::string_view Name; public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + NameType(std::string_view Name_) : Node(KNameType), Name(Name_) {} template void match(Fn F) const { F(Name); } - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } + std::string_view getName() const { return Name; } + std::string_view getBaseName() const override { return Name; } void printLeft(OutputBuffer &OB) const override { OB += Name; } }; +class BitIntType final : public Node { + const Node *Size; + bool Signed; + +public: + BitIntType(const Node *Size_, bool Signed_) + : Node(KBitIntType), Size(Size_), Signed(Signed_) {} + + template void match(Fn F) const { F(Size, Signed); } + + void printLeft(OutputBuffer &OB) const override { + if (!Signed) + OB += "unsigned "; + OB += "_BitInt"; + OB.printOpen(); + Size->printAsOperand(OB); + OB.printClose(); + } +}; + class ElaboratedTypeSpefType : public Node { - StringView Kind; + std::string_view Kind; Node *Child; public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) + ElaboratedTypeSpefType(std::string_view Kind_, Node *Child_) : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} template void match(Fn F) const { F(Kind, Child); } @@ -534,15 +530,17 @@ class ElaboratedTypeSpefType : public Node { struct AbiTagAttr : Node { Node *Base; - StringView Tag; + std::string_view Tag; - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), + AbiTagAttr(Node *Base_, std::string_view Tag_) + : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache, + Base_->FunctionCache), Base(Base_), Tag(Tag_) {} template void match(Fn F) const { F(Base, Tag); } + std::string_view getBaseName() const override { return Base->getBaseName(); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); OB += "[abi:"; @@ -568,12 +566,12 @@ class EnableIfAttr : public Node { class ObjCProtoName : public Node { const Node *Ty; - StringView Protocol; + std::string_view Protocol; friend class PointerType; public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) + ObjCProtoName(const Node *Ty_, std::string_view Protocol_) : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} template void match(Fn F) const { F(Ty, Protocol); } @@ -599,6 +597,8 @@ class PointerType final : public Node { : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} + const Node *getPointee() const { return Pointee; } + template void match(Fn F) const { F(Pointee); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { @@ -690,7 +690,7 @@ class ReferenceType : public Node { void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); std::pair Collapsed = collapse(OB); if (!Collapsed.second) return; @@ -705,7 +705,7 @@ class ReferenceType : public Node { void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); std::pair Collapsed = collapse(OB); if (!Collapsed.second) return; @@ -812,9 +812,9 @@ class FunctionType final : public Node { } void printRight(OutputBuffer &OB) const override { - OB += "("; + OB.printOpen(); Params.printWithComma(OB); - OB += ")"; + OB.printClose(); Ret->printRight(OB); if (CVQuals & QualConst) @@ -844,9 +844,10 @@ class NoexceptSpec : public Node { template void match(Fn F) const { F(E); } void printLeft(OutputBuffer &OB) const override { - OB += "noexcept("; - E->print(OB); - OB += ")"; + OB += "noexcept"; + OB.printOpen(); + E->printAsOperand(OB); + OB.printClose(); } }; @@ -859,9 +860,10 @@ class DynamicExceptionSpec : public Node { template void match(Fn F) const { F(Types); } void printLeft(OutputBuffer &OB) const override { - OB += "throw("; + OB += "throw"; + OB.printOpen(); Types.printWithComma(OB); - OB += ')'; + OB.printClose(); } }; @@ -907,9 +909,9 @@ class FunctionEncoding final : public Node { } void printRight(OutputBuffer &OB) const override { - OB += "("; + OB.printOpen(); Params.printWithComma(OB); - OB += ")"; + OB.printClose(); if (Ret) Ret->printRight(OB); @@ -946,11 +948,11 @@ class LiteralOperator : public Node { }; class SpecialName final : public Node { - const StringView Special; + const std::string_view Special; const Node *Child; public: - SpecialName(StringView Special_, const Node *Child_) + SpecialName(std::string_view Special_, const Node *Child_) : Node(KSpecialName), Special(Special_), Child(Child_) {} template void match(Fn F) const { F(Special, Child); } @@ -989,7 +991,7 @@ struct NestedName : Node { template void match(Fn F) const { F(Qual, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qual->print(OB); @@ -1007,7 +1009,9 @@ struct ModuleName : Node { : Node(KModuleName), Parent(Parent_), Name(Name_), IsPartition(IsPartition_) {} - template void match(Fn F) const { F(Parent, Name); } + template void match(Fn F) const { + F(Parent, Name, IsPartition); + } void printLeft(OutputBuffer &OB) const override { if (Parent) @@ -1027,7 +1031,7 @@ struct ModuleEntity : Node { template void match(Fn F) const { F(Module, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); @@ -1063,7 +1067,7 @@ class QualifiedName final : public Node { template void match(Fn F) const { F(Qualifier, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Qualifier->print(OB); @@ -1077,9 +1081,11 @@ class VectorType final : public Node { const Node *Dimension; public: - VectorType(const Node *BaseType_, Node *Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} + VectorType(const Node *BaseType_, const Node *Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} + + const Node *getBaseType() const { return BaseType; } + const Node *getDimension() const { return Dimension; } template void match(Fn F) const { F(BaseType, Dimension); } @@ -1211,6 +1217,7 @@ class TemplateTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name, Params); } void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); OB += "template<"; Params.printWithComma(OB); OB += "> typename "; @@ -1346,8 +1353,8 @@ class ParameterPackExpansion final : public Node { void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(OB.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(OB.CurrentPackMax, Max); + ScopedOverride SavePackIdx(OB.CurrentPackIndex, Max); + ScopedOverride SavePackMax(OB.CurrentPackMax, Max); size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, @@ -1388,10 +1395,9 @@ class TemplateArgs final : public Node { NodeArray getParams() { return Params; } void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); OB += "<"; Params.printWithComma(OB); - if (OB.back() == '>') - OB += " "; OB += ">"; } }; @@ -1437,38 +1443,38 @@ struct ForwardTemplateReference : Node { bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); return Ref->hasRHSComponent(OB); } bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); return Ref->hasArray(OB); } bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); return Ref->hasFunction(OB); } const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); return Ref->getSyntaxNode(OB); } void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); Ref->printLeft(OB); } void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); + ScopedOverride SavePrinting(Printing, true); Ref->printRight(OB); } }; @@ -1483,7 +1489,7 @@ struct NameWithTemplateArgs : Node { template void match(Fn F) const { F(Name, TemplateArgs); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } void printLeft(OutputBuffer &OB) const override { Name->print(OB); @@ -1500,7 +1506,7 @@ class GlobalQualifiedName final : public Node { template void match(Fn F) const { F(Child); } - StringView getBaseName() const override { return Child->getBaseName(); } + std::string_view getBaseName() const override { return Child->getBaseName(); } void printLeft(OutputBuffer &OB) const override { OB += "::"; @@ -1517,109 +1523,81 @@ enum class SpecialSubKind { iostream, }; -class ExpandedSpecialSubstitution final : public Node { +class SpecialSubstitution; +class ExpandedSpecialSubstitution : public Node { +protected: SpecialSubKind SSK; + ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) + : Node(K_), SSK(SSK_) {} public: ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} + inline ExpandedSpecialSubstitution(SpecialSubstitution const *); template void match(Fn F) const { F(SSK); } - StringView getBaseName() const override { +protected: + bool isInstantiation() const { + return unsigned(SSK) >= unsigned(SpecialSubKind::string); + } + + std::string_view getBaseName() const override { switch (SSK) { case SpecialSubKind::allocator: - return StringView("allocator"); + return {"allocator"}; case SpecialSubKind::basic_string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::istream: - return StringView("basic_istream"); + return {"basic_istream"}; case SpecialSubKind::ostream: - return StringView("basic_ostream"); + return {"basic_ostream"}; case SpecialSubKind::iostream: - return StringView("basic_iostream"); + return {"basic_iostream"}; } DEMANGLE_UNREACHABLE; } +private: void printLeft(OutputBuffer &OB) const override { - switch (SSK) { - case SpecialSubKind::allocator: - OB += "std::allocator"; - break; - case SpecialSubKind::basic_string: - OB += "std::basic_string"; - break; - case SpecialSubKind::string: - OB += "std::basic_string, " - "std::allocator >"; - break; - case SpecialSubKind::istream: - OB += "std::basic_istream >"; - break; - case SpecialSubKind::ostream: - OB += "std::basic_ostream >"; - break; - case SpecialSubKind::iostream: - OB += "std::basic_iostream >"; - break; + OB << "std::" << getBaseName(); + if (isInstantiation()) { + OB << ""; + if (SSK == SpecialSubKind::string) + OB << ", std::allocator"; + OB << ">"; } } }; -class SpecialSubstitution final : public Node { +class SpecialSubstitution final : public ExpandedSpecialSubstitution { public: - SpecialSubKind SSK; - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} template void match(Fn F) const { F(SSK); } - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); + std::string_view getBaseName() const override { + std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); + if (isInstantiation()) { + // The instantiations are typedefs that drop the "basic_" prefix. + assert(llvm::itanium_demangle::starts_with(SV, "basic_")); + SV.remove_prefix(sizeof("basic_") - 1); } - DEMANGLE_UNREACHABLE; + return SV; } void printLeft(OutputBuffer &OB) const override { - switch (SSK) { - case SpecialSubKind::allocator: - OB += "std::allocator"; - break; - case SpecialSubKind::basic_string: - OB += "std::basic_string"; - break; - case SpecialSubKind::string: - OB += "std::string"; - break; - case SpecialSubKind::istream: - OB += "std::istream"; - break; - case SpecialSubKind::ostream: - OB += "std::ostream"; - break; - case SpecialSubKind::iostream: - OB += "std::iostream"; - break; - } + OB << "std::" << getBaseName(); } }; +inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( + SpecialSubstitution const *SS) + : ExpandedSpecialSubstitution(SS->SSK) {} + class CtorDtorName final : public Node { const Node *Basename; const bool IsDtor; @@ -1654,10 +1632,11 @@ class DtorName : public Node { }; class UnnamedTypeName : public Node { - const StringView Count; + const std::string_view Count; public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + UnnamedTypeName(std::string_view Count_) + : Node(KUnnamedTypeName), Count(Count_) {} template void match(Fn F) const { F(Count); } @@ -1671,11 +1650,11 @@ class UnnamedTypeName : public Node { class ClosureTypeName : public Node { NodeArray TemplateParams; NodeArray Params; - StringView Count; + std::string_view Count; public: ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, - StringView Count_) + std::string_view Count_) : Node(KClosureTypeName), TemplateParams(TemplateParams_), Params(Params_), Count(Count_) {} @@ -1685,13 +1664,14 @@ class ClosureTypeName : public Node { void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { + ScopedOverride LT(OB.GtIsGt, 0); OB += "<"; TemplateParams.printWithComma(OB); OB += ">"; } - OB += "("; + OB.printOpen(); Params.printWithComma(OB); - OB += ")"; + OB.printClose(); } void printLeft(OutputBuffer &OB) const override { @@ -1711,9 +1691,9 @@ class StructuredBindingName : public Node { template void match(Fn F) const { F(Bindings); } void printLeft(OutputBuffer &OB) const override { - OB += '['; + OB.printOpen('['); Bindings.printWithComma(OB); - OB += ']'; + OB.printClose(']'); } }; @@ -1721,32 +1701,35 @@ class StructuredBindingName : public Node { class BinaryExpr : public Node { const Node *LHS; - const StringView InfixOperator; + const std::string_view InfixOperator; const Node *RHS; public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { - } + BinaryExpr(const Node *LHS_, std::string_view InfixOperator_, + const Node *RHS_, Prec Prec_) + : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), + RHS(RHS_) {} - template void match(Fn F) const { F(LHS, InfixOperator, RHS); } + template void match(Fn F) const { + F(LHS, InfixOperator, RHS, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - OB += "("; - - OB += "("; - LHS->print(OB); - OB += ") "; + bool ParenAll = OB.isGtInsideTemplateArgs() && + (InfixOperator == ">" || InfixOperator == ">>"); + if (ParenAll) + OB.printOpen(); + // Assignment is right associative, with special LHS precedence. + bool IsAssign = getPrecedence() == Prec::Assign; + LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign); + // No space before comma operator + if (!(InfixOperator == ",")) + OB += " "; OB += InfixOperator; - OB += " ("; - RHS->print(OB); - OB += ")"; - - if (InfixOperator == ">") - OB += ")"; + OB += " "; + RHS->printAsOperand(OB, getPrecedence(), IsAssign); + if (ParenAll) + OB.printClose(); } }; @@ -1755,34 +1738,35 @@ class ArraySubscriptExpr : public Node { const Node *Op2; public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) + : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} - template void match(Fn F) const { F(Op1, Op2); } + template void match(Fn F) const { + F(Op1, Op2, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - OB += "("; - Op1->print(OB); - OB += ")["; - Op2->print(OB); - OB += "]"; + Op1->printAsOperand(OB, getPrecedence()); + OB.printOpen('['); + Op2->printAsOperand(OB); + OB.printClose(']'); } }; class PostfixExpr : public Node { const Node *Child; - const StringView Operator; + const std::string_view Operator; public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + PostfixExpr(const Node *Child_, std::string_view Operator_, Prec Prec_) + : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} - template void match(Fn F) const { F(Child, Operator); } + template void match(Fn F) const { + F(Child, Operator, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - OB += "("; - Child->print(OB); - OB += ")"; + Child->printAsOperand(OB, getPrecedence(), true); OB += Operator; } }; @@ -1793,56 +1777,55 @@ class ConditionalExpr : public Node { const Node *Else; public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, + Prec Prec_) + : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} - template void match(Fn F) const { F(Cond, Then, Else); } + template void match(Fn F) const { + F(Cond, Then, Else, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - OB += "("; - Cond->print(OB); - OB += ") ? ("; - Then->print(OB); - OB += ") : ("; - Else->print(OB); - OB += ")"; + Cond->printAsOperand(OB, getPrecedence()); + OB += " ? "; + Then->printAsOperand(OB); + OB += " : "; + Else->printAsOperand(OB, Prec::Assign, true); } }; class MemberExpr : public Node { const Node *LHS; - const StringView Kind; + const std::string_view Kind; const Node *RHS; public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + MemberExpr(const Node *LHS_, std::string_view Kind_, const Node *RHS_, + Prec Prec_) + : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - template void match(Fn F) const { F(LHS, Kind, RHS); } + template void match(Fn F) const { + F(LHS, Kind, RHS, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - LHS->print(OB); + LHS->printAsOperand(OB, getPrecedence(), true); OB += Kind; - // Parenthesize pointer-to-member deference argument. - bool IsPtr = Kind.back() == '*'; - if (IsPtr) - OB += '('; - RHS->print(OB); - if (IsPtr) - OB += ')'; + RHS->printAsOperand(OB, getPrecedence(), false); } }; class SubobjectExpr : public Node { const Node *Type; const Node *SubExpr; - StringView Offset; + std::string_view Offset; NodeArray UnionSelectors; bool OnePastTheEnd; public: - SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, - NodeArray UnionSelectors_, bool OnePastTheEnd_) + SubobjectExpr(const Node *Type_, const Node *SubExpr_, + std::string_view Offset_, NodeArray UnionSelectors_, + bool OnePastTheEnd_) : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} @@ -1859,7 +1842,7 @@ class SubobjectExpr : public Node { OB += "0"; } else if (Offset[0] == 'n') { OB += "-"; - OB += Offset.dropFront(); + OB += std::string_view(Offset.data() + 1, Offset.size() - 1); } else { OB += Offset; } @@ -1868,43 +1851,54 @@ class SubobjectExpr : public Node { }; class EnclosingExpr : public Node { - const StringView Prefix; + const std::string_view Prefix; const Node *Infix; - const StringView Postfix; + const std::string_view Postfix; public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} + EnclosingExpr(std::string_view Prefix_, const Node *Infix_, + Prec Prec_ = Prec::Primary) + : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} - template void match(Fn F) const { F(Prefix, Infix, Postfix); } + template void match(Fn F) const { + F(Prefix, Infix, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { OB += Prefix; + OB.printOpen(); Infix->print(OB); + OB.printClose(); OB += Postfix; } }; class CastExpr : public Node { // cast_kind(from) - const StringView CastKind; + const std::string_view 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_) {} + CastExpr(std::string_view CastKind_, const Node *To_, const Node *From_, + Prec Prec_) + : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} - template void match(Fn F) const { F(CastKind, To, From); } + template void match(Fn F) const { + F(CastKind, To, From, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { OB += CastKind; - OB += "<"; - To->printLeft(OB); - OB += ">("; - From->printLeft(OB); - OB += ")"; + { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + To->printLeft(OB); + OB += ">"; + } + OB.printOpen(); + From->printAsOperand(OB); + OB.printClose(); } }; @@ -1918,10 +1912,11 @@ class SizeofParamPackExpr : public Node { template void match(Fn F) const { F(Pack); } void printLeft(OutputBuffer &OB) const override { - OB += "sizeof...("; + OB += "sizeof..."; + OB.printOpen(); ParameterPackExpansion PPE(Pack); PPE.printLeft(OB); - OB += ")"; + OB.printClose(); } }; @@ -1930,16 +1925,18 @@ class CallExpr : public Node { NodeArray Args; public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) + : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} - template void match(Fn F) const { F(Callee, Args); } + template void match(Fn F) const { + F(Callee, Args, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { Callee->print(OB); - OB += "("; + OB.printOpen(); Args.printWithComma(OB); - OB += ")"; + OB.printClose(); } }; @@ -1952,12 +1949,12 @@ class NewExpr : public Node { bool IsArray; // new[] ? public: NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} + bool IsArray_, Prec Prec_) + : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), + InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); + F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); } void printLeft(OutputBuffer &OB) const override { @@ -1967,16 +1964,16 @@ class NewExpr : public Node { if (IsArray) OB += "[]"; if (!ExprList.empty()) { - OB += "("; + OB.printOpen(); ExprList.printWithComma(OB); - OB += ")"; + OB.printClose(); } - OB += ' '; + OB += " "; Type->print(OB); if (!InitList.empty()) { - OB += "("; + OB.printOpen(); InitList.printWithComma(OB); - OB += ")"; + OB.printClose(); } } }; @@ -1987,10 +1984,13 @@ class DeleteExpr : public Node { bool IsArray; public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) + : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} - template void match(Fn F) const { F(Op, IsGlobal, IsArray); } + template void match(Fn F) const { + F(Op, IsGlobal, IsArray, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { if (IsGlobal) @@ -2004,28 +2004,29 @@ class DeleteExpr : public Node { }; class PrefixExpr : public Node { - StringView Prefix; + std::string_view Prefix; Node *Child; public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + PrefixExpr(std::string_view Prefix_, Node *Child_, Prec Prec_) + : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} - template void match(Fn F) const { F(Prefix, Child); } + template void match(Fn F) const { + F(Prefix, Child, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { OB += Prefix; - OB += "("; - Child->print(OB); - OB += ")"; + Child->printAsOperand(OB, getPrecedence()); } }; class FunctionParam : public Node { - StringView Number; + std::string_view Number; public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} + FunctionParam(std::string_view Number_) + : Node(KFunctionParam), Number(Number_) {} template void match(Fn F) const { F(Number); } @@ -2040,39 +2041,45 @@ class ConversionExpr : public Node { NodeArray Expressions; public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) + : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} - template void match(Fn F) const { F(Type, Expressions); } + template void match(Fn F) const { + F(Type, Expressions, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - OB += "("; + OB.printOpen(); Type->print(OB); - OB += ")("; + OB.printClose(); + OB.printOpen(); Expressions.printWithComma(OB); - OB += ")"; + OB.printClose(); } }; class PointerToMemberConversionExpr : public Node { const Node *Type; const Node *SubExpr; - StringView Offset; + std::string_view Offset; public: PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, - StringView Offset_) - : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_), - Offset(Offset_) {} + std::string_view Offset_, Prec Prec_) + : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), + SubExpr(SubExpr_), Offset(Offset_) {} - template void match(Fn F) const { F(Type, SubExpr, Offset); } + template void match(Fn F) const { + F(Type, SubExpr, Offset, getPrecedence()); + } void printLeft(OutputBuffer &OB) const override { - OB += "("; + OB.printOpen(); Type->print(OB); - OB += ")("; + OB.printClose(); + OB.printOpen(); SubExpr->print(OB); - OB += ")"; + OB.printClose(); } }; @@ -2143,11 +2150,11 @@ class BracedRangeExpr : public Node { class FoldExpr : public Node { const Node *Pack, *Init; - StringView OperatorName; + std::string_view OperatorName; bool IsLeftFold; public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, + FoldExpr(bool IsLeftFold_, std::string_view OperatorName_, const Node *Pack_, const Node *Init_) : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), IsLeftFold(IsLeftFold_) {} @@ -2158,41 +2165,33 @@ class FoldExpr : public Node { void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - OB += '('; + OB.printOpen(); ParameterPackExpansion(Pack).print(OB); - OB += ')'; + OB.printClose(); }; - OB += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(OB); - OB += ' '; - OB += OperatorName; - OB += ' '; - } - // ... op pack - OB += "... "; - OB += OperatorName; - OB += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - OB += ' '; - OB += OperatorName; - OB += " ..."; - // pack op ... op init - if (Init != nullptr) { - OB += ' '; - OB += OperatorName; - OB += ' '; - Init->print(OB); - } + OB.printOpen(); + // Either '[init op ]... op pack' or 'pack op ...[ op init]' + // Refactored to '[(init|pack) op ]...[ op (pack|init)]' + // Fold expr operands are cast-expressions + if (!IsLeftFold || Init != nullptr) { + // '(init|pack) op ' + if (IsLeftFold) + Init->printAsOperand(OB, Prec::Cast, true); + else + PrintPack(); + OB << " " << OperatorName << " "; + } + OB << "..."; + if (IsLeftFold || Init != nullptr) { + // ' op (init|pack)' + OB << " " << OperatorName << " "; + if (IsLeftFold) + PrintPack(); + else + Init->printAsOperand(OB, Prec::Cast, true); } - OB += ')'; + OB.printClose(); } }; @@ -2219,7 +2218,7 @@ class BoolExpr : public Node { template void match(Fn F) const { F(Value); } void printLeft(OutputBuffer &OB) const override { - OB += Value ? StringView("true") : StringView("false"); + OB += Value ? std::string_view("true") : std::string_view("false"); } }; @@ -2257,47 +2256,46 @@ class LambdaExpr : public Node { class EnumLiteral : public Node { // ty(integer) const Node *Ty; - StringView Integer; + std::string_view Integer; public: - EnumLiteral(const Node *Ty_, StringView Integer_) + EnumLiteral(const Node *Ty_, std::string_view Integer_) : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {} template void match(Fn F) const { F(Ty, Integer); } void printLeft(OutputBuffer &OB) const override { - OB << "("; + OB.printOpen(); Ty->print(OB); - OB << ")"; + OB.printClose(); if (Integer[0] == 'n') - OB << "-" << Integer.dropFront(1); + OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1); else OB << Integer; } }; class IntegerLiteral : public Node { - StringView Type; - StringView Value; + std::string_view Type; + std::string_view Value; public: - IntegerLiteral(StringView Type_, StringView Value_) + IntegerLiteral(std::string_view Type_, std::string_view Value_) : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} template void match(Fn F) const { F(Type, Value); } void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - OB += "("; + OB.printOpen(); OB += Type; - OB += ")"; + OB.printClose(); } - if (Value[0] == 'n') { - OB += "-"; - OB += Value.dropFront(1); - } else + if (Value[0] == 'n') + OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1); + else OB += Value; if (Type.size() <= 3) @@ -2320,29 +2318,26 @@ constexpr Node::Kind getFloatLiteralKind(long double *) { } template class FloatLiteralImpl : public Node { - const StringView Contents; + const std::string_view Contents; static constexpr Kind KindForClass = float_literal_impl::getFloatLiteralKind((Float *)nullptr); public: - FloatLiteralImpl(StringView Contents_) + FloatLiteralImpl(std::string_view Contents_) : Node(KindForClass), Contents(Contents_) {} template void match(Fn F) const { F(Contents); } void printLeft(OutputBuffer &OB) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - const size_t N = FloatData::mangled_size; - if (static_cast(last - first) > N) { - last = first + N; + if (Contents.size() >= N) { union { Float value; char buf[sizeof(Float)]; }; - const char *t = first; + const char *t = &*Contents.begin(); + const char *last = t + N; char *e = buf; for (; t != last; ++t, ++e) { unsigned d1 = isdigit(*t) ? static_cast(*t - '0') @@ -2357,7 +2352,7 @@ template class FloatLiteralImpl : public Node { #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - OB += StringView(num, num + n); + OB += std::string_view(num, n); } } }; @@ -2371,24 +2366,22 @@ using LongDoubleLiteral = FloatLiteralImpl; template void Node::visit(Fn F) const { switch (K) { -#define CASE(X) case K ## X: return F(static_cast(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE +#define NODE(X) \ + case K##X: \ + return F(static_cast(this)); +#include "ItaniumNodes.def" } assert(0 && "unknown mangling node kind"); } /// Determine the kind of a node from its type. template struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ +#define NODE(X) \ + template <> struct NodeKind { \ + static constexpr Node::Kind Kind = Node::K##X; \ + static constexpr const char *name() { return #X; } \ }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef SPECIALIZATION - -#undef FOR_EACH_NODE_KIND +#include "ItaniumNodes.def" template struct AbstractManglingParser { const char *First; @@ -2486,8 +2479,9 @@ template struct AbstractManglingParser { return res; } - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { + bool consumeIf(std::string_view S) { + if (llvm::itanium_demangle::starts_with( + std::string_view(First, Last - First), S)) { First += S.size(); return true; } @@ -2512,10 +2506,10 @@ template struct AbstractManglingParser { size_t numLeft() const { return static_cast(Last - First); } - StringView parseNumber(bool AllowNegative = false); + std::string_view parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); + std::string_view parseBareSourceName(); bool parseSeqId(size_t *Out); Node *parseSubstitution(); @@ -2526,16 +2520,16 @@ template struct AbstractManglingParser { /// Parse the production. Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); - Node *parseIntegerLiteral(StringView Lit); + Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); + Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); + Node *parseIntegerLiteral(std::string_view Lit); Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); - Node *parsePointerToMemberConversionExpr(); + Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); /// Parse the production. @@ -2615,11 +2609,13 @@ template struct AbstractManglingParser { char Enc[2]; // Encoding OIKind Kind; // Kind of operator bool Flag : 1; // Entry-specific flag + Node::Prec Prec : 7; // Precedence const char *Name; // Spelling public: - constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, const char *N) - : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Name{N} {} + constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P, + const char *N) + : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {} public: bool operator<(const OperatorInfo &Other) const { @@ -2634,20 +2630,24 @@ template struct AbstractManglingParser { bool operator!=(const char *Peek) const { return !this->operator==(Peek); } public: - StringView getSymbol() const { - StringView Res = Name; + std::string_view getSymbol() const { + std::string_view Res = Name; if (Kind < Unnameable) { - assert(Res.startsWith("operator") && + assert(llvm::itanium_demangle::starts_with(Res, "operator") && "operator name does not start with 'operator'"); - Res = Res.dropFront(sizeof("operator") - 1); - Res.consumeFront(' '); + Res.remove_prefix(sizeof("operator") - 1); + if (llvm::itanium_demangle::starts_with(Res, ' ')) + Res.remove_prefix(1); } return Res; } - StringView getName() const { return Name; } + std::string_view getName() const { return Name; } OIKind getKind() const { return Kind; } bool getFlag() const { return Flag; } + Node::Prec getPrecedence() const { return Prec; } }; + static const OperatorInfo Ops[]; + static const size_t NumOps; const OperatorInfo *parseOperatorEncoding(); /// Parse the production. @@ -2739,8 +2739,8 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { return make(Encoding, Entity); } -// ::= [L]* -// ::= St [L]* # ::std:: +// ::= +// ::= St # ::std:: // [*] extension template Node * @@ -2753,7 +2753,6 @@ AbstractManglingParser::parseUnscopedName(NameState *State, if (Std == nullptr) return nullptr; } - consumeIf('L'); Node *Res = nullptr; ModuleName *Module = nullptr; @@ -2771,29 +2770,32 @@ AbstractManglingParser::parseUnscopedName(NameState *State, } } - if (Res == nullptr) + if (Res == nullptr || Std != nullptr) { Res = getDerived().parseUnqualifiedName(State, Std, Module); + } return Res; } -// ::= [] [] +// ::= [] L? [] // ::= [] [] -// ::= [] [] -// ::= [] [] +// ::= [] L? [] +// ::= [] L? [] // # structured binding declaration -// ::= [] DC + E +// ::= [] L? DC + E template Node *AbstractManglingParser::parseUnqualifiedName( NameState *State, Node *Scope, ModuleName *Module) { if (getDerived().parseModuleNameOpt(Module)) return nullptr; + consumeIf('L'); + Node *Result; - if (look() == 'U') { - Result = getDerived().parseUnnamedTypeName(State); - } else if (look() >= '1' && look() <= '9') { + if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); + } else if (look() == 'U') { + Result = getDerived().parseUnnamedTypeName(State); } else if (consumeIf("DC")) { // Structured binding size_t BindingsBegin = Names.size(); @@ -2813,7 +2815,7 @@ Node *AbstractManglingParser::parseUnqualifiedName( Result = getDerived().parseOperatorName(State); } - if (Module) + if (Result != nullptr && Module != nullptr) Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); @@ -2859,19 +2861,19 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { TemplateParams.clear(); if (consumeIf("Ut")) { - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Count); } if (consumeIf("Ul")) { - SwapAndRestore SwapParams(ParsingLambdaParamsAtLevel, + ScopedOverride SwapParams(ParsingLambdaParamsAtLevel, TemplateParams.size()); ScopedTemplateParamList LambdaTemplateParams(this); size_t ParamsBegin = Names.size(); while (look() == 'T' && - StringView("yptn").find(look(1)) != StringView::npos) { + std::string_view("yptn").find(look(1)) != std::string_view::npos) { Node *T = parseTemplateParamDecl(); if (!T) return nullptr; @@ -2914,7 +2916,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { } NodeArray Params = popTrailingNodeArray(ParamsBegin); - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make(TempParams, Params, Count); @@ -2936,108 +2938,122 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return nullptr; if (numLeft() < Length || Length == 0) return nullptr; - StringView Name(First, First + Length); + std::string_view Name(First, Length); First += Length; - if (Name.startsWith("_GLOBAL__N")) + if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N")) return make("(anonymous namespace)"); return make(Name); } +// Operator encodings +template +const typename AbstractManglingParser< + Derived, Alloc>::OperatorInfo AbstractManglingParser::Ops[] = { + // Keep ordered by encoding + {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, + {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, + {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, + {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, + {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, + {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "}, + {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, + "operator co_await"}, + {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "}, + {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, + {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, + {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, + {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, + {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast + {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, + {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, + "operator delete[]"}, + {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"}, + {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, + {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, + "operator delete"}, + {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator.*"}, + {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix, + "operator."}, + {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"}, + {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="}, + {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"}, + {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="}, + {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="}, + {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"}, + {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"}, + {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="}, + {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="}, + {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"}, + {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"}, + {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="}, + {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="}, + {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"}, + {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator*"}, + {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"}, + {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary, + "operator new[]"}, + {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, + {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, + {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, + {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"}, + {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, + {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, + {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, + {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="}, + {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"}, + {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator->*"}, + {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"}, + {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"}, + {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix, + "operator->"}, + {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional, + "operator?"}, + {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="}, + {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="}, + {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, + "reinterpret_cast"}, + {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator%"}, + {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, + {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"}, + {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, + {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, + {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "}, + {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, + "typeid "}, + {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "}, +}; +template +const size_t AbstractManglingParser::NumOps = sizeof(Ops) / + sizeof(Ops[0]); + // If the next 2 chars are an operator encoding, consume them and return their // OperatorInfo. Otherwise return nullptr. template const typename AbstractManglingParser::OperatorInfo * AbstractManglingParser::parseOperatorEncoding() { - static const OperatorInfo Ops[] = { - // Keep ordered by encoding - {"aN", OperatorInfo::Binary, false, "operator&="}, - {"aS", OperatorInfo::Binary, false, "operator="}, - {"aa", OperatorInfo::Binary, false, "operator&&"}, - {"ad", OperatorInfo::Prefix, false, "operator&"}, - {"an", OperatorInfo::Binary, false, "operator&"}, - {"at", OperatorInfo::OfIdOp, /*Type*/ true, "alignof ("}, - {"aw", OperatorInfo::NameOnly, false, "operator co_await"}, - {"az", OperatorInfo::OfIdOp, /*Type*/ false, "alignof ("}, - {"cc", OperatorInfo::NamedCast, false, "const_cast"}, - {"cl", OperatorInfo::Call, false, "operator()"}, - {"cm", OperatorInfo::Binary, false, "operator,"}, - {"co", OperatorInfo::Prefix, false, "operator~"}, - {"cv", OperatorInfo::CCast, false, "operator"}, // C Cast - {"dV", OperatorInfo::Binary, false, "operator/="}, - {"da", OperatorInfo::Del, /*Ary*/ true, "operator delete[]"}, - {"dc", OperatorInfo::NamedCast, false, "dynamic_cast"}, - {"de", OperatorInfo::Prefix, false, "operator*"}, - {"dl", OperatorInfo::Del, /*Ary*/ false, "operator delete"}, - {"ds", OperatorInfo::Member, /*Named*/ false, "operator.*"}, - {"dt", OperatorInfo::Member, /*Named*/ false, "operator."}, - {"dv", OperatorInfo::Binary, false, "operator/"}, - {"eO", OperatorInfo::Binary, false, "operator^="}, - {"eo", OperatorInfo::Binary, false, "operator^"}, - {"eq", OperatorInfo::Binary, false, "operator=="}, - {"ge", OperatorInfo::Binary, false, "operator>="}, - {"gt", OperatorInfo::Binary, false, "operator>"}, - {"ix", OperatorInfo::Array, false, "operator[]"}, - {"lS", OperatorInfo::Binary, false, "operator<<="}, - {"le", OperatorInfo::Binary, false, "operator<="}, - {"ls", OperatorInfo::Binary, false, "operator<<"}, - {"lt", OperatorInfo::Binary, false, "operator<"}, - {"mI", OperatorInfo::Binary, false, "operator-="}, - {"mL", OperatorInfo::Binary, false, "operator*="}, - {"mi", OperatorInfo::Binary, false, "operator-"}, - {"ml", OperatorInfo::Binary, false, "operator*"}, - {"mm", OperatorInfo::Postfix, false, "operator--"}, - {"na", OperatorInfo::New, /*Ary*/ true, "operator new[]"}, - {"ne", OperatorInfo::Binary, false, "operator!="}, - {"ng", OperatorInfo::Prefix, false, "operator-"}, - {"nt", OperatorInfo::Prefix, false, "operator!"}, - {"nw", OperatorInfo::New, /*Ary*/ false, "operator new"}, - {"oR", OperatorInfo::Binary, false, "operator|="}, - {"oo", OperatorInfo::Binary, false, "operator||"}, - {"or", OperatorInfo::Binary, false, "operator|"}, - {"pL", OperatorInfo::Binary, false, "operator+="}, - {"pl", OperatorInfo::Binary, false, "operator+"}, - {"pm", OperatorInfo::Member, /*Named*/ false, "operator->*"}, - {"pp", OperatorInfo::Postfix, false, "operator++"}, - {"ps", OperatorInfo::Prefix, false, "operator+"}, - {"pt", OperatorInfo::Member, /*Named*/ true, "operator->"}, - {"qu", OperatorInfo::Conditional, false, "operator?"}, - {"rM", OperatorInfo::Binary, false, "operator%="}, - {"rS", OperatorInfo::Binary, false, "operator>>="}, - {"rc", OperatorInfo::NamedCast, false, "reinterpret_cast"}, - {"rm", OperatorInfo::Binary, false, "operator%"}, - {"rs", OperatorInfo::Binary, false, "operator>>"}, - {"sc", OperatorInfo::NamedCast, false, "static_cast"}, - {"ss", OperatorInfo::Binary, false, "operator<=>"}, - {"st", OperatorInfo::OfIdOp, /*Type*/ true, "sizeof ("}, - {"sz", OperatorInfo::OfIdOp, /*Type*/ false, "sizeof ("}, - {"te", OperatorInfo::OfIdOp, /*Type*/ false, "typeid ("}, - {"ti", OperatorInfo::OfIdOp, /*Type*/ true, "typeid ("}, - }; - const auto NumOps = sizeof(Ops) / sizeof(Ops[0]); - -#ifndef NDEBUG - { - // Verify table order. - static bool Done; - if (!Done) { - Done = true; - for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++) - assert(Op[0] < Op[1] && "Operator table is not ordered"); - } - } -#endif - if (numLeft() < 2) return nullptr; - auto Op = std::lower_bound( - &Ops[0], &Ops[NumOps], First, - [](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; }); - if (Op == &Ops[NumOps] || *Op != First) + // We can't use lower_bound as that can link to symbols in the C++ library, + // and this must remain independant of that. + size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. + while (upper != lower) { + size_t middle = (upper + lower) / 2; + if (Ops[middle] < First) + lower = middle + 1; + else + upper = middle; + } + if (Ops[lower] != First) return nullptr; First += 2; - return Op; + return &Ops[lower]; } // ::= See parseOperatorEncoding() @@ -3049,11 +3065,11 @@ AbstractManglingParser::parseOperatorName(NameState *State) { if (const auto *Op = parseOperatorEncoding()) { if (Op->getKind() == OperatorInfo::CCast) { // ::= cv # (cast) - SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); + ScopedOverride SaveTemplate(TryToParseTemplateArgs, false); // If we're parsing an encoding, State != nullptr and the conversion // operators' could have a that refers to some // s further ahead in the mangled name. - SwapAndRestore SavePermit(PermitForwardTemplateReferences, + ScopedOverride SavePermit(PermitForwardTemplateReferences, PermitForwardTemplateReferences || State != nullptr); Node *Ty = getDerived().parseType(); @@ -3111,19 +3127,11 @@ Node * AbstractManglingParser::parseCtorDtorName(Node *&SoFar, NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } + // Expand the special substitution. + SoFar = make( + static_cast(SoFar)); + if (!SoFar) + return nullptr; } if (consumeIf('C')) { @@ -3152,10 +3160,12 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, return nullptr; } -// ::= N [] [] E -// ::= N [] [] E +// ::= N [] [] +// E +// ::= N [] [] +// E // -// ::= [L]* +// ::= // ::= // ::= // ::= @@ -3219,7 +3229,6 @@ AbstractManglingParser::parseNestedName(NameState *State) { SoFar = getDerived().parseDecltype(); } else { ModuleName *Module = nullptr; - bool IsLocal = consumeIf('L'); // extension if (look() == 'S') { // ::= @@ -3234,7 +3243,7 @@ AbstractManglingParser::parseNestedName(NameState *State) { return nullptr; if (S->getKind() == Node::KModuleName) { Module = static_cast(S); - } else if (SoFar != nullptr || IsLocal) { + } else if (SoFar != nullptr) { return nullptr; // Cannot have a prefix. } else { SoFar = S; @@ -3445,7 +3454,7 @@ Node *AbstractManglingParser::parseUnresolvedName(bool Global) { template Node *AbstractManglingParser::parseAbiTags(Node *N) { while (consumeIf('B')) { - StringView SN = parseBareSourceName(); + std::string_view SN = parseBareSourceName(); if (SN.empty()) return nullptr; N = make(N, SN); @@ -3457,16 +3466,16 @@ Node *AbstractManglingParser::parseAbiTags(Node *N) { // ::= [n] template -StringView +std::string_view AbstractManglingParser::parseNumber(bool AllowNegative) { const char *Tmp = First; if (AllowNegative) consumeIf('n'); if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); + return std::string_view(); while (numLeft() != 0 && std::isdigit(*First)) ++First; - return StringView(Tmp, First); + return std::string_view(Tmp, First - Tmp); } // ::= [0-9]* @@ -3483,11 +3492,11 @@ bool AbstractManglingParser::parsePositiveInteger(size_t *Out) { } template -StringView AbstractManglingParser::parseBareSourceName() { +std::string_view AbstractManglingParser::parseBareSourceName() { size_t Int = 0; if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); + return {}; + std::string_view R(First, Int); First += Int; return R; } @@ -3618,7 +3627,7 @@ Node *AbstractManglingParser::parseDecltype() { return nullptr; if (!consumeIf('E')) return nullptr; - return make("decltype(", E, ")"); + return make("decltype", E); } // ::= A _ @@ -3671,7 +3680,7 @@ Node *AbstractManglingParser::parsePointerToMemberType() { // ::= Te # dependent elaborated type specifier using 'enum' template Node *AbstractManglingParser::parseClassEnumType() { - StringView ElabSpef; + std::string_view ElabSpef; if (consumeIf("Ts")) ElabSpef = "struct"; else if (consumeIf("Tu")) @@ -3695,17 +3704,19 @@ Node *AbstractManglingParser::parseClassEnumType() { template Node *AbstractManglingParser::parseQualifiedType() { if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); + std::string_view Qual = parseBareSourceName(); if (Qual.empty()) return nullptr; // extension ::= U # objc-type - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; + if (llvm::itanium_demangle::starts_with(Qual, "objcproto")) { + constexpr size_t Len = sizeof("objcproto") - 1; + std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len); + std::string_view Proto; { - SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); + ScopedOverride SaveFirst(First, + &*ProtoSourceName.begin()), + SaveLast(Last, &*ProtoSourceName.rbegin() + 1); Proto = parseBareSourceName(); } if (Proto.empty()) @@ -3873,7 +3884,7 @@ Node *AbstractManglingParser::parseType() { // ::= u # vendor extended type case 'u': { ++First; - StringView Res = parseBareSourceName(); + std::string_view Res = parseBareSourceName(); if (Res.empty()) return nullptr; // Typically, s are not considered substitution candidates, @@ -3910,6 +3921,22 @@ Node *AbstractManglingParser::parseType() { return nullptr; return make(DimensionNumber); } + // ::= DB _ # C23 signed _BitInt(N) + // ::= DB _ # C23 signed _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + case 'B': + case 'U': { + bool Signed = look(1) == 'B'; + First += 2; + Node *Size = std::isdigit(look()) ? make(parseNumber()) + : getDerived().parseExpr(); + if (!Size) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(Size, Signed); + } // ::= Di # char32_t case 'i': First += 2; @@ -4105,28 +4132,32 @@ Node *AbstractManglingParser::parseType() { } template -Node *AbstractManglingParser::parsePrefixExpr(StringView Kind) { +Node * +AbstractManglingParser::parsePrefixExpr(std::string_view Kind, + Node::Prec Prec) { Node *E = getDerived().parseExpr(); if (E == nullptr) return nullptr; - return make(Kind, E); + return make(Kind, E, Prec); } template -Node *AbstractManglingParser::parseBinaryExpr(StringView Kind) { +Node * +AbstractManglingParser::parseBinaryExpr(std::string_view Kind, + Node::Prec Prec) { Node *LHS = getDerived().parseExpr(); if (LHS == nullptr) return nullptr; Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(LHS, Kind, RHS); + return make(LHS, Kind, RHS, Prec); } template -Node * -AbstractManglingParser::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); +Node *AbstractManglingParser::parseIntegerLiteral( + std::string_view Lit) { + std::string_view Tmp = parseNumber(true); if (!Tmp.empty() && consumeIf('E')) return make(Lit, Tmp); return nullptr; @@ -4156,7 +4187,7 @@ Node *AbstractManglingParser::parseFunctionParam() { return make("this"); if (consumeIf("fp")) { parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Num); @@ -4167,7 +4198,7 @@ Node *AbstractManglingParser::parseFunctionParam() { if (!consumeIf('p')) return nullptr; parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make(Num); @@ -4183,7 +4214,7 @@ Node *AbstractManglingParser::parseConversionExpr() { return nullptr; Node *Ty; { - SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); Ty = getDerived().parseType(); } @@ -4300,7 +4331,7 @@ Node *AbstractManglingParser::parseExprPrimary() { return nullptr; } case 'D': - if (consumeIf("DnE")) + if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E'))) return make("nullptr"); return nullptr; case 'T': @@ -4321,7 +4352,7 @@ Node *AbstractManglingParser::parseExprPrimary() { Node *T = getDerived().parseType(); if (T == nullptr) return nullptr; - StringView N = parseNumber(/*AllowNegative=*/true); + std::string_view N = parseNumber(/*AllowNegative=*/true); if (N.empty()) return nullptr; if (!consumeIf('E')) @@ -4407,7 +4438,11 @@ Node *AbstractManglingParser::parseFoldExpr() { ++First; const auto *Op = parseOperatorEncoding(); - if (!Op || Op->getKind() != OperatorInfo::Binary) + if (!Op) + return nullptr; + if (!(Op->getKind() == OperatorInfo::Binary + || (Op->getKind() == OperatorInfo::Member + && Op->getName().back() == '*'))) return nullptr; Node *Pack = getDerived().parseExpr(); @@ -4431,17 +4466,19 @@ Node *AbstractManglingParser::parseFoldExpr() { // // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 template -Node *AbstractManglingParser::parsePointerToMemberConversionExpr() { +Node * +AbstractManglingParser::parsePointerToMemberConversionExpr( + Node::Prec Prec) { Node *Ty = getDerived().parseType(); if (!Ty) return nullptr; Node *Expr = getDerived().parseExpr(); if (!Expr) return nullptr; - StringView Offset = getDerived().parseNumber(true); + std::string_view Offset = getDerived().parseNumber(true); if (!consumeIf('E')) return nullptr; - return make(Ty, Expr, Offset); + return make(Ty, Expr, Offset, Prec); } // ::= so [] * [p] E @@ -4456,7 +4493,7 @@ Node *AbstractManglingParser::parseSubobjectExpr() { Node *Expr = getDerived().parseExpr(); if (!Expr) return nullptr; - StringView Offset = getDerived().parseNumber(true); + std::string_view Offset = getDerived().parseNumber(true); size_t SelectorsBegin = Names.size(); while (consumeIf('_')) { Node *Selector = make(parseNumber()); @@ -4525,18 +4562,18 @@ Node *AbstractManglingParser::parseExpr() { switch (Op->getKind()) { case OperatorInfo::Binary: // Binary operator: lhs @ rhs - return getDerived().parseBinaryExpr(Sym); + return getDerived().parseBinaryExpr(Sym, Op->getPrecedence()); case OperatorInfo::Prefix: // Prefix unary operator: @ expr - return getDerived().parsePrefixExpr(Sym); + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); case OperatorInfo::Postfix: { // Postfix unary operator: expr @ if (consumeIf('_')) - return getDerived().parsePrefixExpr(Sym); + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return nullptr; - return make(Ex, Sym); + return make(Ex, Sym, Op->getPrecedence()); } case OperatorInfo::Array: { // Array Index: lhs [ rhs ] @@ -4546,7 +4583,7 @@ Node *AbstractManglingParser::parseExpr() { Node *Index = getDerived().parseExpr(); if (Index == nullptr) return nullptr; - return make(Base, Index); + return make(Base, Index, Op->getPrecedence()); } case OperatorInfo::Member: { // Member access lhs @ rhs @@ -4556,7 +4593,7 @@ Node *AbstractManglingParser::parseExpr() { Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(LHS, Sym, RHS); + return make(LHS, Sym, RHS, Op->getPrecedence()); } case OperatorInfo::New: { // New @@ -4587,14 +4624,15 @@ Node *AbstractManglingParser::parseExpr() { } NodeArray Inits = popTrailingNodeArray(InitsBegin); return make(ExprList, Ty, Inits, Global, - /*IsArray=*/Op->getFlag()); + /*IsArray=*/Op->getFlag(), Op->getPrecedence()); } case OperatorInfo::Del: { // Delete Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return nullptr; - return make(Ex, Global, /*IsArray=*/Op->getFlag()); + return make(Ex, Global, /*IsArray=*/Op->getFlag(), + Op->getPrecedence()); } case OperatorInfo::Call: { // Function Call @@ -4608,13 +4646,14 @@ Node *AbstractManglingParser::parseExpr() { return nullptr; Names.push_back(E); } - return make(Callee, popTrailingNodeArray(ExprsBegin)); + return make(Callee, popTrailingNodeArray(ExprsBegin), + Op->getPrecedence()); } case OperatorInfo::CCast: { // C Cast: (type)expr Node *Ty; { - SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); Ty = getDerived().parseType(); } if (Ty == nullptr) @@ -4633,7 +4672,7 @@ Node *AbstractManglingParser::parseExpr() { NodeArray Exprs = popTrailingNodeArray(ExprsBegin); if (!IsMany && Exprs.size() != 1) return nullptr; - return make(Ty, Exprs); + return make(Ty, Exprs, Op->getPrecedence()); } case OperatorInfo::Conditional: { // Conditional operator: expr ? expr : expr @@ -4646,7 +4685,7 @@ Node *AbstractManglingParser::parseExpr() { Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(Cond, LHS, RHS); + return make(Cond, LHS, RHS, Op->getPrecedence()); } case OperatorInfo::NamedCast: { // Named cast operation, @(expr) @@ -4656,7 +4695,7 @@ Node *AbstractManglingParser::parseExpr() { Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return nullptr; - return make(Sym, Ty, Ex); + return make(Sym, Ty, Ex, Op->getPrecedence()); } case OperatorInfo::OfIdOp: { // [sizeof/alignof/typeid] ( | ) @@ -4664,7 +4703,7 @@ Node *AbstractManglingParser::parseExpr() { Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); if (!Arg) return nullptr; - return make(Sym, Arg, ")"); + return make(Sym, Arg, Op->getPrecedence()); } case OperatorInfo::NameOnly: { // Not valid as an expression operand. @@ -4698,12 +4737,12 @@ Node *AbstractManglingParser::parseExpr() { return make(nullptr, popTrailingNodeArray(InitsBegin)); } if (consumeIf("mc")) - return parsePointerToMemberConversionExpr(); + return parsePointerToMemberConversionExpr(Node::Prec::Unary); if (consumeIf("nx")) { Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return Ex; - return make("noexcept (", Ex, ")"); + return make("noexcept ", Ex, Node::Prec::Unary); } if (consumeIf("so")) return parseSubobjectExpr(); @@ -4723,7 +4762,7 @@ Node *AbstractManglingParser::parseExpr() { Node *FP = getDerived().parseFunctionParam(); if (FP == nullptr) return nullptr; - return make("sizeof... (", FP, ")"); + return make("sizeof... ", FP); } if (consumeIf("sP")) { size_t ArgsBegin = Names.size(); @@ -4736,7 +4775,7 @@ Node *AbstractManglingParser::parseExpr() { auto *Pack = make(popTrailingNodeArray(ArgsBegin)); if (!Pack) return nullptr; - return make("sizeof... (", Pack, ")"); + return make("sizeof... ", Pack); } if (consumeIf("tl")) { Node *Ty = getDerived().parseType(); @@ -4792,7 +4831,8 @@ Node *AbstractManglingParser::parseExpr() { Names.push_back(E); } } - return make(Name, popTrailingNodeArray(ExprsBegin)); + return make(Name, popTrailingNodeArray(ExprsBegin), + Node::Prec::Postfix); } // Only unresolved names remain. @@ -5090,7 +5130,7 @@ template <> struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) + defined(__wasm__) || defined(__riscv) || defined(__loongarch__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; @@ -5112,7 +5152,7 @@ Node *AbstractManglingParser::parseFloatingLiteral() { const size_t N = FloatData::mangled_size; if (numLeft() <= N) return nullptr; - StringView Data(First, First + N); + std::string_view Data(First, N); for (char C : Data) if (!std::isxdigit(C)) return nullptr; @@ -5432,7 +5472,8 @@ Node *AbstractManglingParser::parse() { if (Encoding == nullptr) return nullptr; if (look() == '.') { - Encoding = make(Encoding, StringView(First, Last)); + Encoding = + make(Encoding, std::string_view(First, Last - First)); First = Last; } if (numLeft() != 0) diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def b/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def new file mode 100644 index 0000000..c0e277d --- /dev/null +++ b/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def @@ -0,0 +1,95 @@ +//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===// +// Do not edit! See README.txt. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Define the demangler's node names + +#ifndef NODE +#error Define NODE to handle nodes +#endif + +NODE(NodeArrayNode) +NODE(DotSuffix) +NODE(VendorExtQualType) +NODE(QualType) +NODE(ConversionOperatorType) +NODE(PostfixQualifiedType) +NODE(ElaboratedTypeSpefType) +NODE(NameType) +NODE(AbiTagAttr) +NODE(EnableIfAttr) +NODE(ObjCProtoName) +NODE(PointerType) +NODE(ReferenceType) +NODE(PointerToMemberType) +NODE(ArrayType) +NODE(FunctionType) +NODE(NoexceptSpec) +NODE(DynamicExceptionSpec) +NODE(FunctionEncoding) +NODE(LiteralOperator) +NODE(SpecialName) +NODE(CtorVtableSpecialName) +NODE(QualifiedName) +NODE(NestedName) +NODE(LocalName) +NODE(ModuleName) +NODE(ModuleEntity) +NODE(VectorType) +NODE(PixelVectorType) +NODE(BinaryFPType) +NODE(BitIntType) +NODE(SyntheticTemplateParamName) +NODE(TypeTemplateParamDecl) +NODE(NonTypeTemplateParamDecl) +NODE(TemplateTemplateParamDecl) +NODE(TemplateParamPackDecl) +NODE(ParameterPack) +NODE(TemplateArgumentPack) +NODE(ParameterPackExpansion) +NODE(TemplateArgs) +NODE(ForwardTemplateReference) +NODE(NameWithTemplateArgs) +NODE(GlobalQualifiedName) +NODE(ExpandedSpecialSubstitution) +NODE(SpecialSubstitution) +NODE(CtorDtorName) +NODE(DtorName) +NODE(UnnamedTypeName) +NODE(ClosureTypeName) +NODE(StructuredBindingName) +NODE(BinaryExpr) +NODE(ArraySubscriptExpr) +NODE(PostfixExpr) +NODE(ConditionalExpr) +NODE(MemberExpr) +NODE(SubobjectExpr) +NODE(EnclosingExpr) +NODE(CastExpr) +NODE(SizeofParamPackExpr) +NODE(CallExpr) +NODE(NewExpr) +NODE(DeleteExpr) +NODE(PrefixExpr) +NODE(FunctionParam) +NODE(ConversionExpr) +NODE(PointerToMemberConversionExpr) +NODE(InitListExpr) +NODE(FoldExpr) +NODE(ThrowExpr) +NODE(BoolExpr) +NODE(StringLiteral) +NODE(LambdaExpr) +NODE(EnumLiteral) +NODE(IntegerLiteral) +NODE(FloatLiteral) +NODE(DoubleLiteral) +NODE(LongDoubleLiteral) +NODE(BracedExpr) +NODE(BracedRangeExpr) + +#undef NODE diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h index 6f2d041..1529b80 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h @@ -10,8 +10,9 @@ #define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H #include "llvm/Demangle/MicrosoftDemangleNodes.h" -#include "llvm/Demangle/StringView.h" +#include +#include #include namespace llvm { @@ -100,7 +101,7 @@ class ArenaAllocator { if (Head->Used <= Head->Capacity) return new (PP) T(std::forward(ConstructorArgs)...); - static_assert(Size < AllocUnit, ""); + static_assert(Size < AllocUnit); addNode(AllocUnit); Head->Used = Size; return new (Head->Buf) T(std::forward(ConstructorArgs)...); @@ -142,9 +143,9 @@ class Demangler { // You are supposed to call parse() first and then check if error is true. If // it is false, call output() to write the formatted name to the given stream. - SymbolNode *parse(StringView &MangledName); + SymbolNode *parse(std::string_view &MangledName); - TagTypeNode *parseTagUniqueName(StringView &MangledName); + TagTypeNode *parseTagUniqueName(std::string_view &MangledName); // True if an error occurred. bool Error = false; @@ -152,104 +153,112 @@ class Demangler { void dumpBackReferences(); private: - SymbolNode *demangleEncodedSymbol(StringView &MangledName, + SymbolNode *demangleEncodedSymbol(std::string_view &MangledName, QualifiedNameNode *QN); - SymbolNode *demangleDeclarator(StringView &MangledName); - SymbolNode *demangleMD5Name(StringView &MangledName); - SymbolNode *demangleTypeinfoName(StringView &MangledName); + SymbolNode *demangleDeclarator(std::string_view &MangledName); + SymbolNode *demangleMD5Name(std::string_view &MangledName); + SymbolNode *demangleTypeinfoName(std::string_view &MangledName); - VariableSymbolNode *demangleVariableEncoding(StringView &MangledName, + VariableSymbolNode *demangleVariableEncoding(std::string_view &MangledName, StorageClass SC); - FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName); + FunctionSymbolNode *demangleFunctionEncoding(std::string_view &MangledName); - Qualifiers demanglePointerExtQualifiers(StringView &MangledName); + Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName); // Parser functions. This is a recursive-descent parser. - TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM); - PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName); - CustomTypeNode *demangleCustomType(StringView &MangledName); - TagTypeNode *demangleClassType(StringView &MangledName); - PointerTypeNode *demanglePointerType(StringView &MangledName); - PointerTypeNode *demangleMemberPointerType(StringView &MangledName); - FunctionSignatureNode *demangleFunctionType(StringView &MangledName, + TypeNode *demangleType(std::string_view &MangledName, + QualifierMangleMode QMM); + PrimitiveTypeNode *demanglePrimitiveType(std::string_view &MangledName); + CustomTypeNode *demangleCustomType(std::string_view &MangledName); + TagTypeNode *demangleClassType(std::string_view &MangledName); + PointerTypeNode *demanglePointerType(std::string_view &MangledName); + PointerTypeNode *demangleMemberPointerType(std::string_view &MangledName); + FunctionSignatureNode *demangleFunctionType(std::string_view &MangledName, bool HasThisQuals); - ArrayTypeNode *demangleArrayType(StringView &MangledName); + ArrayTypeNode *demangleArrayType(std::string_view &MangledName); - NodeArrayNode *demangleFunctionParameterList(StringView &MangledName, + NodeArrayNode *demangleFunctionParameterList(std::string_view &MangledName, bool &IsVariadic); - NodeArrayNode *demangleTemplateParameterList(StringView &MangledName); + NodeArrayNode *demangleTemplateParameterList(std::string_view &MangledName); - std::pair demangleNumber(StringView &MangledName); - uint64_t demangleUnsigned(StringView &MangledName); - int64_t demangleSigned(StringView &MangledName); + std::pair demangleNumber(std::string_view &MangledName); + uint64_t demangleUnsigned(std::string_view &MangledName); + int64_t demangleSigned(std::string_view &MangledName); - void memorizeString(StringView s); + void memorizeString(std::string_view s); void memorizeIdentifier(IdentifierNode *Identifier); /// Allocate a copy of \p Borrowed into memory that we own. - StringView copyString(StringView Borrowed); + std::string_view copyString(std::string_view Borrowed); - QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName); - QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName); + QualifiedNameNode * + demangleFullyQualifiedTypeName(std::string_view &MangledName); + QualifiedNameNode * + demangleFullyQualifiedSymbolName(std::string_view &MangledName); - IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName, + IdentifierNode *demangleUnqualifiedTypeName(std::string_view &MangledName, bool Memorize); - IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName, + IdentifierNode *demangleUnqualifiedSymbolName(std::string_view &MangledName, NameBackrefBehavior NBB); - QualifiedNameNode *demangleNameScopeChain(StringView &MangledName, + QualifiedNameNode *demangleNameScopeChain(std::string_view &MangledName, IdentifierNode *UnqualifiedName); - IdentifierNode *demangleNameScopePiece(StringView &MangledName); + IdentifierNode *demangleNameScopePiece(std::string_view &MangledName); - NamedIdentifierNode *demangleBackRefName(StringView &MangledName); - IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName, - NameBackrefBehavior NBB); + NamedIdentifierNode *demangleBackRefName(std::string_view &MangledName); + IdentifierNode * + demangleTemplateInstantiationName(std::string_view &MangledName, + NameBackrefBehavior NBB); IntrinsicFunctionKind translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group); - IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName); + IdentifierNode *demangleFunctionIdentifierCode(std::string_view &MangledName); IdentifierNode * - demangleFunctionIdentifierCode(StringView &MangledName, + demangleFunctionIdentifierCode(std::string_view &MangledName, FunctionIdentifierCodeGroup Group); - StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName, - bool IsDestructor); + StructorIdentifierNode * + demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor); ConversionOperatorIdentifierNode * - demangleConversionOperatorIdentifier(StringView &MangledName); + demangleConversionOperatorIdentifier(std::string_view &MangledName); LiteralOperatorIdentifierNode * - demangleLiteralOperatorIdentifier(StringView &MangledName); + demangleLiteralOperatorIdentifier(std::string_view &MangledName); - SymbolNode *demangleSpecialIntrinsic(StringView &MangledName); + SymbolNode *demangleSpecialIntrinsic(std::string_view &MangledName); SpecialTableSymbolNode * - demangleSpecialTableSymbolNode(StringView &MangledName, + demangleSpecialTableSymbolNode(std::string_view &MangledName, SpecialIntrinsicKind SIK); LocalStaticGuardVariableNode * - demangleLocalStaticGuard(StringView &MangledName, bool IsThread); + demangleLocalStaticGuard(std::string_view &MangledName, bool IsThread); VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena, - StringView &MangledName, - StringView VariableName); + std::string_view &MangledName, + std::string_view VariableName); VariableSymbolNode * demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, - StringView &MangledName); - FunctionSymbolNode *demangleInitFiniStub(StringView &MangledName, + std::string_view &MangledName); + FunctionSymbolNode *demangleInitFiniStub(std::string_view &MangledName, bool IsDestructor); - NamedIdentifierNode *demangleSimpleName(StringView &MangledName, + NamedIdentifierNode *demangleSimpleName(std::string_view &MangledName, bool Memorize); - NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName); - NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName); - EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName); - FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName); - - StringView demangleSimpleString(StringView &MangledName, bool Memorize); - - FuncClass demangleFunctionClass(StringView &MangledName); - CallingConv demangleCallingConvention(StringView &MangledName); - StorageClass demangleVariableStorageClass(StringView &MangledName); - bool demangleThrowSpecification(StringView &MangledName); - wchar_t demangleWcharLiteral(StringView &MangledName); - uint8_t demangleCharLiteral(StringView &MangledName); - - std::pair demangleQualifiers(StringView &MangledName); + NamedIdentifierNode * + demangleAnonymousNamespaceName(std::string_view &MangledName); + NamedIdentifierNode * + demangleLocallyScopedNamePiece(std::string_view &MangledName); + EncodedStringLiteralNode * + demangleStringLiteral(std::string_view &MangledName); + FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName); + + std::string_view demangleSimpleString(std::string_view &MangledName, + bool Memorize); + + FuncClass demangleFunctionClass(std::string_view &MangledName); + CallingConv demangleCallingConvention(std::string_view &MangledName); + StorageClass demangleVariableStorageClass(std::string_view &MangledName); + bool demangleThrowSpecification(std::string_view &MangledName); + wchar_t demangleWcharLiteral(std::string_view &MangledName); + uint8_t demangleCharLiteral(std::string_view &MangledName); + + std::pair demangleQualifiers(std::string_view &MangledName); // Memory allocator. ArenaAllocator Arena; diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h index 8ad2472..1913bff 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h @@ -13,10 +13,10 @@ #ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H #define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H -#include "llvm/Demangle/StringView.h" #include #include #include +#include namespace llvm { namespace itanium_demangle { @@ -25,7 +25,6 @@ class OutputBuffer; } using llvm::itanium_demangle::OutputBuffer; -using llvm::itanium_demangle::StringView; namespace llvm { namespace ms_demangle { @@ -384,7 +383,7 @@ struct NamedIdentifierNode : public IdentifierNode { void output(OutputBuffer &OB, OutputFlags Flags) const override; - StringView Name; + std::string_view Name; }; struct IntrinsicFunctionIdentifierNode : public IdentifierNode { @@ -403,7 +402,7 @@ struct LiteralOperatorIdentifierNode : public IdentifierNode { void output(OutputBuffer &OB, OutputFlags Flags) const override; - StringView Name; + std::string_view Name; }; struct LocalStaticGuardIdentifierNode : public IdentifierNode { @@ -516,7 +515,8 @@ struct NodeArrayNode : public Node { void output(OutputBuffer &OB, OutputFlags Flags) const override; - void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const; + void output(OutputBuffer &OB, OutputFlags Flags, + std::string_view Separator) const; Node **Nodes = nullptr; size_t Count = 0; @@ -601,7 +601,7 @@ struct EncodedStringLiteralNode : public SymbolNode { void output(OutputBuffer &OB, OutputFlags Flags) const override; - StringView DecodedString; + std::string_view DecodedString; bool IsTruncated = false; CharKind Char = CharKind::Char; }; diff --git a/third_party/llvm/include/llvm/Demangle/StringViewExtras.h b/third_party/llvm/include/llvm/Demangle/StringViewExtras.h new file mode 100644 index 0000000..93940a5 --- /dev/null +++ b/third_party/llvm/include/llvm/Demangle/StringViewExtras.h @@ -0,0 +1,38 @@ +//===--- StringViewExtras.h ----------*- mode:c++;eval:(read-only-mode) -*-===// +// Do not edit! See README.txt. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. +// +//===----------------------------------------------------------------------===// + +#ifndef DEMANGLE_STRINGVIEW_H +#define DEMANGLE_STRINGVIEW_H + +#include "DemangleConfig.h" + +#include + +DEMANGLE_NAMESPACE_BEGIN + +inline bool starts_with(std::string_view self, char C) noexcept { + return !self.empty() && *self.begin() == C; +} + +inline bool starts_with(std::string_view haystack, + std::string_view needle) noexcept { + if (needle.size() > haystack.size()) + return false; + haystack.remove_suffix(haystack.size() - needle.size()); + return haystack == needle; +} + +DEMANGLE_NAMESPACE_END + +#endif diff --git a/third_party/llvm/include/llvm/Demangle/Utility.h b/third_party/llvm/include/llvm/Demangle/Utility.h index 5f012d7..a906d23 100644 --- a/third_party/llvm/include/llvm/Demangle/Utility.h +++ b/third_party/llvm/include/llvm/Demangle/Utility.h @@ -16,13 +16,16 @@ #ifndef DEMANGLE_UTILITY_H #define DEMANGLE_UTILITY_H -#include "StringView.h" +#include "DemangleConfig.h" + #include +#include #include #include #include #include #include +#include DEMANGLE_NAMESPACE_BEGIN @@ -64,21 +67,22 @@ class OutputBuffer { if (isNeg) *--TempPtr = '-'; - return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); + return operator+=( + std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); } public: OutputBuffer(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} + : Buffer(StartBuf), BufferCapacity(Size) {} + OutputBuffer(char *StartBuf, size_t *SizePtr) + : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} OutputBuffer() = default; // Non-copyable OutputBuffer(const OutputBuffer &) = delete; OutputBuffer &operator=(const OutputBuffer &) = delete; - void reset(char *Buffer_, size_t BufferCapacity_) { - CurrentPosition = 0; - Buffer = Buffer_; - BufferCapacity = BufferCapacity_; + operator std::string_view() const { + return std::string_view(Buffer, CurrentPosition); } /// If a ParameterPackExpansion (or similar type) is encountered, the offset @@ -86,10 +90,25 @@ class OutputBuffer { unsigned CurrentPackIndex = std::numeric_limits::max(); unsigned CurrentPackMax = std::numeric_limits::max(); - OutputBuffer &operator+=(StringView R) { + /// When zero, we're printing template args and '>' needs to be parenthesized. + /// Use a counter so we can simply increment inside parentheses. + unsigned GtIsGt = 1; + + bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } + + void printOpen(char Open = '(') { + GtIsGt++; + *this += Open; + } + void printClose(char Close = ')') { + GtIsGt--; + *this += Close; + } + + OutputBuffer &operator+=(std::string_view R) { if (size_t Size = R.size()) { grow(Size); - std::memcpy(Buffer + CurrentPosition, R.begin(), Size); + std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size); CurrentPosition += Size; } return *this; @@ -101,18 +120,18 @@ class OutputBuffer { return *this; } - OutputBuffer &prepend(StringView R) { + OutputBuffer &prepend(std::string_view R) { size_t Size = R.size(); grow(Size); std::memmove(Buffer + Size, Buffer, CurrentPosition); - std::memcpy(Buffer, R.begin(), Size); + std::memcpy(Buffer, &*R.begin(), Size); CurrentPosition += Size; return *this; } - OutputBuffer &operator<<(StringView R) { return (*this += R); } + OutputBuffer &operator<<(std::string_view R) { return (*this += R); } OutputBuffer &operator<<(char C) { return (*this += C); } @@ -154,7 +173,8 @@ class OutputBuffer { void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } char back() const { - return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + assert(CurrentPosition); + return Buffer[CurrentPosition - 1]; } bool empty() const { return CurrentPosition == 0; } @@ -164,38 +184,22 @@ class OutputBuffer { size_t getBufferCapacity() const { return BufferCapacity; } }; -template class SwapAndRestore { - T &Restore; - T OriginalValue; +template class ScopedOverride { + T &Loc; + T Original; public: - SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} + ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} - SwapAndRestore(T &Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); + ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { + Loc_ = std::move(NewVal); } - ~SwapAndRestore() { Restore = std::move(OriginalValue); } + ~ScopedOverride() { Loc = std::move(Original); } - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; + ScopedOverride(const ScopedOverride &) = delete; + ScopedOverride &operator=(const ScopedOverride &) = delete; }; -inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, - size_t InitSize) { - size_t BufferSize; - if (Buf == nullptr) { - Buf = static_cast(std::malloc(InitSize)); - if (Buf == nullptr) - return false; - BufferSize = InitSize; - } else - BufferSize = *N; - - OB.reset(Buf, BufferSize); - return true; -} - DEMANGLE_NAMESPACE_END #endif diff --git a/third_party/llvm/lib/Demangle/DLangDemangle.cpp b/third_party/llvm/lib/Demangle/DLangDemangle.cpp index 7cecd80..8856302 100644 --- a/third_party/llvm/lib/Demangle/DLangDemangle.cpp +++ b/third_party/llvm/lib/Demangle/DLangDemangle.cpp @@ -14,16 +14,17 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/Demangle.h" -#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/StringViewExtras.h" #include "llvm/Demangle/Utility.h" #include #include #include +#include using namespace llvm; using llvm::itanium_demangle::OutputBuffer; -using llvm::itanium_demangle::StringView; +using llvm::itanium_demangle::starts_with; namespace { @@ -32,7 +33,7 @@ struct Demangler { /// Initialize the information structure we use to pass around information. /// /// \param Mangled String to demangle. - Demangler(const char *Mangled); + Demangler(std::string_view Mangled); /// Extract and demangle the mangled symbol and append it to the output /// string. @@ -52,46 +53,42 @@ struct Demangler { /// \param Demangled output buffer to write the demangled name. /// \param Mangled mangled symbol to be demangled. /// - /// \return The remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#name_mangling . /// \see https://dlang.org/spec/abi.html#MangledName . - const char *parseMangle(OutputBuffer *Demangled, const char *Mangled); + void parseMangle(OutputBuffer *Demangled, std::string_view &Mangled); /// Extract the number from a given string. /// /// \param Mangled string to extract the number. /// \param Ret assigned result value. /// - /// \return The remaining string on success or nullptr on failure. - /// - /// \note A result larger than UINT_MAX is considered a failure. + /// \note Ret larger than UINT_MAX is considered a failure. /// /// \see https://dlang.org/spec/abi.html#Number . - const char *decodeNumber(const char *Mangled, unsigned long &Ret); + void decodeNumber(std::string_view &Mangled, unsigned long &Ret); /// Extract the back reference position from a given string. /// /// \param Mangled string to extract the back reference position. /// \param Ret assigned result value. /// - /// \return the remaining string on success or nullptr on failure. + /// \return true on success, false on error. /// /// \note Ret is always >= 0 on success, and unspecified on failure /// /// \see https://dlang.org/spec/abi.html#back_ref . /// \see https://dlang.org/spec/abi.html#NumberBackRef . - const char *decodeBackrefPos(const char *Mangled, long &Ret); + bool decodeBackrefPos(std::string_view &Mangled, long &Ret); /// Extract the symbol pointed by the back reference form a given string. /// /// \param Mangled string to extract the back reference position. /// \param Ret assigned result value. /// - /// \return the remaining string on success or nullptr on failure. + /// \return true on success, false on error. /// /// \see https://dlang.org/spec/abi.html#back_ref . - const char *decodeBackref(const char *Mangled, const char *&Ret); + bool decodeBackref(std::string_view &Mangled, std::string_view &Ret); /// Extract and demangle backreferenced symbol from a given mangled symbol /// and append it to the output string. @@ -99,22 +96,18 @@ struct Demangler { /// \param Demangled output buffer to write the demangled name. /// \param Mangled mangled symbol to be demangled. /// - /// \return the remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#back_ref . /// \see https://dlang.org/spec/abi.html#IdentifierBackRef . - const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled); + void parseSymbolBackref(OutputBuffer *Demangled, std::string_view &Mangled); /// Extract and demangle backreferenced type from a given mangled symbol /// and append it to the output string. /// /// \param Mangled mangled symbol to be demangled. /// - /// \return the remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#back_ref . /// \see https://dlang.org/spec/abi.html#TypeBackRef . - const char *parseTypeBackref(const char *Mangled); + void parseTypeBackref(std::string_view &Mangled); /// Check whether it is the beginning of a symbol name. /// @@ -123,7 +116,7 @@ struct Demangler { /// \return true on success, false otherwise. /// /// \see https://dlang.org/spec/abi.html#SymbolName . - bool isSymbolName(const char *Mangled); + bool isSymbolName(std::string_view Mangled); /// Extract and demangle an identifier from a given mangled symbol append it /// to the output string. @@ -131,10 +124,8 @@ struct Demangler { /// \param Demangled Output buffer to write the demangled name. /// \param Mangled Mangled symbol to be demangled. /// - /// \return The remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#SymbolName . - const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled); + void parseIdentifier(OutputBuffer *Demangled, std::string_view &Mangled); /// Extract and demangle the plain identifier from a given mangled symbol and /// prepend/append it to the output string, with a special treatment for some @@ -144,11 +135,9 @@ struct Demangler { /// \param Mangled Mangled symbol to be demangled. /// \param Len Length of the mangled symbol name. /// - /// \return The remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#LName . - const char *parseLName(OutputBuffer *Demangled, const char *Mangled, - unsigned long Len); + void parseLName(OutputBuffer *Demangled, std::string_view &Mangled, + unsigned long Len); /// Extract and demangle the qualified symbol from a given mangled symbol /// append it to the output string. @@ -156,33 +145,38 @@ struct Demangler { /// \param Demangled Output buffer to write the demangled name. /// \param Mangled Mangled symbol to be demangled. /// - /// \return The remaining string on success or nullptr on failure. - /// /// \see https://dlang.org/spec/abi.html#QualifiedName . - const char *parseQualified(OutputBuffer *Demangled, const char *Mangled); + void parseQualified(OutputBuffer *Demangled, std::string_view &Mangled); /// Extract and demangle a type from a given mangled symbol append it to /// the output string. /// /// \param Mangled mangled symbol to be demangled. /// - /// \return the remaining string on success or nullptr on failure. + /// \return true on success, false on error. /// /// \see https://dlang.org/spec/abi.html#Type . - const char *parseType(const char *Mangled); + bool parseType(std::string_view &Mangled); - /// The string we are demangling. - const char *Str; + /// An immutable view of the string we are demangling. + const std::string_view Str; /// The index of the last back reference. int LastBackref; }; } // namespace -const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) { - // Return nullptr if trying to extract something that isn't a digit. - if (Mangled == nullptr || !std::isdigit(*Mangled)) - return nullptr; +void Demangler::decodeNumber(std::string_view &Mangled, unsigned long &Ret) { + // Clear Mangled if trying to extract something that isn't a digit. + if (Mangled.empty()) { + Mangled = {}; + return; + } + + if (!std::isdigit(Mangled.front())) { + Mangled = {}; + return; + } unsigned long Val = 0; @@ -190,25 +184,29 @@ const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) { unsigned long Digit = Mangled[0] - '0'; // Check for overflow. - if (Val > (std::numeric_limits::max() - Digit) / 10) - return nullptr; + if (Val > (std::numeric_limits::max() - Digit) / 10) { + Mangled = {}; + return; + } Val = Val * 10 + Digit; - ++Mangled; - } while (std::isdigit(*Mangled)); + Mangled.remove_prefix(1); + } while (!Mangled.empty() && std::isdigit(Mangled.front())); - if (*Mangled == '\0') - return nullptr; + if (Mangled.empty()) { + Mangled = {}; + return; + } Ret = Val; - return Mangled; } -const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { +bool Demangler::decodeBackrefPos(std::string_view &Mangled, long &Ret) { // Return nullptr if trying to extract something that isn't a digit - if (Mangled == nullptr || !std::isalpha(*Mangled)) - return nullptr; - + if (Mangled.empty()) { + Mangled = {}; + return false; + } // Any identifier or non-basic type that has been emitted to the mangled // symbol before will not be emitted again, but is referenced by a special // sequence encoding the relative position of the original occurrence in the @@ -221,7 +219,7 @@ const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { // ^ unsigned long Val = 0; - while (std::isalpha(*Mangled)) { + while (!Mangled.empty() && std::isalpha(Mangled.front())) { // Check for overflow if (Val > (std::numeric_limits::max() - 25) / 26) break; @@ -233,116 +231,133 @@ const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { if ((long)Val <= 0) break; Ret = Val; - return Mangled + 1; + Mangled.remove_prefix(1); + return true; } Val += Mangled[0] - 'A'; - ++Mangled; + Mangled.remove_prefix(1); } - return nullptr; + Mangled = {}; + return false; } -const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) { - assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!"); - Ret = nullptr; +bool Demangler::decodeBackref(std::string_view &Mangled, + std::string_view &Ret) { + assert(!Mangled.empty() && Mangled.front() == 'Q' && + "Invalid back reference!"); + Ret = {}; // Position of 'Q' - const char *Qpos = Mangled; + const char *Qpos = Mangled.data(); long RefPos; - ++Mangled; + Mangled.remove_prefix(1); - Mangled = decodeBackrefPos(Mangled, RefPos); - if (Mangled == nullptr) - return nullptr; + if (!decodeBackrefPos(Mangled, RefPos)) { + Mangled = {}; + return false; + } - if (RefPos > Qpos - Str) - return nullptr; + if (RefPos > Qpos - Str.data()) { + Mangled = {}; + return false; + } // Set the position of the back reference. Ret = Qpos - RefPos; - return Mangled; + return true; } -const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled, - const char *Mangled) { +void Demangler::parseSymbolBackref(OutputBuffer *Demangled, + std::string_view &Mangled) { // An identifier back reference always points to a digit 0 to 9. // IdentifierBackRef: // Q NumberBackRef // ^ - const char *Backref; unsigned long Len; // Get position of the back reference - Mangled = decodeBackref(Mangled, Backref); + std::string_view Backref; + if (!decodeBackref(Mangled, Backref)) { + Mangled = {}; + return; + } // Must point to a simple identifier - Backref = decodeNumber(Backref, Len); - if (Backref == nullptr || strlen(Backref) < Len) - return nullptr; - - Backref = parseLName(Demangled, Backref, Len); - if (Backref == nullptr) - return nullptr; + decodeNumber(Backref, Len); + if (Backref.empty() || Backref.length() < Len) { + Mangled = {}; + return; + } - return Mangled; + parseLName(Demangled, Backref, Len); + if (Backref.empty()) + Mangled = {}; } -const char *Demangler::parseTypeBackref(const char *Mangled) { +void Demangler::parseTypeBackref(std::string_view &Mangled) { // A type back reference always points to a letter. // TypeBackRef: // Q NumberBackRef // ^ - const char *Backref; // If we appear to be moving backwards through the mangle string, then // bail as this may be a recursive back reference. - if (Mangled - Str >= LastBackref) - return nullptr; + if (Mangled.data() - Str.data() >= LastBackref) { + Mangled = {}; + return; + } int SaveRefPos = LastBackref; - LastBackref = Mangled - Str; + LastBackref = Mangled.data() - Str.data(); // Get position of the back reference. - Mangled = decodeBackref(Mangled, Backref); + std::string_view Backref; + if (!decodeBackref(Mangled, Backref)) { + Mangled = {}; + return; + } // Can't decode back reference. - if (Backref == nullptr) - return nullptr; + if (Backref.empty()) { + Mangled = {}; + return; + } // TODO: Add support for function type back references. - Backref = parseType(Backref); + if (!parseType(Backref)) + Mangled = {}; LastBackref = SaveRefPos; - if (Backref == nullptr) - return nullptr; - - return Mangled; + if (Backref.empty()) + Mangled = {}; } -bool Demangler::isSymbolName(const char *Mangled) { +bool Demangler::isSymbolName(std::string_view Mangled) { long Ret; - const char *Qref = Mangled; + const char *Qref = Mangled.data(); - if (std::isdigit(*Mangled)) + if (std::isdigit(Mangled.front())) return true; // TODO: Handle template instances. - if (*Mangled != 'Q') + if (Mangled.front() != 'Q') return false; - Mangled = decodeBackrefPos(Mangled + 1, Ret); - if (Mangled == nullptr || Ret > Qref - Str) + Mangled.remove_prefix(1); + bool Valid = decodeBackrefPos(Mangled, Ret); + if (!Valid || Ret > Qref - Str.data()) return false; return std::isdigit(Qref[-Ret]); } -const char *Demangler::parseMangle(OutputBuffer *Demangled, - const char *Mangled) { +void Demangler::parseMangle(OutputBuffer *Demangled, + std::string_view &Mangled) { // A D mangled symbol is comprised of both scope and type information. // MangleName: // _D QualifiedName Type @@ -352,24 +367,24 @@ const char *Demangler::parseMangle(OutputBuffer *Demangled, // above location. // Note that type is never a function type, but only the return type of // a function or the type of a variable. - Mangled += 2; + Mangled.remove_prefix(2); - Mangled = parseQualified(Demangled, Mangled); + parseQualified(Demangled, Mangled); - if (Mangled != nullptr) { - // Artificial symbols end with 'Z' and have no type. - if (*Mangled == 'Z') - ++Mangled; - else { - Mangled = parseType(Mangled); - } + if (Mangled.empty()) { + Mangled = {}; + return; } - return Mangled; + // Artificial symbols end with 'Z' and have no type. + if (Mangled.front() == 'Z') { + Mangled.remove_prefix(1); + } else if (!parseType(Mangled)) + Mangled = {}; } -const char *Demangler::parseQualified(OutputBuffer *Demangled, - const char *Mangled) { +void Demangler::parseQualified(OutputBuffer *Demangled, + std::string_view &Mangled) { // Qualified names are identifiers separated by their encoded length. // Nested functions also encode their argument types without specifying // what they return. @@ -388,10 +403,10 @@ const char *Demangler::parseQualified(OutputBuffer *Demangled, size_t NotFirst = false; do { // Skip over anonymous symbols. - if (*Mangled == '0') { + if (!Mangled.empty() && Mangled.front() == '0') { do - ++Mangled; - while (*Mangled == '0'); + Mangled.remove_prefix(1); + while (!Mangled.empty() && Mangled.front() == '0'); continue; } @@ -400,62 +415,63 @@ const char *Demangler::parseQualified(OutputBuffer *Demangled, *Demangled << '.'; NotFirst = true; - Mangled = parseIdentifier(Demangled, Mangled); - - } while (Mangled && isSymbolName(Mangled)); - - return Mangled; + parseIdentifier(Demangled, Mangled); + } while (!Mangled.empty() && isSymbolName(Mangled)); } -const char *Demangler::parseIdentifier(OutputBuffer *Demangled, - const char *Mangled) { - unsigned long Len; - - if (Mangled == nullptr || *Mangled == '\0') - return nullptr; +void Demangler::parseIdentifier(OutputBuffer *Demangled, + std::string_view &Mangled) { + if (Mangled.empty()) { + Mangled = {}; + return; + } - if (*Mangled == 'Q') + if (Mangled.front() == 'Q') return parseSymbolBackref(Demangled, Mangled); // TODO: Parse lengthless template instances. - const char *Endptr = decodeNumber(Mangled, Len); - - if (Endptr == nullptr || Len == 0) - return nullptr; - - if (strlen(Endptr) < Len) - return nullptr; + unsigned long Len; + decodeNumber(Mangled, Len); - Mangled = Endptr; + if (Mangled.empty()) { + Mangled = {}; + return; + } + if (!Len || Mangled.length() < Len) { + Mangled = {}; + return; + } // TODO: Parse template instances with a length prefix. // There can be multiple different declarations in the same function that // have the same mangled name. To make the mangled names unique, a fake // parent in the form `__Sddd' is added to the symbol. - if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { - const char *NumPtr = Mangled + 3; - while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) - ++NumPtr; - - if (Mangled + Len == NumPtr) { + if (Len >= 4 && starts_with(Mangled, "__S")) { + const size_t SuffixLen = Mangled.length() - Len; + std::string_view P = Mangled.substr(3); + while (P.length() > SuffixLen && std::isdigit(P.front())) + P.remove_prefix(1); + if (P.length() == SuffixLen) { // Skip over the fake parent. - Mangled += Len; + Mangled.remove_prefix(Len); return parseIdentifier(Demangled, Mangled); } // Else demangle it as a plain identifier. } - return parseLName(Demangled, Mangled, Len); + parseLName(Demangled, Mangled, Len); } -const char *Demangler::parseType(const char *Mangled) { - if (*Mangled == '\0') - return nullptr; +bool Demangler::parseType(std::string_view &Mangled) { + if (Mangled.empty()) { + Mangled = {}; + return false; + } - switch (*Mangled) { + switch (Mangled.front()) { // TODO: Parse type qualifiers. // TODO: Parse function types. // TODO: Parse compound types. @@ -464,102 +480,102 @@ const char *Demangler::parseType(const char *Mangled) { // Basic types. case 'i': - ++Mangled; + Mangled.remove_prefix(1); // TODO: Add type name dumping - return Mangled; + return true; // TODO: Add support for the rest of the basic types. // Back referenced type. - case 'Q': - return parseTypeBackref(Mangled); + case 'Q': { + parseTypeBackref(Mangled); + return true; + } default: // unhandled. - return nullptr; + Mangled = {}; + return false; } } -const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled, - unsigned long Len) { +void Demangler::parseLName(OutputBuffer *Demangled, std::string_view &Mangled, + unsigned long Len) { switch (Len) { case 6: - if (strncmp(Mangled, "__initZ", Len + 1) == 0) { + if (starts_with(Mangled, "__initZ")) { // The static initializer for a given symbol. Demangled->prepend("initializer for "); Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); - Mangled += Len; - return Mangled; + Mangled.remove_prefix(Len); + return; } - if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { + if (starts_with(Mangled, "__vtblZ")) { // The vtable symbol for a given class. Demangled->prepend("vtable for "); Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); - Mangled += Len; - return Mangled; + Mangled.remove_prefix(Len); + return; } break; case 7: - if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { + if (starts_with(Mangled, "__ClassZ")) { // The classinfo symbol for a given class. Demangled->prepend("ClassInfo for "); Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); - Mangled += Len; - return Mangled; + Mangled.remove_prefix(Len); + return; } break; case 11: - if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { + if (starts_with(Mangled, "__InterfaceZ")) { // The interface symbol for a given class. Demangled->prepend("Interface for "); Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); - Mangled += Len; - return Mangled; + Mangled.remove_prefix(Len); + return; } break; case 12: - if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { + if (starts_with(Mangled, "__ModuleInfoZ")) { // The ModuleInfo symbol for a given module. Demangled->prepend("ModuleInfo for "); Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); - Mangled += Len; - return Mangled; + Mangled.remove_prefix(Len); + return; } break; } - *Demangled << StringView(Mangled, Len); - Mangled += Len; - - return Mangled; + *Demangled << Mangled.substr(0, Len); + Mangled.remove_prefix(Len); } -Demangler::Demangler(const char *Mangled) - : Str(Mangled), LastBackref(strlen(Mangled)) {} +Demangler::Demangler(std::string_view Mangled) + : Str(Mangled), LastBackref(Mangled.length()) {} const char *Demangler::parseMangle(OutputBuffer *Demangled) { - return parseMangle(Demangled, this->Str); + std::string_view M(this->Str); + parseMangle(Demangled, M); + return M.data(); } -char *llvm::dlangDemangle(const char *MangledName) { - if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0) +char *llvm::dlangDemangle(std::string_view MangledName) { + if (MangledName.empty() || !starts_with(MangledName, "_D")) return nullptr; OutputBuffer Demangled; - if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024)) - return nullptr; - - if (strcmp(MangledName, "_Dmain") == 0) { + if (MangledName == "_Dmain") { Demangled << "D main"; } else { - Demangler D = Demangler(MangledName); - MangledName = D.parseMangle(&Demangled); + Demangler D(MangledName); + const char *M = D.parseMangle(&Demangled); // Check that the entire symbol was successfully demangled. - if (MangledName == nullptr || *MangledName != '\0') { + if (M == nullptr || *M != '\0') { std::free(Demangled.getBuffer()); return nullptr; } diff --git a/third_party/llvm/lib/Demangle/Demangle.cpp b/third_party/llvm/lib/Demangle/Demangle.cpp index 13aa286..f2aa571 100644 --- a/third_party/llvm/lib/Demangle/Demangle.cpp +++ b/third_party/llvm/lib/Demangle/Demangle.cpp @@ -11,47 +11,47 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringViewExtras.h" #include -#include +#include -static bool isItaniumEncoding(const char *S) { - // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'. - return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0; -} - -static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; } - -static bool isDLangEncoding(const std::string &MangledName) { - return MangledName.size() >= 2 && MangledName[0] == '_' && - MangledName[1] == 'D'; -} +using llvm::itanium_demangle::starts_with; -std::string llvm::demangle(const std::string &MangledName) { +std::string llvm::demangle(std::string_view MangledName) { std::string Result; - const char *S = MangledName.c_str(); - if (nonMicrosoftDemangle(S, Result)) + if (nonMicrosoftDemangle(MangledName, Result)) return Result; - if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result)) + if (starts_with(MangledName, '_') && + nonMicrosoftDemangle(MangledName.substr(1), Result)) return Result; - if (char *Demangled = - microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) { + if (char *Demangled = microsoftDemangle(MangledName, nullptr, nullptr)) { Result = Demangled; std::free(Demangled); - return Result; + } else { + Result = MangledName; } + return Result; +} - return MangledName; +static bool isItaniumEncoding(std::string_view S) { + // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'. + return starts_with(S, "_Z") || starts_with(S, "___Z"); } -bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) { +static bool isRustEncoding(std::string_view S) { return starts_with(S, "_R"); } + +static bool isDLangEncoding(std::string_view S) { return starts_with(S, "_D"); } + +bool llvm::nonMicrosoftDemangle(std::string_view MangledName, + std::string &Result) { char *Demangled = nullptr; if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr); + Demangled = itaniumDemangle(MangledName); else if (isRustEncoding(MangledName)) - Demangled = rustDemangle(MangledName, nullptr, nullptr, nullptr); + Demangled = rustDemangle(MangledName); else if (isDLangEncoding(MangledName)) Demangled = dlangDemangle(MangledName); diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp index 5d2fb2b..f2ce6eb 100644 --- a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -78,8 +78,8 @@ struct DumpVisitor { } void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); + void print(std::string_view SV) { + fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin()); } void print(const Node *N) { if (N) @@ -172,6 +172,50 @@ struct DumpVisitor { return printStr("TemplateParamKind::Template"); } } + void print(Node::Prec P) { + switch (P) { + case Node::Prec::Primary: + return printStr("Node::Prec::Primary"); + case Node::Prec::Postfix: + return printStr("Node::Prec::Postfix"); + case Node::Prec::Unary: + return printStr("Node::Prec::Unary"); + case Node::Prec::Cast: + return printStr("Node::Prec::Cast"); + case Node::Prec::PtrMem: + return printStr("Node::Prec::PtrMem"); + case Node::Prec::Multiplicative: + return printStr("Node::Prec::Multiplicative"); + case Node::Prec::Additive: + return printStr("Node::Prec::Additive"); + case Node::Prec::Shift: + return printStr("Node::Prec::Shift"); + case Node::Prec::Spaceship: + return printStr("Node::Prec::Spaceship"); + case Node::Prec::Relational: + return printStr("Node::Prec::Relational"); + case Node::Prec::Equality: + return printStr("Node::Prec::Equality"); + case Node::Prec::And: + return printStr("Node::Prec::And"); + case Node::Prec::Xor: + return printStr("Node::Prec::Xor"); + case Node::Prec::Ior: + return printStr("Node::Prec::Ior"); + case Node::Prec::AndIf: + return printStr("Node::Prec::AndIf"); + case Node::Prec::OrIf: + return printStr("Node::Prec::OrIf"); + case Node::Prec::Conditional: + return printStr("Node::Prec::Conditional"); + case Node::Prec::Assign: + return printStr("Node::Prec::Assign"); + case Node::Prec::Comma: + return printStr("Node::Prec::Comma"); + case Node::Prec::Default: + return printStr("Node::Prec::Default"); + } + } void newLine() { printStr("\n"); @@ -321,36 +365,21 @@ class DefaultAllocator { using Demangler = itanium_demangle::ManglingParser; -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; +char *llvm::itaniumDemangle(std::string_view MangledName) { + if (MangledName.empty()) return nullptr; - } - - int InternalStatus = demangle_success; - Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputBuffer OB; + Demangler Parser(MangledName.data(), + MangledName.data() + MangledName.length()); Node *AST = Parser.parse(); + if (!AST) + return nullptr; - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputBuffer(Buf, N, OB, 1024)) - InternalStatus = demangle_memory_alloc_failure; - else { - assert(Parser.ForwardTemplateRefs.empty()); - AST->print(OB); - OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); - Buf = OB.getBuffer(); - } - - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; + OutputBuffer OB; + assert(Parser.ForwardTemplateRefs.empty()); + AST->print(OB); + OB += '\0'; + return OB.getBuffer(); } ItaniumPartialDemangler::ItaniumPartialDemangler() @@ -383,9 +412,7 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { } static char *printNode(const Node *RootNode, char *Buf, size_t *N) { - OutputBuffer OB; - if (!initializeOutputBuffer(Buf, N, OB, 128)) - return nullptr; + OutputBuffer OB(Buf, N); RootNode->print(OB); OB += '\0'; if (N != nullptr) @@ -428,9 +455,7 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, return nullptr; const Node *Name = static_cast(RootNode)->getName(); - OutputBuffer OB; - if (!initializeOutputBuffer(Buf, N, OB, 128)) - return nullptr; + OutputBuffer OB(Buf, N); KeepGoingLocalFunction: while (true) { @@ -481,9 +506,7 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, return nullptr; NodeArray Params = static_cast(RootNode)->getParams(); - OutputBuffer OB; - if (!initializeOutputBuffer(Buf, N, OB, 128)) - return nullptr; + OutputBuffer OB(Buf, N); OB += '('; Params.printWithComma(OB); @@ -499,9 +522,7 @@ char *ItaniumPartialDemangler::getFunctionReturnType( if (!isFunction()) return nullptr; - OutputBuffer OB; - if (!initializeOutputBuffer(Buf, N, OB, 128)) - return nullptr; + OutputBuffer OB(Buf, N); if (const Node *Ret = static_cast(RootNode)->getReturnType()) diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index d8da3b4..b38b8a1 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -14,34 +14,50 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/MicrosoftDemangle.h" -#include "llvm/Demangle/Demangle.h" -#include "llvm/Demangle/MicrosoftDemangleNodes.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Demangle/DemangleConfig.h" -#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/MicrosoftDemangleNodes.h" +#include "llvm/Demangle/StringViewExtras.h" #include "llvm/Demangle/Utility.h" #include #include #include +#include #include using namespace llvm; using namespace ms_demangle; -static bool startsWithDigit(StringView S) { +static bool startsWithDigit(std::string_view S) { return !S.empty() && std::isdigit(S.front()); } - struct NodeList { Node *N = nullptr; NodeList *Next = nullptr; }; -static bool isMemberPointer(StringView MangledName, bool &Error) { +static bool consumeFront(std::string_view &S, char C) { + if (!llvm::itanium_demangle::starts_with(S, C)) + return false; + S.remove_prefix(1); + return true; +} + +static bool consumeFront(std::string_view &S, std::string_view C) { + if (!llvm::itanium_demangle::starts_with(S, C)) + return false; + S.remove_prefix(C.size()); + return true; +} + +static bool isMemberPointer(std::string_view MangledName, bool &Error) { Error = false; - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case '$': // This is probably an rvalue reference (e.g. $$Q), and you cannot have an // rvalue reference to a member. @@ -75,9 +91,9 @@ static bool isMemberPointer(StringView MangledName, bool &Error) { // Remove ext qualifiers since those can appear on either type and are // therefore not indicative. - MangledName.consumeFront('E'); // 64-bit - MangledName.consumeFront('I'); // restrict - MangledName.consumeFront('F'); // unaligned + consumeFront(MangledName, 'E'); // 64-bit + consumeFront(MangledName, 'I'); // restrict + consumeFront(MangledName, 'F'); // unaligned if (MangledName.empty()) { Error = true; @@ -103,50 +119,50 @@ static bool isMemberPointer(StringView MangledName, bool &Error) { } static SpecialIntrinsicKind -consumeSpecialIntrinsicKind(StringView &MangledName) { - if (MangledName.consumeFront("?_7")) +consumeSpecialIntrinsicKind(std::string_view &MangledName) { + if (consumeFront(MangledName, "?_7")) return SpecialIntrinsicKind::Vftable; - if (MangledName.consumeFront("?_8")) + if (consumeFront(MangledName, "?_8")) return SpecialIntrinsicKind::Vbtable; - if (MangledName.consumeFront("?_9")) + if (consumeFront(MangledName, "?_9")) return SpecialIntrinsicKind::VcallThunk; - if (MangledName.consumeFront("?_A")) + if (consumeFront(MangledName, "?_A")) return SpecialIntrinsicKind::Typeof; - if (MangledName.consumeFront("?_B")) + if (consumeFront(MangledName, "?_B")) return SpecialIntrinsicKind::LocalStaticGuard; - if (MangledName.consumeFront("?_C")) + if (consumeFront(MangledName, "?_C")) return SpecialIntrinsicKind::StringLiteralSymbol; - if (MangledName.consumeFront("?_P")) + if (consumeFront(MangledName, "?_P")) return SpecialIntrinsicKind::UdtReturning; - if (MangledName.consumeFront("?_R0")) + if (consumeFront(MangledName, "?_R0")) return SpecialIntrinsicKind::RttiTypeDescriptor; - if (MangledName.consumeFront("?_R1")) + if (consumeFront(MangledName, "?_R1")) return SpecialIntrinsicKind::RttiBaseClassDescriptor; - if (MangledName.consumeFront("?_R2")) + if (consumeFront(MangledName, "?_R2")) return SpecialIntrinsicKind::RttiBaseClassArray; - if (MangledName.consumeFront("?_R3")) + if (consumeFront(MangledName, "?_R3")) return SpecialIntrinsicKind::RttiClassHierarchyDescriptor; - if (MangledName.consumeFront("?_R4")) + if (consumeFront(MangledName, "?_R4")) return SpecialIntrinsicKind::RttiCompleteObjLocator; - if (MangledName.consumeFront("?_S")) + if (consumeFront(MangledName, "?_S")) return SpecialIntrinsicKind::LocalVftable; - if (MangledName.consumeFront("?__E")) + if (consumeFront(MangledName, "?__E")) return SpecialIntrinsicKind::DynamicInitializer; - if (MangledName.consumeFront("?__F")) + if (consumeFront(MangledName, "?__F")) return SpecialIntrinsicKind::DynamicAtexitDestructor; - if (MangledName.consumeFront("?__J")) + if (consumeFront(MangledName, "?__J")) return SpecialIntrinsicKind::LocalStaticThreadGuard; return SpecialIntrinsicKind::None; } -static bool startsWithLocalScopePattern(StringView S) { - if (!S.consumeFront('?')) +static bool startsWithLocalScopePattern(std::string_view S) { + if (!consumeFront(S, '?')) return false; size_t End = S.find('?'); - if (End == StringView::npos) + if (End == std::string_view::npos) return false; - StringView Candidate = S.substr(0, End); + std::string_view Candidate = S.substr(0, End); if (Candidate.empty()) return false; @@ -158,7 +174,7 @@ static bool startsWithLocalScopePattern(StringView S) { // If it's not 0-9, then it's an encoded number terminated with an @ if (Candidate.back() != '@') return false; - Candidate = Candidate.dropBack(); + Candidate.remove_suffix(1); // An encoded number starts with B-P and all subsequent digits are in A-P. // Note that the reason the first digit cannot be A is two fold. First, it @@ -168,17 +184,17 @@ static bool startsWithLocalScopePattern(StringView S) { // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J. if (Candidate[0] < 'B' || Candidate[0] > 'P') return false; - Candidate = Candidate.dropFront(); + Candidate.remove_prefix(1); while (!Candidate.empty()) { if (Candidate[0] < 'A' || Candidate[0] > 'P') return false; - Candidate = Candidate.dropFront(); + Candidate.remove_prefix(1); } return true; } -static bool isTagType(StringView S) { +static bool isTagType(std::string_view S) { switch (S.front()) { case 'T': // union case 'U': // struct @@ -189,10 +205,10 @@ static bool isTagType(StringView S) { return false; } -static bool isCustomType(StringView S) { return S[0] == '?'; } +static bool isCustomType(std::string_view S) { return S[0] == '?'; } -static bool isPointerType(StringView S) { - if (S.startsWith("$$Q")) // foo && +static bool isPointerType(std::string_view S) { + if (llvm::itanium_demangle::starts_with(S, "$$Q")) // foo && return true; switch (S.front()) { @@ -206,27 +222,30 @@ static bool isPointerType(StringView S) { return false; } -static bool isArrayType(StringView S) { return S[0] == 'Y'; } +static bool isArrayType(std::string_view S) { return S[0] == 'Y'; } -static bool isFunctionType(StringView S) { - return S.startsWith("$$A8@@") || S.startsWith("$$A6"); +static bool isFunctionType(std::string_view S) { + return llvm::itanium_demangle::starts_with(S, "$$A8@@") || + llvm::itanium_demangle::starts_with(S, "$$A6"); } static FunctionRefQualifier -demangleFunctionRefQualifier(StringView &MangledName) { - if (MangledName.consumeFront('G')) +demangleFunctionRefQualifier(std::string_view &MangledName) { + if (consumeFront(MangledName, 'G')) return FunctionRefQualifier::Reference; - else if (MangledName.consumeFront('H')) + else if (consumeFront(MangledName, 'H')) return FunctionRefQualifier::RValueReference; return FunctionRefQualifier::None; } static std::pair -demanglePointerCVQualifiers(StringView &MangledName) { - if (MangledName.consumeFront("$$Q")) +demanglePointerCVQualifiers(std::string_view &MangledName) { + if (consumeFront(MangledName, "$$Q")) return std::make_pair(Q_None, PointerAffinity::RValueReference); - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case 'A': return std::make_pair(Q_None, PointerAffinity::Reference); case 'P': @@ -244,15 +263,18 @@ demanglePointerCVQualifiers(StringView &MangledName) { DEMANGLE_UNREACHABLE; } -StringView Demangler::copyString(StringView Borrowed) { - char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); - std::strcpy(Stable, Borrowed.begin()); +std::string_view Demangler::copyString(std::string_view Borrowed) { + char *Stable = Arena.allocUnalignedBuffer(Borrowed.size()); + // This is not a micro-optimization, it avoids UB, should Borrowed be an null + // buffer. + if (Borrowed.size()) + std::memcpy(Stable, &*Borrowed.begin(), Borrowed.size()); return {Stable, Borrowed.size()}; } SpecialTableSymbolNode * -Demangler::demangleSpecialTableSymbolNode(StringView &MangledName, +Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName, SpecialIntrinsicKind K) { NamedIdentifierNode *NI = Arena.alloc(); switch (K) { @@ -279,20 +301,22 @@ Demangler::demangleSpecialTableSymbolNode(StringView &MangledName, Error = true; return nullptr; } - char Front = MangledName.popFront(); + char Front = MangledName.front(); + MangledName.remove_prefix(1); if (Front != '6' && Front != '7') { Error = true; return nullptr; } std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName); - if (!MangledName.consumeFront('@')) + if (!consumeFront(MangledName, '@')) STSN->TargetName = demangleFullyQualifiedTypeName(MangledName); return STSN; } LocalStaticGuardVariableNode * -Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) { +Demangler::demangleLocalStaticGuard(std::string_view &MangledName, + bool IsThread) { LocalStaticGuardIdentifierNode *LSGI = Arena.alloc(); LSGI->IsThread = IsThread; @@ -301,9 +325,9 @@ Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) { Arena.alloc(); LSGVN->Name = QN; - if (MangledName.consumeFront("4IA")) + if (consumeFront(MangledName, "4IA")) LSGVN->IsVisible = false; - else if (MangledName.consumeFront("5")) + else if (consumeFront(MangledName, "5")) LSGVN->IsVisible = true; else { Error = true; @@ -316,7 +340,7 @@ Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) { } static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena, - StringView Name) { + std::string_view Name) { NamedIdentifierNode *Id = Arena.alloc(); Id->Name = Name; return Id; @@ -333,27 +357,29 @@ static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, } static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena, - StringView Name) { + std::string_view Name) { NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name); return synthesizeQualifiedName(Arena, Id); } static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena, TypeNode *Type, - StringView VariableName) { + std::string_view VariableName) { VariableSymbolNode *VSN = Arena.alloc(); VSN->Type = Type; VSN->Name = synthesizeQualifiedName(Arena, VariableName); return VSN; } -VariableSymbolNode *Demangler::demangleUntypedVariable( - ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) { +VariableSymbolNode * +Demangler::demangleUntypedVariable(ArenaAllocator &Arena, + std::string_view &MangledName, + std::string_view VariableName) { NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName); QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI); VariableSymbolNode *VSN = Arena.alloc(); VSN->Name = QN; - if (MangledName.consumeFront("8")) + if (consumeFront(MangledName, "8")) return VSN; Error = true; @@ -362,7 +388,7 @@ VariableSymbolNode *Demangler::demangleUntypedVariable( VariableSymbolNode * Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, - StringView &MangledName) { + std::string_view &MangledName) { RttiBaseClassDescriptorNode *RBCDN = Arena.alloc(); RBCDN->NVOffset = demangleUnsigned(MangledName); @@ -374,18 +400,19 @@ Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena, VariableSymbolNode *VSN = Arena.alloc(); VSN->Name = demangleNameScopeChain(MangledName, RBCDN); - MangledName.consumeFront('8'); + consumeFront(MangledName, '8'); return VSN; } -FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, - bool IsDestructor) { +FunctionSymbolNode * +Demangler::demangleInitFiniStub(std::string_view &MangledName, + bool IsDestructor) { DynamicStructorIdentifierNode *DSIN = Arena.alloc(); DSIN->IsDestructor = IsDestructor; bool IsKnownStaticDataMember = false; - if (MangledName.consumeFront('?')) + if (consumeFront(MangledName, '?')) IsKnownStaticDataMember = true; SymbolNode *Symbol = demangleDeclarator(MangledName); @@ -403,7 +430,7 @@ FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, // both cases. int AtCount = IsKnownStaticDataMember ? 2 : 1; for (int I = 0; I < AtCount; ++I) { - if (MangledName.consumeFront('@')) + if (consumeFront(MangledName, '@')) continue; Error = true; return nullptr; @@ -427,7 +454,7 @@ FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName, return FSN; } -SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { +SymbolNode *Demangler::demangleSpecialIntrinsic(std::string_view &MangledName) { SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName); switch (SIK) { @@ -450,7 +477,7 @@ SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); if (Error) break; - if (!MangledName.consumeFront("@8")) + if (!consumeFront(MangledName, "@8")) break; if (!MangledName.empty()) break; @@ -481,18 +508,18 @@ SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) { } IdentifierNode * -Demangler::demangleFunctionIdentifierCode(StringView &MangledName) { - assert(MangledName.startsWith('?')); - MangledName = MangledName.dropFront(); +Demangler::demangleFunctionIdentifierCode(std::string_view &MangledName) { + assert(llvm::itanium_demangle::starts_with(MangledName, '?')); + MangledName.remove_prefix(1); if (MangledName.empty()) { Error = true; return nullptr; } - if (MangledName.consumeFront("__")) + if (consumeFront(MangledName, "__")) return demangleFunctionIdentifierCode( MangledName, FunctionIdentifierCodeGroup::DoubleUnder); - if (MangledName.consumeFront("_")) + if (consumeFront(MangledName, "_")) return demangleFunctionIdentifierCode(MangledName, FunctionIdentifierCodeGroup::Under); return demangleFunctionIdentifierCode(MangledName, @@ -500,7 +527,7 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName) { } StructorIdentifierNode * -Demangler::demangleStructorIdentifier(StringView &MangledName, +Demangler::demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor) { StructorIdentifierNode *N = Arena.alloc(); N->IsDestructor = IsDestructor; @@ -508,14 +535,14 @@ Demangler::demangleStructorIdentifier(StringView &MangledName, } ConversionOperatorIdentifierNode * -Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) { +Demangler::demangleConversionOperatorIdentifier(std::string_view &MangledName) { ConversionOperatorIdentifierNode *N = Arena.alloc(); return N; } LiteralOperatorIdentifierNode * -Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) { +Demangler::demangleLiteralOperatorIdentifier(std::string_view &MangledName) { LiteralOperatorIdentifierNode *N = Arena.alloc(); N->Name = demangleSimpleString(MangledName, /*Memorize=*/false); @@ -663,15 +690,17 @@ Demangler::translateIntrinsicFunctionCode(char CH, } IdentifierNode * -Demangler::demangleFunctionIdentifierCode(StringView &MangledName, +Demangler::demangleFunctionIdentifierCode(std::string_view &MangledName, FunctionIdentifierCodeGroup Group) { if (MangledName.empty()) { Error = true; return nullptr; } + const char CH = MangledName.front(); switch (Group) { case FunctionIdentifierCodeGroup::Basic: - switch (char CH = MangledName.popFront()) { + MangledName.remove_prefix(1); + switch (CH) { case '0': case '1': return demangleStructorIdentifier(MangledName, CH == '1'); @@ -682,10 +711,12 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName, translateIntrinsicFunctionCode(CH, Group)); } case FunctionIdentifierCodeGroup::Under: + MangledName.remove_prefix(1); return Arena.alloc( - translateIntrinsicFunctionCode(MangledName.popFront(), Group)); + translateIntrinsicFunctionCode(CH, Group)); case FunctionIdentifierCodeGroup::DoubleUnder: - switch (char CH = MangledName.popFront()) { + MangledName.remove_prefix(1); + switch (CH) { case 'K': return demangleLiteralOperatorIdentifier(MangledName); default: @@ -697,7 +728,7 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName, DEMANGLE_UNREACHABLE; } -SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName, +SymbolNode *Demangler::demangleEncodedSymbol(std::string_view &MangledName, QualifiedNameNode *Name) { if (MangledName.empty()) { Error = true; @@ -727,7 +758,7 @@ SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName, return FSN; } -SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) { +SymbolNode *Demangler::demangleDeclarator(std::string_view &MangledName) { // What follows is a main symbol name. This may include namespaces or class // back references. QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName); @@ -751,18 +782,19 @@ SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) { return Symbol; } -SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) { - assert(MangledName.startsWith("??@")); +SymbolNode *Demangler::demangleMD5Name(std::string_view &MangledName) { + assert(llvm::itanium_demangle::starts_with(MangledName, "??@")); // This is an MD5 mangled name. We can't demangle it, just return the // mangled name. // An MD5 mangled name is ??@ followed by 32 characters and a terminating @. size_t MD5Last = MangledName.find('@', strlen("??@")); - if (MD5Last == StringView::npos) { + if (MD5Last == std::string_view::npos) { Error = true; return nullptr; } - const char *Start = MangledName.begin(); - MangledName = MangledName.dropFront(MD5Last + 1); + const char *Start = &*MangledName.begin(); + const size_t StartSize = MangledName.size(); + MangledName.remove_prefix(MD5Last + 1); // There are two additional special cases for MD5 names: // 1. For complete object locators where the object name is long enough @@ -774,18 +806,20 @@ SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) { // instead of_CT??@...@8 with just one MD5 name. Since we don't yet // demangle catchable types anywhere, this isn't handled for MD5 names // either. - MangledName.consumeFront("??_R4@"); + consumeFront(MangledName, "??_R4@"); - StringView MD5(Start, MangledName.begin()); + assert(MangledName.size() < StartSize); + const size_t Count = StartSize - MangledName.size(); + std::string_view MD5(Start, Count); SymbolNode *S = Arena.alloc(NodeKind::Md5Symbol); S->Name = synthesizeQualifiedName(Arena, MD5); return S; } -SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) { - assert(MangledName.startsWith('.')); - MangledName.consumeFront('.'); +SymbolNode *Demangler::demangleTypeinfoName(std::string_view &MangledName) { + assert(llvm::itanium_demangle::starts_with(MangledName, '.')); + consumeFront(MangledName, '.'); TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result); if (Error || !MangledName.empty()) { @@ -796,23 +830,23 @@ SymbolNode *Demangler::demangleTypeinfoName(StringView &MangledName) { } // Parser entry point. -SymbolNode *Demangler::parse(StringView &MangledName) { +SymbolNode *Demangler::parse(std::string_view &MangledName) { // Typeinfo names are strings stored in RTTI data. They're not symbol names. // It's still useful to demangle them. They're the only demangled entity // that doesn't start with a "?" but a ".". - if (MangledName.startsWith('.')) + if (llvm::itanium_demangle::starts_with(MangledName, '.')) return demangleTypeinfoName(MangledName); - if (MangledName.startsWith("??@")) + if (llvm::itanium_demangle::starts_with(MangledName, "??@")) return demangleMD5Name(MangledName); // MSVC-style mangled symbols must start with '?'. - if (!MangledName.startsWith('?')) { + if (!llvm::itanium_demangle::starts_with(MangledName, '?')) { Error = true; return nullptr; } - MangledName.consumeFront('?'); + consumeFront(MangledName, '?'); // ?$ is a template instantiation, but all other names that start with ? are // operators / special names. @@ -822,12 +856,16 @@ SymbolNode *Demangler::parse(StringView &MangledName) { return demangleDeclarator(MangledName); } -TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) { - if (!MangledName.consumeFront(".?A")) +TagTypeNode *Demangler::parseTagUniqueName(std::string_view &MangledName) { + if (!consumeFront(MangledName, ".?A")) { + Error = true; return nullptr; - MangledName.consumeFront(".?A"); - if (MangledName.empty()) + } + consumeFront(MangledName, ".?A"); + if (MangledName.empty()) { + Error = true; return nullptr; + } return demangleClassType(MangledName); } @@ -839,8 +877,9 @@ TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) { // ::= 3 # global // ::= 4 # static local -VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName, - StorageClass SC) { +VariableSymbolNode * +Demangler::demangleVariableEncoding(std::string_view &MangledName, + StorageClass SC) { VariableSymbolNode *VSN = Arena.alloc(); VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop); @@ -890,12 +929,13 @@ VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName, // ::= + @ # when Number == 0 or >= 10 // // ::= [A-P] # A = 0, B = 1, ... -std::pair Demangler::demangleNumber(StringView &MangledName) { - bool IsNegative = MangledName.consumeFront('?'); +std::pair +Demangler::demangleNumber(std::string_view &MangledName) { + bool IsNegative = consumeFront(MangledName, '?'); if (startsWithDigit(MangledName)) { uint64_t Ret = MangledName[0] - '0' + 1; - MangledName = MangledName.dropFront(1); + MangledName.remove_prefix(1); return {Ret, IsNegative}; } @@ -903,7 +943,7 @@ std::pair Demangler::demangleNumber(StringView &MangledName) { for (size_t i = 0; i < MangledName.size(); ++i) { char C = MangledName[i]; if (C == '@') { - MangledName = MangledName.dropFront(i + 1); + MangledName.remove_prefix(i + 1); return {Ret, IsNegative}; } if ('A' <= C && C <= 'P') { @@ -917,7 +957,7 @@ std::pair Demangler::demangleNumber(StringView &MangledName) { return {0ULL, false}; } -uint64_t Demangler::demangleUnsigned(StringView &MangledName) { +uint64_t Demangler::demangleUnsigned(std::string_view &MangledName) { bool IsNegative = false; uint64_t Number = 0; std::tie(Number, IsNegative) = demangleNumber(MangledName); @@ -926,7 +966,7 @@ uint64_t Demangler::demangleUnsigned(StringView &MangledName) { return Number; } -int64_t Demangler::demangleSigned(StringView &MangledName) { +int64_t Demangler::demangleSigned(std::string_view &MangledName) { bool IsNegative = false; uint64_t Number = 0; std::tie(Number, IsNegative) = demangleNumber(MangledName); @@ -938,7 +978,7 @@ int64_t Demangler::demangleSigned(StringView &MangledName) { // First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9. // Memorize it. -void Demangler::memorizeString(StringView S) { +void Demangler::memorizeString(std::string_view S) { if (Backrefs.NamesCount >= BackrefContext::Max) return; for (size_t i = 0; i < Backrefs.NamesCount; ++i) @@ -949,7 +989,8 @@ void Demangler::memorizeString(StringView S) { Backrefs.Names[Backrefs.NamesCount++] = N; } -NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { +NamedIdentifierNode * +Demangler::demangleBackRefName(std::string_view &MangledName) { assert(startsWithDigit(MangledName)); size_t I = MangledName[0] - '0'; @@ -958,7 +999,7 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) { return nullptr; } - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); return Backrefs.Names[I]; } @@ -966,23 +1007,17 @@ void Demangler::memorizeIdentifier(IdentifierNode *Identifier) { // Render this class template name into a string buffer so that we can // memorize it for the purpose of back-referencing. OutputBuffer OB; - if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) - // FIXME: Propagate out-of-memory as an error? - std::terminate(); Identifier->output(OB, OF_Default); - OB << '\0'; - char *Name = OB.getBuffer(); - - StringView Owned = copyString(Name); + std::string_view Owned = copyString(OB); memorizeString(Owned); - std::free(Name); + std::free(OB.getBuffer()); } IdentifierNode * -Demangler::demangleTemplateInstantiationName(StringView &MangledName, +Demangler::demangleTemplateInstantiationName(std::string_view &MangledName, NameBackrefBehavior NBB) { - assert(MangledName.startsWith("?$")); - MangledName.consumeFront("?$"); + assert(llvm::itanium_demangle::starts_with(MangledName, "?$")); + consumeFront(MangledName, "?$"); BackrefContext OuterContext; std::swap(OuterContext, Backrefs); @@ -1012,9 +1047,9 @@ Demangler::demangleTemplateInstantiationName(StringView &MangledName, return Identifier; } -NamedIdentifierNode *Demangler::demangleSimpleName(StringView &MangledName, - bool Memorize) { - StringView S = demangleSimpleString(MangledName, Memorize); +NamedIdentifierNode * +Demangler::demangleSimpleName(std::string_view &MangledName, bool Memorize) { + std::string_view S = demangleSimpleString(MangledName, Memorize); if (Error) return nullptr; @@ -1030,33 +1065,36 @@ static uint8_t rebasedHexDigitToNumber(char C) { return (C <= 'J') ? (C - 'A') : (10 + C - 'K'); } -uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { +uint8_t Demangler::demangleCharLiteral(std::string_view &MangledName) { assert(!MangledName.empty()); - if (!MangledName.startsWith('?')) - return MangledName.popFront(); + if (!llvm::itanium_demangle::starts_with(MangledName, '?')) { + const uint8_t F = MangledName.front(); + MangledName.remove_prefix(1); + return F; + } - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); if (MangledName.empty()) goto CharLiteralError; - if (MangledName.consumeFront('$')) { + if (consumeFront(MangledName, '$')) { // Two hex digits if (MangledName.size() < 2) goto CharLiteralError; - StringView Nibbles = MangledName.substr(0, 2); + std::string_view Nibbles = MangledName.substr(0, 2); if (!isRebasedHexDigit(Nibbles[0]) || !isRebasedHexDigit(Nibbles[1])) goto CharLiteralError; // Don't append the null terminator. uint8_t C1 = rebasedHexDigitToNumber(Nibbles[0]); uint8_t C2 = rebasedHexDigitToNumber(Nibbles[1]); - MangledName = MangledName.dropFront(2); + MangledName.remove_prefix(2); return (C1 << 4) | C2; } if (startsWithDigit(MangledName)) { const char *Lookup = ",/\\:. \n\t'-"; char C = Lookup[MangledName[0] - '0']; - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); return C; } @@ -1066,7 +1104,7 @@ uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { '\xEF', '\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7', '\xF8', '\xF9', '\xFA'}; char C = Lookup[MangledName[0] - 'a']; - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); return C; } @@ -1076,7 +1114,7 @@ uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { '\xCF', '\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', '\xD8', '\xD9', '\xDA'}; char C = Lookup[MangledName[0] - 'A']; - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); return C; } @@ -1085,7 +1123,7 @@ uint8_t Demangler::demangleCharLiteral(StringView &MangledName) { return '\0'; } -wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) { +wchar_t Demangler::demangleWcharLiteral(std::string_view &MangledName) { uint8_t C1, C2; C1 = demangleCharLiteral(MangledName); @@ -1130,7 +1168,7 @@ static void outputHex(OutputBuffer &OB, unsigned C) { TempBuffer[Pos--] = 'x'; assert(Pos >= 0); TempBuffer[Pos--] = '\\'; - OB << StringView(&TempBuffer[Pos + 1]); + OB << std::string_view(&TempBuffer[Pos + 1]); } static void outputEscapedChar(OutputBuffer &OB, unsigned C) { @@ -1252,7 +1290,8 @@ static unsigned decodeMultiByteChar(const uint8_t *StringBytes, return Result; } -FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { +FunctionSymbolNode * +Demangler::demangleVcallThunkNode(std::string_view &MangledName) { FunctionSymbolNode *FSN = Arena.alloc(); VcallThunkIdentifierNode *VTIN = Arena.alloc(); FSN->Signature = Arena.alloc(); @@ -1260,42 +1299,39 @@ FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) { FSN->Name = demangleNameScopeChain(MangledName, VTIN); if (!Error) - Error = !MangledName.consumeFront("$B"); + Error = !consumeFront(MangledName, "$B"); if (!Error) VTIN->OffsetInVTable = demangleUnsigned(MangledName); if (!Error) - Error = !MangledName.consumeFront('A'); + Error = !consumeFront(MangledName, 'A'); if (!Error) FSN->Signature->CallConvention = demangleCallingConvention(MangledName); return (Error) ? nullptr : FSN; } EncodedStringLiteralNode * -Demangler::demangleStringLiteral(StringView &MangledName) { +Demangler::demangleStringLiteral(std::string_view &MangledName) { // This function uses goto, so declare all variables up front. OutputBuffer OB; - StringView CRC; + std::string_view CRC; uint64_t StringByteSize; bool IsWcharT = false; bool IsNegative = false; size_t CrcEndPos = 0; - char *ResultBuffer = nullptr; + char F; EncodedStringLiteralNode *Result = Arena.alloc(); - // Must happen before the first `goto StringLiteralError`. - if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) - // FIXME: Propagate out-of-memory as an error? - std::terminate(); - // Prefix indicating the beginning of a string literal - if (!MangledName.consumeFront("@_")) + if (!consumeFront(MangledName, "@_")) goto StringLiteralError; if (MangledName.empty()) goto StringLiteralError; // Char Type (regular or wchar_t) - switch (MangledName.popFront()) { + F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case '1': IsWcharT = true; DEMANGLE_FALLTHROUGH; @@ -1312,10 +1348,10 @@ Demangler::demangleStringLiteral(StringView &MangledName) { // CRC 32 (always 8 characters plus a terminator) CrcEndPos = MangledName.find('@'); - if (CrcEndPos == StringView::npos) + if (CrcEndPos == std::string_view::npos) goto StringLiteralError; CRC = MangledName.substr(0, CrcEndPos); - MangledName = MangledName.dropFront(CrcEndPos + 1); + MangledName.remove_prefix(CrcEndPos + 1); if (MangledName.empty()) goto StringLiteralError; @@ -1324,7 +1360,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) { if (StringByteSize > 64) Result->IsTruncated = true; - while (!MangledName.consumeFront('@')) { + while (!consumeFront(MangledName, '@')) { if (MangledName.size() < 2) goto StringLiteralError; wchar_t W = demangleWcharLiteral(MangledName); @@ -1341,7 +1377,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) { uint8_t StringBytes[MaxStringByteLength]; unsigned BytesDecoded = 0; - while (!MangledName.consumeFront('@')) { + while (!consumeFront(MangledName, '@')) { if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength) goto StringLiteralError; StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName); @@ -1375,10 +1411,8 @@ Demangler::demangleStringLiteral(StringView &MangledName) { } } - OB << '\0'; - ResultBuffer = OB.getBuffer(); - Result->DecodedString = copyString(ResultBuffer); - std::free(ResultBuffer); + Result->DecodedString = copyString(OB); + std::free(OB.getBuffer()); return Result; StringLiteralError: @@ -1389,16 +1423,16 @@ Demangler::demangleStringLiteral(StringView &MangledName) { // Returns MangledName's prefix before the first '@', or an error if // MangledName contains no '@' or the prefix has length 0. -StringView Demangler::demangleSimpleString(StringView &MangledName, - bool Memorize) { - StringView S; +std::string_view Demangler::demangleSimpleString(std::string_view &MangledName, + bool Memorize) { + std::string_view S; for (size_t i = 0; i < MangledName.size(); ++i) { if (MangledName[i] != '@') continue; if (i == 0) break; S = MangledName.substr(0, i); - MangledName = MangledName.dropFront(i + 1); + MangledName.remove_prefix(i + 1); if (Memorize) memorizeString(S); @@ -1410,36 +1444,36 @@ StringView Demangler::demangleSimpleString(StringView &MangledName, } NamedIdentifierNode * -Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { - assert(MangledName.startsWith("?A")); - MangledName.consumeFront("?A"); +Demangler::demangleAnonymousNamespaceName(std::string_view &MangledName) { + assert(llvm::itanium_demangle::starts_with(MangledName, "?A")); + consumeFront(MangledName, "?A"); NamedIdentifierNode *Node = Arena.alloc(); Node->Name = "`anonymous namespace'"; size_t EndPos = MangledName.find('@'); - if (EndPos == StringView::npos) { + if (EndPos == std::string_view::npos) { Error = true; return nullptr; } - StringView NamespaceKey = MangledName.substr(0, EndPos); + std::string_view NamespaceKey = MangledName.substr(0, EndPos); memorizeString(NamespaceKey); MangledName = MangledName.substr(EndPos + 1); return Node; } NamedIdentifierNode * -Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { +Demangler::demangleLocallyScopedNamePiece(std::string_view &MangledName) { assert(startsWithLocalScopePattern(MangledName)); NamedIdentifierNode *Identifier = Arena.alloc(); - MangledName.consumeFront('?'); + consumeFront(MangledName, '?'); uint64_t Number = 0; bool IsNegative = false; std::tie(Number, IsNegative) = demangleNumber(MangledName); assert(!IsNegative); // One ? to terminate the number - MangledName.consumeFront('?'); + consumeFront(MangledName, '?'); assert(!Error); Node *Scope = parse(MangledName); @@ -1448,23 +1482,19 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { // Render the parent symbol's name into a buffer. OutputBuffer OB; - if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) - // FIXME: Propagate out-of-memory as an error? - std::terminate(); OB << '`'; Scope->output(OB, OF_Default); OB << '\''; OB << "::`" << Number << "'"; - OB << '\0'; - char *Result = OB.getBuffer(); - Identifier->Name = copyString(Result); - std::free(Result); + + Identifier->Name = copyString(OB); + std::free(OB.getBuffer()); return Identifier; } // Parses a type name in the form of A@B@C@@ which represents C::B::A. QualifiedNameNode * -Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { +Demangler::demangleFullyQualifiedTypeName(std::string_view &MangledName) { IdentifierNode *Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); if (Error) @@ -1482,7 +1512,7 @@ Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { // Symbol names have slightly different rules regarding what can appear // so we separate out the implementations for flexibility. QualifiedNameNode * -Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { +Demangler::demangleFullyQualifiedSymbolName(std::string_view &MangledName) { // This is the final component of a symbol name (i.e. the leftmost component // of a mangled name. Since the only possible template instantiation that // can appear in this context is a function template, and since those are @@ -1511,8 +1541,9 @@ Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { return QN; } -IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName, - bool Memorize) { +IdentifierNode * +Demangler::demangleUnqualifiedTypeName(std::string_view &MangledName, + bool Memorize) { // An inner-most name can be a back-reference, because a fully-qualified name // (e.g. Scope + Inner) can contain other fully qualified names inside of // them (for example template parameters), and these nested parameters can @@ -1520,32 +1551,33 @@ IdentifierNode *Demangler::demangleUnqualifiedTypeName(StringView &MangledName, if (startsWithDigit(MangledName)) return demangleBackRefName(MangledName); - if (MangledName.startsWith("?$")) + if (llvm::itanium_demangle::starts_with(MangledName, "?$")) return demangleTemplateInstantiationName(MangledName, NBB_Template); return demangleSimpleName(MangledName, Memorize); } IdentifierNode * -Demangler::demangleUnqualifiedSymbolName(StringView &MangledName, +Demangler::demangleUnqualifiedSymbolName(std::string_view &MangledName, NameBackrefBehavior NBB) { if (startsWithDigit(MangledName)) return demangleBackRefName(MangledName); - if (MangledName.startsWith("?$")) + if (llvm::itanium_demangle::starts_with(MangledName, "?$")) return demangleTemplateInstantiationName(MangledName, NBB); - if (MangledName.startsWith('?')) + if (llvm::itanium_demangle::starts_with(MangledName, '?')) return demangleFunctionIdentifierCode(MangledName); return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0); } -IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) { +IdentifierNode * +Demangler::demangleNameScopePiece(std::string_view &MangledName) { if (startsWithDigit(MangledName)) return demangleBackRefName(MangledName); - if (MangledName.startsWith("?$")) + if (llvm::itanium_demangle::starts_with(MangledName, "?$")) return demangleTemplateInstantiationName(MangledName, NBB_Template); - if (MangledName.startsWith("?A")) + if (llvm::itanium_demangle::starts_with(MangledName, "?A")) return demangleAnonymousNamespaceName(MangledName); if (startsWithLocalScopePattern(MangledName)) @@ -1567,14 +1599,14 @@ static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head, } QualifiedNameNode * -Demangler::demangleNameScopeChain(StringView &MangledName, +Demangler::demangleNameScopeChain(std::string_view &MangledName, IdentifierNode *UnqualifiedName) { NodeList *Head = Arena.alloc(); Head->N = UnqualifiedName; size_t Count = 1; - while (!MangledName.consumeFront("@")) { + while (!consumeFront(MangledName, "@")) { ++Count; NodeList *NewHead = Arena.alloc(); NewHead->Next = Head; @@ -1598,8 +1630,10 @@ Demangler::demangleNameScopeChain(StringView &MangledName, return QN; } -FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { - switch (MangledName.popFront()) { +FuncClass Demangler::demangleFunctionClass(std::string_view &MangledName) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case '9': return FuncClass(FC_ExternC | FC_NoParameterList); case 'A': @@ -1656,11 +1690,13 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { return FuncClass(FC_Global | FC_Far); case '$': { FuncClass VFlag = FC_VirtualThisAdjust; - if (MangledName.consumeFront('R')) + if (consumeFront(MangledName, 'R')) VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx); if (MangledName.empty()) break; - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case '0': return FuncClass(FC_Private | FC_Virtual | VFlag); case '1': @@ -1681,13 +1717,16 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) { return FC_Public; } -CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { +CallingConv +Demangler::demangleCallingConvention(std::string_view &MangledName) { if (MangledName.empty()) { Error = true; return CallingConv::None; } - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case 'A': case 'B': return CallingConv::Cdecl; @@ -1720,10 +1759,13 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) { return CallingConv::None; } -StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { +StorageClass +Demangler::demangleVariableStorageClass(std::string_view &MangledName) { assert(MangledName.front() >= '0' && MangledName.front() <= '4'); - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case '0': return StorageClass::PrivateStatic; case '1': @@ -1739,13 +1781,15 @@ StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) { } std::pair -Demangler::demangleQualifiers(StringView &MangledName) { +Demangler::demangleQualifiers(std::string_view &MangledName) { if (MangledName.empty()) { Error = true; return std::make_pair(Q_None, false); } - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { // Member qualifiers case 'Q': return std::make_pair(Q_None, true); @@ -1771,14 +1815,14 @@ Demangler::demangleQualifiers(StringView &MangledName) { // ::= // ::= # pointers, references -TypeNode *Demangler::demangleType(StringView &MangledName, +TypeNode *Demangler::demangleType(std::string_view &MangledName, QualifierMangleMode QMM) { Qualifiers Quals = Q_None; bool IsMember = false; if (QMM == QualifierMangleMode::Mangle) { std::tie(Quals, IsMember) = demangleQualifiers(MangledName); } else if (QMM == QualifierMangleMode::Result) { - if (MangledName.consumeFront('?')) + if (consumeFront(MangledName, '?')) std::tie(Quals, IsMember) = demangleQualifiers(MangledName); } @@ -1800,11 +1844,11 @@ TypeNode *Demangler::demangleType(StringView &MangledName, } else if (isArrayType(MangledName)) Ty = demangleArrayType(MangledName); else if (isFunctionType(MangledName)) { - if (MangledName.consumeFront("$$A8@@")) + if (consumeFront(MangledName, "$$A8@@")) Ty = demangleFunctionType(MangledName, true); else { - assert(MangledName.startsWith("$$A6")); - MangledName.consumeFront("$$A6"); + assert(llvm::itanium_demangle::starts_with(MangledName, "$$A6")); + consumeFront(MangledName, "$$A6"); Ty = demangleFunctionType(MangledName, false); } } else if (isCustomType(MangledName)) { @@ -1819,18 +1863,19 @@ TypeNode *Demangler::demangleType(StringView &MangledName, return Ty; } -bool Demangler::demangleThrowSpecification(StringView &MangledName) { - if (MangledName.consumeFront("_E")) +bool Demangler::demangleThrowSpecification(std::string_view &MangledName) { + if (consumeFront(MangledName, "_E")) return true; - if (MangledName.consumeFront('Z')) + if (consumeFront(MangledName, 'Z')) return false; Error = true; return false; } -FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, - bool HasThisQuals) { +FunctionSignatureNode * +Demangler::demangleFunctionType(std::string_view &MangledName, + bool HasThisQuals) { FunctionSignatureNode *FTy = Arena.alloc(); if (HasThisQuals) { @@ -1844,7 +1889,7 @@ FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, // ::= // ::= @ # structors (they have no declared return type) - bool IsStructor = MangledName.consumeFront('@'); + bool IsStructor = consumeFront(MangledName, '@'); if (!IsStructor) FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); @@ -1856,9 +1901,9 @@ FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName, } FunctionSymbolNode * -Demangler::demangleFunctionEncoding(StringView &MangledName) { +Demangler::demangleFunctionEncoding(std::string_view &MangledName) { FuncClass ExtraFlags = FC_None; - if (MangledName.consumeFront("$$J0")) + if (consumeFront(MangledName, "$$J0")) ExtraFlags = FC_ExternC; if (MangledName.empty()) { @@ -1908,13 +1953,13 @@ Demangler::demangleFunctionEncoding(StringView &MangledName) { return Symbol; } -CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) { - assert(MangledName.startsWith('?')); - MangledName.popFront(); +CustomTypeNode *Demangler::demangleCustomType(std::string_view &MangledName) { + assert(llvm::itanium_demangle::starts_with(MangledName, '?')); + MangledName.remove_prefix(1); CustomTypeNode *CTN = Arena.alloc(); CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true); - if (!MangledName.consumeFront('@')) + if (!consumeFront(MangledName, '@')) Error = true; if (Error) return nullptr; @@ -1922,11 +1967,14 @@ CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) { } // Reads a primitive type. -PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { - if (MangledName.consumeFront("$$T")) +PrimitiveTypeNode * +Demangler::demanglePrimitiveType(std::string_view &MangledName) { + if (consumeFront(MangledName, "$$T")) return Arena.alloc(PrimitiveKind::Nullptr); - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case 'X': return Arena.alloc(PrimitiveKind::Void); case 'D': @@ -1958,7 +2006,9 @@ PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { Error = true; return nullptr; } - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case 'N': return Arena.alloc(PrimitiveKind::Bool); case 'J': @@ -1981,10 +2031,12 @@ PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) { return nullptr; } -TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { +TagTypeNode *Demangler::demangleClassType(std::string_view &MangledName) { TagTypeNode *TT = nullptr; - switch (MangledName.popFront()) { + const char F = MangledName.front(); + MangledName.remove_prefix(1); + switch (F) { case 'T': TT = Arena.alloc(TagKind::Union); break; @@ -1995,7 +2047,7 @@ TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { TT = Arena.alloc(TagKind::Class); break; case 'W': - if (!MangledName.consumeFront('4')) { + if (!consumeFront(MangledName, '4')) { Error = true; return nullptr; } @@ -2011,13 +2063,13 @@ TagTypeNode *Demangler::demangleClassType(StringView &MangledName) { // ::= E? // # the E is required for 64-bit non-static pointers -PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) { +PointerTypeNode *Demangler::demanglePointerType(std::string_view &MangledName) { PointerTypeNode *Pointer = Arena.alloc(); std::tie(Pointer->Quals, Pointer->Affinity) = demanglePointerCVQualifiers(MangledName); - if (MangledName.consumeFront("6")) { + if (consumeFront(MangledName, "6")) { Pointer->Pointee = demangleFunctionType(MangledName, false); return Pointer; } @@ -2029,7 +2081,8 @@ PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) { return Pointer; } -PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { +PointerTypeNode * +Demangler::demangleMemberPointerType(std::string_view &MangledName) { PointerTypeNode *Pointer = Arena.alloc(); std::tie(Pointer->Quals, Pointer->Affinity) = @@ -2041,7 +2094,7 @@ PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { // isMemberPointer() only returns true if there is at least one character // after the qualifiers. - if (MangledName.consumeFront("8")) { + if (consumeFront(MangledName, "8")) { Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName); Pointer->Pointee = demangleFunctionType(MangledName, true); } else { @@ -2059,21 +2112,22 @@ PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) { return Pointer; } -Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) { +Qualifiers +Demangler::demanglePointerExtQualifiers(std::string_view &MangledName) { Qualifiers Quals = Q_None; - if (MangledName.consumeFront('E')) + if (consumeFront(MangledName, 'E')) Quals = Qualifiers(Quals | Q_Pointer64); - if (MangledName.consumeFront('I')) + if (consumeFront(MangledName, 'I')) Quals = Qualifiers(Quals | Q_Restrict); - if (MangledName.consumeFront('F')) + if (consumeFront(MangledName, 'F')) Quals = Qualifiers(Quals | Q_Unaligned); return Quals; } -ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { +ArrayTypeNode *Demangler::demangleArrayType(std::string_view &MangledName) { assert(MangledName.front() == 'Y'); - MangledName.popFront(); + MangledName.remove_prefix(1); uint64_t Rank = 0; bool IsNegative = false; @@ -2102,7 +2156,7 @@ ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { } ATy->Dimensions = nodeListToNodeArray(Arena, Head, Rank); - if (MangledName.consumeFront("$$C")) { + if (consumeFront(MangledName, "$$C")) { bool IsMember = false; std::tie(ATy->Quals, IsMember) = demangleQualifiers(MangledName); if (IsMember) { @@ -2116,17 +2170,18 @@ ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) { } // Reads a function's parameters. -NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, - bool &IsVariadic) { +NodeArrayNode * +Demangler::demangleFunctionParameterList(std::string_view &MangledName, + bool &IsVariadic) { // Empty parameter list. - if (MangledName.consumeFront('X')) + if (consumeFront(MangledName, 'X')) return nullptr; NodeList *Head = Arena.alloc(); NodeList **Current = &Head; size_t Count = 0; - while (!Error && !MangledName.startsWith('@') && - !MangledName.startsWith('Z')) { + while (!Error && !llvm::itanium_demangle::starts_with(MangledName, '@') && + !llvm::itanium_demangle::starts_with(MangledName, 'Z')) { ++Count; if (startsWithDigit(MangledName)) { @@ -2135,7 +2190,7 @@ NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, Error = true; return nullptr; } - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); *Current = Arena.alloc(); (*Current)->N = Backrefs.FunctionParams[N]; @@ -2170,10 +2225,10 @@ NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, // A non-empty parameter list is terminated by either 'Z' (variadic) parameter // list or '@' (non variadic). Careful not to consume "@Z", as in that case // the following Z could be a throw specifier. - if (MangledName.consumeFront('@')) + if (consumeFront(MangledName, '@')) return NA; - if (MangledName.consumeFront('Z')) { + if (consumeFront(MangledName, 'Z')) { IsVariadic = true; return NA; } @@ -2182,14 +2237,14 @@ NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName, } NodeArrayNode * -Demangler::demangleTemplateParameterList(StringView &MangledName) { +Demangler::demangleTemplateParameterList(std::string_view &MangledName) { NodeList *Head = nullptr; NodeList **Current = &Head; size_t Count = 0; - while (!MangledName.startsWith('@')) { - if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || - MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) { + while (!llvm::itanium_demangle::starts_with(MangledName, '@')) { + if (consumeFront(MangledName, "$S") || consumeFront(MangledName, "$$V") || + consumeFront(MangledName, "$$$V") || consumeFront(MangledName, "$$Z")) { // parameter pack separator continue; } @@ -2202,29 +2257,32 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { NodeList &TP = **Current; TemplateParameterReferenceNode *TPRN = nullptr; - if (MangledName.consumeFront("$$Y")) { + if (consumeFront(MangledName, "$$Y")) { // Template alias TP.N = demangleFullyQualifiedTypeName(MangledName); - } else if (MangledName.consumeFront("$$B")) { + } else if (consumeFront(MangledName, "$$B")) { // Array TP.N = demangleType(MangledName, QualifierMangleMode::Drop); - } else if (MangledName.consumeFront("$$C")) { + } else if (consumeFront(MangledName, "$$C")) { // Type has qualifiers. TP.N = demangleType(MangledName, QualifierMangleMode::Mangle); - } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") || - MangledName.startsWith("$I") || MangledName.startsWith("$J")) { + } else if (llvm::itanium_demangle::starts_with(MangledName, "$1") || + llvm::itanium_demangle::starts_with(MangledName, "$H") || + llvm::itanium_demangle::starts_with(MangledName, "$I") || + llvm::itanium_demangle::starts_with(MangledName, "$J")) { // Pointer to member TP.N = TPRN = Arena.alloc(); TPRN->IsMemberPointer = true; - MangledName = MangledName.dropFront(); + MangledName.remove_prefix(1); // 1 - single inheritance // H - multiple inheritance // I - virtual inheritance // J - unspecified inheritance - char InheritanceSpecifier = MangledName.popFront(); + char InheritanceSpecifier = MangledName.front(); + MangledName.remove_prefix(1); SymbolNode *S = nullptr; - if (MangledName.startsWith('?')) { + if (llvm::itanium_demangle::starts_with(MangledName, '?')) { S = parse(MangledName); if (Error || !S->Name) { Error = true; @@ -2253,18 +2311,20 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { } TPRN->Affinity = PointerAffinity::Pointer; TPRN->Symbol = S; - } else if (MangledName.startsWith("$E?")) { - MangledName.consumeFront("$E"); + } else if (llvm::itanium_demangle::starts_with(MangledName, "$E?")) { + consumeFront(MangledName, "$E"); // Reference to symbol TP.N = TPRN = Arena.alloc(); TPRN->Symbol = parse(MangledName); TPRN->Affinity = PointerAffinity::Reference; - } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) { + } else if (llvm::itanium_demangle::starts_with(MangledName, "$F") || + llvm::itanium_demangle::starts_with(MangledName, "$G")) { TP.N = TPRN = Arena.alloc(); // Data member pointer. - MangledName = MangledName.dropFront(); - char InheritanceSpecifier = MangledName.popFront(); + MangledName.remove_prefix(1); + char InheritanceSpecifier = MangledName.front(); + MangledName.remove_prefix(1); switch (InheritanceSpecifier) { case 'G': @@ -2282,7 +2342,7 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { } TPRN->IsMemberPointer = true; - } else if (MangledName.consumeFront("$0")) { + } else if (consumeFront(MangledName, "$0")) { // Integral non-type template parameter bool IsNegative = false; uint64_t Value = 0; @@ -2303,8 +2363,9 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { // Template parameter lists cannot be variadic, so it can only be terminated // by @ (as opposed to 'Z' in the function parameter case). - assert(MangledName.startsWith('@')); // The above loop exits only on '@'. - MangledName.consumeFront('@'); + assert(llvm::itanium_demangle::starts_with( + MangledName, '@')); // The above loop exits only on '@'. + consumeFront(MangledName, '@'); return nodeListToNodeArray(Arena, Head, Count); } @@ -2314,16 +2375,14 @@ void Demangler::dumpBackReferences() { // Create an output stream so we can render each type. OutputBuffer OB; - if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024)) - std::terminate(); for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) { OB.setCurrentPosition(0); TypeNode *T = Backrefs.FunctionParams[I]; T->output(OB, OF_Default); - std::printf(" [%d] - %.*s\n", (int)I, (int)OB.getCurrentPosition(), - OB.getBuffer()); + std::string_view B = OB; + std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), &*B.begin()); } std::free(OB.getBuffer()); @@ -2332,22 +2391,20 @@ void Demangler::dumpBackReferences() { std::printf("%d name backreferences\n", (int)Backrefs.NamesCount); for (size_t I = 0; I < Backrefs.NamesCount; ++I) { std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(), - Backrefs.Names[I]->Name.begin()); + &*Backrefs.Names[I]->Name.begin()); } if (Backrefs.NamesCount > 0) std::printf("\n"); } -char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, - char *Buf, size_t *N, +char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled, int *Status, MSDemangleFlags Flags) { Demangler D; - OutputBuffer OB; - StringView Name{MangledName}; + std::string_view Name{MangledName}; SymbolNode *AST = D.parse(Name); if (!D.Error && NMangled) - *NMangled = Name.begin() - MangledName; + *NMangled = Name.empty() ? 0 : &*Name.begin() - &*MangledName.begin(); if (Flags & MSDF_DumpBackrefs) D.dumpBackReferences(); @@ -2365,15 +2422,13 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled, OF = OutputFlags(OF | OF_NoVariableType); int InternalStatus = demangle_success; + char *Buf; if (D.Error) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputBuffer(Buf, N, OB, 1024)) - InternalStatus = demangle_memory_alloc_failure; else { + OutputBuffer OB; AST->output(OB, OF); OB += '\0'; - if (N != nullptr) - *N = OB.getCurrentPosition(); Buf = OB.getBuffer(); } diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp index d07d05a..9a9c34e 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp @@ -119,10 +119,9 @@ static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { std::string Node::toString(OutputFlags Flags) const { OutputBuffer OB; - initializeOutputBuffer(nullptr, nullptr, OB, 1024); this->output(OB, Flags); - OB << '\0'; - std::string Owned(OB.getBuffer()); + std::string_view SV = OB; + std::string Owned(SV.begin(), SV.end()); std::free(OB.getBuffer()); return Owned; } @@ -159,7 +158,7 @@ void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { } void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, - StringView Separator) const { + std::string_view Separator) const { if (Count == 0) return; if (Nodes[0]) diff --git a/third_party/llvm/lib/Demangle/RustDemangle.cpp b/third_party/llvm/lib/Demangle/RustDemangle.cpp index dcac0bd..f0d70de 100644 --- a/third_party/llvm/lib/Demangle/RustDemangle.cpp +++ b/third_party/llvm/lib/Demangle/RustDemangle.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/Demangle.h" -#include "llvm/Demangle/StringView.h" +#include "llvm/Demangle/StringViewExtras.h" #include "llvm/Demangle/Utility.h" #include @@ -20,17 +20,18 @@ #include #include #include +#include using namespace llvm; using llvm::itanium_demangle::OutputBuffer; -using llvm::itanium_demangle::StringView; -using llvm::itanium_demangle::SwapAndRestore; +using llvm::itanium_demangle::ScopedOverride; +using llvm::itanium_demangle::starts_with; namespace { struct Identifier { - StringView Name; + std::string_view Name; bool Punycode; bool empty() const { return Name.empty(); } @@ -77,7 +78,7 @@ class Demangler { size_t RecursionLevel; size_t BoundLifetimes; // Input string that is being demangled with "_R" prefix removed. - StringView Input; + std::string_view Input; // Position in the input string. size_t Position; // When true, print methods append the output to the stream. @@ -92,7 +93,7 @@ class Demangler { Demangler(size_t MaxRecursionLevel = 500); - bool demangle(StringView MangledName); + bool demangle(std::string_view MangledName); private: bool demanglePath(IsInType Type, @@ -119,7 +120,7 @@ class Demangler { if (!Print) return; - SwapAndRestore SavePosition(Position, Position); + ScopedOverride SavePosition(Position, Position); Position = Backref; Demangler(); } @@ -128,10 +129,10 @@ class Demangler { uint64_t parseOptionalBase62Number(char Tag); uint64_t parseBase62Number(); uint64_t parseDecimalNumber(); - uint64_t parseHexNumber(StringView &HexDigits); + uint64_t parseHexNumber(std::string_view &HexDigits); void print(char C); - void print(StringView S); + void print(std::string_view S); void printDecimalNumber(uint64_t N); void printBasicType(BasicType); void printLifetime(uint64_t Index); @@ -147,57 +148,20 @@ class Demangler { } // namespace -char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N, - int *Status) { - if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status != nullptr) - *Status = demangle_invalid_args; - return nullptr; - } - +char *llvm::rustDemangle(std::string_view MangledName) { // Return early if mangled name doesn't look like a Rust symbol. - StringView Mangled(MangledName); - if (!Mangled.startsWith("_R")) { - if (Status != nullptr) - *Status = demangle_invalid_mangled_name; + if (MangledName.empty() || !starts_with(MangledName, "_R")) return nullptr; - } Demangler D; - if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024)) { - if (Status != nullptr) - *Status = demangle_memory_alloc_failure; - return nullptr; - } - - if (!D.demangle(Mangled)) { - if (Status != nullptr) - *Status = demangle_invalid_mangled_name; + if (!D.demangle(MangledName)) { std::free(D.Output.getBuffer()); return nullptr; } D.Output += '\0'; - char *Demangled = D.Output.getBuffer(); - size_t DemangledLen = D.Output.getCurrentPosition(); - - if (Buf != nullptr) { - if (DemangledLen <= *N) { - std::memcpy(Buf, Demangled, DemangledLen); - std::free(Demangled); - Demangled = Buf; - } else { - std::free(Buf); - } - } - - if (N != nullptr) - *N = DemangledLen; - - if (Status != nullptr) - *Status = demangle_success; - return Demangled; + return D.Output.getBuffer(); } Demangler::Demangler(size_t MaxRecursionLevel) @@ -223,34 +187,34 @@ static inline bool isValid(const char C) { // responsibility of the caller to free the memory behind the output stream. // // = "_R" [] -bool Demangler::demangle(StringView Mangled) { +bool Demangler::demangle(std::string_view Mangled) { Position = 0; Error = false; Print = true; RecursionLevel = 0; BoundLifetimes = 0; - if (!Mangled.consumeFront("_R")) { + if (!starts_with(Mangled, "_R")) { Error = true; return false; } + Mangled.remove_prefix(2); size_t Dot = Mangled.find('.'); - Input = Mangled.substr(0, Dot); - StringView Suffix = Mangled.dropFront(Dot); + Input = Dot == std::string_view::npos ? Mangled : Mangled.substr(0, Dot); demanglePath(IsInType::No); if (Position != Input.size()) { - SwapAndRestore SavePrint(Print, false); + ScopedOverride SavePrint(Print, false); demanglePath(IsInType::No); } if (Position != Input.size()) Error = true; - if (!Suffix.empty()) { + if (Dot != std::string_view::npos) { print(" ("); - print(Suffix); + print(Mangled.substr(Dot)); print(")"); } @@ -279,7 +243,7 @@ bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { Error = true; return false; } - SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); switch (consume()) { case 'C': { @@ -380,7 +344,7 @@ bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { // = [] // = "s" void Demangler::demangleImplPath(IsInType InType) { - SwapAndRestore SavePrint(Print, false); + ScopedOverride SavePrint(Print, false); parseOptionalBase62Number('s'); demanglePath(InType); } @@ -574,7 +538,7 @@ void Demangler::demangleType() { Error = true; return; } - SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); size_t Start = Position; char C = consume(); @@ -657,7 +621,7 @@ void Demangler::demangleType() { // = "C" // | void Demangler::demangleFnSig() { - SwapAndRestore SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + ScopedOverride SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); demangleOptionalBinder(); if (consumeIf('U')) @@ -699,7 +663,7 @@ void Demangler::demangleFnSig() { // = [] {} "E" void Demangler::demangleDynBounds() { - SwapAndRestore SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); + ScopedOverride SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); print("dyn "); demangleOptionalBinder(); for (size_t I = 0; !Error && !consumeIf('E'); ++I) { @@ -763,7 +727,7 @@ void Demangler::demangleConst() { Error = true; return; } - SwapAndRestore SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); + ScopedOverride SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); char C = consume(); BasicType Type; @@ -808,7 +772,7 @@ void Demangler::demangleConstInt() { if (consumeIf('n')) print('-'); - StringView HexDigits; + std::string_view HexDigits; uint64_t Value = parseHexNumber(HexDigits); if (HexDigits.size() <= 16) { printDecimalNumber(Value); @@ -821,7 +785,7 @@ void Demangler::demangleConstInt() { // = "0_" // false // | "1_" // true void Demangler::demangleConstBool() { - StringView HexDigits; + std::string_view HexDigits; parseHexNumber(HexDigits); if (HexDigits == "0") print("false"); @@ -838,7 +802,7 @@ static bool isAsciiPrintable(uint64_t CodePoint) { // = void Demangler::demangleConstChar() { - StringView HexDigits; + std::string_view HexDigits; uint64_t CodePoint = parseHexNumber(HexDigits); if (Error || HexDigits.size() > 6) { Error = true; @@ -892,7 +856,7 @@ Identifier Demangler::parseIdentifier() { Error = true; return {}; } - StringView S = Input.substr(Position, Bytes); + std::string_view S = Input.substr(Position, Bytes); Position += Bytes; if (!std::all_of(S.begin(), S.end(), isValid)) { @@ -1000,7 +964,7 @@ uint64_t Demangler::parseDecimalNumber() { // // = "0_" // | <1-9a-f> {<0-9a-f>} "_" -uint64_t Demangler::parseHexNumber(StringView &HexDigits) { +uint64_t Demangler::parseHexNumber(std::string_view &HexDigits) { size_t Start = Position; uint64_t Value = 0; @@ -1024,7 +988,7 @@ uint64_t Demangler::parseHexNumber(StringView &HexDigits) { } if (Error) { - HexDigits = StringView(); + HexDigits = std::string_view(); return 0; } @@ -1041,7 +1005,7 @@ void Demangler::print(char C) { Output += C; } -void Demangler::print(StringView S) { +void Demangler::print(std::string_view S) { if (Error || !Print) return; @@ -1138,17 +1102,17 @@ static inline bool encodeUTF8(size_t CodePoint, char *Output) { // Decodes string encoded using punycode and appends results to Output. // Returns true if decoding was successful. -static bool decodePunycode(StringView Input, OutputBuffer &Output) { +static bool decodePunycode(std::string_view Input, OutputBuffer &Output) { size_t OutputSize = Output.getCurrentPosition(); size_t InputIdx = 0; // Rust uses an underscore as a delimiter. - size_t DelimiterPos = StringView::npos; + size_t DelimiterPos = std::string_view::npos; for (size_t I = 0; I != Input.size(); ++I) if (Input[I] == '_') DelimiterPos = I; - if (DelimiterPos != StringView::npos) { + if (DelimiterPos != std::string_view::npos) { // Copy basic code points before the last delimiter to the output. for (; InputIdx != DelimiterPos; ++InputIdx) { char C = Input[InputIdx]; @@ -1156,7 +1120,7 @@ static bool decodePunycode(StringView Input, OutputBuffer &Output) { return false; // Code points are padded with zeros while decoding is in progress. char UTF8[4] = {C}; - Output += StringView(UTF8, UTF8 + 4); + Output += std::string_view(UTF8, 4); } // Skip over the delimiter. ++InputIdx; From d6fd58e3e75fb519054ddf47f4a7216baa3679eb Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jul 2023 10:30:53 -0400 Subject: [PATCH 25/42] simplify a bit now that upstream takes string_view \o/ --- demumble.cc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/demumble.cc b/demumble.cc index a8f5cc9..3874573 100644 --- a/demumble.cc +++ b/demumble.cc @@ -22,18 +22,19 @@ static int print_help(FILE* out) { return out == stdout ? 0 : 1; } -static void print_demangled(const char* format, const char* s, size_t* n_used) { +static void print_demangled(const char* format, std::string_view s, + size_t* n_used) { if (char* itanium = llvm::itaniumDemangle(s)) { - printf(format, itanium, s); + printf(format, itanium, (int)s.size(), s.data()); free(itanium); } else if (char* rust = llvm::rustDemangle(s)) { - printf(format, rust, s); + printf(format, rust, (int)s.size(), s.data()); free(rust); } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL)) { - printf(format, ms, s); + printf(format, ms, (int)s.size(), s.data()); free(ms); } else { - printf("%s", s); + printf("%.*s", (int)s.size(), s.data()); } } @@ -84,7 +85,7 @@ int main(int argc, char* argv[]) { } else if (argv[1][0] == '-' && argv[1][1] != '-') { for (size_t i = 1; i < strlen(argv[1]); ++i) switch (argv[1][i]) { - case 'b': print_format = "\"%s\" (%s)"; break; + case 'b': print_format = "\"%s\" (%.*s)"; break; case 'h': return print_help(stdout); case 'm': print_mode = kPrintMatching; break; case 'u': setbuf(stdout, NULL); break; @@ -102,7 +103,7 @@ int main(int argc, char* argv[]) { } for (int i = 1; i < argc; ++i) { size_t used = strlen(argv[i]); - print_demangled(print_format, argv[i], &used); + print_demangled(print_format, { argv[i], used }, &used); printf("\n"); if (used < strlen(argv[i])) printf(" unused suffix: %s\n", argv[i] + used); @@ -145,12 +146,9 @@ int main(int argc, char* argv[]) { continue; } - char tmp = cur[n_sym]; - cur[n_sym] = '\0'; size_t n_used = n_sym; - print_demangled(print_format, cur, &n_used); + print_demangled(print_format, { cur, n_sym }, &n_used); need_separator = true; - cur[n_sym] = tmp; cur += n_used; } From 6a3f5533f9c71786214e109358eb6a01ec409142 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jul 2023 10:34:47 -0400 Subject: [PATCH 26/42] add a .gitignore file ignores the directories and zip files created by dist.py, and vim swap files. --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2762c56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.*.sw? + +buildlinux/ +buildmac/ +buildwin/ + +demumble-linux.zip +demumble-mac.zip +demumble-win.zip From 766d2f866233684eebf5039f4e049f04bd8ca0de Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jul 2023 10:38:05 -0400 Subject: [PATCH 27/42] gitignore outputs of a normal build --- .gitignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2762c56..765e2bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,18 @@ .*.sw? +# dist.py outputs: buildlinux/ buildmac/ buildwin/ - demumble-linux.zip demumble-mac.zip demumble-win.zip + +# build outputs when building as described in README.md: +.ninja_deps +.ninja_log +CMakeCache.txt +CMakeFiles/ +build.ninja +cmake_install.cmake +demumble From b6d584c63ed9da4bbe7c7b14636a13718ecd49d1 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jul 2023 11:02:08 -0400 Subject: [PATCH 28/42] add a downstream workaround for llvm/llvm-project#63740 See the upstream issue for some discussion. This lands the minimal fix. Upstream will hopefully have a nicer fix soon :) This allows re-enabling tests and makes trunk work again. --- demumble_test.py | 11 ++++------- third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/demumble_test.py b/demumble_test.py index e72582a..c7d6242 100755 --- a/demumble_test.py +++ b/demumble_test.py @@ -1,9 +1,6 @@ #!/usr/bin/env python3 import os, re, subprocess, sys -# FIXME: Re-enable disabled tests once -# https://github.com/llvm/llvm-project/issues/63740 is fixed. -# Don't make a release until then. tests = [ ('demumble hello', 'hello\n'), ('demumble _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'), @@ -12,9 +9,9 @@ 'std::mem::align_of::\nmylib::foo::bar\n'), ('demumble < _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar', 'std::mem::align_of::\nmylib::foo::bar\n'), - #('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), - #('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), - #('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), + ('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'), + ('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'), + ('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'), ('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for macOS) ('demumble < __Znwi', 'operator new(int)\n'), # Also from stdin ('demumble -m hi _Z1fv ho _Z1gv', 'hi\nf()\nho\ng()\n'), @@ -45,7 +42,7 @@ ('demumble -bx < bar', re.compile(".*unrecognized option `x' in `-bx'.*")), ('demumble < _ZZ3fooiENK3$_0clEi', 'foo(int)::$_0::operator()(int) const\n'), - #('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"), + ('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"), ('demumble < asdf?x@@3HAjkl', 'asdfint xjkl\n'), ('demumble < asdf?x@@3Hjkl', 'asdf?x@@3Hjkl\n'), ('demumble ?x@@3HAjkl', 'int x\n unused suffix: jkl\n'), diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index b38b8a1..8ec9900 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -2404,7 +2404,7 @@ char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled, std::string_view Name{MangledName}; SymbolNode *AST = D.parse(Name); if (!D.Error && NMangled) - *NMangled = Name.empty() ? 0 : &*Name.begin() - &*MangledName.begin(); + *NMangled = Name.empty() ? MangledName.size() : &*Name.begin() - &*MangledName.begin(); if (Flags & MSDF_DumpBackrefs) D.dumpBackReferences(); From 4e2d63c805acd02fa3d24e84be03ac5342166d2b Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:13:17 -0400 Subject: [PATCH 29/42] Add GitHub actions continuous integration --- .github/workflows/test.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4fbd176 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,36 @@ +name: Build and test + +on: [push, pull_request] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + python-version: [3.11] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: "Install Ubuntu dependencies" + run: | + sudo apt-get update + sudo apt-get install -y gcc-12 g++-12 libstdc++-12-dev ninja-build + + - name: CMake + run: | + cmake -GNinja + + - name: Build + run: | + ninja + + - name: Test + run: | + ./demumble_test.py From 5a25811517d227198fd0d7e2a538589d577de13b Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:18:27 -0400 Subject: [PATCH 30/42] Update LLVM lib/Demangle 0cc19b564dd3a2b7ce51840d6...2dea832ef064bb86 This removes the downstream patch I added in b6d584c63e: https://github.com/llvm/llvm-project/issues/63740 is now fixed upstream. Ran: cp ~/src/llvm-project/llvm/include/llvm/Demangle/*.{h,def} third_party/llvm/include/llvm/Demangle/ cp ~/src/llvm-project/llvm/lib/Demangle/*.cpp third_party/llvm/lib/Demangle/ cp ~/src/llvm-project/llvm/LICENSE.TXT third_party/llvm/LICENSE.txt --- .../llvm/include/llvm/Demangle/ItaniumDemangle.h | 5 ++--- third_party/llvm/lib/Demangle/ItaniumDemangle.cpp | 3 ++- third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h index 68db8c6..550e169 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -2336,7 +2336,7 @@ template class FloatLiteralImpl : public Node { Float value; char buf[sizeof(Float)]; }; - const char *t = &*Contents.begin(); + const char *t = Contents.data(); const char *last = t + N; char *e = buf; for (; t != last; ++t, ++e) { @@ -3714,8 +3714,7 @@ Node *AbstractManglingParser::parseQualifiedType() { std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len); std::string_view Proto; { - ScopedOverride SaveFirst(First, - &*ProtoSourceName.begin()), + ScopedOverride SaveFirst(First, ProtoSourceName.data()), SaveLast(Last, &*ProtoSourceName.rbegin() + 1); Proto = parseBareSourceName(); } diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp index f2ce6eb..e3f208f 100644 --- a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -79,7 +80,7 @@ struct DumpVisitor { void printStr(const char *S) { fprintf(stderr, "%s", S); } void print(std::string_view SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin()); + fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data()); } void print(const Node *N) { if (N) diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index 8ec9900..cd7ff40 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -268,7 +268,7 @@ std::string_view Demangler::copyString(std::string_view Borrowed) { // This is not a micro-optimization, it avoids UB, should Borrowed be an null // buffer. if (Borrowed.size()) - std::memcpy(Stable, &*Borrowed.begin(), Borrowed.size()); + std::memcpy(Stable, Borrowed.data(), Borrowed.size()); return {Stable, Borrowed.size()}; } @@ -792,7 +792,7 @@ SymbolNode *Demangler::demangleMD5Name(std::string_view &MangledName) { Error = true; return nullptr; } - const char *Start = &*MangledName.begin(); + const char *Start = MangledName.data(); const size_t StartSize = MangledName.size(); MangledName.remove_prefix(MD5Last + 1); @@ -2382,7 +2382,7 @@ void Demangler::dumpBackReferences() { T->output(OB, OF_Default); std::string_view B = OB; - std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), &*B.begin()); + std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.data()); } std::free(OB.getBuffer()); @@ -2391,7 +2391,7 @@ void Demangler::dumpBackReferences() { std::printf("%d name backreferences\n", (int)Backrefs.NamesCount); for (size_t I = 0; I < Backrefs.NamesCount; ++I) { std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(), - &*Backrefs.Names[I]->Name.begin()); + Backrefs.Names[I]->Name.data()); } if (Backrefs.NamesCount > 0) std::printf("\n"); @@ -2404,7 +2404,7 @@ char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled, std::string_view Name{MangledName}; SymbolNode *AST = D.parse(Name); if (!D.Error && NMangled) - *NMangled = Name.empty() ? MangledName.size() : &*Name.begin() - &*MangledName.begin(); + *NMangled = MangledName.size() - Name.size(); if (Flags & MSDF_DumpBackrefs) D.dumpBackReferences(); From 0d38a72035d70a69072844ba2a16321415c3015f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:27:34 -0400 Subject: [PATCH 31/42] github actions: don't explicitly install gcc 12 Per https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md#language-and-runtime gcc-12 is already part of the image. Thanks to @ADKaster for pointing this out! --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4fbd176..0280f8a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: - name: "Install Ubuntu dependencies" run: | sudo apt-get update - sudo apt-get install -y gcc-12 g++-12 libstdc++-12-dev ninja-build + sudo apt-get install -y ninja-build - name: CMake run: | From 5735ad80925ac24269e6250ca6e0a6b153a8d3fb Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:34:03 -0400 Subject: [PATCH 32/42] github actions: Explicitly pass `.` to cmake Trying to fix: CMake Warning: No source or binary directory provided. Both will be assumed to be the same as the current working directory, but note that this warning will become a fatal error in future CMake releases. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0280f8a..332b9da 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: - name: CMake run: | - cmake -GNinja + cmake -GNinja . - name: Build run: | From aa8f849673bf209e72f325effc3fdf79648d2d13 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:37:41 -0400 Subject: [PATCH 33/42] require cmake 3.5+ Trying to fix: CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required): Compatibility with CMake < 3.5 will be removed from a future version of CMake. Update the VERSION argument value or use a ... suffix to tell CMake that the project does not need compatibility with older versions. 3.5 is from Dec 2018, so requiring this hopefully doesn't cause too many inconveniences. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1891592..6684703 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) project(demumble CXX) if (UNIX) From 4fb4904196d1e91e17854b92684855a4f8869a4a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 19:41:40 -0400 Subject: [PATCH 34/42] README.md: Use same cmake command as on github actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba795c5..e6dc4e0 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Optionally print both mangled and demangled names: ## Build instructions -Use cmake to build: `cmake -G Ninja && ninja` +Use cmake to build: `cmake -G Ninja . && ninja` Run tests after building: `python demumble_test.py` From 43392a920d6b39c09c1776206b7ecbe9fa3e78aa Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 20:04:19 -0400 Subject: [PATCH 35/42] github actions: Use setup-ninja instead of apt for installing ninja This will work on other host OSs. Also, `apt-get update`, while cool, takes pretty long to run. (On the downside, this misprints "Received" in the log, and upstream seems to have stopped acception PRs, ah well.) --- .github/workflows/test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 332b9da..77e62ba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,10 +18,8 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: "Install Ubuntu dependencies" - run: | - sudo apt-get update - sudo apt-get install -y ninja-build + - name: Set up Ninja + uses: ashutoshvarma/setup-ninja@v1.1 - name: CMake run: | From 50b22a66634f14c3222baa55b2dc817431ca0ab0 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 20:06:49 -0400 Subject: [PATCH 36/42] github actions: Also run on macOS --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 77e62ba..f436d10 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - os: [ubuntu-latest] + os: [macos-latest, ubuntu-latest] python-version: [3.11] steps: From 04eeab24d7e14264ba58143ca8e9f70e5a80406e Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 20:13:27 -0400 Subject: [PATCH 37/42] github actions: Also run on Windows ...using MSVC's cl.exe. The CMakeLists.txt doesn't support gcc on Windows. --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f436d10..7018445 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - os: [macos-latest, ubuntu-latest] + os: [macos-latest, ubuntu-latest, windows-latest] python-version: [3.11] steps: @@ -21,6 +21,8 @@ jobs: - name: Set up Ninja uses: ashutoshvarma/setup-ninja@v1.1 + - uses: ilammy/msvc-dev-cmd@v1.12.1 + - name: CMake run: | cmake -GNinja . From b31d5ea22353a1f3f292be0ab8d6c37da3cfa88d Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 21:16:35 -0400 Subject: [PATCH 38/42] cmake: Try to fix cl.exe warnings on CI --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6684703..0343801 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,17 @@ if (UNIX) endif() if (WIN32) + # https://gitlab.kitware.com/cmake/cmake/-/issues/20610 + string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + add_definitions(-D_HAS_EXCEPTIONS=0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline /EHs-c- /GR-") add_definitions(-D_CRT_SECURE_NO_WARNINGS) # The LLVM build sets this. + # Disable cl.exe warnings that LLVM disables as well. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4267") + # This is apparently the simplest way to statically link the CRT in CMake: string(TOUPPER "${CMAKE_BUILD_TYPE}" build) set(flag_var "CMAKE_CXX_FLAGS_${build}") From 0931036329408ff3342b0545ce289e629a4141c3 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 31 Jul 2023 21:23:19 -0400 Subject: [PATCH 39/42] github actions: Actually run tests on Windows Verified it works now by pushing a commit that adds print('os name:', os.name, sys.version) if os.name == 'nt': tests += [('demumble _Z4funcPci _Z1fv', 'fnc(char*, int)\nf()\n')] to demumble_test.py on a test branch and checking that CI now fails on Windows, while it didn't before. Also, the 'passed' output now shows up. (Just `python` instead of `python3` also runs Python 3.11 on all the github action images demumble currently uses, and normally python is called just `python` on Windows, not `python3`. But `python3` seems to work on GitHub actions, so let's be explicit about it.) --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7018445..8c43bbc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,4 +33,4 @@ jobs: - name: Test run: | - ./demumble_test.py + python3 demumble_test.py From 2512dd71544b2670ee28fc022550f922cb98735d Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 2 Aug 2023 09:27:05 -0400 Subject: [PATCH 40/42] make readme a bit less awkward Now it no longer says "demangles both" followed by three things. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e6dc4e0..4470d5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # demumble -`demumble` demangles both Itanium, Rust, and Visual Studio symbols. It runs on +`demumble` demangles both Itanium and Visual Studio symbols. It runs on both POSIX and Windows. $ demumble _Z4funcPci @@ -8,6 +8,8 @@ both POSIX and Windows. $ demumble '?Fx_i@@YAHP6AHH@Z@Z' int __cdecl Fx_i(int (__cdecl *)(int)) +It can also demangle Rust and D symbols. + ## Download There are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the From 9c2d3589ed4caf187a3108a992da19edabda4741 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 2 Aug 2023 09:37:42 -0400 Subject: [PATCH 41/42] github actions: Use container's default python version --- .github/workflows/test.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c43bbc..9c0d4a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,15 +9,10 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - python-version: [3.11] steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Set up Ninja uses: ashutoshvarma/setup-ninja@v1.1 From 3ade67e442ff0d8b4e58a1fc872224812351a4b0 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 7 Aug 2023 14:04:12 -0400 Subject: [PATCH 42/42] mark this 1.2.3.git --- demumble.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demumble.cc b/demumble.cc index 3874573..8b60ed2 100644 --- a/demumble.cc +++ b/demumble.cc @@ -6,7 +6,7 @@ #include "llvm/Demangle/Demangle.h" -const char kDemumbleVersion[] = "1.2.2.git"; +const char kDemumbleVersion[] = "1.2.3.git"; static int print_help(FILE* out) { fprintf(out,