v1.2.3
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..9c0d4a5
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,31 @@
+name: Build and test
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ matrix:
+ os: [macos-latest, ubuntu-latest, windows-latest]
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Ninja
+ uses: ashutoshvarma/setup-ninja@v1.1
+
+ - uses: ilammy/msvc-dev-cmd@v1.12.1
+
+ - name: CMake
+ run: |
+ cmake -GNinja .
+
+ - name: Build
+ run: |
+ ninja
+
+ - name: Test
+ run: |
+ python3 demumble_test.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..765e2bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +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
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd35e5b..0343801 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)
@@ -19,9 +19,17 @@
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}")
@@ -33,9 +41,12 @@
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/DLangDemangle.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 11
+set_target_properties(demumble PROPERTIES CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)
diff --git a/README.md b/README.md
index 4e1af91..4470d5f 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,15 @@
# demumble
-`demumble` demangles both Itanium and Visual Studio symbols. It runs on both
-POSIX and Windows.
+`demumble` demangles both Itanium 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))
-
+
+It can also demangle Rust and D symbols.
+
## Download
There are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the
@@ -19,9 +21,9 @@
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:
@@ -75,7 +77,7 @@
## 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`
diff --git a/RELEASING b/RELEASING
index d799f1b..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
-2. update demumble.cc with new version (with ".git"), then
+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
-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)
+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
- # 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)
+ ./dist.py # on the 'release' branch
+ # 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
diff --git a/demumble.cc b/demumble.cc
index d5d2f1d..5fdcaa3 100644
--- a/demumble.cc
+++ b/demumble.cc
@@ -6,7 +6,7 @@
#include "llvm/Demangle/Demangle.h"
-const char kDemumbleVersion[] = "1.2.2";
+const char kDemumbleVersion[] = "1.2.3";
static int print_help(FILE* out) {
fprintf(out,
@@ -22,15 +22,19 @@
return out == stdout ? 0 : 1;
}
-static void print_demangled(const char* format, const char* s) {
- if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) {
- printf(format, itanium, s);
+static void print_demangled(const char* format, std::string_view s,
+ size_t* n_used) {
+ if (char* itanium = llvm::itaniumDemangle(s)) {
+ printf(format, itanium, (int)s.size(), s.data());
free(itanium);
- } else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL)) {
- printf(format, ms, s);
+ } else if (char* rust = llvm::rustDemangle(s)) {
+ printf(format, rust, (int)s.size(), s.data());
+ free(rust);
+ } else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL)) {
+ printf(format, ms, (int)s.size(), s.data());
free(ms);
} else {
- printf("%s", s);
+ printf("%.*s", (int)s.size(), s.data());
}
}
@@ -39,6 +43,12 @@
(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 +63,11 @@
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;
@@ -68,9 +83,9 @@
++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 'b': print_format = "\"%s\" (%.*s)"; break;
case 'h': return print_help(stdout);
case 'm': print_mode = kPrintMatching; break;
case 'u': setbuf(stdout, NULL); break;
@@ -87,8 +102,11 @@
++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 }, &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
@@ -118,6 +136,9 @@
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("_");
@@ -125,13 +146,11 @@
continue;
}
- 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_sym }, &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..c7d6242 100755
--- a/demumble_test.py
+++ b/demumble_test.py
@@ -1,15 +1,18 @@
-#!/usr/bin/env python
-from __future__ import print_function
+#!/usr/bin/env python3
import os, re, subprocess, sys
tests = [
('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::<f64>\nmylib::foo::bar\n'),
+ ('demumble < _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar',
+ 'std::mem::align_of::<f64>\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 __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'),
@@ -40,6 +43,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
@@ -50,12 +56,12 @@
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("`%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")
+print('passed' if status == 0 else 'failed')
sys.exit(status)
diff --git a/dist.py b/dist.py
index b1be851..b842bf8 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
@@ -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.
@@ -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']
@@ -58,57 +60,67 @@
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'
-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'
+ print('building linux')
subprocess.check_call(call_cmake + [
'-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'])
- 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')
+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 + [
+ print('building mac')
+ 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_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', '..'])
# Win.
win_sysroot = glob.glob(
crsrc + '/third_party/depot_tools/win_toolchain/vs_files/*')[0]
-win_bindir = win_sysroot + '/win_sdk/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']]
-cflags = ['--target=x86_64-pc-windows'] + win_include
+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.
+# 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),
- # 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)
@@ -117,9 +129,11 @@
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)'
-subprocess.check_call(['cp', 'buildmac/demumble', '.'])
+# 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(f'rm -f demumble && cp build{platform}/demumble .',
+ shell=True)
subprocess.check_call(['./demumble_test.py'])
# Show zip files.
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,54 +14,211 @@
#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 <new>
#endif
+#include <stddef.h>
+
+#if defined(_MSC_VER)
+#include <sal.h>
#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
-#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))
+// 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_GNUC_PREREQ(maj, min, patch) 0
+# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
#endif
#endif
+/// \macro LLVM_GNUC_PREREQ
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// available.
+#ifndef LLVM_GNUC_PREREQ
+# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
+ ((maj) << 20) + ((min) << 10) + (patch))
+# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+# else
+# define LLVM_GNUC_PREREQ(maj, min, patch) 0
+# endif
+#endif
+
+/// \macro LLVM_MSC_PREREQ
+/// Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1910: VS2017, version 15.1 & 15.2
+/// * 1911: VS2017, version 15.3 & 15.4
+/// * 1912: VS2017, version 15.5
+/// * 1913: VS2017, version 15.6
+/// * 1914: VS2017, version 15.7
+/// * 1915: VS2017, version 15.8
+/// * 1916: VS2017, version 15.9
+/// * 1920: VS2019, version 16.0
+/// * 1921: VS2019, version 16.1
+#ifdef _MSC_VER
+#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
+
+// We require at least MSVC 2017.
+#if !LLVM_MSC_PREREQ(1910)
+#error LLVM requires at least MSVC 2017.
+#endif
+
+#else
+#define LLVM_MSC_PREREQ(version) 0
+#endif
+
+/// Does the compiler support ref-qualifiers for *this?
+///
+/// Sadly, this is separate from just rvalue reference support because GCC
+/// and MSVC implemented this later than everything else. This appears to be
+/// corrected in MSVC 2019 but not MSVC 2017.
+#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \
+ LLVM_MSC_PREREQ(1920)
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
+#else
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
+#endif
+
+/// Expands to '&' if ref-qualifiers for *this are supported.
+///
+/// This can be used to provide lvalue/rvalue overrides of member functions.
+/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+#define LLVM_LVALUE_FUNCTION &
+#else
+#define LLVM_LVALUE_FUNCTION
+#endif
+
+/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
+/// into a shared library, then the class should be private to the library and
+/// not accessible from outside it. Can also be used to mark variables and
+/// functions, making them private to any shared library they are linked into.
+/// On PE/COFF targets, library visibility is the default, so this isn't needed.
+///
+/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
+/// this attribute will be made public and visible outside of any shared library
+/// they are linked in to.
+#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
+ !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
+#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
+#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default")))
+#else
+#define LLVM_LIBRARY_VISIBILITY
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+
+#if defined(__GNUC__)
+#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
+#else
+#define LLVM_PREFETCH(addr, rw, locality)
+#endif
+
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
#else
#define LLVM_ATTRIBUTE_USED
#endif
-#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
+/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
+/// so, mark a method "always inline" because it is performance sensitive. GCC
+/// 3.4 supported this but is buggy in various cases and produces unimplemented
+/// errors, just use it in GCC 4.0 and later.
+#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
+#endif
+
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define LLVM_ATTRIBUTE_NORETURN
+#endif
+
+#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
+/// pointer that does not alias any other valid pointer.
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#endif
+
+/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
+#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif __has_attribute(fallthrough)
+#define LLVM_FALLTHROUGH __attribute__((fallthrough))
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+
+/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
+/// they are constant initialized.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
+ [[clang::require_constant_initialization]]
+#else
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+
+/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
+/// lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
+#define LLVM_GSL_OWNER [[gsl::Owner]]
+#else
+#define LLVM_GSL_OWNER
+#endif
+
+/// LLVM_GSL_POINTER - Apply this to non-owning classes like
+/// StringRef to enable lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
+#define LLVM_GSL_POINTER [[gsl::Pointer]]
+#else
+#define LLVM_GSL_POINTER
+#endif
+
+/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
+/// pedantic diagnostics.
+#ifdef __GNUC__
+#define LLVM_EXTENSION __extension__
+#else
+#define LLVM_EXTENSION
+#endif
+
+// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
+// This macro will be removed.
+// Use C++14's attribute instead: [[deprecated("message")]]
+#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
+
+/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
+/// to an expression which states that it is undefined behavior for the
+/// compiler to reach this point. Otherwise is not defined.
+#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
+# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+# define LLVM_BUILTIN_UNREACHABLE __assume(false)
+#endif
+
+/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
+/// which causes the program to exit abnormally.
+#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
+# define LLVM_BUILTIN_TRAP __builtin_trap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC, does not require forward
+// declarations involving platform-specific typedefs (unlike RaiseException),
+// results in a call to vectored exception handlers, and encodes to a short
+// instruction that still causes the trapping behavior we want.
+# define LLVM_BUILTIN_TRAP __debugbreak()
+#else
+# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
+#endif
+
+/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
+/// an expression which causes the program to break while running
+/// under a debugger.
+#if __has_builtin(__builtin_debugtrap)
+# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC and breaks while
+// running under the debugger, and also supports invoking a debugger
+// when the OS is configured appropriately.
+# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
+#else
+// Just continue execution when built with compilers that have no
+// support. This is a debugging aid and not intended to force the
+// program to abort if encountered.
+# define LLVM_BUILTIN_DEBUGTRAP
+#endif
+
+/// \macro LLVM_ASSUME_ALIGNED
+/// Returns a pointer with an assumed alignment.
+#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
+# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+# define LLVM_ASSUME_ALIGNED(p, a) \
+ (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
+#else
+# define LLVM_ASSUME_ALIGNED(p, a) (p)
+#endif
+
+/// \macro LLVM_PACKED
+/// Used to specify a packed structure.
+/// LLVM_PACKED(
+/// struct A {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// });
+///
+/// LLVM_PACKED_START
+/// struct B {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// };
+/// LLVM_PACKED_END
+#ifdef _MSC_VER
+# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
+# define LLVM_PACKED_START __pragma(pack(push, 1))
+# define LLVM_PACKED_END __pragma(pack(pop))
+#else
+# define LLVM_PACKED(d) d __attribute__((packed))
+# define LLVM_PACKED_START _Pragma("pack(push, 1)")
+# define LLVM_PACKED_END _Pragma("pack(pop)")
+#endif
+
+/// \macro LLVM_PTR_SIZE
+/// A constant integer equivalent to the value of sizeof(void*).
+/// Generally used in combination with alignas or when doing computation in the
+/// preprocessor.
+#ifdef __SIZEOF_POINTER__
+# define LLVM_PTR_SIZE __SIZEOF_POINTER__
+#elif defined(_WIN64)
+# define LLVM_PTR_SIZE 8
+#elif defined(_WIN32)
+# define LLVM_PTR_SIZE 4
+#elif defined(_MSC_VER)
+# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
+#else
+# define LLVM_PTR_SIZE sizeof(void *)
+#endif
+
+/// \macro LLVM_MEMORY_SANITIZER_BUILD
+/// Whether LLVM itself is built with MemorySanitizer instrumentation.
+#if __has_feature(memory_sanitizer)
+# define LLVM_MEMORY_SANITIZER_BUILD 1
+# include <sanitizer/msan_interface.h>
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
+#else
+# define LLVM_MEMORY_SANITIZER_BUILD 0
+# define __msan_allocated_memory(p, size)
+# define __msan_unpoison(p, size)
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
+#endif
+
+/// \macro LLVM_ADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define LLVM_ADDRESS_SANITIZER_BUILD 1
+# include <sanitizer/asan_interface.h>
+#else
+# define LLVM_ADDRESS_SANITIZER_BUILD 0
+# define __asan_poison_memory_region(p, size)
+# define __asan_unpoison_memory_region(p, size)
+#endif
+
+/// \macro LLVM_THREAD_SANITIZER_BUILD
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
+#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define LLVM_THREAD_SANITIZER_BUILD 1
+#else
+# define LLVM_THREAD_SANITIZER_BUILD 0
+#endif
+
+#if LLVM_THREAD_SANITIZER_BUILD
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
+void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+#ifdef __cplusplus
+}
+#endif
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else
+# define TsanHappensBefore(cv)
+# define TsanHappensAfter(cv)
+# define TsanIgnoreWritesBegin()
+# define TsanIgnoreWritesEnd()
+#endif
+
+/// \macro LLVM_NO_SANITIZE
+/// Disable a particular sanitizer for a function.
+#if __has_attribute(no_sanitize)
+#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
+#else
+#define LLVM_NO_SANITIZE(KIND)
+#endif
+
+/// Mark debug helper function definitions like dump() that should not be
+/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
+// FIXME: Move this to a private config.h as it's not usable in public headers.
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
#else
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
#endif
-#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
-#define LLVM_FALLTHROUGH [[fallthrough]]
-#elif __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)
-#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+/// \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_FALLTHROUGH
+#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 7b85b9a..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 <cstddef>
#include <string>
+#include <string_view>
namespace llvm {
/// This is a llvm local version of __cxa_demangle. Other than the name and
@@ -28,9 +29,10 @@
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,
@@ -39,16 +41,33 @@
MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
+ MSDF_NoVariableType = 1 << 5,
};
-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.
+/// status receives one of the demangle_ enum entries above if it's not nullptr.
+/// Flags controls various details of the demangled representation.
+char *microsoftDemangle(std::string_view mangled_name, size_t *n_read,
int *status, MSDemangleFlags Flags = MSDF_None);
+// Demangles a Rust v0 mangled symbol.
+char *rustDemangle(std::string_view MangledName);
+
+// Demangles a D mangled symbol.
+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(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
@@ -65,7 +84,7 @@
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
@@ -101,6 +120,7 @@
bool isSpecialName() const;
~ItaniumPartialDemangler();
+
private:
void *RootNode;
void *Context;
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..550e169 100644
--- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1,149 +1,225 @@
-//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===//
-//
+//===--- ItaniumDemangle.h -----------*- mode:c++;eval:(read-only-mode) -*-===//
+// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// Generic itanium demangler library. This file has two byte-per-byte identical
-// copies in the source tree, one in libcxxabi, and the other in llvm.
+// Generic itanium demangler library.
+// There are two copies of this file in the source tree. The one under
+// libcxxabi is the original and the one under llvm is the copy. Use
+// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_ITANIUMDEMANGLE_H
#define DEMANGLE_ITANIUMDEMANGLE_H
-// FIXME: (possibly) incomplete list of features that clang mangles that this
-// file does not yet support:
-// - C++ modules TS
-
#include "DemangleConfig.h"
-#include "StringView.h"
+#include "StringViewExtras.h"
#include "Utility.h"
+#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <numeric>
+#include <limits>
+#include <new>
+#include <string_view>
+#include <type_traits>
#include <utility>
-#define FOR_EACH_NODE_KIND(X) \
- X(NodeArrayNode) \
- X(DotSuffix) \
- X(VendorExtQualType) \
- X(QualType) \
- X(ConversionOperatorType) \
- X(PostfixQualifiedType) \
- X(ElaboratedTypeSpefType) \
- X(NameType) \
- X(AbiTagAttr) \
- X(EnableIfAttr) \
- X(ObjCProtoName) \
- X(PointerType) \
- X(ReferenceType) \
- X(PointerToMemberType) \
- X(ArrayType) \
- X(FunctionType) \
- X(NoexceptSpec) \
- X(DynamicExceptionSpec) \
- X(FunctionEncoding) \
- X(LiteralOperator) \
- X(SpecialName) \
- X(CtorVtableSpecialName) \
- X(QualifiedName) \
- X(NestedName) \
- X(LocalName) \
- X(VectorType) \
- X(PixelVectorType) \
- X(SyntheticTemplateParamName) \
- X(TypeTemplateParamDecl) \
- X(NonTypeTemplateParamDecl) \
- X(TemplateTemplateParamDecl) \
- X(TemplateParamPackDecl) \
- X(ParameterPack) \
- X(TemplateArgumentPack) \
- X(ParameterPackExpansion) \
- X(TemplateArgs) \
- X(ForwardTemplateReference) \
- X(NameWithTemplateArgs) \
- X(GlobalQualifiedName) \
- X(StdQualifiedName) \
- X(ExpandedSpecialSubstitution) \
- X(SpecialSubstitution) \
- X(CtorDtorName) \
- X(DtorName) \
- X(UnnamedTypeName) \
- X(ClosureTypeName) \
- X(StructuredBindingName) \
- X(BinaryExpr) \
- X(ArraySubscriptExpr) \
- X(PostfixExpr) \
- X(ConditionalExpr) \
- X(MemberExpr) \
- X(EnclosingExpr) \
- X(CastExpr) \
- X(SizeofParamPackExpr) \
- X(CallExpr) \
- X(NewExpr) \
- X(DeleteExpr) \
- X(PrefixExpr) \
- X(FunctionParam) \
- X(ConversionExpr) \
- X(InitListExpr) \
- X(FoldExpr) \
- X(ThrowExpr) \
- X(UUIDOfExpr) \
- X(BoolExpr) \
- X(StringLiteral) \
- X(LambdaExpr) \
- X(EnumLiteral) \
- X(IntegerLiteral) \
- X(FloatLiteral) \
- X(DoubleLiteral) \
- X(LongDoubleLiteral) \
- X(BracedExpr) \
- X(BracedRangeExpr)
-
DEMANGLE_NAMESPACE_BEGIN
+template <class T, size_t N> class PODSmallVector {
+ static_assert(std::is_pod<T>::value,
+ "T is required to be a plain old data type");
+
+ T *First = nullptr;
+ T *Last = nullptr;
+ T *Cap = nullptr;
+ T Inline[N] = {0};
+
+ bool isInline() const { return First == Inline; }
+
+ void clearInline() {
+ First = Inline;
+ Last = Inline;
+ Cap = Inline + N;
+ }
+
+ void reserve(size_t NewCap) {
+ size_t S = size();
+ if (isInline()) {
+ auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T)));
+ if (Tmp == nullptr)
+ std::terminate();
+ std::copy(First, Last, Tmp);
+ First = Tmp;
+ } else {
+ First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T)));
+ if (First == nullptr)
+ std::terminate();
+ }
+ Last = First + S;
+ Cap = First + NewCap;
+ }
+
+public:
+ PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
+
+ PODSmallVector(const PODSmallVector &) = delete;
+ PODSmallVector &operator=(const PODSmallVector &) = delete;
+
+ PODSmallVector(PODSmallVector &&Other) : PODSmallVector() {
+ if (Other.isInline()) {
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return;
+ }
+
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ }
+
+ PODSmallVector &operator=(PODSmallVector &&Other) {
+ if (Other.isInline()) {
+ if (!isInline()) {
+ std::free(First);
+ clearInline();
+ }
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return *this;
+ }
+
+ if (isInline()) {
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ return *this;
+ }
+
+ std::swap(First, Other.First);
+ std::swap(Last, Other.Last);
+ std::swap(Cap, Other.Cap);
+ Other.clear();
+ return *this;
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void push_back(const T &Elem) {
+ if (Last == Cap)
+ reserve(size() * 2);
+ *Last++ = Elem;
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void pop_back() {
+ assert(Last != First && "Popping empty vector!");
+ --Last;
+ }
+
+ void dropBack(size_t Index) {
+ assert(Index <= size() && "dropBack() can't expand!");
+ Last = First + Index;
+ }
+
+ T *begin() { return First; }
+ T *end() { return Last; }
+
+ bool empty() const { return First == Last; }
+ size_t size() const { return static_cast<size_t>(Last - First); }
+ T &back() {
+ assert(Last != First && "Calling back() on empty vector!");
+ return *(Last - 1);
+ }
+ T &operator[](size_t Index) {
+ assert(Index < size() && "Invalid access!");
+ return *(begin() + Index);
+ }
+ void clear() { Last = First; }
+
+ ~PODSmallVector() {
+ if (!isInline())
+ std::free(First);
+ }
+};
+
// Base class of all AST nodes. The AST is built by the parser, then is
// traversed by the printLeft/Right functions to produce a demangled string.
class Node {
public:
enum Kind : unsigned char {
-#define 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<typename Fn> void visit(Fn F) const;
@@ -154,52 +230,65 @@
// would construct an equivalent node.
//template<typename Fn> void match(Fn F) const;
- bool hasRHSComponent(OutputStream &S) const {
+ bool hasRHSComponent(OutputBuffer &OB) const {
if (RHSComponentCache != Cache::Unknown)
return RHSComponentCache == Cache::Yes;
- return hasRHSComponentSlow(S);
+ return hasRHSComponentSlow(OB);
}
- bool hasArray(OutputStream &S) const {
+ bool hasArray(OutputBuffer &OB) const {
if (ArrayCache != Cache::Unknown)
return ArrayCache == Cache::Yes;
- return hasArraySlow(S);
+ return hasArraySlow(OB);
}
- bool hasFunction(OutputStream &S) const {
+ bool hasFunction(OutputBuffer &OB) const {
if (FunctionCache != Cache::Unknown)
return FunctionCache == Cache::Yes;
- return hasFunctionSlow(S);
+ return hasFunctionSlow(OB);
}
Kind getKind() const { return K; }
- virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
- virtual bool hasArraySlow(OutputStream &) const { return false; }
- virtual bool hasFunctionSlow(OutputStream &) const { return false; }
+ Prec getPrecedence() const { return Precedence; }
+
+ virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; }
+ virtual bool hasArraySlow(OutputBuffer &) const { return false; }
+ virtual bool hasFunctionSlow(OutputBuffer &) const { return false; }
// Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
// get at a node that actually represents some concrete syntax.
- virtual const Node *getSyntaxNode(OutputStream &) const {
- return this;
+ virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; }
+
+ // Print this node as an expression operand, surrounding it in parentheses if
+ // its precedence is [Strictly] weaker than P.
+ void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default,
+ bool StrictlyWorse = false) const {
+ bool Paren =
+ unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse);
+ if (Paren)
+ OB.printOpen();
+ print(OB);
+ if (Paren)
+ OB.printClose();
}
- void print(OutputStream &S) const {
- printLeft(S);
+ void print(OutputBuffer &OB) const {
+ printLeft(OB);
if (RHSComponentCache != Cache::No)
- printRight(S);
+ printRight(OB);
}
- // Print the "left" side of this Node into OutputStream.
- virtual void printLeft(OutputStream &) const = 0;
+ // Print the "left" side of this Node into OutputBuffer.
+ virtual void printLeft(OutputBuffer &) const = 0;
// Print the "right". This distinction is necessary to represent C++ types
// that appear on the RHS of their subtype, such as arrays or functions.
// Since most types don't have such a component, provide a default
// implementation.
- virtual void printRight(OutputStream &) const {}
+ virtual void printRight(OutputBuffer &) const {}
- virtual StringView getBaseName() const { return StringView(); }
+ virtual std::string_view getBaseName() const { return {}; }
// Silence compiler warnings, this dtor will never be called.
virtual ~Node() = default;
@@ -226,19 +315,19 @@
Node *operator[](size_t Idx) const { return Elements[Idx]; }
- void printWithComma(OutputStream &S) const {
+ void printWithComma(OutputBuffer &OB) const {
bool FirstElement = true;
for (size_t Idx = 0; Idx != NumElements; ++Idx) {
- size_t BeforeComma = S.getCurrentPosition();
+ size_t BeforeComma = OB.getCurrentPosition();
if (!FirstElement)
- S += ", ";
- size_t AfterComma = S.getCurrentPosition();
- Elements[Idx]->print(S);
+ OB += ", ";
+ size_t AfterComma = OB.getCurrentPosition();
+ Elements[Idx]->printAsOperand(OB, Node::Prec::Comma);
// Elements[Idx] is an empty parameter pack expansion, we should erase the
// comma we just printed.
- if (AfterComma == S.getCurrentPosition()) {
- S.setCurrentPosition(BeforeComma);
+ if (AfterComma == OB.getCurrentPosition()) {
+ OB.setCurrentPosition(BeforeComma);
continue;
}
@@ -253,43 +342,48 @@
template<typename Fn> 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 {
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<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }
- void printLeft(OutputStream &s) const override {
- Prefix->print(s);
- s += " (";
- s += Suffix;
- s += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ Prefix->print(OB);
+ OB += " (";
+ OB += Suffix;
+ OB += ")";
}
};
class VendorExtQualType final : public Node {
const Node *Ty;
- StringView Ext;
+ std::string_view Ext;
+ const Node *TA;
public:
- VendorExtQualType(const Node *Ty_, StringView Ext_)
- : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}
+ VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_)
+ : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {}
- template<typename Fn> void match(Fn F) const { F(Ty, Ext); }
+ const Node *getTy() const { return Ty; }
+ std::string_view getExt() const { return Ext; }
+ const Node *getTA() const { return TA; }
- void printLeft(OutputStream &S) const override {
- Ty->print(S);
- S += " ";
- S += Ext;
+ template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Ty->print(OB);
+ OB += " ";
+ OB += Ext;
+ if (TA != nullptr)
+ TA->print(OB);
}
};
@@ -315,13 +409,13 @@
const Qualifiers Quals;
const Node *Child;
- void printQuals(OutputStream &S) const {
+ void printQuals(OutputBuffer &OB) const {
if (Quals & QualConst)
- S += " const";
+ OB += " const";
if (Quals & QualVolatile)
- S += " volatile";
+ OB += " volatile";
if (Quals & QualRestrict)
- S += " restrict";
+ OB += " restrict";
}
public:
@@ -330,24 +424,27 @@
Child_->ArrayCache, Child_->FunctionCache),
Quals(Quals_), Child(Child_) {}
+ Qualifiers getQuals() const { return Quals; }
+ const Node *getChild() const { return Child; }
+
template<typename Fn> void match(Fn F) const { F(Child, Quals); }
- bool hasRHSComponentSlow(OutputStream &S) const override {
- return Child->hasRHSComponent(S);
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
+ return Child->hasRHSComponent(OB);
}
- bool hasArraySlow(OutputStream &S) const override {
- return Child->hasArray(S);
+ bool hasArraySlow(OutputBuffer &OB) const override {
+ return Child->hasArray(OB);
}
- bool hasFunctionSlow(OutputStream &S) const override {
- return Child->hasFunction(S);
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
+ return Child->hasFunction(OB);
}
- void printLeft(OutputStream &S) const override {
- Child->printLeft(S);
- printQuals(S);
+ void printLeft(OutputBuffer &OB) const override {
+ Child->printLeft(OB);
+ printQuals(OB);
}
- void printRight(OutputStream &S) const override { Child->printRight(S); }
+ void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
};
class ConversionOperatorType final : public Node {
@@ -359,74 +456,96 @@
template<typename Fn> 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);
}
};
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<typename Fn> 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;
}
};
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<typename Fn> 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(OutputStream &s) const override { s += Name; }
+ void printLeft(OutputBuffer &OB) const override { OB += Name; }
+};
+
+class BitIntType final : public Node {
+ const Node *Size;
+ bool Signed;
+
+public:
+ BitIntType(const Node *Size_, bool Signed_)
+ : Node(KBitIntType), Size(Size_), Signed(Signed_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Size, Signed); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (!Signed)
+ OB += "unsigned ";
+ OB += "_BitInt";
+ OB.printOpen();
+ Size->printAsOperand(OB);
+ OB.printClose();
+ }
};
class ElaboratedTypeSpefType : public Node {
- StringView Kind;
+ 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<typename Fn> 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);
}
};
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<typename Fn> void match(Fn F) const { F(Base, Tag); }
- void printLeft(OutputStream &S) const override {
- Base->printLeft(S);
- S += "[abi:";
- S += Tag;
- S += "]";
+ std::string_view getBaseName() const override { return Base->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Base->printLeft(OB);
+ OB += "[abi:";
+ OB += Tag;
+ OB += "]";
}
};
@@ -438,21 +557,21 @@
template<typename Fn> 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 += ']';
}
};
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<typename Fn> void match(Fn F) const { F(Ty, Protocol); }
@@ -462,11 +581,11 @@
static_cast<const NameType *>(Ty)->getName() == "objc_object";
}
- void printLeft(OutputStream &S) const override {
- Ty->print(S);
- S += "<";
- S += Protocol;
- S += ">";
+ void printLeft(OutputBuffer &OB) const override {
+ Ty->print(OB);
+ OB += "<";
+ OB += Protocol;
+ OB += ">";
}
};
@@ -478,36 +597,38 @@
: Node(KPointerType, Pointee_->RHSComponentCache),
Pointee(Pointee_) {}
+ const Node *getPointee() const { return Pointee; }
+
template<typename Fn> 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<SomeProtocol>* into id<SomeProtocol>.
if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
- Pointee->printLeft(s);
- if (Pointee->hasArray(s))
- s += " ";
- if (Pointee->hasArray(s) || Pointee->hasFunction(s))
- s += "(";
- s += "*";
+ Pointee->printLeft(OB);
+ if (Pointee->hasArray(OB))
+ OB += " ";
+ if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
+ OB += "(";
+ OB += "*";
} else {
const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
- 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<const ObjCProtoName *>(Pointee)->isObjCObject()) {
- if (Pointee->hasArray(s) || Pointee->hasFunction(s))
- s += ")";
- Pointee->printRight(s);
+ if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
+ OB += ")";
+ Pointee->printRight(OB);
}
}
};
@@ -527,15 +648,30 @@
// Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
// rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
// other combination collapses to a lvalue ref.
- std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const {
+ //
+ // A combination of a TemplateForwardReference and a back-ref Substitution
+ // from an ill-formed string may have created a cycle; use cycle detection to
+ // avoid looping forever.
+ std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const {
auto SoFar = std::make_pair(RK, Pointee);
+ // Track the chain of nodes for the Floyd's 'tortoise and hare'
+ // cycle-detection algorithm, since getSyntaxNode(S) is impure
+ PODSmallVector<const Node *, 8> Prev;
for (;;) {
- const Node *SN = SoFar.second->getSyntaxNode(S);
+ const Node *SN = SoFar.second->getSyntaxNode(OB);
if (SN->getKind() != KReferenceType)
break;
auto *RT = static_cast<const ReferenceType *>(SN);
SoFar.second = RT->Pointee;
SoFar.first = std::min(SoFar.first, RT->RK);
+
+ // The middle of Prev is the 'slow' pointer moving at half speed
+ Prev.push_back(SoFar.second);
+ if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) {
+ // Cycle detected
+ SoFar.second = nullptr;
+ break;
+ }
}
return SoFar;
}
@@ -547,31 +683,35 @@
template<typename Fn> 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<bool> SavePrinting(Printing, true);
- std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
- Collapsed.second->printLeft(s);
- if (Collapsed.second->hasArray(s))
- s += " ";
- if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
- s += "(";
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
+ if (!Collapsed.second)
+ return;
+ Collapsed.second->printLeft(OB);
+ if (Collapsed.second->hasArray(OB))
+ OB += " ";
+ if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
+ OB += "(";
- 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<bool> SavePrinting(Printing, true);
- std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
- if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
- s += ")";
- Collapsed.second->printRight(s);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
+ if (!Collapsed.second)
+ return;
+ if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
+ OB += ")";
+ Collapsed.second->printRight(OB);
}
};
@@ -586,24 +726,24 @@
template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }
- bool hasRHSComponentSlow(OutputStream &S) const override {
- return MemberType->hasRHSComponent(S);
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
+ return MemberType->hasRHSComponent(OB);
}
- void printLeft(OutputStream &s) const override {
- MemberType->printLeft(s);
- if (MemberType->hasArray(s) || MemberType->hasFunction(s))
- s += "(";
+ void printLeft(OutputBuffer &OB) const override {
+ MemberType->printLeft(OB);
+ if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
+ OB += "(";
else
- s += " ";
- ClassType->print(s);
- s += "::*";
+ OB += " ";
+ ClassType->print(OB);
+ OB += "::*";
}
- void printRight(OutputStream &s) const override {
- if (MemberType->hasArray(s) || MemberType->hasFunction(s))
- s += ")";
- MemberType->printRight(s);
+ void printRight(OutputBuffer &OB) const override {
+ if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
+ OB += ")";
+ MemberType->printRight(OB);
}
};
@@ -620,19 +760,19 @@
template<typename Fn> void match(Fn F) const { F(Base, Dimension); }
- bool hasRHSComponentSlow(OutputStream &) const override { return true; }
- bool hasArraySlow(OutputStream &) const override { return true; }
+ bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
+ bool hasArraySlow(OutputBuffer &) const override { return true; }
- void printLeft(OutputStream &S) const override { Base->printLeft(S); }
+ void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
- void printRight(OutputStream &S) const override {
- if (S.back() != ']')
- S += " ";
- S += "[";
+ void printRight(OutputBuffer &OB) const override {
+ if (OB.back() != ']')
+ OB += " ";
+ OB += "[";
if (Dimension)
- Dimension->print(S);
- S += "]";
- Base->printRight(S);
+ Dimension->print(OB);
+ OB += "]";
+ Base->printRight(OB);
}
};
@@ -656,8 +796,8 @@
F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
}
- bool hasRHSComponentSlow(OutputStream &) const override { return true; }
- bool hasFunctionSlow(OutputStream &) const override { return true; }
+ bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
+ bool hasFunctionSlow(OutputBuffer &) const override { return true; }
// Handle C++'s ... quirky decl grammar by using the left & right
// distinction. Consider:
@@ -666,32 +806,32 @@
// that takes a char and returns an int. If we're trying to print f, start
// by printing out the return types's left, then print our parameters, then
// finally print right of the return type.
- void printLeft(OutputStream &S) const override {
- Ret->printLeft(S);
- S += " ";
+ void printLeft(OutputBuffer &OB) const override {
+ Ret->printLeft(OB);
+ OB += " ";
}
- void printRight(OutputStream &S) const override {
- S += "(";
- Params.printWithComma(S);
- S += ")";
- Ret->printRight(S);
+ void printRight(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
+ Ret->printRight(OB);
if (CVQuals & QualConst)
- S += " const";
+ OB += " const";
if (CVQuals & QualVolatile)
- S += " volatile";
+ OB += " volatile";
if (CVQuals & QualRestrict)
- S += " restrict";
+ OB += " restrict";
if (RefQual == FrefQualLValue)
- S += " &";
+ OB += " &";
else if (RefQual == FrefQualRValue)
- S += " &&";
+ OB += " &&";
if (ExceptionSpec != nullptr) {
- S += ' ';
- ExceptionSpec->print(S);
+ OB += ' ';
+ ExceptionSpec->print(OB);
}
}
};
@@ -703,10 +843,11 @@
template<typename Fn> void match(Fn F) const { F(E); }
- void printLeft(OutputStream &S) const override {
- S += "noexcept(";
- E->print(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "noexcept";
+ OB.printOpen();
+ E->printAsOperand(OB);
+ OB.printClose();
}
};
@@ -718,10 +859,11 @@
template<typename Fn> void match(Fn F) const { F(Types); }
- void printLeft(OutputStream &S) const override {
- S += "throw(";
- Types.printWithComma(S);
- S += ')';
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "throw";
+ OB.printOpen();
+ Types.printWithComma(OB);
+ OB.printClose();
}
};
@@ -752,41 +894,41 @@
NodeArray getParams() const { return Params; }
const Node *getReturnType() const { return Ret; }
- bool hasRHSComponentSlow(OutputStream &) const override { return true; }
- bool hasFunctionSlow(OutputStream &) const override { return true; }
+ bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
+ bool hasFunctionSlow(OutputBuffer &) const override { return true; }
const Node *getName() const { return Name; }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (Ret) {
- Ret->printLeft(S);
- if (!Ret->hasRHSComponent(S))
- S += " ";
+ Ret->printLeft(OB);
+ if (!Ret->hasRHSComponent(OB))
+ OB += " ";
}
- Name->print(S);
+ Name->print(OB);
}
- void printRight(OutputStream &S) const override {
- S += "(";
- Params.printWithComma(S);
- S += ")";
+ void printRight(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
if (Ret)
- Ret->printRight(S);
+ Ret->printRight(OB);
if (CVQuals & QualConst)
- S += " const";
+ OB += " const";
if (CVQuals & QualVolatile)
- S += " volatile";
+ OB += " volatile";
if (CVQuals & QualRestrict)
- S += " restrict";
+ OB += " restrict";
if (RefQual == FrefQualLValue)
- S += " &";
+ OB += " &";
else if (RefQual == FrefQualRValue)
- S += " &&";
+ OB += " &&";
if (Attrs != nullptr)
- Attrs->print(S);
+ Attrs->print(OB);
}
};
@@ -799,25 +941,25 @@
template<typename Fn> 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);
}
};
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<typename Fn> void match(Fn F) const { F(Special, Child); }
- void printLeft(OutputStream &S) const override {
- S += Special;
- Child->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ OB += Special;
+ Child->print(OB);
}
};
@@ -832,11 +974,11 @@
template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }
- void printLeft(OutputStream &S) const override {
- S += "construction vtable for ";
- FirstType->print(S);
- S += "-in-";
- SecondType->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "construction vtable for ";
+ FirstType->print(OB);
+ OB += "-in-";
+ SecondType->print(OB);
}
};
@@ -849,12 +991,52 @@
template<typename Fn> 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(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 <typename Fn> void match(Fn F) const {
+ F(Parent, Name, IsPartition);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Parent)
+ Parent->print(OB);
+ if (Parent || IsPartition)
+ OB += IsPartition ? ':' : '.';
+ Name->print(OB);
+ }
+};
+
+struct ModuleEntity : Node {
+ ModuleName *Module;
+ Node *Name;
+
+ ModuleEntity(ModuleName *Module_, Node *Name_)
+ : Node(KModuleEntity), Module(Module_), Name(Name_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Module, Name); }
+
+ std::string_view getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Name->print(OB);
+ OB += '@';
+ Module->print(OB);
}
};
@@ -867,10 +1049,10 @@
template<typename Fn> 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);
}
};
@@ -885,12 +1067,12 @@
template<typename Fn> 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(OutputStream &S) const override {
- Qualifier->print(S);
- S += "::";
- Name->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ Qualifier->print(OB);
+ OB += "::";
+ Name->print(OB);
}
};
@@ -899,18 +1081,20 @@
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<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
- void printLeft(OutputStream &S) const override {
- BaseType->print(S);
- S += " vector[";
+ void printLeft(OutputBuffer &OB) const override {
+ BaseType->print(OB);
+ OB += " vector[";
if (Dimension)
- Dimension->print(S);
- S += "]";
+ Dimension->print(OB);
+ OB += "]";
}
};
@@ -923,11 +1107,26 @@
template<typename Fn> 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<typename Fn> void match(Fn F) const { F(Dimension); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "_Float";
+ Dimension->print(OB);
}
};
@@ -949,20 +1148,20 @@
template<typename Fn> void match(Fn F) const { F(Kind, Index); }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
switch (Kind) {
case TemplateParamKind::Type:
- S += "$T";
+ OB += "$T";
break;
case TemplateParamKind::NonType:
- S += "$N";
+ OB += "$N";
break;
case TemplateParamKind::Template:
- S += "$TT";
+ OB += "$TT";
break;
}
if (Index > 0)
- S << Index - 1;
+ OB << Index - 1;
}
};
@@ -976,13 +1175,9 @@
template<typename Fn> void match(Fn F) const { F(Name); }
- void printLeft(OutputStream &S) const override {
- S += "typename ";
- }
+ void printLeft(OutputBuffer &OB) const override { OB += "typename "; }
- void printRight(OutputStream &S) const override {
- Name->print(S);
- }
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
};
/// A non-type template parameter declaration, 'int N'.
@@ -996,15 +1191,15 @@
template<typename Fn> void match(Fn F) const { F(Name, Type); }
- void printLeft(OutputStream &S) const override {
- Type->printLeft(S);
- if (!Type->hasRHSComponent(S))
- S += " ";
+ void printLeft(OutputBuffer &OB) const override {
+ Type->printLeft(OB);
+ if (!Type->hasRHSComponent(OB))
+ OB += " ";
}
- void printRight(OutputStream &S) const override {
- Name->print(S);
- Type->printRight(S);
+ void printRight(OutputBuffer &OB) const override {
+ Name->print(OB);
+ Type->printRight(OB);
}
};
@@ -1021,15 +1216,14 @@
template<typename Fn> void match(Fn F) const { F(Name, Params); }
- void printLeft(OutputStream &S) const override {
- S += "template<";
- Params.printWithComma(S);
- S += "> typename ";
+ void printLeft(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "template<";
+ Params.printWithComma(OB);
+ OB += "> typename ";
}
- void printRight(OutputStream &S) const override {
- Name->print(S);
- }
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
};
/// A template parameter pack declaration, 'typename ...T'.
@@ -1042,14 +1236,12 @@
template<typename Fn> void match(Fn F) const { F(Param); }
- void printLeft(OutputStream &S) const override {
- Param->printLeft(S);
- S += "...";
+ void printLeft(OutputBuffer &OB) const override {
+ Param->printLeft(OB);
+ OB += "...";
}
- void printRight(OutputStream &S) const override {
- Param->printRight(S);
- }
+ void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
};
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1063,11 +1255,12 @@
class ParameterPack final : public Node {
NodeArray Data;
- // Setup OutputStream for a pack expansion unless we're already expanding one.
- void initializePackExpansion(OutputStream &S) const {
- if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
- S.CurrentPackMax = static_cast<unsigned>(Data.size());
- S.CurrentPackIndex = 0;
+ // Setup OutputBuffer for a pack expansion, unless we're already expanding
+ // one.
+ void initializePackExpansion(OutputBuffer &OB) const {
+ if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
+ OB.CurrentPackMax = static_cast<unsigned>(Data.size());
+ OB.CurrentPackIndex = 0;
}
}
@@ -1090,38 +1283,38 @@
template<typename Fn> void match(Fn F) const { F(Data); }
- bool hasRHSComponentSlow(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
- return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB);
}
- bool hasArraySlow(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
- return Idx < Data.size() && Data[Idx]->hasArray(S);
+ bool hasArraySlow(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasArray(OB);
}
- bool hasFunctionSlow(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
- return Idx < Data.size() && Data[Idx]->hasFunction(S);
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasFunction(OB);
}
- const Node *getSyntaxNode(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
- return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
+ const Node *getSyntaxNode(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
+ return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this;
}
- void printLeft(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
+ void printLeft(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printLeft(S);
+ Data[Idx]->printLeft(OB);
}
- void printRight(OutputStream &S) const override {
- initializePackExpansion(S);
- size_t Idx = S.CurrentPackIndex;
+ void printRight(OutputBuffer &OB) const override {
+ initializePackExpansion(OB);
+ size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printRight(S);
+ Data[Idx]->printRight(OB);
}
};
@@ -1140,8 +1333,8 @@
NodeArray getElements() const { return Elements; }
- void printLeft(OutputStream &S) const override {
- Elements.printWithComma(S);
+ void printLeft(OutputBuffer &OB) const override {
+ Elements.printWithComma(OB);
}
};
@@ -1158,35 +1351,35 @@
const Node *getChild() const { return Child; }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
constexpr unsigned Max = std::numeric_limits<unsigned>::max();
- SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);
- SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);
- size_t StreamPos = S.getCurrentPosition();
+ ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
+ ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max);
+ size_t StreamPos = OB.getCurrentPosition();
// Print the first element in the pack. If Child contains a ParameterPack,
// it will set up S.CurrentPackMax and print the first element.
- Child->print(S);
+ Child->print(OB);
// No ParameterPack was found in Child. This can occur if we've found a pack
// expansion on a <function-param>.
- if (S.CurrentPackMax == Max) {
- S += "...";
+ if (OB.CurrentPackMax == Max) {
+ OB += "...";
return;
}
// We found a ParameterPack, but it has no elements. Erase whatever we may
// of printed.
- if (S.CurrentPackMax == 0) {
- S.setCurrentPosition(StreamPos);
+ if (OB.CurrentPackMax == 0) {
+ OB.setCurrentPosition(StreamPos);
return;
}
// Else, iterate through the rest of the elements in the pack.
- for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
- S += ", ";
- S.CurrentPackIndex = I;
- Child->print(S);
+ for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) {
+ OB += ", ";
+ OB.CurrentPackIndex = I;
+ Child->print(OB);
}
}
};
@@ -1201,12 +1394,11 @@
NodeArray getParams() { return Params; }
- void printLeft(OutputStream &S) const override {
- S += "<";
- Params.printWithComma(S);
- if (S.back() == '>')
- S += " ";
- S += ">";
+ void printLeft(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ Params.printWithComma(OB);
+ OB += ">";
}
};
@@ -1248,42 +1440,42 @@
// special handling.
template<typename Fn> void match(Fn F) const = delete;
- bool hasRHSComponentSlow(OutputStream &S) const override {
+ bool hasRHSComponentSlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- return Ref->hasRHSComponent(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasRHSComponent(OB);
}
- bool hasArraySlow(OutputStream &S) const override {
+ bool hasArraySlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- return Ref->hasArray(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasArray(OB);
}
- bool hasFunctionSlow(OutputStream &S) const override {
+ bool hasFunctionSlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- return Ref->hasFunction(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->hasFunction(OB);
}
- const Node *getSyntaxNode(OutputStream &S) const override {
+ const Node *getSyntaxNode(OutputBuffer &OB) const override {
if (Printing)
return this;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- return Ref->getSyntaxNode(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ return Ref->getSyntaxNode(OB);
}
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- Ref->printLeft(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ Ref->printLeft(OB);
}
- void printRight(OutputStream &S) const override {
+ void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
- Ref->printRight(S);
+ ScopedOverride<bool> SavePrinting(Printing, true);
+ Ref->printRight(OB);
}
};
@@ -1297,11 +1489,11 @@
template<typename Fn> 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(OutputStream &S) const override {
- Name->print(S);
- TemplateArgs->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ Name->print(OB);
+ TemplateArgs->print(OB);
}
};
@@ -1314,26 +1506,11 @@
template<typename Fn> 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(OutputStream &S) const override {
- S += "::";
- Child->print(S);
- }
-};
-
-struct StdQualifiedName : Node {
- Node *Child;
-
- StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
-
- template<typename Fn> void match(Fn F) const { F(Child); }
-
- StringView getBaseName() const override { return Child->getBaseName(); }
-
- void printLeft(OutputStream &S) const override {
- S += "std::";
- Child->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "::";
+ Child->print(OB);
}
};
@@ -1346,109 +1523,81 @@
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<typename Fn> 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;
}
- void printLeft(OutputStream &S) const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- S += "std::allocator";
- break;
- case SpecialSubKind::basic_string:
- S += "std::basic_string";
- break;
- case SpecialSubKind::string:
- S += "std::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >";
- break;
- case SpecialSubKind::istream:
- S += "std::basic_istream<char, std::char_traits<char> >";
- break;
- case SpecialSubKind::ostream:
- S += "std::basic_ostream<char, std::char_traits<char> >";
- break;
- case SpecialSubKind::iostream:
- S += "std::basic_iostream<char, std::char_traits<char> >";
- break;
+private:
+ void printLeft(OutputBuffer &OB) const override {
+ OB << "std::" << getBaseName();
+ if (isInstantiation()) {
+ OB << "<char, std::char_traits<char>";
+ if (SSK == SpecialSubKind::string)
+ OB << ", std::allocator<char>";
+ OB << ">";
}
}
};
-class SpecialSubstitution final : public Node {
+class SpecialSubstitution final : public ExpandedSpecialSubstitution {
public:
- SpecialSubKind SSK;
-
SpecialSubstitution(SpecialSubKind SSK_)
- : Node(KSpecialSubstitution), SSK(SSK_) {}
+ : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {}
template<typename Fn> void match(Fn F) const { F(SSK); }
- StringView getBaseName() const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- return StringView("allocator");
- case SpecialSubKind::basic_string:
- return StringView("basic_string");
- case SpecialSubKind::string:
- return StringView("string");
- case SpecialSubKind::istream:
- return StringView("istream");
- case SpecialSubKind::ostream:
- return StringView("ostream");
- case SpecialSubKind::iostream:
- return StringView("iostream");
+ 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(OutputStream &S) const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- S += "std::allocator";
- break;
- case SpecialSubKind::basic_string:
- S += "std::basic_string";
- break;
- case SpecialSubKind::string:
- S += "std::string";
- break;
- case SpecialSubKind::istream:
- S += "std::istream";
- break;
- case SpecialSubKind::ostream:
- S += "std::ostream";
- break;
- case SpecialSubKind::iostream:
- S += "std::iostream";
- break;
- }
+ void printLeft(OutputBuffer &OB) const override {
+ OB << "std::" << getBaseName();
}
};
+inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution(
+ SpecialSubstitution const *SS)
+ : ExpandedSpecialSubstitution(SS->SSK) {}
+
class CtorDtorName final : public Node {
const Node *Basename;
const bool IsDtor;
@@ -1461,10 +1610,10 @@
template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (IsDtor)
- S += "~";
- S += Basename->getBaseName();
+ OB += "~";
+ OB += Basename->getBaseName();
}
};
@@ -1476,35 +1625,36 @@
template<typename Fn> 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);
}
};
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<typename Fn> 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 += "\'";
}
};
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_) {}
@@ -1512,22 +1662,23 @@
F(TemplateParams, Params, Count);
}
- void printDeclarator(OutputStream &S) const {
+ void printDeclarator(OutputBuffer &OB) const {
if (!TemplateParams.empty()) {
- S += "<";
- TemplateParams.printWithComma(S);
- S += ">";
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ TemplateParams.printWithComma(OB);
+ OB += ">";
}
- S += "(";
- Params.printWithComma(S);
- S += ")";
+ OB.printOpen();
+ Params.printWithComma(OB);
+ OB.printClose();
}
- void printLeft(OutputStream &S) const override {
- S += "\'lambda";
- S += Count;
- S += "\'";
- printDeclarator(S);
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "\'lambda";
+ OB += Count;
+ OB += "\'";
+ printDeclarator(OB);
}
};
@@ -1539,10 +1690,10 @@
template<typename Fn> void match(Fn F) const { F(Bindings); }
- void printLeft(OutputStream &S) const override {
- S += '[';
- Bindings.printWithComma(S);
- S += ']';
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen('[');
+ Bindings.printWithComma(OB);
+ OB.printClose(']');
}
};
@@ -1550,32 +1701,35 @@
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 <typename Fn> void match(Fn F) const {
+ F(LHS, InfixOperator, RHS, getPrecedence());
}
- template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }
-
- void printLeft(OutputStream &S) const override {
- // might be a template argument expression, then we need to disambiguate
- // with parens.
- if (InfixOperator == ">")
- S += "(";
-
- S += "(";
- LHS->print(S);
- S += ") ";
- S += InfixOperator;
- S += " (";
- RHS->print(S);
- S += ")";
-
- if (InfixOperator == ">")
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ bool ParenAll = OB.isGtInsideTemplateArgs() &&
+ (InfixOperator == ">" || InfixOperator == ">>");
+ if (ParenAll)
+ OB.printOpen();
+ // Assignment is right associative, with special LHS precedence.
+ bool IsAssign = getPrecedence() == Prec::Assign;
+ LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign);
+ // No space before comma operator
+ if (!(InfixOperator == ","))
+ OB += " ";
+ OB += InfixOperator;
+ OB += " ";
+ RHS->printAsOperand(OB, getPrecedence(), IsAssign);
+ if (ParenAll)
+ OB.printClose();
}
};
@@ -1584,35 +1738,36 @@
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<typename Fn> void match(Fn F) const { F(Op1, Op2); }
+ template <typename Fn> void match(Fn F) const {
+ F(Op1, Op2, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += "(";
- Op1->print(S);
- S += ")[";
- Op2->print(S);
- S += "]";
+ void printLeft(OutputBuffer &OB) const override {
+ Op1->printAsOperand(OB, getPrecedence());
+ OB.printOpen('[');
+ Op2->printAsOperand(OB);
+ OB.printClose(']');
}
};
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<typename Fn> void match(Fn F) const { F(Child, Operator); }
+ template <typename Fn> void match(Fn F) const {
+ F(Child, Operator, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += "(";
- Child->print(S);
- S += ")";
- S += Operator;
+ void printLeft(OutputBuffer &OB) const override {
+ Child->printAsOperand(OB, getPrecedence(), true);
+ OB += Operator;
}
};
@@ -1622,78 +1777,128 @@
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<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }
+ template <typename Fn> void match(Fn F) const {
+ F(Cond, Then, Else, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += "(";
- Cond->print(S);
- S += ") ? (";
- Then->print(S);
- S += ") : (";
- Else->print(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ Cond->printAsOperand(OB, getPrecedence());
+ OB += " ? ";
+ Then->printAsOperand(OB);
+ OB += " : ";
+ Else->printAsOperand(OB, Prec::Assign, true);
}
};
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<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }
+ template <typename Fn> void match(Fn F) const {
+ F(LHS, Kind, RHS, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- LHS->print(S);
- S += Kind;
- RHS->print(S);
+ void printLeft(OutputBuffer &OB) const override {
+ LHS->printAsOperand(OB, getPrecedence(), true);
+ OB += Kind;
+ RHS->printAsOperand(OB, getPrecedence(), false);
+ }
+};
+
+class SubobjectExpr : public Node {
+ const Node *Type;
+ const Node *SubExpr;
+ std::string_view Offset;
+ NodeArray UnionSelectors;
+ bool OnePastTheEnd;
+
+public:
+ 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_) {}
+
+ template<typename Fn> void match(Fn F) const {
+ F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ SubExpr->print(OB);
+ OB += ".<";
+ Type->print(OB);
+ OB += " at offset ";
+ if (Offset.empty()) {
+ OB += "0";
+ } else if (Offset[0] == 'n') {
+ OB += "-";
+ OB += std::string_view(Offset.data() + 1, Offset.size() - 1);
+ } else {
+ OB += Offset;
+ }
+ OB += ">";
}
};
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<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Infix, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += Prefix;
- Infix->print(S);
- S += Postfix;
+ void printLeft(OutputBuffer &OB) const override {
+ OB += Prefix;
+ OB.printOpen();
+ Infix->print(OB);
+ OB.printClose();
+ OB += Postfix;
}
};
class CastExpr : public Node {
// cast_kind<to>(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<typename Fn> void match(Fn F) const { F(CastKind, To, From); }
+ template <typename Fn> void match(Fn F) const {
+ F(CastKind, To, From, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += CastKind;
- S += "<";
- To->printLeft(S);
- S += ">(";
- From->printLeft(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += CastKind;
+ {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ To->printLeft(OB);
+ OB += ">";
+ }
+ OB.printOpen();
+ From->printAsOperand(OB);
+ OB.printClose();
}
};
@@ -1706,11 +1911,12 @@
template<typename Fn> void match(Fn F) const { F(Pack); }
- void printLeft(OutputStream &S) const override {
- S += "sizeof...(";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "sizeof...";
+ OB.printOpen();
ParameterPackExpansion PPE(Pack);
- PPE.printLeft(S);
- S += ")";
+ PPE.printLeft(OB);
+ OB.printClose();
}
};
@@ -1719,16 +1925,18 @@
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<typename Fn> void match(Fn F) const { F(Callee, Args); }
+ template <typename Fn> void match(Fn F) const {
+ F(Callee, Args, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- Callee->print(S);
- S += "(";
- Args.printWithComma(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ Callee->print(OB);
+ OB.printOpen();
+ Args.printWithComma(OB);
+ OB.printClose();
}
};
@@ -1741,33 +1949,32 @@
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<typename Fn> void match(Fn F) const {
- F(ExprList, Type, InitList, IsGlobal, IsArray);
+ F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence());
}
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (IsGlobal)
- S += "::operator ";
- S += "new";
+ OB += "::";
+ OB += "new";
if (IsArray)
- S += "[]";
- S += ' ';
+ OB += "[]";
if (!ExprList.empty()) {
- S += "(";
- ExprList.printWithComma(S);
- S += ")";
+ OB.printOpen();
+ ExprList.printWithComma(OB);
+ OB.printClose();
}
- Type->print(S);
+ OB += " ";
+ Type->print(OB);
if (!InitList.empty()) {
- S += "(";
- InitList.printWithComma(S);
- S += ")";
+ OB.printOpen();
+ InitList.printWithComma(OB);
+ OB.printClose();
}
-
}
};
@@ -1777,50 +1984,55 @@
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<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }
+ template <typename Fn> void match(Fn F) const {
+ F(Op, IsGlobal, IsArray, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (IsGlobal)
- S += "::";
- S += "delete";
+ OB += "::";
+ OB += "delete";
if (IsArray)
- S += "[] ";
- Op->print(S);
+ OB += "[]";
+ OB += ' ';
+ Op->print(OB);
}
};
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<typename Fn> void match(Fn F) const { F(Prefix, Child); }
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Child, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += Prefix;
- S += "(";
- Child->print(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += Prefix;
+ Child->printAsOperand(OB, getPrecedence());
}
};
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<typename Fn> void match(Fn F) const { F(Number); }
- void printLeft(OutputStream &S) const override {
- S += "fp";
- S += Number;
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "fp";
+ OB += Number;
}
};
@@ -1829,17 +2041,45 @@
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<typename Fn> void match(Fn F) const { F(Type, Expressions); }
+ template <typename Fn> void match(Fn F) const {
+ F(Type, Expressions, getPrecedence());
+ }
- void printLeft(OutputStream &S) const override {
- S += "(";
- Type->print(S);
- S += ")(";
- Expressions.printWithComma(S);
- S += ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Type->print(OB);
+ OB.printClose();
+ OB.printOpen();
+ Expressions.printWithComma(OB);
+ OB.printClose();
+ }
+};
+
+class PointerToMemberConversionExpr : public Node {
+ const Node *Type;
+ const Node *SubExpr;
+ std::string_view Offset;
+
+public:
+ PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
+ std::string_view Offset_, Prec Prec_)
+ : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_),
+ SubExpr(SubExpr_), Offset(Offset_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Type, SubExpr, Offset, getPrecedence());
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Type->print(OB);
+ OB.printClose();
+ OB.printOpen();
+ SubExpr->print(OB);
+ OB.printClose();
}
};
@@ -1852,12 +2092,12 @@
template<typename Fn> void match(Fn F) const { F(Ty, Inits); }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (Ty)
- Ty->print(S);
- S += '{';
- Inits.printWithComma(S);
- S += '}';
+ Ty->print(OB);
+ OB += '{';
+ Inits.printWithComma(OB);
+ OB += '}';
}
};
@@ -1871,18 +2111,18 @@
template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (IsArray) {
- S += '[';
- Elem->print(S);
- S += ']';
+ OB += '[';
+ Elem->print(OB);
+ OB += ']';
} else {
- S += '.';
- Elem->print(S);
+ OB += '.';
+ Elem->print(OB);
}
if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
- S += " = ";
- Init->print(S);
+ OB += " = ";
+ Init->print(OB);
}
};
@@ -1896,25 +2136,25 @@
template<typename Fn> void match(Fn F) const { F(First, Last, Init); }
- void printLeft(OutputStream &S) const override {
- S += '[';
- First->print(S);
- S += " ... ";
- Last->print(S);
- S += ']';
+ 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);
}
};
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_) {}
@@ -1923,43 +2163,35 @@
F(IsLeftFold, OperatorName, Pack, Init);
}
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
auto PrintPack = [&] {
- S += '(';
- ParameterPackExpansion(Pack).print(S);
- S += ')';
+ OB.printOpen();
+ ParameterPackExpansion(Pack).print(OB);
+ OB.printClose();
};
- S += '(';
-
- if (IsLeftFold) {
- // init op ... op pack
- if (Init != nullptr) {
- Init->print(S);
- S += ' ';
- S += OperatorName;
- S += ' ';
- }
- // ... op pack
- S += "... ";
- S += OperatorName;
- S += ' ';
- PrintPack();
- } else { // !IsLeftFold
- // pack op ...
- PrintPack();
- S += ' ';
- S += OperatorName;
- S += " ...";
- // pack op ... op init
- if (Init != nullptr) {
- S += ' ';
- S += OperatorName;
- S += ' ';
- Init->print(S);
- }
+ OB.printOpen();
+ // Either '[init op ]... op pack' or 'pack op ...[ op init]'
+ // Refactored to '[(init|pack) op ]...[ op (pack|init)]'
+ // Fold expr operands are cast-expressions
+ if (!IsLeftFold || Init != nullptr) {
+ // '(init|pack) op '
+ if (IsLeftFold)
+ Init->printAsOperand(OB, Prec::Cast, true);
+ else
+ PrintPack();
+ OB << " " << OperatorName << " ";
}
- S += ')';
+ OB << "...";
+ if (IsLeftFold || Init != nullptr) {
+ // ' op (init|pack)'
+ OB << " " << OperatorName << " ";
+ if (IsLeftFold)
+ PrintPack();
+ else
+ Init->printAsOperand(OB, Prec::Cast, true);
+ }
+ OB.printClose();
}
};
@@ -1971,24 +2203,9 @@
template<typename Fn> void match(Fn F) const { F(Op); }
- void printLeft(OutputStream &S) const override {
- S += "throw ";
- Op->print(S);
- }
-};
-
-// MSVC __uuidof extension, generated by clang in -fms-extensions mode.
-class UUIDOfExpr : public Node {
- Node *Operand;
-public:
- UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {}
-
- template<typename Fn> void match(Fn F) const { F(Operand); }
-
- void printLeft(OutputStream &S) const override {
- S << "__uuidof(";
- Operand->print(S);
- S << ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "throw ";
+ Op->print(OB);
}
};
@@ -2000,8 +2217,8 @@
template<typename Fn> 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 ? std::string_view("true") : std::string_view("false");
}
};
@@ -2013,10 +2230,10 @@
template<typename Fn> void match(Fn F) const { F(Type); }
- void printLeft(OutputStream &S) const override {
- S += "\"<";
- Type->print(S);
- S += ">\"";
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "\"<";
+ Type->print(OB);
+ OB += ">\"";
}
};
@@ -2028,62 +2245,61 @@
template<typename Fn> 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<const ClosureTypeName *>(Type)->printDeclarator(S);
- S += "{...}";
+ static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB);
+ OB += "{...}";
}
};
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<typename Fn> void match(Fn F) const { F(Ty, Integer); }
- void printLeft(OutputStream &S) const override {
- S << "(";
- Ty->print(S);
- S << ")";
+ void printLeft(OutputBuffer &OB) const override {
+ OB.printOpen();
+ Ty->print(OB);
+ OB.printClose();
if (Integer[0] == 'n')
- S << "-" << Integer.dropFront(1);
+ OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1);
else
- S << Integer;
+ 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<typename Fn> void match(Fn F) const { F(Type, Value); }
- void printLeft(OutputStream &S) const override {
+ void printLeft(OutputBuffer &OB) const override {
if (Type.size() > 3) {
- S += "(";
- S += Type;
- S += ")";
+ OB.printOpen();
+ OB += Type;
+ OB.printClose();
}
- if (Value[0] == 'n') {
- S += "-";
- S += Value.dropFront(1);
- } else
- S += Value;
+ if (Value[0] == 'n')
+ OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1);
+ else
+ OB += Value;
if (Type.size() <= 3)
- S += Type;
+ OB += Type;
}
};
@@ -2102,29 +2318,26 @@
}
template <class Float> 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<typename Fn> void match(Fn F) const { F(Contents); }
- void printLeft(OutputStream &s) const override {
- const char *first = Contents.begin();
- const char *last = Contents.end() + 1;
-
+ void printLeft(OutputBuffer &OB) const override {
const size_t N = FloatData<Float>::mangled_size;
- if (static_cast<std::size_t>(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.data();
+ const char *last = t + N;
char *e = buf;
for (; t != last; ++t, ++e) {
unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
@@ -2139,7 +2352,7 @@
#endif
char num[FloatData<Float>::max_demangled_size] = {0};
int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
- s += StringView(num, num + n);
+ OB += std::string_view(num, n);
}
}
};
@@ -2153,143 +2366,22 @@
template<typename Fn>
void Node::visit(Fn F) const {
switch (K) {
-#define CASE(X) case K ## X: return F(static_cast<const X*>(this));
- FOR_EACH_NODE_KIND(CASE)
-#undef CASE
+#define NODE(X) \
+ case K##X: \
+ return F(static_cast<const X *>(this));
+#include "ItaniumNodes.def"
}
assert(0 && "unknown mangling node kind");
}
/// Determine the kind of a node from its type.
template<typename NodeT> struct NodeKind;
-#define SPECIALIZATION(X) \
- template<> struct NodeKind<X> { \
- static constexpr Node::Kind Kind = Node::K##X; \
- static constexpr const char *name() { return #X; } \
+#define NODE(X) \
+ template <> struct NodeKind<X> { \
+ static constexpr Node::Kind Kind = Node::K##X; \
+ static constexpr const char *name() { return #X; } \
};
-FOR_EACH_NODE_KIND(SPECIALIZATION)
-#undef SPECIALIZATION
-
-#undef FOR_EACH_NODE_KIND
-
-template <class T, size_t N>
-class PODSmallVector {
- static_assert(std::is_pod<T>::value,
- "T is required to be a plain old data type");
-
- T* First = nullptr;
- T* Last = nullptr;
- T* Cap = nullptr;
- T Inline[N] = {0};
-
- bool isInline() const { return First == Inline; }
-
- void clearInline() {
- First = Inline;
- Last = Inline;
- Cap = Inline + N;
- }
-
- void reserve(size_t NewCap) {
- size_t S = size();
- if (isInline()) {
- auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
- if (Tmp == nullptr)
- std::terminate();
- std::copy(First, Last, Tmp);
- First = Tmp;
- } else {
- First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
- if (First == nullptr)
- std::terminate();
- }
- Last = First + S;
- Cap = First + NewCap;
- }
-
-public:
- PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
-
- PODSmallVector(const PODSmallVector&) = delete;
- PODSmallVector& operator=(const PODSmallVector&) = delete;
-
- PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
- if (Other.isInline()) {
- std::copy(Other.begin(), Other.end(), First);
- Last = First + Other.size();
- Other.clear();
- return;
- }
-
- First = Other.First;
- Last = Other.Last;
- Cap = Other.Cap;
- Other.clearInline();
- }
-
- PODSmallVector& operator=(PODSmallVector&& Other) {
- if (Other.isInline()) {
- if (!isInline()) {
- std::free(First);
- clearInline();
- }
- std::copy(Other.begin(), Other.end(), First);
- Last = First + Other.size();
- Other.clear();
- return *this;
- }
-
- if (isInline()) {
- First = Other.First;
- Last = Other.Last;
- Cap = Other.Cap;
- Other.clearInline();
- return *this;
- }
-
- std::swap(First, Other.First);
- std::swap(Last, Other.Last);
- std::swap(Cap, Other.Cap);
- Other.clear();
- return *this;
- }
-
- void push_back(const T& Elem) {
- if (Last == Cap)
- reserve(size() * 2);
- *Last++ = Elem;
- }
-
- void pop_back() {
- assert(Last != First && "Popping empty vector!");
- --Last;
- }
-
- void dropBack(size_t Index) {
- assert(Index <= size() && "dropBack() can't expand!");
- Last = First + Index;
- }
-
- T* begin() { return First; }
- T* end() { return Last; }
-
- bool empty() const { return First == Last; }
- size_t size() const { return static_cast<size_t>(Last - First); }
- T& back() {
- assert(Last != First && "Calling back() on empty vector!");
- return *(Last - 1);
- }
- T& operator[](size_t Index) {
- assert(Index < size() && "Invalid access!");
- return *(begin() + Index);
- }
- void clear() { Last = First; }
-
- ~PODSmallVector() {
- if (!isInline())
- std::free(First);
- }
-};
+#include "ItaniumNodes.def"
template <typename Derived, typename Alloc> struct AbstractManglingParser {
const char *First;
@@ -2313,9 +2405,9 @@
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() {
@@ -2387,8 +2479,9 @@
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;
}
@@ -2405,7 +2498,7 @@
char consume() { return First != Last ? *First++ : '\0'; }
- char look(unsigned Lookahead = 0) {
+ char look(unsigned Lookahead = 0) const {
if (static_cast<size_t>(Last - First) <= Lookahead)
return '\0';
return First[Lookahead];
@@ -2413,10 +2506,10 @@
size_t numLeft() const { return static_cast<size_t>(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();
@@ -2427,16 +2520,17 @@
/// Parse the <expr> 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 <class Float> Node *parseFloatingLiteral();
Node *parseFunctionParam();
- Node *parseNewExpr();
Node *parseConversionExpr();
Node *parseBracedExpr();
Node *parseFoldExpr();
+ Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
+ Node *parseSubobjectExpr();
/// Parse the <type> production.
Node *parseType();
@@ -2483,17 +2577,81 @@
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, @<type>(expr)
+ OfIdOp, // alignof, sizeof, typeid
+
+ Unnameable = NamedCast,
+ };
+ char Enc[2]; // Encoding
+ OIKind Kind; // Kind of operator
+ bool Flag : 1; // Entry-specific flag
+ Node::Prec Prec : 7; // Precedence
+ const char *Name; // Spelling
+
+ public:
+ constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P,
+ const char *N)
+ : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {}
+
+ public:
+ bool operator<(const OperatorInfo &Other) const {
+ return *this < Other.Enc;
+ }
+ bool operator<(const char *Peek) const {
+ return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
+ }
+ bool operator==(const char *Peek) const {
+ return Enc[0] == Peek[0] && Enc[1] == Peek[1];
+ }
+ bool operator!=(const char *Peek) const { return !this->operator==(Peek); }
+
+ public:
+ std::string_view getSymbol() const {
+ std::string_view Res = Name;
+ if (Kind < Unnameable) {
+ assert(llvm::itanium_demangle::starts_with(Res, "operator") &&
+ "operator name does not start with 'operator'");
+ Res.remove_prefix(sizeof("operator") - 1);
+ if (llvm::itanium_demangle::starts_with(Res, ' '))
+ Res.remove_prefix(1);
+ }
+ return Res;
+ }
+ 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 <unresolved-name> production.
- Node *parseUnresolvedName();
+ Node *parseUnresolvedName(bool Global);
Node *parseSimpleId();
Node *parseBaseUnresolvedName();
Node *parseUnresolvedType();
@@ -2514,41 +2672,35 @@
// ::= <substitution>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) {
- consumeIf('L'); // extension
-
if (look() == 'N')
return getDerived().parseNestedName(State);
if (look() == 'Z')
return getDerived().parseLocalName(State);
- // ::= <unscoped-template-name> <template-args>
- if (look() == 'S' && look(1) != 't') {
- Node *S = getDerived().parseSubstitution();
- if (S == nullptr)
- return nullptr;
- if (look() != 'I')
- return nullptr;
+ Node *Result = nullptr;
+ bool IsSubst = false;
+
+ Result = getDerived().parseUnscopedName(State, &IsSubst);
+ if (!Result)
+ return nullptr;
+
+ if (look() == 'I') {
+ // ::= <unscoped-template-name> <template-args>
+ if (!IsSubst)
+ // An unscoped-template-name is substitutable.
+ Subs.push_back(Result);
Node *TA = getDerived().parseTemplateArgs(State != nullptr);
if (TA == nullptr)
return nullptr;
- if (State) State->EndsWithTemplateArgs = true;
- return make<NameWithTemplateArgs>(S, TA);
+ if (State)
+ State->EndsWithTemplateArgs = true;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else if (IsSubst) {
+ // The substitution case must be followed by <template-args>.
+ return nullptr;
}
- Node *N = getDerived().parseUnscopedName(State);
- if (N == nullptr)
- return nullptr;
- // ::= <unscoped-template-name> <template-args>
- if (look() == 'I') {
- Subs.push_back(N);
- Node *TA = getDerived().parseTemplateArgs(State != nullptr);
- if (TA == nullptr)
- return nullptr;
- if (State) State->EndsWithTemplateArgs = true;
- return make<NameWithTemplateArgs>(N, TA);
- }
- // ::= <unscoped-name>
- return N;
+ return Result;
}
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
@@ -2589,34 +2741,63 @@
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
+// [*] extension
template <typename Derived, typename Alloc>
Node *
-AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) {
- if (consumeIf("StL") || consumeIf("St")) {
- Node *R = getDerived().parseUnqualifiedName(State);
- if (R == nullptr)
+AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
+ bool *IsSubst) {
+
+ Node *Std = nullptr;
+ if (consumeIf("St")) {
+ Std = make<NameType>("std");
+ if (Std == nullptr)
return nullptr;
- return make<StdQualifiedName>(R);
}
- return getDerived().parseUnqualifiedName(State);
+
+ Node *Res = nullptr;
+ ModuleName *Module = nullptr;
+ if (look() == 'S') {
+ Node *S = getDerived().parseSubstitution();
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName)
+ Module = static_cast<ModuleName *>(S);
+ else if (IsSubst && Std == nullptr) {
+ Res = S;
+ *IsSubst = true;
+ } else {
+ return nullptr;
+ }
+ }
+
+ if (Res == nullptr || Std != nullptr) {
+ Res = getDerived().parseUnqualifiedName(State, Std, Module);
+ }
+
+ return Res;
}
-// <unqualified-name> ::= <operator-name> [abi-tags]
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-// ::= DC <source-name>+ E # structured binding declaration
+// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
+// ::= [<module-name>] L? <source-name> [<abi-tags>]
+// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
+// # structured binding declaration
+// ::= [<module-name>] L? DC <source-name>+ E
template <typename Derived, typename Alloc>
-Node *
-AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
- // <ctor-dtor-name>s are special-cased in parseNestedName().
+Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
+ NameState *State, Node *Scope, ModuleName *Module) {
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+
+ consumeIf('L');
+
Node *Result;
- if (look() == 'U')
- Result = getDerived().parseUnnamedTypeName(State);
- else if (look() >= '1' && look() <= '9')
+ if (look() >= '1' && look() <= '9') {
Result = getDerived().parseSourceName(State);
- else if (consumeIf("DC")) {
+ } else if (look() == 'U') {
+ Result = getDerived().parseUnnamedTypeName(State);
+ } else if (consumeIf("DC")) {
+ // Structured binding
size_t BindingsBegin = Names.size();
do {
Node *Binding = getDerived().parseSourceName(State);
@@ -2625,13 +2806,46 @@
Names.push_back(Binding);
} while (!consumeIf('E'));
Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
- } else
+ } else if (look() == 'C' || look() == 'D') {
+ // A <ctor-dtor-name>.
+ if (Scope == nullptr || Module != nullptr)
+ return nullptr;
+ Result = getDerived().parseCtorDtorName(Scope, State);
+ } else {
Result = getDerived().parseOperatorName(State);
+ }
+
+ if (Result != nullptr && Module != nullptr)
+ Result = make<ModuleEntity>(Module, Result);
if (Result != nullptr)
Result = getDerived().parseAbiTags(Result);
+ if (Result != nullptr && Scope != nullptr)
+ Result = make<NestedName>(Scope, Result);
+
return Result;
}
+// <module-name> ::= <module-subname>
+// ::= <module-name> <module-subname>
+// ::= <substitution> # passed in by caller
+// <module-subname> ::= W <source-name>
+// ::= W P <source-name>
+template <typename Derived, typename Alloc>
+bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
+ ModuleName *&Module) {
+ while (consumeIf('W')) {
+ bool IsPartition = consumeIf('P');
+ Node *Sub = getDerived().parseSourceName(nullptr);
+ if (!Sub)
+ return true;
+ Module =
+ static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition));
+ Subs.push_back(Module);
+ }
+
+ return false;
+}
+
// <unnamed-type-name> ::= Ut [<nonnegative number>] _
// ::= <closure-type-name>
//
@@ -2647,19 +2861,19 @@
TemplateParams.clear();
if (consumeIf("Ut")) {
- StringView Count = parseNumber();
+ std::string_view Count = parseNumber();
if (!consumeIf('_'))
return nullptr;
return make<UnnamedTypeName>(Count);
}
if (consumeIf("Ul")) {
- SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel,
+ ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel,
TemplateParams.size());
ScopedTemplateParamList LambdaTemplateParams(this);
size_t ParamsBegin = Names.size();
while (look() == 'T' &&
- StringView("yptn").find(look(1)) != StringView::npos) {
+ std::string_view("yptn").find(look(1)) != std::string_view::npos) {
Node *T = parseTemplateParamDecl();
if (!T)
return nullptr;
@@ -2702,7 +2916,7 @@
}
NodeArray Params = popTrailingNodeArray(ParamsBegin);
- StringView Count = parseNumber();
+ std::string_view Count = parseNumber();
if (!consumeIf('_'))
return nullptr;
return make<ClosureTypeName>(TempParams, Params, Count);
@@ -2724,104 +2938,138 @@
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<NameType>("(anonymous namespace)");
return make<NameType>(Name);
}
-// <operator-name> ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
+// Operator encodings
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<
+ Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
+ Alloc>::Ops[] = {
+ // Keep ordered by encoding
+ {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
+ {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
+ {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
+ {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
+ {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
+ {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
+ {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
+ "operator co_await"},
+ {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
+ {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
+ {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+ {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
+ {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
+ {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
+ {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
+ {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
+ "operator delete[]"},
+ {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
+ {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
+ {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
+ "operator delete"},
+ {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator.*"},
+ {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix,
+ "operator."},
+ {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"},
+ {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="},
+ {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"},
+ {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="},
+ {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="},
+ {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"},
+ {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"},
+ {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="},
+ {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="},
+ {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"},
+ {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"},
+ {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="},
+ {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="},
+ {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"},
+ {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator*"},
+ {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"},
+ {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary,
+ "operator new[]"},
+ {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
+ {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
+ {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
+ {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
+ {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
+ {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
+ {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
+ {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="},
+ {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"},
+ {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator->*"},
+ {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"},
+ {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"},
+ {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix,
+ "operator->"},
+ {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional,
+ "operator?"},
+ {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="},
+ {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="},
+ {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix,
+ "reinterpret_cast"},
+ {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator%"},
+ {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
+ {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
+ {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
+ {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
+ {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
+ {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
+ "typeid "},
+ {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
+};
+template <typename Derived, typename Alloc>
+const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
+ sizeof(Ops[0]);
+
+// If the next 2 chars are an operator encoding, consume them and return their
+// OperatorInfo. Otherwise return nullptr.
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
+AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
+ if (numLeft() < 2)
+ return nullptr;
+
+ // We can't use lower_bound as that can link to symbols in the C++ library,
+ // and this must remain independant of that.
+ size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds.
+ while (upper != lower) {
+ size_t middle = (upper + lower) / 2;
+ if (Ops[middle] < First)
+ lower = middle + 1;
+ else
+ upper = middle;
+ }
+ if (Ops[lower] != First)
+ return nullptr;
+
+ First += 2;
+ return &Ops[lower];
+}
+
+// <operator-name> ::= See parseOperatorEncoding()
// ::= li <source-name> # operator ""
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= ss # <=> C++2a
-// ::= v <digit> <source-name> # vendor extended operator
+// ::= v <digit> <source-name> # vendor extended operator
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
- switch (look()) {
- case 'a':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator&&");
- case 'd':
- case 'n':
- First += 2;
- return make<NameType>("operator&");
- case 'N':
- First += 2;
- return make<NameType>("operator&=");
- case 'S':
- First += 2;
- return make<NameType>("operator=");
- }
- return nullptr;
- case 'c':
- switch (look(1)) {
- case 'l':
- First += 2;
- return make<NameType>("operator()");
- case 'm':
- First += 2;
- return make<NameType>("operator,");
- case 'o':
- First += 2;
- return make<NameType>("operator~");
- // ::= cv <type> # (cast)
- case 'v': {
- First += 2;
- SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+ if (const auto *Op = parseOperatorEncoding()) {
+ if (Op->getKind() == OperatorInfo::CCast) {
+ // ::= cv <type> # (cast)
+ ScopedOverride<bool> SaveTemplate(TryToParseTemplateArgs, false);
// If we're parsing an encoding, State != nullptr and the conversion
// operators' <type> could have a <template-param> that refers to some
// <template-arg>s further ahead in the mangled name.
- SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
+ ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences,
PermitForwardTemplateReferences ||
State != nullptr);
Node *Ty = getDerived().parseType();
@@ -2830,185 +3078,29 @@
if (State) State->CtorDtorConversion = true;
return make<ConversionOperatorType>(Ty);
}
- }
- return nullptr;
- case 'd':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator delete[]");
- case 'e':
- First += 2;
- return make<NameType>("operator*");
- case 'l':
- First += 2;
- return make<NameType>("operator delete");
- case 'v':
- First += 2;
- return make<NameType>("operator/");
- case 'V':
- First += 2;
- return make<NameType>("operator/=");
- }
- return nullptr;
- case 'e':
- switch (look(1)) {
- case 'o':
- First += 2;
- return make<NameType>("operator^");
- case 'O':
- First += 2;
- return make<NameType>("operator^=");
- case 'q':
- First += 2;
- return make<NameType>("operator==");
- }
- return nullptr;
- case 'g':
- switch (look(1)) {
- case 'e':
- First += 2;
- return make<NameType>("operator>=");
- case 't':
- First += 2;
- return make<NameType>("operator>");
- }
- return nullptr;
- case 'i':
- if (look(1) == 'x') {
- First += 2;
- return make<NameType>("operator[]");
- }
- return nullptr;
- case 'l':
- switch (look(1)) {
- case 'e':
- First += 2;
- return make<NameType>("operator<=");
+
+ if (Op->getKind() >= OperatorInfo::Unnameable)
+ /* Not a nameable operator. */
+ return nullptr;
+ if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
+ /* Not a nameable MemberExpr */
+ return nullptr;
+
+ return make<NameType>(Op->getName());
+ }
+
+ if (consumeIf("li")) {
// ::= li <source-name> # operator ""
- case 'i': {
- First += 2;
- Node *SN = getDerived().parseSourceName(State);
- if (SN == nullptr)
- return nullptr;
- return make<LiteralOperator>(SN);
- }
- case 's':
- First += 2;
- return make<NameType>("operator<<");
- case 'S':
- First += 2;
- return make<NameType>("operator<<=");
- case 't':
- First += 2;
- return make<NameType>("operator<");
- }
- return nullptr;
- case 'm':
- switch (look(1)) {
- case 'i':
- First += 2;
- return make<NameType>("operator-");
- case 'I':
- First += 2;
- return make<NameType>("operator-=");
- case 'l':
- First += 2;
- return make<NameType>("operator*");
- case 'L':
- First += 2;
- return make<NameType>("operator*=");
- case 'm':
- First += 2;
- return make<NameType>("operator--");
- }
- return nullptr;
- case 'n':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator new[]");
- case 'e':
- First += 2;
- return make<NameType>("operator!=");
- case 'g':
- First += 2;
- return make<NameType>("operator-");
- case 't':
- First += 2;
- return make<NameType>("operator!");
- case 'w':
- First += 2;
- return make<NameType>("operator new");
- }
- return nullptr;
- case 'o':
- switch (look(1)) {
- case 'o':
- First += 2;
- return make<NameType>("operator||");
- case 'r':
- First += 2;
- return make<NameType>("operator|");
- case 'R':
- First += 2;
- return make<NameType>("operator|=");
- }
- return nullptr;
- case 'p':
- switch (look(1)) {
- case 'm':
- First += 2;
- return make<NameType>("operator->*");
- case 'l':
- First += 2;
- return make<NameType>("operator+");
- case 'L':
- First += 2;
- return make<NameType>("operator+=");
- case 'p':
- First += 2;
- return make<NameType>("operator++");
- case 's':
- First += 2;
- return make<NameType>("operator+");
- case 't':
- First += 2;
- return make<NameType>("operator->");
- }
- return nullptr;
- case 'q':
- if (look(1) == 'u') {
- First += 2;
- return make<NameType>("operator?");
- }
- return nullptr;
- case 'r':
- switch (look(1)) {
- case 'm':
- First += 2;
- return make<NameType>("operator%");
- case 'M':
- First += 2;
- return make<NameType>("operator%=");
- case 's':
- First += 2;
- return make<NameType>("operator>>");
- case 'S':
- First += 2;
- return make<NameType>("operator>>=");
- }
- return nullptr;
- case 's':
- if (look(1) == 's') {
- First += 2;
- return make<NameType>("operator<=>");
- }
- return nullptr;
- // ::= v <digit> <source-name> # vendor extended operator
- case 'v':
- if (std::isdigit(look(1))) {
- First += 2;
+ Node *SN = getDerived().parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<LiteralOperator>(SN);
+ }
+
+ if (consumeIf('v')) {
+ // ::= v <digit> <source-name> # vendor extended operator
+ if (look() >= '0' && look() <= '9') {
+ First++;
Node *SN = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
@@ -3016,6 +3108,7 @@
}
return nullptr;
}
+
return nullptr;
}
@@ -3034,19 +3127,11 @@
AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
NameState *State) {
if (SoFar->getKind() == Node::KSpecialSubstitution) {
- auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
- switch (SSK) {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- SoFar = make<ExpandedSpecialSubstitution>(SSK);
- if (!SoFar)
- return nullptr;
- break;
- default:
- break;
- }
+ // Expand the special substitution.
+ SoFar = make<ExpandedSpecialSubstitution>(
+ static_cast<SpecialSubstitution *>(SoFar));
+ if (!SoFar)
+ return nullptr;
}
if (consumeIf('C')) {
@@ -3075,8 +3160,10 @@
return nullptr;
}
-// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix>
+// <unqualified-name> E
+// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix>
+// <template-args> E
//
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
@@ -3085,7 +3172,7 @@
// ::= # empty
// ::= <substitution>
// ::= <prefix> <data-member-prefix>
-// extension ::= L
+// [*] extension
//
// <data-member-prefix> := <member source-name> [<template-args>] M
//
@@ -3105,90 +3192,76 @@
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<NestedName>(SoFar, Comp);
- else SoFar = Comp;
- if (State) State->EndsWithTemplateArgs = false;
- return SoFar != nullptr;
- };
-
- if (consumeIf("St")) {
- SoFar = make<NameType>("std");
- if (!SoFar)
- return nullptr;
}
+ Node *SoFar = nullptr;
while (!consumeIf('E')) {
- consumeIf('L'); // extension
+ if (State)
+ // Only set end-with-template on the case that does that.
+ State->EndsWithTemplateArgs = false;
- // <data-member-prefix> := <member source-name> [<template-args>] M
- if (consumeIf('M')) {
- if (SoFar == nullptr)
- return nullptr;
- continue;
- }
-
- // ::= <template-param>
if (look() == 'T') {
- if (!PushComponent(getDerived().parseTemplateParam()))
- return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <template-prefix> <template-args>
- if (look() == 'I') {
+ // ::= <template-param>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseTemplateParam();
+ } else if (look() == 'I') {
+ // ::= <template-prefix> <template-args>
+ if (SoFar == nullptr)
+ return nullptr; // Must have a prefix.
Node *TA = getDerived().parseTemplateArgs(State != nullptr);
- if (TA == nullptr || SoFar == nullptr)
+ if (TA == nullptr)
return nullptr;
+ if (SoFar->getKind() == Node::KNameWithTemplateArgs)
+ // Semantically <template-args> <template-args> cannot be generated by a
+ // C++ entity. There will always be [something like] a name between
+ // them.
+ return nullptr;
+ if (State)
+ State->EndsWithTemplateArgs = true;
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
- if (!SoFar)
- return nullptr;
- if (State) State->EndsWithTemplateArgs = true;
- Subs.push_back(SoFar);
- continue;
+ } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+ // ::= <decltype>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseDecltype();
+ } else {
+ ModuleName *Module = nullptr;
+
+ if (look() == 'S') {
+ // ::= <substitution>
+ Node *S = nullptr;
+ if (look(1) == 't') {
+ First += 2;
+ S = make<NameType>("std");
+ } else {
+ S = getDerived().parseSubstitution();
+ }
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName) {
+ Module = static_cast<ModuleName *>(S);
+ } else if (SoFar != nullptr) {
+ return nullptr; // Cannot have a prefix.
+ } else {
+ SoFar = S;
+ continue; // Do not push a new substitution.
+ }
+ }
+
+ // ::= [<prefix>] <unqualified-name>
+ SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module);
}
- // ::= <decltype>
- if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
- if (!PushComponent(getDerived().parseDecltype()))
- return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <substitution>
- if (look() == 'S' && look(1) != 't') {
- Node *S = getDerived().parseSubstitution();
- if (!PushComponent(S))
- return nullptr;
- if (SoFar != S)
- Subs.push_back(S);
- continue;
- }
-
- // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
- if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
- if (SoFar == nullptr)
- return nullptr;
- if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
- return nullptr;
- SoFar = getDerived().parseAbiTags(SoFar);
- if (SoFar == nullptr)
- return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <prefix> <unqualified-name>
- if (!PushComponent(getDerived().parseUnqualifiedName(State)))
+ if (SoFar == nullptr)
return nullptr;
Subs.push_back(SoFar);
+
+ // No longer used.
+ // <data-member-prefix> := <member source-name> [<template-args>] M
+ consumeIf('M');
}
if (SoFar == nullptr || Subs.empty())
@@ -3283,6 +3356,7 @@
// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// [gs] has been parsed by caller.
// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
// # T::N::x /decltype(p)::N::x
@@ -3290,7 +3364,7 @@
//
// <unresolved-qualifier-level> ::= <simple-id>
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) {
Node *SoFar = nullptr;
// srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
@@ -3324,8 +3398,6 @@
return make<QualifiedName>(SoFar, Base);
}
- bool Global = consumeIf("gs");
-
// [gs] <base-unresolved-name> # x or (with "gs") ::x
if (!consumeIf("sr")) {
SoFar = getDerived().parseBaseUnresolvedName();
@@ -3382,7 +3454,7 @@
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
while (consumeIf('B')) {
- StringView SN = parseBareSourceName();
+ std::string_view SN = parseBareSourceName();
if (SN.empty())
return nullptr;
N = make<AbiTagAttr>(N, SN);
@@ -3394,16 +3466,16 @@
// <number> ::= [n] <non-negative decimal integer>
template <typename Alloc, typename Derived>
-StringView
+std::string_view
AbstractManglingParser<Alloc, Derived>::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);
}
// <positive length number> ::= [0-9]*
@@ -3420,11 +3492,11 @@
}
template <typename Alloc, typename Derived>
-StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() {
+std::string_view AbstractManglingParser<Alloc, Derived>::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;
}
@@ -3555,7 +3627,7 @@
return nullptr;
if (!consumeIf('E'))
return nullptr;
- return make<EnclosingExpr>("decltype(", E, ")");
+ return make<EnclosingExpr>("decltype", E);
}
// <array-type> ::= A <positive dimension number> _ <element type>
@@ -3608,7 +3680,7 @@
// ::= Te <name> # dependent elaborated type specifier using 'enum'
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
- StringView ElabSpef;
+ std::string_view ElabSpef;
if (consumeIf("Ts"))
ElabSpef = "struct";
else if (consumeIf("Tu"))
@@ -3632,19 +3704,18 @@
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
if (consumeIf('U')) {
- StringView Qual = parseBareSourceName();
+ std::string_view Qual = parseBareSourceName();
if (Qual.empty())
return nullptr;
- // FIXME parse the optional <template-args> here!
-
// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
- if (Qual.startsWith("objcproto")) {
- StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
- StringView Proto;
+ 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<const char *> SaveFirst(First, ProtoSourceName.begin()),
- SaveLast(Last, ProtoSourceName.end());
+ ScopedOverride<const char *> SaveFirst(First, ProtoSourceName.data()),
+ SaveLast(Last, &*ProtoSourceName.rbegin() + 1);
Proto = parseBareSourceName();
}
if (Proto.empty())
@@ -3655,10 +3726,17 @@
return make<ObjCProtoName>(Child, Proto);
}
+ Node *TA = nullptr;
+ if (look() == 'I') {
+ TA = getDerived().parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ }
+
Node *Child = getDerived().parseQualifiedType();
if (Child == nullptr)
return nullptr;
- return make<VendorExtQualType>(Child, Qual);
+ return make<VendorExtQualType>(Child, Qual, TA);
}
Qualifiers Quals = parseCVQualifiers();
@@ -3805,7 +3883,7 @@
// <builtin-type> ::= u <source-name> # vendor extended type
case 'u': {
++First;
- StringView Res = parseBareSourceName();
+ std::string_view Res = parseBareSourceName();
if (Res.empty())
return nullptr;
// Typically, <builtin-type>s are not considered substitution candidates,
@@ -3831,7 +3909,33 @@
// ::= Dh # IEEE 754r half-precision floating point (16 bits)
case 'h':
First += 2;
- return make<NameType>("decimal16");
+ return make<NameType>("half");
+ // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits)
+ case 'F': {
+ First += 2;
+ Node *DimensionNumber = make<NameType>(parseNumber());
+ if (!DimensionNumber)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<BinaryFPType>(DimensionNumber);
+ }
+ // ::= DB <number> _ # C23 signed _BitInt(N)
+ // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N)
+ // ::= DU <number> _ # C23 unsigned _BitInt(N)
+ // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N)
+ case 'B':
+ case 'U': {
+ bool Signed = look(1) == 'B';
+ First += 2;
+ Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber())
+ : getDerived().parseExpr();
+ if (!Size)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<BitIntType>(Size, Signed);
+ }
// ::= Di # char32_t
case 'i':
First += 2;
@@ -3979,9 +4083,10 @@
}
// ::= <substitution> # See Compression below
case 'S': {
- if (look(1) && look(1) != 't') {
- Node *Sub = getDerived().parseSubstitution();
- if (Sub == nullptr)
+ if (look(1) != 't') {
+ bool IsSubst = false;
+ Result = getDerived().parseUnscopedName(nullptr, &IsSubst);
+ if (!Result)
return nullptr;
// Sub could be either of:
@@ -3994,17 +4099,19 @@
// If this is followed by some <template-args>, 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<NameWithTemplateArgs>(Sub, TA);
- break;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else if (IsSubst) {
+ // If all we parsed was a substitution, don't re-insert into the
+ // substitution table.
+ return Result;
}
-
- // If all we parsed was a substitution, don't re-insert into the
- // substitution table.
- return Sub;
+ break;
}
DEMANGLE_FALLTHROUGH;
}
@@ -4024,28 +4131,32 @@
}
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) {
+Node *
+AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(std::string_view Kind,
+ Node::Prec Prec) {
Node *E = getDerived().parseExpr();
if (E == nullptr)
return nullptr;
- return make<PrefixExpr>(Kind, E);
+ return make<PrefixExpr>(Kind, E, Prec);
}
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) {
+Node *
+AbstractManglingParser<Derived, Alloc>::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<BinaryExpr>(LHS, Kind, RHS);
+ return make<BinaryExpr>(LHS, Kind, RHS, Prec);
}
template <typename Derived, typename Alloc>
-Node *
-AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) {
- StringView Tmp = parseNumber(true);
+Node *AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(
+ std::string_view Lit) {
+ std::string_view Tmp = parseNumber(true);
if (!Tmp.empty() && consumeIf('E'))
return make<IntegerLiteral>(Lit, Tmp);
return nullptr;
@@ -4075,7 +4186,7 @@
return make<NameType>("this");
if (consumeIf("fp")) {
parseCVQualifiers();
- StringView Num = parseNumber();
+ std::string_view Num = parseNumber();
if (!consumeIf('_'))
return nullptr;
return make<FunctionParam>(Num);
@@ -4086,7 +4197,7 @@
if (!consumeIf('p'))
return nullptr;
parseCVQualifiers();
- StringView Num = parseNumber();
+ std::string_view Num = parseNumber();
if (!consumeIf('_'))
return nullptr;
return make<FunctionParam>(Num);
@@ -4094,43 +4205,6 @@
return nullptr;
}
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
- bool Global = consumeIf("gs");
- bool IsArray = look(1) == 'a';
- if (!consumeIf("nw") && !consumeIf("na"))
- return nullptr;
- size_t Exprs = Names.size();
- while (!consumeIf('_')) {
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return nullptr;
- Names.push_back(Ex);
- }
- NodeArray ExprList = popTrailingNodeArray(Exprs);
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
- if (consumeIf("pi")) {
- size_t InitsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *Init = getDerived().parseExpr();
- if (Init == nullptr)
- return Init;
- Names.push_back(Init);
- }
- NodeArray Inits = popTrailingNodeArray(InitsBegin);
- return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
- } else if (!consumeIf('E'))
- return nullptr;
- return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
-}
-
// cv <type> <expression> # conversion with one argument
// cv <type> _ <expression>* E # conversion with a different number of arguments
template <typename Derived, typename Alloc>
@@ -4139,7 +4213,7 @@
return nullptr;
Node *Ty;
{
- SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+ ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
Ty = getDerived().parseType();
}
@@ -4256,7 +4330,7 @@
return nullptr;
}
case 'D':
- if (consumeIf("DnE"))
+ if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E')))
return make<NameType>("nullptr");
return nullptr;
case 'T':
@@ -4277,7 +4351,7 @@
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'))
@@ -4343,55 +4417,38 @@
if (!consumeIf('f'))
return nullptr;
- char FoldKind = look();
- bool IsLeftFold, HasInitializer;
- HasInitializer = FoldKind == 'L' || FoldKind == 'R';
- if (FoldKind == 'l' || FoldKind == 'L')
- IsLeftFold = true;
- else if (FoldKind == 'r' || FoldKind == 'R')
- IsLeftFold = false;
- else
+ bool IsLeftFold = false, HasInitializer = false;
+ switch (look()) {
+ default:
return nullptr;
+ case 'L':
+ IsLeftFold = true;
+ HasInitializer = true;
+ break;
+ case 'R':
+ HasInitializer = true;
+ break;
+ case 'l':
+ IsLeftFold = true;
+ break;
+ case 'r':
+ break;
+ }
++First;
- // FIXME: This map is duplicated in parseOperatorName and parseExpr.
- StringView OperatorName;
- if (consumeIf("aa")) OperatorName = "&&";
- else if (consumeIf("an")) OperatorName = "&";
- else if (consumeIf("aN")) OperatorName = "&=";
- else if (consumeIf("aS")) OperatorName = "=";
- else if (consumeIf("cm")) OperatorName = ",";
- else if (consumeIf("ds")) OperatorName = ".*";
- else if (consumeIf("dv")) OperatorName = "/";
- else if (consumeIf("dV")) OperatorName = "/=";
- else if (consumeIf("eo")) OperatorName = "^";
- else if (consumeIf("eO")) OperatorName = "^=";
- else if (consumeIf("eq")) OperatorName = "==";
- else if (consumeIf("ge")) OperatorName = ">=";
- else if (consumeIf("gt")) OperatorName = ">";
- else if (consumeIf("le")) OperatorName = "<=";
- else if (consumeIf("ls")) OperatorName = "<<";
- else if (consumeIf("lS")) OperatorName = "<<=";
- else if (consumeIf("lt")) OperatorName = "<";
- else if (consumeIf("mi")) OperatorName = "-";
- else if (consumeIf("mI")) OperatorName = "-=";
- else if (consumeIf("ml")) OperatorName = "*";
- else if (consumeIf("mL")) OperatorName = "*=";
- else if (consumeIf("ne")) OperatorName = "!=";
- else if (consumeIf("oo")) OperatorName = "||";
- else if (consumeIf("or")) OperatorName = "|";
- else if (consumeIf("oR")) OperatorName = "|=";
- else if (consumeIf("pl")) OperatorName = "+";
- else if (consumeIf("pL")) OperatorName = "+=";
- else if (consumeIf("rm")) OperatorName = "%";
- else if (consumeIf("rM")) OperatorName = "%=";
- else if (consumeIf("rs")) OperatorName = ">>";
- else if (consumeIf("rS")) OperatorName = ">>=";
- else return nullptr;
+ const auto *Op = parseOperatorEncoding();
+ if (!Op)
+ return nullptr;
+ if (!(Op->getKind() == OperatorInfo::Binary
+ || (Op->getKind() == OperatorInfo::Member
+ && Op->getName().back() == '*')))
+ return nullptr;
- Node *Pack = getDerived().parseExpr(), *Init = nullptr;
+ Node *Pack = getDerived().parseExpr();
if (Pack == nullptr)
return nullptr;
+
+ Node *Init = nullptr;
if (HasInitializer) {
Init = getDerived().parseExpr();
if (Init == nullptr)
@@ -4401,7 +4458,53 @@
if (IsLeftFold && Init)
std::swap(Pack, Init);
- return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
+ return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
+}
+
+// <expression> ::= mc <parameter type> <expr> [<offset number>] E
+//
+// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
+template <typename Derived, typename Alloc>
+Node *
+AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr(
+ Node::Prec Prec) {
+ Node *Ty = getDerived().parseType();
+ if (!Ty)
+ return nullptr;
+ Node *Expr = getDerived().parseExpr();
+ if (!Expr)
+ return nullptr;
+ std::string_view Offset = getDerived().parseNumber(true);
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec);
+}
+
+// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
+// <union-selector> ::= _ [<number>]
+//
+// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
+ Node *Ty = getDerived().parseType();
+ if (!Ty)
+ return nullptr;
+ Node *Expr = getDerived().parseExpr();
+ if (!Expr)
+ return nullptr;
+ std::string_view Offset = getDerived().parseNumber(true);
+ size_t SelectorsBegin = Names.size();
+ while (consumeIf('_')) {
+ Node *Selector = make<NameType>(parseNumber());
+ if (!Selector)
+ return nullptr;
+ Names.push_back(Selector);
+ }
+ bool OnePastTheEnd = consumeIf('p');
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<SubobjectExpr>(
+ Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
}
// <expression> ::= <unary operator-name> <expression>
@@ -4451,313 +4554,127 @@
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
bool Global = consumeIf("gs");
- if (numLeft() < 2)
- return nullptr;
- switch (*First) {
- case 'L':
- return getDerived().parseExprPrimary();
- case 'T':
- return getDerived().parseTemplateParam();
- case 'f': {
- // Disambiguate a fold expression from a <function-param>.
- if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
- return getDerived().parseFunctionParam();
- return getDerived().parseFoldExpr();
- }
- case 'a':
- switch (First[1]) {
- case 'a':
- First += 2;
- return getDerived().parseBinaryExpr("&&");
- case 'd':
- First += 2;
- return getDerived().parsePrefixExpr("&");
- case 'n':
- First += 2;
- return getDerived().parseBinaryExpr("&");
- case 'N':
- First += 2;
- return getDerived().parseBinaryExpr("&=");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr("=");
- case 't': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- case 'z': {
- First += 2;
- Node *Ty = getDerived().parseExpr();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- }
- return nullptr;
- case 'c':
- switch (First[1]) {
- // cc <type> <expression> # const_cast<type>(expression)
- case 'c': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
+ const auto *Op = parseOperatorEncoding();
+ if (Op) {
+ auto Sym = Op->getSymbol();
+ switch (Op->getKind()) {
+ case OperatorInfo::Binary:
+ // Binary operator: lhs @ rhs
+ return getDerived().parseBinaryExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Prefix:
+ // Prefix unary operator: @ expr
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Postfix: {
+ // Postfix unary operator: expr @
+ if (consumeIf('_'))
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("const_cast", Ty, Ex);
- }
- // cl <expression>+ E # call
- case 'l': {
- First += 2;
- Node *Callee = getDerived().parseExpr();
- if (Callee == nullptr)
- return Callee;
- size_t ExprsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = getDerived().parseExpr();
- if (E == nullptr)
- return E;
- Names.push_back(E);
- }
- return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
- }
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr(",");
- case 'o':
- First += 2;
- return getDerived().parsePrefixExpr("~");
- case 'v':
- return getDerived().parseConversionExpr();
- }
- return nullptr;
- case 'd':
- switch (First[1]) {
- case 'a': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
- }
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("dynamic_cast", T, Ex);
- }
- case 'e':
- First += 2;
- return getDerived().parsePrefixExpr("*");
- case 'l': {
- First += 2;
- Node *E = getDerived().parseExpr();
- if (E == nullptr)
- return E;
- return make<DeleteExpr>(E, Global, /*is_array=*/false);
- }
- case 'n':
- return getDerived().parseUnresolvedName();
- case 's': {
- First += 2;
- Node *LHS = getDerived().parseExpr();
- if (LHS == nullptr)
return nullptr;
- Node *RHS = getDerived().parseExpr();
- if (RHS == nullptr)
- return nullptr;
- return make<MemberExpr>(LHS, ".*", RHS);
+ return make<PostfixExpr>(Ex, Sym, Op->getPrecedence());
}
- case 't': {
- First += 2;
- Node *LHS = getDerived().parseExpr();
- if (LHS == nullptr)
- return LHS;
- Node *RHS = getDerived().parseExpr();
- if (RHS == nullptr)
- return nullptr;
- return make<MemberExpr>(LHS, ".", RHS);
- }
- case 'v':
- First += 2;
- return getDerived().parseBinaryExpr("/");
- case 'V':
- First += 2;
- return getDerived().parseBinaryExpr("/=");
- }
- return nullptr;
- case 'e':
- switch (First[1]) {
- case 'o':
- First += 2;
- return getDerived().parseBinaryExpr("^");
- case 'O':
- First += 2;
- return getDerived().parseBinaryExpr("^=");
- case 'q':
- First += 2;
- return getDerived().parseBinaryExpr("==");
- }
- return nullptr;
- case 'g':
- switch (First[1]) {
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr(">=");
- case 't':
- First += 2;
- return getDerived().parseBinaryExpr(">");
- }
- return nullptr;
- case 'i':
- switch (First[1]) {
- case 'x': {
- First += 2;
+ case OperatorInfo::Array: {
+ // Array Index: lhs [ rhs ]
Node *Base = getDerived().parseExpr();
if (Base == nullptr)
return nullptr;
Node *Index = getDerived().parseExpr();
if (Index == nullptr)
- return Index;
- return make<ArraySubscriptExpr>(Base, Index);
+ return nullptr;
+ return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence());
}
- case 'l': {
- First += 2;
+ case OperatorInfo::Member: {
+ // Member access lhs @ rhs
+ Node *LHS = getDerived().parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = getDerived().parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence());
+ }
+ case OperatorInfo::New: {
+ // New
+ // # new (expr-list) type [(init)]
+ // [gs] nw <expression>* _ <type> [pi <expression>*] E
+ // # new[] (expr-list) type [(init)]
+ // [gs] na <expression>* _ <type> [pi <expression>*] E
+ size_t Exprs = Names.size();
+ while (!consumeIf('_')) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ Names.push_back(Ex);
+ }
+ NodeArray ExprList = popTrailingNodeArray(Exprs);
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
- Node *E = getDerived().parseBracedExpr();
+ if (!HaveInits)
+ return nullptr;
+ Node *Init = getDerived().parseExpr();
+ if (Init == nullptr)
+ return Init;
+ Names.push_back(Init);
+ }
+ NodeArray Inits = popTrailingNodeArray(InitsBegin);
+ return make<NewExpr>(ExprList, Ty, Inits, Global,
+ /*IsArray=*/Op->getFlag(), Op->getPrecedence());
+ }
+ case OperatorInfo::Del: {
+ // Delete
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(),
+ Op->getPrecedence());
+ }
+ case OperatorInfo::Call: {
+ // Function Call
+ Node *Callee = getDerived().parseExpr();
+ if (Callee == nullptr)
+ return nullptr;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
if (E == nullptr)
return nullptr;
Names.push_back(E);
}
- return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
+ Op->getPrecedence());
}
- }
- return nullptr;
- case 'l':
- switch (First[1]) {
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr("<=");
- case 's':
- First += 2;
- return getDerived().parseBinaryExpr("<<");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr("<<=");
- case 't':
- First += 2;
- return getDerived().parseBinaryExpr("<");
- }
- return nullptr;
- case 'm':
- switch (First[1]) {
- case 'i':
- First += 2;
- return getDerived().parseBinaryExpr("-");
- case 'I':
- First += 2;
- return getDerived().parseBinaryExpr("-=");
- case 'l':
- First += 2;
- return getDerived().parseBinaryExpr("*");
- case 'L':
- First += 2;
- return getDerived().parseBinaryExpr("*=");
- case 'm':
- First += 2;
- if (consumeIf('_'))
- return getDerived().parsePrefixExpr("--");
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
+ case OperatorInfo::CCast: {
+ // C Cast: (type)expr
+ Node *Ty;
+ {
+ ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = getDerived().parseType();
+ }
+ if (Ty == nullptr)
return nullptr;
- return make<PostfixExpr>(Ex, "--");
- }
- return nullptr;
- case 'n':
- switch (First[1]) {
- case 'a':
- case 'w':
- return getDerived().parseNewExpr();
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr("!=");
- case 'g':
- First += 2;
- return getDerived().parsePrefixExpr("-");
- case 't':
- First += 2;
- return getDerived().parsePrefixExpr("!");
- case 'x':
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("noexcept (", Ex, ")");
- }
- return nullptr;
- case 'o':
- switch (First[1]) {
- case 'n':
- return getDerived().parseUnresolvedName();
- case 'o':
- First += 2;
- return getDerived().parseBinaryExpr("||");
- case 'r':
- First += 2;
- return getDerived().parseBinaryExpr("|");
- case 'R':
- First += 2;
- return getDerived().parseBinaryExpr("|=");
- }
- return nullptr;
- case 'p':
- switch (First[1]) {
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr("->*");
- case 'l':
- First += 2;
- return getDerived().parseBinaryExpr("+");
- case 'L':
- First += 2;
- return getDerived().parseBinaryExpr("+=");
- case 'p': {
- First += 2;
- if (consumeIf('_'))
- return getDerived().parsePrefixExpr("++");
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<PostfixExpr>(Ex, "++");
- }
- case 's':
- First += 2;
- return getDerived().parsePrefixExpr("+");
- case 't': {
- First += 2;
- Node *L = getDerived().parseExpr();
- if (L == nullptr)
+
+ size_t ExprsBegin = Names.size();
+ bool IsMany = consumeIf('_');
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ if (!IsMany)
+ break;
+ }
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ if (!IsMany && Exprs.size() != 1)
return nullptr;
- Node *R = getDerived().parseExpr();
- if (R == nullptr)
- return nullptr;
- return make<MemberExpr>(L, "->", R);
+ return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence());
}
- }
- return nullptr;
- case 'q':
- if (First[1] == 'u') {
- First += 2;
+ case OperatorInfo::Conditional: {
+ // Conditional operator: expr ? expr : expr
Node *Cond = getDerived().parseExpr();
if (Cond == nullptr)
return nullptr;
@@ -4767,169 +4684,158 @@
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
- return make<ConditionalExpr>(Cond, LHS, RHS);
+ return make<ConditionalExpr>(Cond, LHS, RHS, Op->getPrecedence());
}
- return nullptr;
- case 'r':
- switch (First[1]) {
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("reinterpret_cast", T, Ex);
- }
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr("%");
- case 'M':
- First += 2;
- return getDerived().parseBinaryExpr("%=");
- case 's':
- First += 2;
- return getDerived().parseBinaryExpr(">>");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr(">>=");
- }
- return nullptr;
- case 's':
- switch (First[1]) {
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("static_cast", T, Ex);
- }
- case 'p': {
- First += 2;
- Node *Child = getDerived().parseExpr();
- if (Child == nullptr)
- return nullptr;
- return make<ParameterPackExpansion>(Child);
- }
- case 'r':
- return getDerived().parseUnresolvedName();
- case 't': {
- First += 2;
+ case OperatorInfo::NamedCast: {
+ // Named cast operation, @<type>(expr)
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
- return Ty;
- return make<EnclosingExpr>("sizeof (", Ty, ")");
- }
- case 'z': {
- First += 2;
+ return nullptr;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("sizeof (", Ex, ")");
+ return nullptr;
+ return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence());
}
- case 'Z':
- First += 2;
- if (look() == 'T') {
- Node *R = getDerived().parseTemplateParam();
- if (R == nullptr)
- return nullptr;
- return make<SizeofParamPackExpr>(R);
- } else if (look() == 'f') {
- Node *FP = getDerived().parseFunctionParam();
- if (FP == nullptr)
- return nullptr;
- return make<EnclosingExpr>("sizeof... (", FP, ")");
- }
+ case OperatorInfo::OfIdOp: {
+ // [sizeof/alignof/typeid] ( <type>|<expr> )
+ Node *Arg =
+ Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
+ if (!Arg)
+ return nullptr;
+ return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence());
+ }
+ case OperatorInfo::NameOnly: {
+ // Not valid as an expression operand.
return nullptr;
- case 'P': {
- First += 2;
- size_t ArgsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *Arg = getDerived().parseTemplateArg();
- if (Arg == nullptr)
- return nullptr;
- Names.push_back(Arg);
- }
- auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
- if (!Pack)
- return nullptr;
- return make<EnclosingExpr>("sizeof... (", Pack, ")");
}
}
+ DEMANGLE_UNREACHABLE;
+ }
+
+ if (numLeft() < 2)
return nullptr;
- case 't':
- switch (First[1]) {
- case 'e': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("typeid (", Ex, ")");
- }
- case 'i': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
- return make<EnclosingExpr>("typeid (", Ty, ")");
- }
- case 'l': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
+
+ if (look() == 'L')
+ return getDerived().parseExprPrimary();
+ if (look() == 'T')
+ return getDerived().parseTemplateParam();
+ if (look() == 'f') {
+ // Disambiguate a fold expression from a <function-param>.
+ if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
+ return getDerived().parseFunctionParam();
+ return getDerived().parseFoldExpr();
+ }
+ if (consumeIf("il")) {
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseBracedExpr();
+ if (E == nullptr)
return nullptr;
- size_t InitsBegin = Names.size();
+ Names.push_back(E);
+ }
+ return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+ }
+ if (consumeIf("mc"))
+ return parsePointerToMemberConversionExpr(Node::Prec::Unary);
+ if (consumeIf("nx")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
+ }
+ if (consumeIf("so"))
+ return parseSubobjectExpr();
+ if (consumeIf("sp")) {
+ Node *Child = getDerived().parseExpr();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ParameterPackExpansion>(Child);
+ }
+ if (consumeIf("sZ")) {
+ if (look() == 'T') {
+ Node *R = getDerived().parseTemplateParam();
+ if (R == nullptr)
+ return nullptr;
+ return make<SizeofParamPackExpr>(R);
+ }
+ Node *FP = getDerived().parseFunctionParam();
+ if (FP == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... ", FP);
+ }
+ if (consumeIf("sP")) {
+ size_t ArgsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Arg = getDerived().parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
+ }
+ auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
+ if (!Pack)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... ", Pack);
+ }
+ if (consumeIf("tl")) {
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+ }
+ if (consumeIf("tr"))
+ return make<NameType>("throw");
+ if (consumeIf("tw")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<ThrowExpr>(Ex);
+ }
+ if (consumeIf('u')) {
+ Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
+ if (!Name)
+ return nullptr;
+ // Special case legacy __uuidof mangling. The 't' and 'z' appear where the
+ // standard encoding expects a <template-arg>, and would be otherwise be
+ // interpreted as <type> node 'short' or 'ellipsis'. However, neither
+ // __uuidof(short) nor __uuidof(...) can actually appear, so there is no
+ // actual conflict here.
+ bool IsUUID = false;
+ Node *UUID = nullptr;
+ if (Name->getBaseName() == "__uuidof") {
+ if (consumeIf('t')) {
+ UUID = getDerived().parseType();
+ IsUUID = true;
+ } else if (consumeIf('z')) {
+ UUID = getDerived().parseExpr();
+ IsUUID = true;
+ }
+ }
+ size_t ExprsBegin = Names.size();
+ if (IsUUID) {
+ if (UUID == nullptr)
+ return nullptr;
+ Names.push_back(UUID);
+ } else {
while (!consumeIf('E')) {
- Node *E = getDerived().parseBracedExpr();
+ Node *E = getDerived().parseTemplateArg();
if (E == nullptr)
- return nullptr;
+ return E;
Names.push_back(E);
}
- return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
}
- case 'r':
- First += 2;
- return make<NameType>("throw");
- case 'w': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return nullptr;
- return make<ThrowExpr>(Ex);
- }
- }
- return nullptr;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return getDerived().parseUnresolvedName();
+ return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
+ Node::Prec::Postfix);
}
- if (consumeIf("u8__uuidoft")) {
- Node *Ty = getDerived().parseType();
- if (!Ty)
- return nullptr;
- return make<UUIDOfExpr>(Ty);
- }
-
- if (consumeIf("u8__uuidofz")) {
- Node *Ex = getDerived().parseExpr();
- if (!Ex)
- return nullptr;
- return make<UUIDOfExpr>(Ex);
- }
-
- return nullptr;
+ // Only unresolved names remain.
+ return getDerived().parseUnresolvedName(Global);
}
// <call-offset> ::= h <nv-offset> _
@@ -4962,19 +4868,32 @@
// # second call-offset is result adjustment
// ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
-// ::= GV <object name> # Guard variable for one-time initialization
+// # Guard variable for one-time initialization
+// ::= GV <object name>
// # No <type>
// ::= TW <object name> # Thread-local wrapper
// ::= TH <object name> # Thread-local initialization
// ::= GR <object name> _ # First temporary
// ::= GR <object name> <seq-id> _ # Subsequent temporaries
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// # construction vtable for second-in-first
+// extension ::= TC <first type> <number> _ <second type>
// extension ::= GR <object name> # reference temporary for object
+// extension ::= GI <module name> # module global initializer
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
switch (look()) {
case 'T':
switch (look(1)) {
+ // TA <template-arg> # template parameter object
+ //
+ // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63
+ case 'A': {
+ First += 2;
+ Node *Arg = getDerived().parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ return make<SpecialName>("template parameter object for ", Arg);
+ }
// TV <type> # virtual table
case 'V': {
First += 2;
@@ -5086,6 +5005,16 @@
return nullptr;
return make<SpecialName>("reference temporary for ", Name);
}
+ // GI <module-name> v
+ case 'I': {
+ First += 2;
+ ModuleName *Module = nullptr;
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+ if (Module == nullptr)
+ return nullptr;
+ return make<SpecialName>("initializer for module ", Module);
+ }
}
}
return nullptr;
@@ -5096,6 +5025,26 @@
// ::= <special-name>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+ // The template parameters of an encoding are unrelated to those of the
+ // enclosing context.
+ class SaveTemplateParams {
+ AbstractManglingParser *Parser;
+ decltype(TemplateParams) OldParams;
+ decltype(OuterTemplateParams) OldOuterParams;
+
+ public:
+ SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
+ OldParams = std::move(Parser->TemplateParams);
+ OldOuterParams = std::move(Parser->OuterTemplateParams);
+ Parser->TemplateParams.clear();
+ Parser->OuterTemplateParams.clear();
+ }
+ ~SaveTemplateParams() {
+ Parser->TemplateParams = std::move(OldParams);
+ Parser->OuterTemplateParams = std::move(OldOuterParams);
+ }
+ } SaveTemplateParams(this);
+
if (look() == 'G' || look() == 'T')
return getDerived().parseSpecialName();
@@ -5180,14 +5129,19 @@
struct FloatData<long double>
{
#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;
#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";
};
@@ -5197,7 +5151,7 @@
const size_t N = FloatData<Float>::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;
@@ -5240,43 +5194,41 @@
// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+// The St case is handled specially in parseNestedName.
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
if (!consumeIf('S'))
return nullptr;
- if (std::islower(look())) {
- Node *SpecialSub;
+ if (look() >= 'a' && look() <= 'z') {
+ SpecialSubKind Kind;
switch (look()) {
case 'a':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
+ Kind = SpecialSubKind::allocator;
break;
case 'b':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
- break;
- case 's':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
- break;
- case 'i':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
- break;
- case 'o':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
+ Kind = SpecialSubKind::basic_string;
break;
case 'd':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
+ Kind = SpecialSubKind::iostream;
+ break;
+ case 'i':
+ Kind = SpecialSubKind::istream;
+ break;
+ case 'o':
+ Kind = SpecialSubKind::ostream;
+ break;
+ case 's':
+ Kind = SpecialSubKind::string;
break;
default:
return nullptr;
}
+ ++First;
+ auto *SpecialSub = make<SpecialSubstitution>(Kind);
if (!SpecialSub)
return nullptr;
+
// Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
// has ABI tags, the tags are appended to the substitution; the result is a
// substitutable component.
@@ -5519,7 +5471,8 @@
if (Encoding == nullptr)
return nullptr;
if (look() == '.') {
- Encoding = make<DotSuffix>(Encoding, StringView(First, Last));
+ Encoding =
+ make<DotSuffix>(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 c6f2606..1529b80 100644
--- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
+++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h
@@ -6,14 +6,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
-#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
+#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
+#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
-#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
-#include "llvm/Demangle/StringView.h"
-#include "llvm/Demangle/Utility.h"
+#include <cassert>
+#include <string_view>
#include <utility>
namespace llvm {
@@ -102,7 +101,7 @@
if (Head->Used <= Head->Capacity)
return new (PP) T(std::forward<Args>(ConstructorArgs)...);
- static_assert(Size < AllocUnit, "");
+ static_assert(Size < AllocUnit);
addNode(AllocUnit);
Head->Used = Size;
return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
@@ -144,9 +143,9 @@
// 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;
@@ -154,104 +153,112 @@
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<uint64_t, bool> demangleNumber(StringView &MangledName);
- uint64_t demangleUnsigned(StringView &MangledName);
- int64_t demangleSigned(StringView &MangledName);
+ std::pair<uint64_t, bool> 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);
+ NamedIdentifierNode *
+ demangleAnonymousNamespaceName(std::string_view &MangledName);
+ NamedIdentifierNode *
+ demangleLocallyScopedNamePiece(std::string_view &MangledName);
+ EncodedStringLiteralNode *
+ demangleStringLiteral(std::string_view &MangledName);
+ FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName);
- StringView demangleSimpleString(StringView &MangledName, bool Memorize);
+ std::string_view demangleSimpleString(std::string_view &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);
+ 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<Qualifiers, bool> demangleQualifiers(StringView &MangledName);
+ std::pair<Qualifiers, bool> demangleQualifiers(std::string_view &MangledName);
// Memory allocator.
ArenaAllocator Arena;
@@ -275,4 +282,4 @@
} // 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..1913bff 100644
--- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
+++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -10,23 +10,21 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
-#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
+#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
+#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
-#include "llvm/Demangle/DemangleConfig.h"
-#include "llvm/Demangle/StringView.h"
#include <array>
#include <cstdint>
#include <string>
+#include <string_view>
namespace llvm {
namespace itanium_demangle {
-class OutputStream;
+class OutputBuffer;
}
}
-using llvm::itanium_demangle::OutputStream;
-using llvm::itanium_demangle::StringView;
+using llvm::itanium_demangle::OutputBuffer;
namespace llvm {
namespace ms_demangle {
@@ -67,6 +65,8 @@
Eabi,
Vectorcall,
Regcall,
+ Swift, // Clang-only
+ SwiftAsync, // Clang-only
};
enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
@@ -78,6 +78,7 @@
OF_NoAccessSpecifier = 4,
OF_NoMemberType = 8,
OF_NoReturnType = 16,
+ OF_NoVariableType = 32,
};
// Types
@@ -259,7 +260,7 @@
NodeKind kind() const { return Kind; }
- virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;
+ virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0;
std::string toString(OutputFlags Flags = OF_Default) const;
@@ -280,9 +281,7 @@
struct ThunkSignatureNode;
struct PointerTypeNode;
struct ArrayTypeNode;
-struct CustomNode;
struct TagTypeNode;
-struct IntrinsicTypeNode;
struct NodeArrayNode;
struct QualifiedNameNode;
struct TemplateParameterReferenceNode;
@@ -298,12 +297,12 @@
struct TypeNode : public Node {
explicit TypeNode(NodeKind K) : Node(K) {}
- virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;
- virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;
+ virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0;
+ virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0;
- void output(OutputStream &OS, OutputFlags Flags) const override {
- outputPre(OS, Flags);
- outputPost(OS, Flags);
+ void output(OutputBuffer &OB, OutputFlags Flags) const override {
+ outputPre(OB, Flags);
+ outputPost(OB, Flags);
}
Qualifiers Quals = Q_None;
@@ -313,8 +312,8 @@
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(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {}
PrimitiveKind PrimKind;
};
@@ -323,8 +322,8 @@
explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
- void outputPre(OutputStream &OS, OutputFlags Flags) const override;
- void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
// Valid if this FunctionTypeNode is the Pointee of a PointerType or
// MemberPointerType.
@@ -357,13 +356,13 @@
NodeArrayNode *TemplateParams = nullptr;
protected:
- void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;
+ void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const;
};
struct VcallThunkIdentifierNode : public IdentifierNode {
VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint64_t OffsetInVTable = 0;
};
@@ -372,7 +371,7 @@
DynamicStructorIdentifierNode()
: IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
VariableSymbolNode *Variable = nullptr;
QualifiedNameNode *Name = nullptr;
@@ -382,9 +381,9 @@
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;
+ std::string_view Name;
};
struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
@@ -392,7 +391,7 @@
: IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
Operator(Operator) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
IntrinsicFunctionKind Operator;
};
@@ -401,16 +400,16 @@
LiteralOperatorIdentifierNode()
: IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
- StringView Name;
+ std::string_view Name;
};
struct LocalStaticGuardIdentifierNode : public IdentifierNode {
LocalStaticGuardIdentifierNode()
: IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
bool IsThread = false;
uint32_t ScopeIndex = 0;
@@ -420,7 +419,7 @@
ConversionOperatorIdentifierNode()
: IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
// The type that this operator converts too.
TypeNode *TargetType = nullptr;
@@ -432,7 +431,7 @@
: IdentifierNode(NodeKind::StructorIdentifier),
IsDestructor(IsDestructor) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
// The name of the class that this is a structor of.
IdentifierNode *Class = nullptr;
@@ -442,8 +441,8 @@
struct ThunkSignatureNode : public FunctionSignatureNode {
ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}
- void outputPre(OutputStream &OS, OutputFlags Flags) const override;
- void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
struct ThisAdjustor {
uint32_t StaticOffset = 0;
@@ -457,8 +456,8 @@
struct PointerTypeNode : public TypeNode {
PointerTypeNode() : TypeNode(NodeKind::PointerType) {}
- void outputPre(OutputStream &OS, OutputFlags Flags) const override;
- void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
// Is this a pointer, reference, or rvalue-reference?
PointerAffinity Affinity = PointerAffinity::None;
@@ -474,8 +473,8 @@
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(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *QualifiedName = nullptr;
TagKind Tag;
@@ -484,11 +483,11 @@
struct ArrayTypeNode : public TypeNode {
ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
- void outputPre(OutputStream &OS, OutputFlags Flags) const;
- void outputPost(OutputStream &OS, OutputFlags Flags) const;
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
- void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;
- void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;
+ void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const;
+ void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const;
// A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]`
NodeArrayNode *Dimensions = nullptr;
@@ -499,14 +498,14 @@
struct IntrinsicNode : public TypeNode {
IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}
- void output(OutputStream &OS, OutputFlags Flags) const override {}
+ void output(OutputBuffer &OB, OutputFlags Flags) const override {}
};
struct CustomTypeNode : public TypeNode {
CustomTypeNode() : TypeNode(NodeKind::Custom) {}
- void outputPre(OutputStream &OS, OutputFlags Flags) const override;
- void outputPost(OutputStream &OS, OutputFlags Flags) const override;
+ void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
+ void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
IdentifierNode *Identifier = nullptr;
};
@@ -514,9 +513,10 @@
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,
+ std::string_view Separator) const;
Node **Nodes = nullptr;
size_t Count = 0;
@@ -525,7 +525,7 @@
struct QualifiedNameNode : public Node {
QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
NodeArrayNode *Components = nullptr;
@@ -539,7 +539,7 @@
TemplateParameterReferenceNode()
: Node(NodeKind::TemplateParameterReference) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
SymbolNode *Symbol = nullptr;
@@ -554,7 +554,7 @@
IntegerLiteralNode(uint64_t Value, bool IsNegative)
: Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint64_t Value = 0;
bool IsNegative = false;
@@ -564,7 +564,7 @@
RttiBaseClassDescriptorNode()
: IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint32_t NVOffset = 0;
int32_t VBPtrOffset = 0;
@@ -574,7 +574,7 @@
struct SymbolNode : public Node {
explicit SymbolNode(NodeKind K) : Node(K) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *Name = nullptr;
};
@@ -582,7 +582,7 @@
explicit SpecialTableSymbolNode()
: SymbolNode(NodeKind::SpecialTableSymbol) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *TargetName = nullptr;
Qualifiers Quals = Qualifiers::Q_None;
};
@@ -591,7 +591,7 @@
LocalStaticGuardVariableNode()
: SymbolNode(NodeKind::LocalStaticGuardVariable) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
bool IsVisible = false;
};
@@ -599,9 +599,9 @@
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;
+ std::string_view DecodedString;
bool IsTruncated = false;
CharKind Char = CharKind::Char;
};
@@ -609,7 +609,7 @@
struct VariableSymbolNode : public SymbolNode {
VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
- void output(OutputStream &OS, OutputFlags Flags) const override;
+ void output(OutputBuffer &OB, OutputFlags Flags) const override;
StorageClass SC = StorageClass::None;
TypeNode *Type = nullptr;
@@ -618,7 +618,7 @@
struct 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 ceb6c79..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,6 +7,9 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
@@ -14,7 +17,6 @@
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
-#include <algorithm>
#include <cassert>
#include <cstring>
@@ -36,29 +38,23 @@
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
- StringView substr(size_t From) const {
- return StringView(begin() + From, size() - From);
+ StringView substr(size_t Pos, size_t Len = npos) const {
+ assert(Pos <= size());
+ if (Len > size() - Pos)
+ Len = size() - Pos;
+ return StringView(begin() + Pos, Len);
}
size_t find(char C, size_t From = 0) const {
- size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
- if (FindBegin < size()) {
+ if (From < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
- if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
+ if (const void *P = ::memchr(First + From, C, size() - From))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
- StringView substr(size_t From, size_t To) const {
- if (To >= size())
- To = size() - 1;
- if (From >= size())
- From = size() - 1;
- return StringView(First + From, First + To);
- }
-
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
@@ -105,7 +101,7 @@
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
- return std::equal(Str.begin(), Str.end(), begin());
+ return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@@ -118,7 +114,7 @@
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/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 <string_view>
+
+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 04e1936..a906d23 100644
--- a/third_party/llvm/include/llvm/Demangle/Utility.h
+++ b/third_party/llvm/include/llvm/Demangle/Utility.h
@@ -1,75 +1,88 @@
-//===--- 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 DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
-#include "StringView.h"
+#include "DemangleConfig.h"
+
+#include <array>
+#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
-#include <iterator>
+#include <exception>
#include <limits>
+#include <string_view>
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<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
- void writeUnsigned(uint64_t N, bool isNeg = false) {
- // Handle special case...
- if (N == 0) {
- *this << '0';
- return;
- }
+ OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
+ std::array<char, 21> Temp;
+ char *TempPtr = Temp.data() + Temp.size();
- char Temp[21];
- char *TempPtr = std::end(Temp);
-
- while (N) {
- *--TempPtr = '0' + char(N % 10);
+ // 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+=(
+ std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
}
public:
- OutputStream(char *StartBuf, size_t Size)
- : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
- OutputStream() = default;
- void reset(char *Buffer_, size_t BufferCapacity_) {
- CurrentPosition = 0;
- Buffer = Buffer_;
- BufferCapacity = BufferCapacity_;
+ OutputBuffer(char *StartBuf, size_t Size)
+ : Buffer(StartBuf), BufferCapacity(Size) {}
+ OutputBuffer(char *StartBuf, size_t *SizePtr)
+ : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
+ OutputBuffer() = default;
+ // Non-copyable
+ OutputBuffer(const OutputBuffer &) = delete;
+ OutputBuffer &operator=(const OutputBuffer &) = delete;
+
+ operator std::string_view() const {
+ return std::string_view(Buffer, CurrentPosition);
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
@@ -77,60 +90,91 @@
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
- OutputStream &operator+=(StringView R) {
- size_t Size = R.size();
- if (Size == 0)
- return *this;
- grow(Size);
- std::memmove(Buffer + CurrentPosition, R.begin(), Size);
- CurrentPosition += Size;
+ /// 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);
+ 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(std::string_view 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<unsigned long long>(-N), true);
- else
- writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
- OutputStream &operator<<(unsigned long long N) {
- writeUnsigned(N, false);
- return *this;
+ OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
+
+ OutputBuffer &operator<<(char C) { return (*this += C); }
+
+ OutputBuffer &operator<<(long long N) {
+ return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
}
- OutputStream &operator<<(long N) {
+ OutputBuffer &operator<<(unsigned long long N) {
+ return writeUnsigned(N, false);
+ }
+
+ OutputBuffer &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
- OutputStream &operator<<(unsigned long N) {
+ OutputBuffer &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
- OutputStream &operator<<(int N) {
+ OutputBuffer &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
- OutputStream &operator<<(unsigned int N) {
+ OutputBuffer &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
+ void insert(size_t Pos, const char *S, size_t N) {
+ assert(Pos <= CurrentPosition);
+ if (N == 0)
+ return;
+ grow(N);
+ std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
+ std::memcpy(Buffer + Pos, S, N);
+ CurrentPosition += N;
+ }
+
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
- return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
+ assert(CurrentPosition);
+ return Buffer[CurrentPosition - 1];
}
bool empty() const { return CurrentPosition == 0; }
@@ -140,52 +184,22 @@
size_t getBufferCapacity() const { return BufferCapacity; }
};
-template <class T> class SwapAndRestore {
- T &Restore;
- T OriginalValue;
- bool ShouldRestore = true;
+template <class T> 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() {
- if (ShouldRestore)
- Restore = std::move(OriginalValue);
- }
+ ~ScopedOverride() { Loc = std::move(Original); }
- void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
-
- void restoreNow(bool Force) {
- if (!Force && !ShouldRestore)
- return;
-
- Restore = std::move(OriginalValue);
- ShouldRestore = false;
- }
-
- SwapAndRestore(const SwapAndRestore &) = delete;
- SwapAndRestore &operator=(const SwapAndRestore &) = delete;
+ ScopedOverride(const ScopedOverride &) = delete;
+ ScopedOverride &operator=(const ScopedOverride &) = delete;
};
-inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
- size_t InitSize) {
- size_t BufferSize;
- if (Buf == nullptr) {
- Buf = static_cast<char *>(std::malloc(InitSize));
- if (Buf == nullptr)
- return false;
- BufferSize = InitSize;
- } else
- BufferSize = *N;
-
- S.reset(Buf, BufferSize);
- return true;
-}
-
DEMANGLE_NAMESPACE_END
#endif
diff --git a/third_party/llvm/lib/Demangle/DLangDemangle.cpp b/third_party/llvm/lib/Demangle/DLangDemangle.cpp
new file mode 100644
index 0000000..8856302
--- /dev/null
+++ b/third_party/llvm/lib/Demangle/DLangDemangle.cpp
@@ -0,0 +1,594 @@
+//===--- 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/StringViewExtras.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <cctype>
+#include <cstring>
+#include <limits>
+#include <string_view>
+
+using namespace llvm;
+using llvm::itanium_demangle::OutputBuffer;
+using llvm::itanium_demangle::starts_with;
+
+namespace {
+
+/// Demangle information structure.
+struct Demangler {
+ /// Initialize the information structure we use to pass around information.
+ ///
+ /// \param Mangled String to demangle.
+ Demangler(std::string_view 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.
+ ///
+ /// \see https://dlang.org/spec/abi.html#name_mangling .
+ /// \see https://dlang.org/spec/abi.html#MangledName .
+ 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.
+ ///
+ /// \note Ret larger than UINT_MAX is considered a failure.
+ ///
+ /// \see https://dlang.org/spec/abi.html#Number .
+ 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 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 .
+ 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 true on success, false on error.
+ ///
+ /// \see https://dlang.org/spec/abi.html#back_ref .
+ 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.
+ ///
+ /// \param Demangled output buffer to write the demangled name.
+ /// \param Mangled mangled symbol to be demangled.
+ ///
+ /// \see https://dlang.org/spec/abi.html#back_ref .
+ /// \see https://dlang.org/spec/abi.html#IdentifierBackRef .
+ 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.
+ ///
+ /// \see https://dlang.org/spec/abi.html#back_ref .
+ /// \see https://dlang.org/spec/abi.html#TypeBackRef .
+ void parseTypeBackref(std::string_view &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(std::string_view 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.
+ ///
+ /// \see https://dlang.org/spec/abi.html#SymbolName .
+ 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
+ /// 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.
+ ///
+ /// \see https://dlang.org/spec/abi.html#LName .
+ 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.
+ ///
+ /// \param Demangled Output buffer to write the demangled name.
+ /// \param Mangled Mangled symbol to be demangled.
+ ///
+ /// \see https://dlang.org/spec/abi.html#QualifiedName .
+ 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 true on success, false on error.
+ ///
+ /// \see https://dlang.org/spec/abi.html#Type .
+ bool parseType(std::string_view &Mangled);
+
+ /// An immutable view of the string we are demangling.
+ const std::string_view Str;
+ /// The index of the last back reference.
+ int LastBackref;
+};
+
+} // namespace
+
+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;
+
+ do {
+ unsigned long Digit = Mangled[0] - '0';
+
+ // Check for overflow.
+ if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10) {
+ Mangled = {};
+ return;
+ }
+
+ Val = Val * 10 + Digit;
+ Mangled.remove_prefix(1);
+ } while (!Mangled.empty() && std::isdigit(Mangled.front()));
+
+ if (Mangled.empty()) {
+ Mangled = {};
+ return;
+ }
+
+ Ret = Val;
+}
+
+bool Demangler::decodeBackrefPos(std::string_view &Mangled, long &Ret) {
+ // Return nullptr if trying to extract something that isn't a digit
+ 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
+ // 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 (!Mangled.empty() && std::isalpha(Mangled.front())) {
+ // Check for overflow
+ if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26)
+ break;
+
+ Val *= 26;
+
+ if (Mangled[0] >= 'a' && Mangled[0] <= 'z') {
+ Val += Mangled[0] - 'a';
+ if ((long)Val <= 0)
+ break;
+ Ret = Val;
+ Mangled.remove_prefix(1);
+ return true;
+ }
+
+ Val += Mangled[0] - 'A';
+ Mangled.remove_prefix(1);
+ }
+
+ Mangled = {};
+ return false;
+}
+
+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.data();
+ long RefPos;
+ Mangled.remove_prefix(1);
+
+ if (!decodeBackrefPos(Mangled, RefPos)) {
+ Mangled = {};
+ return false;
+ }
+
+ if (RefPos > Qpos - Str.data()) {
+ Mangled = {};
+ return false;
+ }
+
+ // Set the position of the back reference.
+ Ret = Qpos - RefPos;
+
+ return true;
+}
+
+void Demangler::parseSymbolBackref(OutputBuffer *Demangled,
+ std::string_view &Mangled) {
+ // An identifier back reference always points to a digit 0 to 9.
+ // IdentifierBackRef:
+ // Q NumberBackRef
+ // ^
+ unsigned long Len;
+
+ // Get position of the back reference
+ std::string_view Backref;
+ if (!decodeBackref(Mangled, Backref)) {
+ Mangled = {};
+ return;
+ }
+
+ // Must point to a simple identifier
+ decodeNumber(Backref, Len);
+ if (Backref.empty() || Backref.length() < Len) {
+ Mangled = {};
+ return;
+ }
+
+ parseLName(Demangled, Backref, Len);
+ if (Backref.empty())
+ Mangled = {};
+}
+
+void Demangler::parseTypeBackref(std::string_view &Mangled) {
+ // A type back reference always points to a letter.
+ // TypeBackRef:
+ // Q NumberBackRef
+ // ^
+
+ // If we appear to be moving backwards through the mangle string, then
+ // bail as this may be a recursive back reference.
+ if (Mangled.data() - Str.data() >= LastBackref) {
+ Mangled = {};
+ return;
+ }
+
+ int SaveRefPos = LastBackref;
+ LastBackref = Mangled.data() - Str.data();
+
+ // Get position of the back reference.
+ std::string_view Backref;
+ if (!decodeBackref(Mangled, Backref)) {
+ Mangled = {};
+ return;
+ }
+
+ // Can't decode back reference.
+ if (Backref.empty()) {
+ Mangled = {};
+ return;
+ }
+
+ // TODO: Add support for function type back references.
+ if (!parseType(Backref))
+ Mangled = {};
+
+ LastBackref = SaveRefPos;
+
+ if (Backref.empty())
+ Mangled = {};
+}
+
+bool Demangler::isSymbolName(std::string_view Mangled) {
+ long Ret;
+ const char *Qref = Mangled.data();
+
+ if (std::isdigit(Mangled.front()))
+ return true;
+
+ // TODO: Handle template instances.
+
+ if (Mangled.front() != 'Q')
+ return false;
+
+ Mangled.remove_prefix(1);
+ bool Valid = decodeBackrefPos(Mangled, Ret);
+ if (!Valid || Ret > Qref - Str.data())
+ return false;
+
+ return std::isdigit(Qref[-Ret]);
+}
+
+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
+ // _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.remove_prefix(2);
+
+ parseQualified(Demangled, Mangled);
+
+ if (Mangled.empty()) {
+ Mangled = {};
+ return;
+ }
+
+ // Artificial symbols end with 'Z' and have no type.
+ if (Mangled.front() == 'Z') {
+ Mangled.remove_prefix(1);
+ } else if (!parseType(Mangled))
+ 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.
+ // 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.empty() && Mangled.front() == '0') {
+ do
+ Mangled.remove_prefix(1);
+ while (!Mangled.empty() && Mangled.front() == '0');
+
+ continue;
+ }
+
+ if (NotFirst)
+ *Demangled << '.';
+ NotFirst = true;
+
+ parseIdentifier(Demangled, Mangled);
+ } while (!Mangled.empty() && isSymbolName(Mangled));
+}
+
+void Demangler::parseIdentifier(OutputBuffer *Demangled,
+ std::string_view &Mangled) {
+ if (Mangled.empty()) {
+ Mangled = {};
+ return;
+ }
+
+ if (Mangled.front() == 'Q')
+ return parseSymbolBackref(Demangled, Mangled);
+
+ // TODO: Parse lengthless template instances.
+
+ unsigned long Len;
+ decodeNumber(Mangled, Len);
+
+ 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 && 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.remove_prefix(Len);
+ return parseIdentifier(Demangled, Mangled);
+ }
+
+ // Else demangle it as a plain identifier.
+ }
+
+ parseLName(Demangled, Mangled, Len);
+}
+
+bool Demangler::parseType(std::string_view &Mangled) {
+ if (Mangled.empty()) {
+ Mangled = {};
+ return false;
+ }
+
+ switch (Mangled.front()) {
+ // 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.remove_prefix(1);
+ // TODO: Add type name dumping
+ return true;
+
+ // TODO: Add support for the rest of the basic types.
+
+ // Back referenced type.
+ case 'Q': {
+ parseTypeBackref(Mangled);
+ return true;
+ }
+
+ default: // unhandled.
+ Mangled = {};
+ return false;
+ }
+}
+
+void Demangler::parseLName(OutputBuffer *Demangled, std::string_view &Mangled,
+ unsigned long Len) {
+ switch (Len) {
+ case 6:
+ if (starts_with(Mangled, "__initZ")) {
+ // The static initializer for a given symbol.
+ Demangled->prepend("initializer for ");
+ Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
+ Mangled.remove_prefix(Len);
+ return;
+ }
+ if (starts_with(Mangled, "__vtblZ")) {
+ // The vtable symbol for a given class.
+ Demangled->prepend("vtable for ");
+ Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
+ Mangled.remove_prefix(Len);
+ return;
+ }
+ break;
+
+ case 7:
+ if (starts_with(Mangled, "__ClassZ")) {
+ // The classinfo symbol for a given class.
+ Demangled->prepend("ClassInfo for ");
+ Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
+ Mangled.remove_prefix(Len);
+ return;
+ }
+ break;
+
+ case 11:
+ if (starts_with(Mangled, "__InterfaceZ")) {
+ // The interface symbol for a given class.
+ Demangled->prepend("Interface for ");
+ Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
+ Mangled.remove_prefix(Len);
+ return;
+ }
+ break;
+
+ case 12:
+ if (starts_with(Mangled, "__ModuleInfoZ")) {
+ // The ModuleInfo symbol for a given module.
+ Demangled->prepend("ModuleInfo for ");
+ Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
+ Mangled.remove_prefix(Len);
+ return;
+ }
+ break;
+ }
+
+ *Demangled << Mangled.substr(0, Len);
+ Mangled.remove_prefix(Len);
+}
+
+Demangler::Demangler(std::string_view Mangled)
+ : Str(Mangled), LastBackref(Mangled.length()) {}
+
+const char *Demangler::parseMangle(OutputBuffer *Demangled) {
+ std::string_view M(this->Str);
+ parseMangle(Demangled, M);
+ return M.data();
+}
+
+char *llvm::dlangDemangle(std::string_view MangledName) {
+ if (MangledName.empty() || !starts_with(MangledName, "_D"))
+ return nullptr;
+
+ OutputBuffer Demangled;
+ if (MangledName == "_Dmain") {
+ Demangled << "D main";
+ } else {
+
+ Demangler D(MangledName);
+ const char *M = D.parseMangle(&Demangled);
+
+ // Check that the entire symbol was successfully demangled.
+ if (M == nullptr || *M != '\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 5f92153..f2aa571 100644
--- a/third_party/llvm/lib/Demangle/Demangle.cpp
+++ b/third_party/llvm/lib/Demangle/Demangle.cpp
@@ -11,26 +11,54 @@
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Demangle/StringViewExtras.h"
#include <cstdlib>
+#include <string_view>
-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';
+using llvm::itanium_demangle::starts_with;
+
+std::string llvm::demangle(std::string_view MangledName) {
+ std::string Result;
+
+ if (nonMicrosoftDemangle(MangledName, Result))
+ return Result;
+
+ if (starts_with(MangledName, '_') &&
+ nonMicrosoftDemangle(MangledName.substr(1), Result))
+ return Result;
+
+ if (char *Demangled = microsoftDemangle(MangledName, nullptr, nullptr)) {
+ Result = Demangled;
+ std::free(Demangled);
+ } else {
+ Result = MangledName;
+ }
+ return Result;
}
-std::string llvm::demangle(const std::string &MangledName) {
- char *Demangled;
+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");
+}
+
+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.c_str(), nullptr, nullptr, nullptr);
- else
- Demangled =
- microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
+ Demangled = itaniumDemangle(MangledName);
+ else if (isRustEncoding(MangledName))
+ Demangled = rustDemangle(MangledName);
+ else if (isDLangEncoding(MangledName))
+ Demangled = dlangDemangle(MangledName);
if (!Demangled)
- return MangledName;
+ return false;
- std::string Ret = Demangled;
- free(Demangled);
- return Ret;
+ Result = Demangled;
+ std::free(Demangled);
+ return true;
}
diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
index fad9b6b..e3f208f 100644
--- a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -18,10 +18,9 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <exception>
#include <functional>
-#include <numeric>
#include <utility>
-#include <vector>
using namespace llvm;
using namespace llvm::itanium_demangle;
@@ -80,8 +79,8 @@
}
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.data());
}
void print(const Node *N) {
if (N)
@@ -174,6 +173,50 @@
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");
@@ -323,36 +366,21 @@
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
-char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
- size_t *N, int *Status) {
- if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
- if (Status)
- *Status = demangle_invalid_args;
+char *llvm::itaniumDemangle(std::string_view MangledName) {
+ if (MangledName.empty())
return nullptr;
- }
- int InternalStatus = demangle_success;
- Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
- OutputStream S;
-
+ 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 (!initializeOutputStream(Buf, N, S, 1024))
- InternalStatus = demangle_memory_alloc_failure;
- else {
- assert(Parser.ForwardTemplateRefs.empty());
- AST->print(S);
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- Buf = S.getBuffer();
- }
-
- if (Status)
- *Status = InternalStatus;
- return InternalStatus == demangle_success ? Buf : nullptr;
+ OutputBuffer OB;
+ assert(Parser.ForwardTemplateRefs.empty());
+ AST->print(OB);
+ OB += '\0';
+ return OB.getBuffer();
}
ItaniumPartialDemangler::ItaniumPartialDemangler()
@@ -385,14 +413,12 @@
}
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
- RootNode->print(S);
- S += '\0';
+ OutputBuffer OB(Buf, N);
+ 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 +432,8 @@
case Node::KAbiTagAttr:
Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue;
- case Node::KStdQualifiedName:
- Name = static_cast<const StdQualifiedName *>(Name)->Child;
+ case Node::KModuleEntity:
+ Name = static_cast<const ModuleEntity *>(Name)->Name;
continue;
case Node::KNestedName:
Name = static_cast<const NestedName *>(Name)->Name;
@@ -430,9 +456,7 @@
return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
+ OutputBuffer OB(Buf, N);
KeepGoingLocalFunction:
while (true) {
@@ -447,27 +471,27 @@
break;
}
+ if (Name->getKind() == Node::KModuleEntity)
+ Name = static_cast<const ModuleEntity *>(Name)->Name;
+
switch (Name->getKind()) {
- case Node::KStdQualifiedName:
- S += "std";
- break;
case Node::KNestedName:
- static_cast<const NestedName *>(Name)->Qual->print(S);
+ static_cast<const NestedName *>(Name)->Qual->print(OB);
break;
case Node::KLocalName: {
auto *LN = static_cast<const LocalName *>(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 +507,15 @@
return nullptr;
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
+ OutputBuffer OB(Buf, N);
- 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 +523,16 @@
if (!isFunction())
return nullptr;
- OutputStream S;
- if (!initializeOutputStream(Buf, N, S, 128))
- return nullptr;
+ OutputBuffer OB(Buf, N);
if (const Node *Ret =
static_cast<const FunctionEncoding *>(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 +572,8 @@
case Node::KNestedName:
N = static_cast<const NestedName *>(N)->Name;
break;
- case Node::KStdQualifiedName:
- N = static_cast<const StdQualifiedName *>(N)->Child;
+ case Node::KModuleEntity:
+ N = static_cast<const ModuleEntity *>(N)->Name;
break;
}
}
diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
index c681d6e..cd7ff40 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 <array>
#include <cctype>
#include <cstdio>
+#include <string_view>
#include <tuple>
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 @@
// 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 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 @@
// 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 @@
// 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 @@
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 @@
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<Qualifiers, PointerAffinity>
-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 @@
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.data(), Borrowed.size());
return {Stable, Borrowed.size()};
}
SpecialTableSymbolNode *
-Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
+Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,
SpecialIntrinsicKind K) {
NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();
switch (K) {
@@ -279,20 +301,22 @@
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<LocalStaticGuardIdentifierNode>();
LSGI->IsThread = IsThread;
@@ -301,9 +325,9 @@
Arena.alloc<LocalStaticGuardVariableNode>();
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 @@
}
static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,
- StringView Name) {
+ std::string_view Name) {
NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();
Id->Name = Name;
return Id;
@@ -333,27 +357,29 @@
}
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<VariableSymbolNode>();
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<VariableSymbolNode>();
VSN->Name = QN;
- if (MangledName.consumeFront("8"))
+ if (consumeFront(MangledName, "8"))
return VSN;
Error = true;
@@ -362,7 +388,7 @@
VariableSymbolNode *
Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
- StringView &MangledName) {
+ std::string_view &MangledName) {
RttiBaseClassDescriptorNode *RBCDN =
Arena.alloc<RttiBaseClassDescriptorNode>();
RBCDN->NVOffset = demangleUnsigned(MangledName);
@@ -374,18 +400,19 @@
VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
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<DynamicStructorIdentifierNode>();
DSIN->IsDestructor = IsDestructor;
bool IsKnownStaticDataMember = false;
- if (MangledName.consumeFront('?'))
+ if (consumeFront(MangledName, '?'))
IsKnownStaticDataMember = true;
SymbolNode *Symbol = demangleDeclarator(MangledName);
@@ -403,7 +430,7 @@
// 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 @@
return FSN;
}
-SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
+SymbolNode *Demangler::demangleSpecialIntrinsic(std::string_view &MangledName) {
SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);
switch (SIK) {
@@ -450,7 +477,7 @@
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 @@
}
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 @@
}
StructorIdentifierNode *
-Demangler::demangleStructorIdentifier(StringView &MangledName,
+Demangler::demangleStructorIdentifier(std::string_view &MangledName,
bool IsDestructor) {
StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();
N->IsDestructor = IsDestructor;
@@ -508,14 +535,14 @@
}
ConversionOperatorIdentifierNode *
-Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) {
+Demangler::demangleConversionOperatorIdentifier(std::string_view &MangledName) {
ConversionOperatorIdentifierNode *N =
Arena.alloc<ConversionOperatorIdentifierNode>();
return N;
}
LiteralOperatorIdentifierNode *
-Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {
+Demangler::demangleLiteralOperatorIdentifier(std::string_view &MangledName) {
LiteralOperatorIdentifierNode *N =
Arena.alloc<LiteralOperatorIdentifierNode>();
N->Name = demangleSimpleString(MangledName, /*Memorize=*/false);
@@ -663,15 +690,17 @@
}
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 @@
translateIntrinsicFunctionCode(CH, Group));
}
case FunctionIdentifierCodeGroup::Under:
+ MangledName.remove_prefix(1);
return Arena.alloc<IntrinsicFunctionIdentifierNode>(
- 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 @@
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 @@
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 @@
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.data();
+ 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 @@
// 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<SymbolNode>(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 @@
}
// 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 @@
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 @@
// ::= 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<VariableSymbolNode>();
VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
@@ -890,12 +929,13 @@
// ::= <hex digit>+ @ # when Number == 0 or >= 10
//
// <hex-digit> ::= [A-P] # A = 0, B = 1, ...
-std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
- bool IsNegative = MangledName.consumeFront('?');
+std::pair<uint64_t, bool>
+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 @@
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 @@
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 @@
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 @@
// 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 @@
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,31 +999,25 @@
return nullptr;
}
- MangledName = MangledName.dropFront();
+ MangledName.remove_prefix(1);
return Backrefs.Names[I];
}
void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
// Render this class template name into a string buffer so that we can
// memorize it for the purpose of back-referencing.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
- Identifier->output(OS, OF_Default);
- OS << '\0';
- char *Name = OS.getBuffer();
-
- StringView Owned = copyString(Name);
+ OutputBuffer OB;
+ Identifier->output(OB, OF_Default);
+ 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 @@
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 @@
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 @@
'\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 @@
'\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 @@
return '\0';
}
-wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) {
+wchar_t Demangler::demangleWcharLiteral(std::string_view &MangledName) {
uint8_t C1, C2;
C1 = demangleCharLiteral(MangledName);
@@ -1107,7 +1145,7 @@
*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 +1168,43 @@
TempBuffer[Pos--] = 'x';
assert(Pos >= 0);
TempBuffer[Pos--] = '\\';
- OS << StringView(&TempBuffer[Pos + 1]);
+ OB << std::string_view(&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 +1212,11 @@
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) {
@@ -1252,7 +1290,8 @@
return Result;
}
-FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {
+FunctionSymbolNode *
+Demangler::demangleVcallThunkNode(std::string_view &MangledName) {
FunctionSymbolNode *FSN = Arena.alloc<FunctionSymbolNode>();
VcallThunkIdentifierNode *VTIN = Arena.alloc<VcallThunkIdentifierNode>();
FSN->Signature = Arena.alloc<ThunkSignatureNode>();
@@ -1260,42 +1299,39 @@
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.
- OutputStream OS;
- StringView CRC;
+ OutputBuffer OB;
+ 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<EncodedStringLiteralNode>();
- // Must happen before the first `goto StringLiteralError`.
- if (!initializeOutputStream(nullptr, nullptr, OS, 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 @@
// 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,12 +1360,12 @@
if (StringByteSize > 64)
Result->IsTruncated = true;
- while (!MangledName.consumeFront('@')) {
+ while (!consumeFront(MangledName, '@')) {
if (MangledName.size() < 2)
goto StringLiteralError;
wchar_t W = demangleWcharLiteral(MangledName);
if (StringByteSize != 2 || Result->IsTruncated)
- outputEscapedChar(OS, W);
+ outputEscapedChar(OB, W);
StringByteSize -= 2;
if (Error)
goto StringLiteralError;
@@ -1341,7 +1377,7 @@
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);
@@ -1371,34 +1407,32 @@
unsigned NextChar =
decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
if (CharIndex + 1 < NumChars || Result->IsTruncated)
- outputEscapedChar(OS, NextChar);
+ outputEscapedChar(OB, NextChar);
}
}
- OS << '\0';
- ResultBuffer = OS.getBuffer();
- Result->DecodedString = copyString(ResultBuffer);
- std::free(ResultBuffer);
+ Result->DecodedString = copyString(OB);
+ std::free(OB.getBuffer());
return Result;
StringLiteralError:
Error = true;
- std::free(OS.getBuffer());
+ std::free(OB.getBuffer());
return nullptr;
}
// 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 @@
}
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<NamedIdentifierNode>();
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<NamedIdentifierNode>();
- 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);
@@ -1447,24 +1481,20 @@
return nullptr;
// Render the parent symbol's name into a buffer.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
- OS << '`';
- Scope->output(OS, OF_Default);
- OS << '\'';
- OS << "::`" << Number << "'";
- OS << '\0';
- char *Result = OS.getBuffer();
- Identifier->Name = copyString(Result);
- std::free(Result);
+ OutputBuffer OB;
+ OB << '`';
+ Scope->output(OB, OF_Default);
+ OB << '\'';
+ OB << "::`" << Number << "'";
+
+ Identifier->Name = copyString(OB);
+ std::free(OB.getBuffer());
return Identifier;
}
// Parses a type name in the form of A@B@C@@ which represents C::B::A.
QualifiedNameNode *
-Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
+Demangler::demangleFullyQualifiedTypeName(std::string_view &MangledName) {
IdentifierNode *Identifier =
demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
if (Error)
@@ -1482,7 +1512,7 @@
// 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 @@
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 @@
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 @@
}
QualifiedNameNode *
-Demangler::demangleNameScopeChain(StringView &MangledName,
+Demangler::demangleNameScopeChain(std::string_view &MangledName,
IdentifierNode *UnqualifiedName) {
NodeList *Head = Arena.alloc<NodeList>();
Head->N = UnqualifiedName;
size_t Count = 1;
- while (!MangledName.consumeFront("@")) {
+ while (!consumeFront(MangledName, "@")) {
++Count;
NodeList *NewHead = Arena.alloc<NodeList>();
NewHead->Next = Head;
@@ -1598,8 +1630,10 @@
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 @@
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 @@
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;
@@ -1711,15 +1750,22 @@
return CallingConv::Eabi;
case 'Q':
return CallingConv::Vectorcall;
+ case 'S':
+ return CallingConv::Swift;
+ case 'W':
+ return CallingConv::SwiftAsync;
}
return CallingConv::None;
}
-StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
+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':
@@ -1735,13 +1781,15 @@
}
std::pair<Qualifiers, bool>
-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);
@@ -1767,14 +1815,14 @@
// <variable-type> ::= <type> <cvr-qualifiers>
// ::= <type> <pointee-cvr-qualifiers> # 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);
}
@@ -1796,11 +1844,11 @@
} 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)) {
@@ -1815,18 +1863,19 @@
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<FunctionSignatureNode>();
if (HasThisQuals) {
@@ -1840,7 +1889,7 @@
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
- bool IsStructor = MangledName.consumeFront('@');
+ bool IsStructor = consumeFront(MangledName, '@');
if (!IsStructor)
FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);
@@ -1852,9 +1901,9 @@
}
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()) {
@@ -1904,13 +1953,13 @@
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<CustomTypeNode>();
CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
- if (!MangledName.consumeFront('@'))
+ if (!consumeFront(MangledName, '@'))
Error = true;
if (Error)
return nullptr;
@@ -1918,11 +1967,14 @@
}
// 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<PrimitiveTypeNode>(PrimitiveKind::Nullptr);
- switch (MangledName.popFront()) {
+ const char F = MangledName.front();
+ MangledName.remove_prefix(1);
+ switch (F) {
case 'X':
return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Void);
case 'D':
@@ -1954,7 +2006,9 @@
Error = true;
return nullptr;
}
- switch (MangledName.popFront()) {
+ const char F = MangledName.front();
+ MangledName.remove_prefix(1);
+ switch (F) {
case 'N':
return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Bool);
case 'J':
@@ -1977,10 +2031,12 @@
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<TagTypeNode>(TagKind::Union);
break;
@@ -1991,7 +2047,7 @@
TT = Arena.alloc<TagTypeNode>(TagKind::Class);
break;
case 'W':
- if (!MangledName.consumeFront('4')) {
+ if (!consumeFront(MangledName, '4')) {
Error = true;
return nullptr;
}
@@ -2007,13 +2063,13 @@
// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
// # the E is required for 64-bit non-static pointers
-PointerTypeNode *Demangler::demanglePointerType(StringView &MangledName) {
+PointerTypeNode *Demangler::demanglePointerType(std::string_view &MangledName) {
PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
std::tie(Pointer->Quals, Pointer->Affinity) =
demanglePointerCVQualifiers(MangledName);
- if (MangledName.consumeFront("6")) {
+ if (consumeFront(MangledName, "6")) {
Pointer->Pointee = demangleFunctionType(MangledName, false);
return Pointer;
}
@@ -2025,7 +2081,8 @@
return Pointer;
}
-PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {
+PointerTypeNode *
+Demangler::demangleMemberPointerType(std::string_view &MangledName) {
PointerTypeNode *Pointer = Arena.alloc<PointerTypeNode>();
std::tie(Pointer->Quals, Pointer->Affinity) =
@@ -2037,7 +2094,7 @@
// 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 {
@@ -2055,21 +2112,22 @@
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;
@@ -2098,7 +2156,7 @@
}
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) {
@@ -2112,17 +2170,18 @@
}
// 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>();
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)) {
@@ -2131,7 +2190,7 @@
Error = true;
return nullptr;
}
- MangledName = MangledName.dropFront();
+ MangledName.remove_prefix(1);
*Current = Arena.alloc<NodeList>();
(*Current)->N = Backrefs.FunctionParams[N];
@@ -2166,10 +2225,10 @@
// 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;
}
@@ -2178,14 +2237,14 @@
}
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;
}
@@ -2198,29 +2257,32 @@
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<TemplateParameterReferenceNode>();
TPRN->IsMemberPointer = true;
- MangledName = MangledName.dropFront();
+ MangledName.remove_prefix(1);
// 1 - single inheritance <name>
// H - multiple inheritance <name> <number>
// I - virtual inheritance <name> <number> <number>
// J - unspecified inheritance <name> <number> <number> <number>
- char InheritanceSpecifier = MangledName.popFront();
+ 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;
@@ -2249,18 +2311,20 @@
}
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<TemplateParameterReferenceNode>();
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<TemplateParameterReferenceNode>();
// 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':
@@ -2278,7 +2342,7 @@
}
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;
@@ -2299,8 +2363,9 @@
// 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);
}
@@ -2309,39 +2374,37 @@
(int)Backrefs.FunctionParamCount);
// Create an output stream so we can render each type.
- OutputStream OS;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- std::terminate();
+ OutputBuffer OB;
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::string_view B = OB;
+ std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.data());
}
- std::free(OS.getBuffer());
+ std::free(OB.getBuffer());
if (Backrefs.FunctionParamCount > 0)
std::printf("\n");
std::printf("%d name backreferences\n", (int)Backrefs.NamesCount);
for (size_t I = 0; I < Backrefs.NamesCount; ++I) {
std::printf(" [%d] - %.*s\n", (int)I, (int)Backrefs.Names[I]->Name.size(),
- Backrefs.Names[I]->Name.begin());
+ Backrefs.Names[I]->Name.data());
}
if (Backrefs.NamesCount > 0)
std::printf("\n");
}
-char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
+char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled,
int *Status, MSDemangleFlags Flags) {
- int InternalStatus = demangle_success;
Demangler D;
- OutputStream S;
- StringView Name{MangledName};
+ std::string_view Name{MangledName};
SymbolNode *AST = D.parse(Name);
+ if (!D.Error && NMangled)
+ *NMangled = MangledName.size() - Name.size();
if (Flags & MSDF_DumpBackrefs)
D.dumpBackReferences();
@@ -2355,17 +2418,18 @@
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;
+ char *Buf;
if (D.Error)
InternalStatus = demangle_invalid_mangled_name;
- else if (!initializeOutputStream(Buf, N, S, 1024))
- InternalStatus = demangle_memory_alloc_failure;
else {
- AST->output(S, OF);
- S += '\0';
- if (N != nullptr)
- *N = S.getCurrentPosition();
- Buf = S.getBuffer();
+ OutputBuffer OB;
+ AST->output(OB, OF);
+ OB += '\0';
+ Buf = OB.getBuffer();
}
if (Status)
diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
index 9cee975..9a9c34e 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 <cctype>
#include <string>
@@ -21,91 +20,97 @@
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
case Enum::Value: \
- OS << Desc; \
+ OB << Desc; \
break;
// Writes a space if the last token does not end with a punctuation.
-static void outputSpaceIfNecessary(OutputStream &OS) {
- if (OS.empty())
+static void outputSpaceIfNecessary(OutputBuffer &OB) {
+ if (OB.empty())
return;
- char C = OS.back();
+ char C = OB.back();
if (std::isalnum(C) || C == '>')
- OS << " ";
+ OB << " ";
}
-static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
+static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) {
switch (Q) {
case Q_Const:
- OS << "const";
+ OB << "const";
break;
case Q_Volatile:
- OS << "volatile";
+ OB << "volatile";
break;
case Q_Restrict:
- OS << "__restrict";
+ OB << "__restrict";
break;
default:
break;
}
}
-static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
+static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q,
Qualifiers Mask, bool NeedSpace) {
if (!(Q & Mask))
return NeedSpace;
if (NeedSpace)
- OS << " ";
+ OB << " ";
- outputSingleQualifier(OS, Mask);
+ outputSingleQualifier(OB, Mask);
return true;
}
-static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
+static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
bool SpaceAfter) {
if (Q == Q_None)
return;
- size_t Pos1 = OS.getCurrentPosition();
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
- SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
- size_t Pos2 = OS.getCurrentPosition();
+ size_t Pos1 = OB.getCurrentPosition();
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
+ SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
+ size_t Pos2 = OB.getCurrentPosition();
if (SpaceAfter && Pos2 > Pos1)
- OS << " ";
+ OB << " ";
}
-static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
- outputSpaceIfNecessary(OS);
+static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) {
+ outputSpaceIfNecessary(OB);
switch (CC) {
case CallingConv::Cdecl:
- OS << "__cdecl";
+ OB << "__cdecl";
break;
case CallingConv::Fastcall:
- OS << "__fastcall";
+ OB << "__fastcall";
break;
case CallingConv::Pascal:
- OS << "__pascal";
+ OB << "__pascal";
break;
case CallingConv::Regcall:
- OS << "__regcall";
+ OB << "__regcall";
break;
case CallingConv::Stdcall:
- OS << "__stdcall";
+ OB << "__stdcall";
break;
case CallingConv::Thiscall:
- OS << "__thiscall";
+ OB << "__thiscall";
break;
case CallingConv::Eabi:
- OS << "__eabi";
+ OB << "__eabi";
break;
case CallingConv::Vectorcall:
- OS << "__vectorcall";
+ OB << "__vectorcall";
break;
case CallingConv::Clrcall:
- OS << "__clrcall";
+ OB << "__clrcall";
+ break;
+ case CallingConv::Swift:
+ OB << "__attribute__((__swiftcall__)) ";
+ break;
+ case CallingConv::SwiftAsync:
+ OB << "__attribute__((__swiftasynccall__)) ";
break;
default:
break;
@@ -113,14 +118,15 @@
}
std::string Node::toString(OutputFlags Flags) const {
- OutputStream OS;
- initializeOutputStream(nullptr, nullptr, OS, 1024);
- this->output(OS, Flags);
- OS << '\0';
- return {OS.getBuffer()};
+ OutputBuffer OB;
+ this->output(OB, Flags);
+ std::string_view SV = OB;
+ std::string Owned(SV.begin(), SV.end());
+ std::free(OB.getBuffer());
+ return Owned;
}
-void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
switch (PrimKind) {
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
@@ -144,107 +150,107 @@
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,
- StringView Separator) const {
+void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags,
+ std::string_view Separator) const {
if (Count == 0)
return;
if (Nodes[0])
- Nodes[0]->output(OS, Flags);
+ Nodes[0]->output(OB, Flags);
for (size_t I = 1; I < Count; ++I) {
- OS << Separator;
- Nodes[I]->output(OS, Flags);
+ OB << Separator;
+ Nodes[I]->output(OB, Flags);
}
}
-void EncodedStringLiteralNode::output(OutputStream &OS,
+void EncodedStringLiteralNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
switch (Char) {
case CharKind::Wchar:
- OS << "L\"";
+ OB << "L\"";
break;
case CharKind::Char:
- OS << "\"";
+ OB << "\"";
break;
case CharKind::Char16:
- OS << "u\"";
+ OB << "u\"";
break;
case CharKind::Char32:
- OS << "U\"";
+ OB << "U\"";
break;
}
- OS << DecodedString << "\"";
+ OB << DecodedString << "\"";
if (IsTruncated)
- OS << "...";
+ OB << "...";
}
-void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
+void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const {
if (IsNegative)
- OS << '-';
- OS << Value;
+ OB << '-';
+ OB << Value;
}
-void TemplateParameterReferenceNode::output(OutputStream &OS,
+void TemplateParameterReferenceNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
if (ThunkOffsetCount > 0)
- OS << "{";
+ OB << "{";
else if (Affinity == PointerAffinity::Pointer)
- OS << "&";
+ OB << "&";
if (Symbol) {
- Symbol->output(OS, Flags);
+ Symbol->output(OB, Flags);
if (ThunkOffsetCount > 0)
- OS << ", ";
+ OB << ", ";
}
if (ThunkOffsetCount > 0)
- OS << ThunkOffsets[0];
+ OB << ThunkOffsets[0];
for (int I = 1; I < ThunkOffsetCount; ++I) {
- OS << ", " << ThunkOffsets[I];
+ OB << ", " << ThunkOffsets[I];
}
if (ThunkOffsetCount > 0)
- OS << "}";
+ OB << "}";
}
-void IdentifierNode::outputTemplateParameters(OutputStream &OS,
+void IdentifierNode::outputTemplateParameters(OutputBuffer &OB,
OutputFlags Flags) const {
if (!TemplateParams)
return;
- OS << "<";
- TemplateParams->output(OS, Flags);
- OS << ">";
+ OB << "<";
+ TemplateParams->output(OB, Flags);
+ OB << ">";
}
-void DynamicStructorIdentifierNode::output(OutputStream &OS,
+void DynamicStructorIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
if (IsDestructor)
- OS << "`dynamic atexit destructor for ";
+ OB << "`dynamic atexit destructor for ";
else
- OS << "`dynamic initializer for ";
+ OB << "`dynamic initializer for ";
if (Variable) {
- OS << "`";
- Variable->output(OS, Flags);
- OS << "''";
+ OB << "`";
+ Variable->output(OB, Flags);
+ OB << "''";
} else {
- OS << "'";
- Name->output(OS, Flags);
- OS << "''";
+ OB << "'";
+ Name->output(OB, Flags);
+ OB << "''";
}
}
-void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
- OS << Name;
- outputTemplateParameters(OS, Flags);
+void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ OB << Name;
+ outputTemplateParameters(OB, Flags);
}
-void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
+void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
switch (Operator) {
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
@@ -342,188 +348,188 @@
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<const FunctionSignatureNode *>(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<const FunctionSignatureNode *>(Pointee);
- outputCallingConvention(OS, Sig->CallConvention);
- OS << " ";
+ outputCallingConvention(OB, Sig->CallConvention);
+ OB << " ";
}
if (ClassParent) {
- ClassParent->output(OS, Flags);
- OS << "::";
+ ClassParent->output(OB, Flags);
+ OB << "::";
}
switch (Affinity) {
case PointerAffinity::Pointer:
- OS << "*";
+ OB << "*";
break;
case PointerAffinity::Reference:
- OS << "&";
+ OB << "&";
break;
case PointerAffinity::RValueReference:
- OS << "&&";
+ OB << "&&";
break;
default:
assert(false);
}
- outputQualifiers(OS, Quals, false, false);
+ outputQualifiers(OB, Quals, false, false);
}
-void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
+void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
if (Pointee->kind() == NodeKind::ArrayType ||
Pointee->kind() == NodeKind::FunctionSignature)
- OS << ")";
+ OB << ")";
- Pointee->outputPost(OS, Flags);
+ Pointee->outputPost(OB, Flags);
}
-void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
+void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
if (!(Flags & OF_NoTagSpecifier)) {
switch (Tag) {
OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
@@ -531,59 +537,59 @@
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<IntegerLiteralNode *>(N);
if (ILN->Value != 0)
- ILN->output(OS, Flags);
+ ILN->output(OB, Flags);
}
-void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
+void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB,
OutputFlags Flags) const {
if (Dimensions->Count == 0)
return;
- outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
+ outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
for (size_t I = 1; I < Dimensions->Count; ++I) {
- OS << "][";
- outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
+ OB << "][";
+ outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
}
}
-void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
- OS << "[";
- outputDimensionsImpl(OS, Flags);
- OS << "]";
+void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
+ OB << "[";
+ outputDimensionsImpl(OB, Flags);
+ OB << "]";
- ElementType->outputPost(OS, Flags);
+ ElementType->outputPost(OB, Flags);
}
-void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- Name->output(OS, Flags);
+void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Name->output(OB, Flags);
}
-void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- Signature->outputPre(OS, Flags);
- outputSpaceIfNecessary(OS);
- Name->output(OS, Flags);
- Signature->outputPost(OS, Flags);
+void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Signature->outputPre(OB, Flags);
+ outputSpaceIfNecessary(OB);
+ Name->output(OB, Flags);
+ Signature->outputPost(OB, Flags);
}
-void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
+void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
const char *AccessSpec = nullptr;
bool IsStatic = true;
switch (SC) {
@@ -601,53 +607,52 @@
break;
}
if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
- OS << AccessSpec << ": ";
+ OB << AccessSpec << ": ";
if (!(Flags & OF_NoMemberType) && IsStatic)
- OS << "static ";
+ OB << "static ";
- if (Type) {
- Type->outputPre(OS, Flags);
- outputSpaceIfNecessary(OS);
+ if (!(Flags & OF_NoVariableType) && Type) {
+ Type->outputPre(OB, Flags);
+ outputSpaceIfNecessary(OB);
}
- Name->output(OS, Flags);
- if (Type)
- Type->outputPost(OS, Flags);
+ Name->output(OB, Flags);
+ if (!(Flags & OF_NoVariableType) && Type)
+ Type->outputPost(OB, Flags);
}
-void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
- Identifier->output(OS, Flags);
+void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
+ Identifier->output(OB, Flags);
}
-void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
+void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
-void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
- Components->output(OS, Flags, "::");
+void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ Components->output(OB, Flags, "::");
}
-void RttiBaseClassDescriptorNode::output(OutputStream &OS,
+void RttiBaseClassDescriptorNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
- OS << "`RTTI Base Class Descriptor at (";
- OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
+ OB << "`RTTI Base Class Descriptor at (";
+ OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
<< this->Flags;
- OS << ")'";
+ OB << ")'";
}
-void LocalStaticGuardVariableNode::output(OutputStream &OS,
+void LocalStaticGuardVariableNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
- Name->output(OS, Flags);
+ Name->output(OB, Flags);
}
-void VcallThunkIdentifierNode::output(OutputStream &OS,
+void VcallThunkIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
- OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
+ OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
}
-void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
- outputQualifiers(OS, Quals, false, true);
- Name->output(OS, Flags);
+void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
+ outputQualifiers(OB, Quals, false, true);
+ Name->output(OB, Flags);
if (TargetName) {
- OS << "{for `";
- TargetName->output(OS, Flags);
- OS << "'}";
+ OB << "{for `";
+ TargetName->output(OB, Flags);
+ OB << "'}";
}
- return;
}
diff --git a/third_party/llvm/lib/Demangle/RustDemangle.cpp b/third_party/llvm/lib/Demangle/RustDemangle.cpp
new file mode 100644
index 0000000..f0d70de
--- /dev/null
+++ b/third_party/llvm/lib/Demangle/RustDemangle.cpp
@@ -0,0 +1,1259 @@
+//===--- 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/StringViewExtras.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <string_view>
+
+using namespace llvm;
+
+using llvm::itanium_demangle::OutputBuffer;
+using llvm::itanium_demangle::ScopedOverride;
+using llvm::itanium_demangle::starts_with;
+
+namespace {
+
+struct Identifier {
+ std::string_view 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.
+ std::string_view Input;
+ // Position in the input string.
+ size_t Position;
+ // When true, print methods append the output to the stream.
+ // When false, the output is suppressed.
+ bool Print;
+ // True if an error occurred.
+ bool Error;
+
+public:
+ // Demangled output.
+ OutputBuffer Output;
+
+ Demangler(size_t MaxRecursionLevel = 500);
+
+ bool demangle(std::string_view 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 <typename Callable> void demangleBackref(Callable Demangler) {
+ uint64_t Backref = parseBase62Number();
+ if (Error || Backref >= Position) {
+ Error = true;
+ return;
+ }
+
+ if (!Print)
+ return;
+
+ ScopedOverride<size_t> SavePosition(Position, Position);
+ Position = Backref;
+ Demangler();
+ }
+
+ Identifier parseIdentifier();
+ uint64_t parseOptionalBase62Number(char Tag);
+ uint64_t parseBase62Number();
+ uint64_t parseDecimalNumber();
+ uint64_t parseHexNumber(std::string_view &HexDigits);
+
+ void print(char C);
+ void print(std::string_view S);
+ void printDecimalNumber(uint64_t N);
+ void printBasicType(BasicType);
+ void printLifetime(uint64_t Index);
+ void printIdentifier(Identifier Ident);
+
+ char look() const;
+ char consume();
+ bool consumeIf(char Prefix);
+
+ bool addAssign(uint64_t &A, uint64_t B);
+ bool mulAssign(uint64_t &A, uint64_t B);
+};
+
+} // namespace
+
+char *llvm::rustDemangle(std::string_view MangledName) {
+ // Return early if mangled name doesn't look like a Rust symbol.
+ if (MangledName.empty() || !starts_with(MangledName, "_R"))
+ return nullptr;
+
+ Demangler D;
+ if (!D.demangle(MangledName)) {
+ std::free(D.Output.getBuffer());
+ return nullptr;
+ }
+
+ D.Output += '\0';
+
+ return D.Output.getBuffer();
+}
+
+Demangler::Demangler(size_t MaxRecursionLevel)
+ : MaxRecursionLevel(MaxRecursionLevel) {}
+
+static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
+
+static inline bool isHexDigit(const char C) {
+ return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
+}
+
+static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
+
+static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
+
+/// Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
+static inline bool isValid(const char C) {
+ return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
+}
+
+// Demangles Rust v0 mangled symbol. Returns true when successful, and false
+// otherwise. The demangled symbol is stored in Output field. It is
+// responsibility of the caller to free the memory behind the output stream.
+//
+// <symbol-name> = "_R" <path> [<instantiating-crate>]
+bool Demangler::demangle(std::string_view Mangled) {
+ Position = 0;
+ Error = false;
+ Print = true;
+ RecursionLevel = 0;
+ BoundLifetimes = 0;
+
+ if (!starts_with(Mangled, "_R")) {
+ Error = true;
+ return false;
+ }
+ Mangled.remove_prefix(2);
+ size_t Dot = Mangled.find('.');
+ Input = Dot == std::string_view::npos ? Mangled : Mangled.substr(0, Dot);
+
+ demanglePath(IsInType::No);
+
+ if (Position != Input.size()) {
+ ScopedOverride<bool> SavePrint(Print, false);
+ demanglePath(IsInType::No);
+ }
+
+ if (Position != Input.size())
+ Error = true;
+
+ if (Dot != std::string_view::npos) {
+ print(" (");
+ print(Mangled.substr(Dot));
+ 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.
+//
+// <path> = "C" <identifier> // crate root
+// | "M" <impl-path> <type> // <T> (inherent impl)
+// | "X" <impl-path> <type> <path> // <T as Trait> (trait impl)
+// | "Y" <type> <path> // <T as Trait> (trait definition)
+// | "N" <ns> <path> <identifier> // ...::ident (nested path)
+// | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
+// | <backref>
+// <identifier> = [<disambiguator>] <undisambiguated-identifier>
+// <ns> = "C" // closure
+// | "S" // shim
+// | <A-Z> // other special namespaces
+// | <a-z> // internal namespaces
+bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) {
+ if (Error || RecursionLevel >= MaxRecursionLevel) {
+ Error = true;
+ return false;
+ }
+ ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
+
+ switch (consume()) {
+ case 'C': {
+ parseOptionalBase62Number('s');
+ printIdentifier(parseIdentifier());
+ break;
+ }
+ case 'M': {
+ demangleImplPath(InType);
+ print("<");
+ demangleType();
+ print(">");
+ break;
+ }
+ case 'X': {
+ demangleImplPath(InType);
+ print("<");
+ demangleType();
+ print(" as ");
+ demanglePath(IsInType::Yes);
+ print(">");
+ break;
+ }
+ case 'Y': {
+ print("<");
+ demangleType();
+ print(" as ");
+ demanglePath(IsInType::Yes);
+ print(">");
+ break;
+ }
+ case 'N': {
+ char NS = consume();
+ if (!isLower(NS) && !isUpper(NS)) {
+ Error = true;
+ break;
+ }
+ demanglePath(InType);
+
+ uint64_t Disambiguator = parseOptionalBase62Number('s');
+ Identifier Ident = parseIdentifier();
+
+ if (isUpper(NS)) {
+ // Special namespaces
+ print("::{");
+ if (NS == 'C')
+ print("closure");
+ else if (NS == 'S')
+ print("shim");
+ else
+ print(NS);
+ if (!Ident.empty()) {
+ print(":");
+ printIdentifier(Ident);
+ }
+ print('#');
+ printDecimalNumber(Disambiguator);
+ print('}');
+ } else {
+ // Implementation internal namespaces.
+ if (!Ident.empty()) {
+ print("::");
+ printIdentifier(Ident);
+ }
+ }
+ break;
+ }
+ case 'I': {
+ demanglePath(InType);
+ // Omit "::" when in a type, where it is optional.
+ if (InType == IsInType::No)
+ print("::");
+ print("<");
+ for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
+ if (I > 0)
+ print(", ");
+ demangleGenericArg();
+ }
+ if (LeaveOpen == LeaveGenericsOpen::Yes)
+ return true;
+ else
+ print(">");
+ break;
+ }
+ case 'B': {
+ bool IsOpen = false;
+ demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
+ return IsOpen;
+ }
+ default:
+ Error = true;
+ break;
+ }
+
+ return false;
+}
+
+// <impl-path> = [<disambiguator>] <path>
+// <disambiguator> = "s" <base-62-number>
+void Demangler::demangleImplPath(IsInType InType) {
+ ScopedOverride<bool> SavePrint(Print, false);
+ parseOptionalBase62Number('s');
+ demanglePath(InType);
+}
+
+// <generic-arg> = <lifetime>
+// | <type>
+// | "K" <const>
+// <lifetime> = "L" <base-62-number>
+void Demangler::demangleGenericArg() {
+ if (consumeIf('L'))
+ printLifetime(parseBase62Number());
+ else if (consumeIf('K'))
+ demangleConst();
+ else
+ demangleType();
+}
+
+// <basic-type> = "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;
+ }
+}
+
+// <type> = | <basic-type>
+// | <path> // named type
+// | "A" <type> <const> // [T; N]
+// | "S" <type> // [T]
+// | "T" {<type>} "E" // (T1, T2, T3, ...)
+// | "R" [<lifetime>] <type> // &T
+// | "Q" [<lifetime>] <type> // &mut T
+// | "P" <type> // *const T
+// | "O" <type> // *mut T
+// | "F" <fn-sig> // fn(...) -> ...
+// | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
+// | <backref> // backref
+void Demangler::demangleType() {
+ if (Error || RecursionLevel >= MaxRecursionLevel) {
+ Error = true;
+ return;
+ }
+ ScopedOverride<size_t> 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;
+ }
+}
+
+// <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
+// <abi> = "C"
+// | <undisambiguated-identifier>
+void Demangler::demangleFnSig() {
+ ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
+ demangleOptionalBinder();
+
+ if (consumeIf('U'))
+ print("unsafe ");
+
+ if (consumeIf('K')) {
+ print("extern \"");
+ if (consumeIf('C')) {
+ print("C");
+ } else {
+ Identifier Ident = parseIdentifier();
+ if (Ident.Punycode)
+ Error = true;
+ for (char C : Ident.Name) {
+ // When mangling ABI string, the "-" is replaced with "_".
+ if (C == '_')
+ C = '-';
+ print(C);
+ }
+ }
+ print("\" ");
+ }
+
+ print("fn(");
+ for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
+ if (I > 0)
+ print(", ");
+ demangleType();
+ }
+ print(")");
+
+ if (consumeIf('u')) {
+ // Skip the unit type from the output.
+ } else {
+ print(" -> ");
+ demangleType();
+ }
+}
+
+// <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
+void Demangler::demangleDynBounds() {
+ ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
+ print("dyn ");
+ demangleOptionalBinder();
+ for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
+ if (I > 0)
+ print(" + ");
+ demangleDynTrait();
+ }
+}
+
+// <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
+// <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
+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.
+//
+// <binder> = "G" <base-62-number>
+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("> ");
+}
+
+// <const> = <basic-type> <const-data>
+// | "p" // placeholder
+// | <backref>
+void Demangler::demangleConst() {
+ if (Error || RecursionLevel >= MaxRecursionLevel) {
+ Error = true;
+ return;
+ }
+ ScopedOverride<size_t> 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;
+ }
+}
+
+// <const-data> = ["n"] <hex-number>
+void Demangler::demangleConstInt() {
+ if (consumeIf('n'))
+ print('-');
+
+ std::string_view HexDigits;
+ uint64_t Value = parseHexNumber(HexDigits);
+ if (HexDigits.size() <= 16) {
+ printDecimalNumber(Value);
+ } else {
+ print("0x");
+ print(HexDigits);
+ }
+}
+
+// <const-data> = "0_" // false
+// | "1_" // true
+void Demangler::demangleConstBool() {
+ std::string_view 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;
+}
+
+// <const-data> = <hex-number>
+void Demangler::demangleConstChar() {
+ std::string_view 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('\'');
+}
+
+// <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
+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 {};
+ }
+ std::string_view 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.
+//
+// <base-62-number> = {<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.
+//
+// <decimal-number> = "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.
+//
+// <hex-number> = "0_"
+// | <1-9a-f> {<0-9a-f>} "_"
+uint64_t Demangler::parseHexNumber(std::string_view &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 = std::string_view();
+ 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(std::string_view S) {
+ if (Error || !Print)
+ return;
+
+ Output += S;
+}
+
+void Demangler::printDecimalNumber(uint64_t N) {
+ if (Error || !Print)
+ return;
+
+ Output << N;
+}
+
+// Prints a lifetime. An index 0 always represents an erased lifetime. Indices
+// starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
+// bound by one of the enclosing binders.
+void Demangler::printLifetime(uint64_t Index) {
+ if (Index == 0) {
+ print("'_");
+ return;
+ }
+
+ if (Index - 1 >= BoundLifetimes) {
+ Error = true;
+ return;
+ }
+
+ uint64_t Depth = BoundLifetimes - Index;
+ print('\'');
+ if (Depth < 26) {
+ char C = 'a' + Depth;
+ print(C);
+ } else {
+ print('z');
+ printDecimalNumber(Depth - 26 + 1);
+ }
+}
+
+static inline bool decodePunycodeDigit(char C, size_t &Value) {
+ if (isLower(C)) {
+ Value = C - 'a';
+ return true;
+ }
+
+ if (isDigit(C)) {
+ Value = 26 + (C - '0');
+ return true;
+ }
+
+ return false;
+}
+
+static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) {
+ char *Buffer = Output.getBuffer();
+ char *Start = Buffer + StartIdx;
+ char *End = Buffer + Output.getCurrentPosition();
+ Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer);
+}
+
+// Encodes code point as UTF-8 and stores results in Output. Returns false if
+// CodePoint is not a valid unicode scalar value.
+static inline bool encodeUTF8(size_t CodePoint, char *Output) {
+ if (0xD800 <= CodePoint && CodePoint <= 0xDFFF)
+ return false;
+
+ if (CodePoint <= 0x7F) {
+ Output[0] = CodePoint;
+ return true;
+ }
+
+ if (CodePoint <= 0x7FF) {
+ Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F);
+ Output[1] = 0x80 | (CodePoint & 0x3F);
+ return true;
+ }
+
+ if (CodePoint <= 0xFFFF) {
+ Output[0] = 0xE0 | (CodePoint >> 12);
+ Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F);
+ Output[2] = 0x80 | (CodePoint & 0x3F);
+ return true;
+ }
+
+ if (CodePoint <= 0x10FFFF) {
+ Output[0] = 0xF0 | (CodePoint >> 18);
+ Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F);
+ Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F);
+ Output[3] = 0x80 | (CodePoint & 0x3F);
+ return true;
+ }
+
+ return false;
+}
+
+// Decodes string encoded using punycode and appends results to Output.
+// Returns true if decoding was successful.
+static bool decodePunycode(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 = std::string_view::npos;
+ for (size_t I = 0; I != Input.size(); ++I)
+ if (Input[I] == '_')
+ DelimiterPos = I;
+
+ 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];
+ if (!isValid(C))
+ return false;
+ // Code points are padded with zeros while decoding is in progress.
+ char UTF8[4] = {C};
+ Output += std::string_view(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<size_t>::max();
+ for (size_t K = Base; true; K += Base) {
+ if (InputIdx == Input.size())
+ return false;
+ char C = Input[InputIdx++];
+ size_t Digit = 0;
+ if (!decodePunycodeDigit(C, Digit))
+ return false;
+
+ if (Digit > (Max - I) / W)
+ return false;
+ I += Digit * W;
+
+ size_t T;
+ if (K <= Bias)
+ T = TMin;
+ else if (K >= Bias + TMax)
+ T = TMax;
+ else
+ T = K - Bias;
+
+ if (Digit < T)
+ break;
+
+ if (W > Max / (Base - T))
+ return false;
+ W *= (Base - T);
+ }
+ size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1;
+ Bias = Adapt(I - OldI, NumPoints);
+
+ if (I / NumPoints > Max - N)
+ return false;
+ N += I / NumPoints;
+ I = I % NumPoints;
+
+ // Insert N at position I in the output.
+ char UTF8[4] = {};
+ if (!encodeUTF8(N, UTF8))
+ return false;
+ Output.insert(OutputSize + I * 4, UTF8, 4);
+ }
+
+ removeNullBytes(Output, OutputSize);
+ return true;
+}
+
+void Demangler::printIdentifier(Identifier Ident) {
+ if (Error || !Print)
+ return;
+
+ if (Ident.Punycode) {
+ if (!decodePunycode(Ident.Name, Output))
+ Error = true;
+ } else {
+ print(Ident.Name);
+ }
+}
+
+char Demangler::look() const {
+ if (Error || Position >= Input.size())
+ return 0;
+
+ return Input[Position];
+}
+
+char Demangler::consume() {
+ if (Error || Position >= Input.size()) {
+ Error = true;
+ return 0;
+ }
+
+ return Input[Position++];
+}
+
+bool Demangler::consumeIf(char Prefix) {
+ if (Error || Position >= Input.size() || Input[Position] != Prefix)
+ return false;
+
+ Position += 1;
+ return true;
+}
+
+/// Computes A + B. When computation wraps around sets the error and returns
+/// false. Otherwise assigns the result to A and returns true.
+bool Demangler::addAssign(uint64_t &A, uint64_t B) {
+ if (A > std::numeric_limits<uint64_t>::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<uint64_t>::max() / B) {
+ Error = true;
+ return false;
+ }
+
+ A *= B;
+ return true;
+}