diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-01-29 16:35:13 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-01 15:33:35 +0000 |
commit | c8c2d1901aec01e934adf561a9fdf0cc776cdef8 (patch) | |
tree | 9157c3d9815e5870799e070b113813bec53e0535 /chromium/buildtools | |
parent | abefd5095b41dac94ca451d784ab6e27372e981a (diff) | |
download | qtwebengine-chromium-c8c2d1901aec01e934adf561a9fdf0cc776cdef8.tar.gz |
BASELINE: Update Chromium to 64.0.3282.139
Change-Id: I1cae68fe9c94ff7608b26b8382fc19862cdb293a
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/buildtools')
50 files changed, 3885 insertions, 2005 deletions
diff --git a/chromium/buildtools/DEPS b/chromium/buildtools/DEPS index fde9a08366e..4beb84451e1 100644 --- a/chromium/buildtools/DEPS +++ b/chromium/buildtools/DEPS @@ -4,9 +4,9 @@ vars = { "chromium_url": "https://chromium.googlesource.com", "clang_format_rev": "0653eee0c81ea04715c635dd0885e8096ff6ba6d", # r302580 - "libcxx_revision": "3a07dd740be63878167a0ea19fe81869954badd7", # r303878 - "libcxxabi_revision": "4072e8fd76febee37f60aeda76d6d9f5e3791daa", # r303806 - "libunwind_revision": "41f982e5887185b904a456e20dfcd58e6be6cc19", # r306442 + "libcxx_revision": "f56f1bba1ade4a408d403ff050d50e837bae47df", # r317124 + "libcxxabi_revision": "05ba3281482304ae8de31123a594972a495da06d", # r313308 + "libunwind_revision": "fc0a910c25d5415dd72ba9451b7cba380e3cc1e7", # r317125 } deps = { diff --git a/chromium/buildtools/checkdeps/checkdeps.py b/chromium/buildtools/checkdeps/checkdeps.py index 1bf6bacf4b3..f4777abb3a2 100755 --- a/chromium/buildtools/checkdeps/checkdeps.py +++ b/chromium/buildtools/checkdeps/checkdeps.py @@ -148,12 +148,14 @@ class DepsChecker(DepsBuilder): return self.CheckIncludesAndImports( added_includes, cpp_checker.CppChecker(self.verbose)) - def CheckAddedJavaImports(self, added_imports): + def CheckAddedJavaImports(self, added_imports, allow_multiple_definitions=None): """This is used from PRESUBMIT.py to check new import statements added in the change being presubmit checked. Args: added_imports: ((file_path, (import_line, import_line, ...), ...) + allow_multiple_definitions: [file_name, file_name, ...]. List of java file + names allowing multipe definition in presubmit check. Return: A list of tuples, (bad_file_path, rule_type, rule_description) @@ -162,7 +164,8 @@ class DepsChecker(DepsBuilder): """ return self.CheckIncludesAndImports( added_imports, - java_checker.JavaChecker(self.base_directory, self.verbose)) + java_checker.JavaChecker(self.base_directory, self.verbose, + added_imports, allow_multiple_definitions)) def CheckAddedProtoImports(self, added_imports): """This is used from PRESUBMIT.py to check new #import statements added in diff --git a/chromium/buildtools/checkdeps/java_checker.py b/chromium/buildtools/checkdeps/java_checker.py index ff85a7d6fc8..f59b776ea3d 100644 --- a/chromium/buildtools/checkdeps/java_checker.py +++ b/chromium/buildtools/checkdeps/java_checker.py @@ -37,11 +37,25 @@ class JavaChecker(object): # statements. _EXTRACT_IMPORT_PATH = re.compile('^import\s+(?:static\s+)?([\w\.]+)\s*;') - def __init__(self, base_directory, verbose): + def __init__(self, base_directory, verbose, added_imports=None, + allow_multiple_definitions=None): self._base_directory = base_directory self._verbose = verbose self._classmap = {} - self._PrescanFiles() + self._allow_multiple_definitions = allow_multiple_definitions or [] + if added_imports: + added_classset = self._PrescanImportFiles(added_imports) + self._PrescanFiles(added_classset) + + def _GetClassFullName(self, filepath): + """Get the full class name of a file with package name.""" + if not os.path.isfile(filepath): + return None + with codecs.open(filepath, encoding='utf-8') as f: + short_class_name, _ = os.path.splitext(os.path.basename(filepath)) + for line in f: + for package in re.findall('^package\s+([\w\.]+);', line): + return package + '.' + short_class_name def _IgnoreDir(self, d): # Skip hidden directories. @@ -59,7 +73,7 @@ class JavaChecker(object): return True return False - def _PrescanFiles(self): + def _PrescanFiles(self, added_classset): for root, dirs, files in os.walk(self._base_directory): # Skip unwanted subdirectories. TODO(husky): it would be better to do # this via the skip_child_includes flag in DEPS files. Maybe hoist this @@ -67,24 +81,48 @@ class JavaChecker(object): dirs[:] = [d for d in dirs if not self._IgnoreDir(d)] for f in files: if f.endswith('.java'): - self._PrescanFile(os.path.join(root, f)) + self._PrescanFile(os.path.join(root, f), added_classset) + + def _PrescanImportFiles(self, added_imports): + """Build a set of fully-qualified class affected by this patch. + + Prescan imported files and build classset to collect full class names + with package name. This includes both changed files as well as changed imports. + + Args: + added_imports : ((file_path, (import_line, import_line, ...), ...) - def _PrescanFile(self, filepath): + Return: + A set of full class names with package name of imported files. + """ + classset = set() + for filepath, changed_lines in (added_imports or []): + if not self.ShouldCheck(filepath): + continue + full_class_name = self._GetClassFullName(filepath) + if full_class_name: + classset.add(full_class_name) + for line in changed_lines: + found_item = self._EXTRACT_IMPORT_PATH.match(line) + if found_item: + classset.add(found_item.group(1)) + return classset + + def _PrescanFile(self, filepath, added_classset): if self._verbose: print 'Prescanning: ' + filepath - with codecs.open(filepath, encoding='utf-8') as f: - short_class_name, _ = os.path.splitext(os.path.basename(filepath)) - for line in f: - for package in re.findall('^package\s+([\w\.]+);', line): - full_class_name = package + '.' + short_class_name - if full_class_name in self._classmap: + full_class_name = self._GetClassFullName(filepath) + if full_class_name: + if full_class_name in self._classmap: + if self._verbose or full_class_name in added_classset: + if not any((re.match(i, filepath) for i in self._allow_multiple_definitions)): print 'WARNING: multiple definitions of %s:' % full_class_name print ' ' + filepath print ' ' + self._classmap[full_class_name] print - else: - self._classmap[full_class_name] = filepath - return + else: + self._classmap[full_class_name] = filepath + elif self._verbose: print 'WARNING: no package definition found in %s' % filepath def CheckLine(self, rules, line, filepath, fail_on_temp_allow=False): diff --git a/chromium/buildtools/linux64/gn.sha1 b/chromium/buildtools/linux64/gn.sha1 index feb5ba6e579..87d556346da 100644 --- a/chromium/buildtools/linux64/gn.sha1 +++ b/chromium/buildtools/linux64/gn.sha1 @@ -1 +1 @@ -15cc6942069e0463e11752fcdf2244dbeec78a43 +113f5b30a7cfae72015600a119590d45d64c0d0d diff --git a/chromium/buildtools/mac/gn.sha1 b/chromium/buildtools/mac/gn.sha1 index 2ed516e6cea..c7d13b67ab4 100644 --- a/chromium/buildtools/mac/gn.sha1 +++ b/chromium/buildtools/mac/gn.sha1 @@ -1 +1 @@ -f04ec3c6cffc5cf85275b498cbd02e4777b4c518 +b33a6d33c2b2f42762f902672ffdf4837fa1c662 diff --git a/chromium/buildtools/third_party/libc++/BUILD.gn b/chromium/buildtools/third_party/libc++/BUILD.gn index e49a49c842e..ecb42ca679c 100644 --- a/chromium/buildtools/third_party/libc++/BUILD.gn +++ b/chromium/buildtools/third_party/libc++/BUILD.gn @@ -70,19 +70,33 @@ target(link_target_type, "libc++") { "trunk/src/utility.cpp", "trunk/src/valarray.cpp", "trunk/src/variant.cpp", + "trunk/src/vector.cpp", ] configs -= [ "//build/config/compiler:chromium_code", + "//build/config/compiler:no_exceptions", "//build/config/compiler:no_rtti", - "//build/config/gcc:no_exceptions", + "//build/config/coverage:default_coverage", ] + if (is_android && !libcpp_is_static) { + configs -= [ "//build/config/android:hide_all_but_jni_onload" ] + } configs += [ ":config", "//build/config/compiler:no_chromium_code", + "//build/config/compiler:exceptions", "//build/config/compiler:rtti", "//build/config/sanitizers:sanitizer_options_link_helper", ] + defines = [ "_LIBCPP_BUILDING_LIBRARY" ] + if (!is_clang && !libcpp_is_static) { + # This is a temporary workaround to get libc++ builds working with + # gcc. It can be removed with either + # https://reviews.llvm.org/D35326 or + # https://reviews.llvm.org/D35388 lands. + defines += [ "_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS=__attribute__((__visibility__(\"default\")))" ] + } deps = [ "//buildtools/third_party/libc++abi", diff --git a/chromium/buildtools/third_party/libc++/README.chromium b/chromium/buildtools/third_party/libc++/README.chromium index b92145d3e38..0c6fbeeee84 100644 --- a/chromium/buildtools/third_party/libc++/README.chromium +++ b/chromium/buildtools/third_party/libc++/README.chromium @@ -4,10 +4,8 @@ URL: http://libcxx.llvm.org/ Version: 1.0 License: MIT, University of Illinois/NCSA Open Source License License File: trunk/LICENSE.TXT -Security Critical: no +Security Critical: yes Description: libc++ for Chromium. -This is intended for instrumented builds, not for release. -There was no security review for this library. diff --git a/chromium/buildtools/third_party/libc++abi/BUILD.gn b/chromium/buildtools/third_party/libc++abi/BUILD.gn index cf33e624bee..ef5e2f6047b 100644 --- a/chromium/buildtools/third_party/libc++abi/BUILD.gn +++ b/chromium/buildtools/third_party/libc++abi/BUILD.gn @@ -4,10 +4,11 @@ source_set("libc++abi") { visibility = [ "//buildtools/third_party/libc++" ] + deps = [] # This condition should match the one in build/config/c++. - if ((is_linux && current_cpu == "arm") || is_fuchsia) { - deps = [ + if (current_cpu == "arm" || is_fuchsia) { + deps += [ "//buildtools/third_party/libunwind", ] } @@ -15,7 +16,6 @@ source_set("libc++abi") { "trunk/src/abort_message.cpp", "trunk/src/cxa_aux_runtime.cpp", "trunk/src/cxa_default_handlers.cpp", - "trunk/src/cxa_demangle.cpp", "trunk/src/cxa_exception.cpp", "trunk/src/cxa_exception_storage.cpp", "trunk/src/cxa_guard.cpp", @@ -34,6 +34,14 @@ source_set("libc++abi") { "trunk/src/stdlib_stdexcept.cpp", "trunk/src/stdlib_typeinfo.cpp", ] + + # On Android, android_crazy_linker provides __cxa_demangle. + if (is_android) { + deps += [ "//third_party/android_crazy_linker" ] + } else { + sources += [ "trunk/src/cxa_demangle.cpp" ] + } + # This file should really be included on linux as well, but that # would introduce an unwanted glibc 2.18 dependency. if (is_posix && !is_mac && !is_linux) { @@ -41,11 +49,13 @@ source_set("libc++abi") { } configs -= [ "//build/config/compiler:chromium_code", + "//build/config/compiler:no_exceptions", "//build/config/compiler:no_rtti", - "//build/config/gcc:no_exceptions", + "//build/config/coverage:default_coverage", ] configs += [ "//build/config/compiler:no_chromium_code", + "//build/config/compiler:exceptions", "//build/config/compiler:rtti", "//buildtools/third_party/libc++:config", ] diff --git a/chromium/buildtools/third_party/libc++abi/README.chromium b/chromium/buildtools/third_party/libc++abi/README.chromium index c676b3befb0..a57429eeaa3 100644 --- a/chromium/buildtools/third_party/libc++abi/README.chromium +++ b/chromium/buildtools/third_party/libc++abi/README.chromium @@ -4,10 +4,8 @@ URL: http://libcxxabi.llvm.org/ Version: 1.0 License: MIT, University of Illinois/NCSA Open Source License License File: trunk/LICENSE.TXT -Security Critical: no +Security Critical: yes Description: libc++abi for Chromium. -This is intended for instrumented builds, not for release. -There was no security review for this library. diff --git a/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt b/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt index 2a0b4da1621..456250e6d89 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt +++ b/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt @@ -1,3 +1,5 @@ +# See www/CMake.html for instructions on how to build libcxxabi with CMake. + #=============================================================================== # Setup Project #=============================================================================== @@ -16,121 +18,28 @@ set(CMAKE_MODULE_PATH ) if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - project(libcxxabi) - - # Rely on llvm-config. - set(CONFIG_OUTPUT) - if (NOT LLVM_CONFIG_PATH) - find_program(LLVM_CONFIG_PATH "llvm-config") - endif() - if(DEFINED LLVM_PATH) - set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") - set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) - set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") - elseif(LLVM_CONFIG_PATH) - message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") - set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} - "--includedir" - "--prefix" - "--src-root") - execute_process( - COMMAND ${CONFIG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE CONFIG_OUTPUT - ) - if(NOT HAD_ERROR) - string(REGEX REPLACE - "[ \t]*[\r\n]+[ \t]*" ";" - CONFIG_OUTPUT ${CONFIG_OUTPUT}) - else() - string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") - message(STATUS "${CONFIG_COMMAND_STR}") - message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") - endif() - - list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) - list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) - list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) - - set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") - set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") - set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py") - - # --cmakedir is supported since llvm r291218 (4.0 release) - execute_process( - COMMAND ${LLVM_CONFIG_PATH} --cmakedir - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE CONFIG_OUTPUT - ERROR_QUIET) - if(NOT HAD_ERROR) - string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) - else() - set(LLVM_CMAKE_PATH - "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") - endif() - else() - message(FATAL_ERROR "llvm-config not found and LLVM_MAIN_SRC_DIR not defined. " - "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config " - "or -DLLVM_PATH=path/to/llvm-source-root.") - endif() - - if(EXISTS ${LLVM_CMAKE_PATH}) - list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") - include("${LLVM_CMAKE_PATH}/AddLLVM.cmake") - include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake") - else() - message(FATAL_ERROR "Not found: ${LLVM_CMAKE_PATH}") - endif() + project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 5.0.0svn) + set(PACKAGE_VERSION 6.0.0svn) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") - if (NOT DEFINED LLVM_INCLUDE_TESTS) - set(LLVM_INCLUDE_TESTS ON) - endif() - - if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - else() - # Seek installed Lit. - find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit - DOC "Path to lit.py") - endif() - - if(LLVM_LIT) - # Define the default arguments to use with 'lit', and an option for the user - # to override. - set(LIT_ARGS_DEFAULT "-sv") - if (MSVC OR XCODE) - set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") - endif() - set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") - - # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. - if( WIN32 AND NOT CYGWIN ) - set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") - endif() - else() - set(LLVM_INCLUDE_TESTS OFF) - endif() - - set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING - "Define suffix of library directory name (32/64)") - - set(LIBCXXABI_STANDALONE_BUILD 1) -else() - set(LLVM_MAIN_SRC_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "Path to LLVM source tree") - set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py") - set(LIBCXXABI_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX}) + # Find the LLVM sources and simulate LLVM CMake options. + include(HandleOutOfTreeLLVM) endif() +# Require out of source build. +include(MacroEnsureOutOfSourceBuild) +MACRO_ENSURE_OUT_OF_SOURCE_BUILD( + "${PROJECT_NAME} requires an out of source build. Please create a separate + build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there." + ) + #=============================================================================== # Setup CMake Options #=============================================================================== +include(CMakeDependentOption) include(HandleCompilerRT) # Define options. @@ -158,6 +67,8 @@ option(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS provides these definitions" ON) option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS}) option(LIBCXXABI_INCLUDE_TESTS "Generate build targets for the libc++abi unit tests." ${LLVM_INCLUDE_TESTS}) +set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") @@ -245,8 +156,16 @@ else() set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) endif() +set(LIBCXXABI_INSTALL_PREFIX "" CACHE STRING + "Define libc++abi destination prefix.") + +if (NOT LIBCXXABI_INSTALL_PREFIX MATCHES "^$|.*/") + message(FATAL_ERROR "LIBCXXABI_INSTALL_PREFIX has to end with \"/\".") +endif() + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) # By default, for non-standalone builds, libcxx and libcxxabi share a library # directory. @@ -264,30 +183,26 @@ elseif(LIBCXXABI_BUILD_32_BITS) message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.") endif() -#=============================================================================== -# Setup Compiler Flags -#=============================================================================== - -# Get required flags. -macro(append_if list condition var) - if (${condition}) - list(APPEND ${list} ${var}) - endif() -endmacro() - -macro(add_target_flags_if condition var) - if (${condition}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${var}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${var}") - list(APPEND LIBCXXABI_COMPILE_FLAGS ${var}) - list(APPEND LIBCXXABI_LINK_FLAGS ${var}) - endif() -endmacro() +# Declare libc++abi configuration variables. +# They are intended for use as follows: +# LIBCXXABI_C_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_CXX_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_COMPILE_FLAGS: Compile only flags. +# LIBCXXABI_LINK_FLAGS: Linker only flags. +# LIBCXXABI_LIBRARIES: libraries libc++abi is linked to. set(LIBCXXABI_C_FLAGS "") set(LIBCXXABI_CXX_FLAGS "") set(LIBCXXABI_COMPILE_FLAGS "") set(LIBCXXABI_LINK_FLAGS "") +set(LIBCXXABI_LIBRARIES "") + +# Include macros for adding and removing libc++abi flags. +include(HandleLibcxxabiFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== # Configure target flags add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") @@ -322,56 +237,57 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) # Disable DLL annotations on Windows for static builds. if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) - add_definitions(-D_LIBCXXABI_DISABLE_DLL_IMPORT_EXPORT) + add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) endif() -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror=return-type) +add_compile_flags_if_supported(-Werror=return-type) # Get warning flags -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_W_FLAG -W) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WALL_FLAG -Wall) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG -Wchar-subscripts) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCONVERSION_FLAG -Wconversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG -Wmismatched-tags) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISSING_BRACES_FLAG -Wmissing-braces) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNEWLINE_EOF_FLAG -Wnewline-eof) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_FUNCTION_FLAG -Wunused-function) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHADOW_FLAG -Wshadow) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG -Wshorten-64-to-32) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_COMPARE_FLAG -Wsign-compare) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG -Wsign-conversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG -Wstrict-aliasing=2) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG -Wstrict-overflow=4) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG -Wunused-parameter) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG -Wunused-variable) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WWRITE_STRINGS_FLAG -Wwrite-strings) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNDEF_FLAG -Wundef) +add_compile_flags_if_supported(-W) +add_compile_flags_if_supported(-Wall) +add_compile_flags_if_supported(-Wchar-subscripts) +add_compile_flags_if_supported(-Wconversion) +add_compile_flags_if_supported(-Wmismatched-tags) +add_compile_flags_if_supported(-Wmissing-braces) +add_compile_flags_if_supported(-Wnewline-eof) +add_compile_flags_if_supported(-Wunused-function) +add_compile_flags_if_supported(-Wshadow) +add_compile_flags_if_supported(-Wshorten-64-to-32) +add_compile_flags_if_supported(-Wsign-compare) +add_compile_flags_if_supported(-Wsign-conversion) +add_compile_flags_if_supported(-Wstrict-aliasing=2) +add_compile_flags_if_supported(-Wstrict-overflow=4) +add_compile_flags_if_supported(-Wunused-parameter) +add_compile_flags_if_supported(-Wunused-variable) +add_compile_flags_if_supported(-Wwrite-strings) +add_compile_flags_if_supported(-Wundef) if (LIBCXXABI_ENABLE_WERROR) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WX_FLAG -WX) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) else() - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_ERROR_FLAG -Wno-error) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_NO_WX_FLAG -WX-) + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) endif() if (LIBCXXABI_ENABLE_PEDANTIC) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_PEDANTIC_FLAG -pedantic) + add_compile_flags_if_supported(-pedantic) endif() # Get feature flags. -append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG -fstrict-aliasing) +add_compile_flags_if_supported(-fstrict-aliasing) # Exceptions if (LIBCXXABI_ENABLE_EXCEPTIONS) # Catches C++ exceptions only and tells the compiler to assume that extern C # functions never throw a C++ exception. - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_EHSC_FLAG -EHsc) - append_if(LIBCXXABI_C_FLAGS LIBCXXABI_HAS_FUNWIND_TABLES -funwind-tables) + add_compile_flags_if_supported(-EHsc) + # Do we really need to be run through the C compiler ? + add_c_compile_flags_if_supported(-funwind-tables) else() add_definitions(-D_LIBCXXABI_NO_EXCEPTIONS) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG -fno-exceptions) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHS_FLAG -EHs-) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHA_FLAG -EHa-) + add_compile_flags_if_supported(-fno-exceptions) + add_compile_flags_if_supported(-EHs-) + add_compile_flags_if_supported(-EHa-) endif() # Assert @@ -429,6 +345,12 @@ if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) endif() endif() +if (LLVM_ENABLE_MODULES) + # Ignore that the rest of the modules flags are now unused. + add_compile_flags_if_supported(-Wno-unused-command-line-argument) + add_compile_flags(-fno-modules) +endif() + set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS OFF) if ((NOT LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) OR (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXXABI_ENABLE_SHARED) @@ -504,21 +426,6 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) NO_DEFAULT_PATH ) - find_path( - LIBCXXABI_LIBUNWIND_SOURCES - libunwind_ext.h - PATHS ${LIBCXXABI_LIBUNWIND_PATH}/src/ - ${LIBCXXABI_LIBUNWIND_INCLUDES}/../src/ - ${LLVM_MAIN_SRC_DIR}/projects/libunwind/src/ - ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/src/ - NO_DEFAULT_PATH - ) - - if (LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "LIBCXXABI_LIBUNWIND_SOURCES-NOTFOUND") - message(WARNING "LIBCXXABI_LIBUNWIND_SOURCES was not specified and couldn't be infered.") - set(LIBCXXABI_LIBUNWIND_SOURCES "") - endif() - if (LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL-NOTFOUND") set(LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL "") endif() @@ -526,10 +433,6 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) if (NOT LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "") include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}") endif() - - if (NOT LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "") - include_directories("${LIBCXXABI_LIBUNWIND_SOURCES}") - endif() endif() # Add source code. This also contains all of the logic for deciding linker flags diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake new file mode 100644 index 00000000000..3eddd7bdc62 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake @@ -0,0 +1,208 @@ +# HandleLibcxxFlags - A set of macros used to setup the flags used to compile +# and link libc++abi. These macros add flags to the following CMake variables. +# - LIBCXXABI_COMPILE_FLAGS: flags used to compile libc++abi +# - LIBCXXABI_LINK_FLAGS: flags used to link libc++abi +# - LIBCXXABI_LIBRARIES: libraries to link libc++abi to. + +include(CheckCXXCompilerFlag) + +unset(add_flag_if_supported) + +# Mangle the name of a compiler flag into a valid CMake identifier. +# Ex: --std=c++11 -> STD_EQ_CXX11 +macro(mangle_name str output) + string(STRIP "${str}" strippedStr) + string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") + string(REPLACE "-" "_" strippedStr "${strippedStr}") + string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") + string(REPLACE "+" "X" strippedStr "${strippedStr}") + string(TOUPPER "${strippedStr}" ${output}) +endmacro() + +# Remove a list of flags from all CMake variables that affect compile flags. +# This can be used to remove unwanted flags specified on the command line +# or added in other parts of LLVM's cmake configuration. +macro(remove_flags) + foreach(var ${ARGN}) + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") + remove_definitions(${var}) + endforeach() +endmacro(remove_flags) + +macro(check_flag_supported flag) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") +endmacro() + +# Add a macro definition if condition is true. +macro(define_if condition def) + if (${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition if condition is not true. +macro(define_if_not condition def) + if (NOT ${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition to the __config_site file if the specified condition +# is 'true'. Note that '-D${def}' is not added. Instead it is expected that +# the build include the '__config_site' header. +macro(config_define_if condition def) + if (${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define_if_not condition def) + if (NOT ${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define value def) + set(${def} ${value}) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) +endmacro() + +# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags) + foreach(value ${ARGN}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to +# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXXABI_COMPILE_FLAGS' +# and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags_if condition) + if (${condition}) + add_target_flags(${ARGN}) + endif() +endmacro() + +# Add a specified list of flags to both 'LIBCXXABI_COMPILE_FLAGS' and +# 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags) + foreach(value ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to both +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags_if condition) + if (${condition}) + add_flags(${ARGN}) + endif() +endmacro() + +# Add each flag in the list to LIBCXXABI_COMPILE_FLAGS and LIBCXXABI_LINK_FLAGS +# if that flag is supported by the current compiler. +macro(add_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_COMPILE_FLAGS'. +macro(add_compile_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_COMPILE_FLAGS' +macro(add_compile_flags_if condition) + if (${condition}) + add_compile_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C compiler. +macro(add_c_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_c_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_LINK_FLAGS'. +macro(add_link_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_LINK_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_LINK_FLAGS' +macro(add_link_flags_if condition) + if (${condition}) + add_link_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_LINK_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_link_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of libraries or link flags to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags) + foreach(lib ${ARGN}) + list(APPEND LIBCXXABI_LIBRARIES ${lib}) + endforeach() +endmacro() + +# if 'condition' is true then add the specified list of libraries and flags +# to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags_if condition) + if(${condition}) + add_library_flags(${ARGN}) + endif() +endmacro() + +# Turn a comma separated CMake list into a space separated string. +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake new file mode 100644 index 00000000000..8e742088978 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake @@ -0,0 +1,131 @@ +macro(find_llvm_parts) +# Rely on llvm-config. + set(CONFIG_OUTPUT) + if(NOT LLVM_CONFIG_PATH) + find_program(LLVM_CONFIG_PATH "llvm-config") + endif() + if(DEFINED LLVM_PATH) + set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") + set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) + set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") + elseif(LLVM_CONFIG_PATH) + message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") + set(LIBCXXABI_USING_INSTALLED_LLVM 1) + set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} + "--includedir" + "--prefix" + "--src-root") + execute_process( + COMMAND ${CONFIG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ) + if(NOT HAD_ERROR) + string(REGEX REPLACE + "[ \t]*[\r\n]+[ \t]*" ";" + CONFIG_OUTPUT ${CONFIG_OUTPUT}) + else() + string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") + message(STATUS "${CONFIG_COMMAND_STR}") + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + + list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) + list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) + list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) + + set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + + # --cmakedir is supported since llvm r291218 (4.0 release) + execute_process( + COMMAND ${LLVM_CONFIG_PATH} --cmakedir + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ERROR_QUIET) + if(NOT HAD_ERROR) + string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) + else() + set(LLVM_CMAKE_PATH + "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") + endif() + else() + set(LLVM_FOUND OFF) + message(WARNING "UNSUPPORTED LIBCXXABI CONFIGURATION DETECTED: " + "llvm-config not found and LLVM_PATH not defined.\n" + "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config " + "or -DLLVM_PATH=path/to/llvm-source-root.") + return() + endif() + + if (EXISTS "${LLVM_CMAKE_PATH}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + elseif (EXISTS "${LLVM_MAIN_SRC_DIR}/cmake/modules") + list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules") + else() + set(LLVM_FOUND OFF) + message(WARNING "Neither ${LLVM_CMAKE_PATH} nor ${LLVM_MAIN_SRC_DIR}/cmake/modules found") + return() + endif() + + set(LLVM_FOUND ON) +endmacro(find_llvm_parts) + +macro(configure_out_of_tree_llvm) + message(STATUS "Configuring for standalone build.") + set(LIBCXXABI_STANDALONE_BUILD 1) + + find_llvm_parts() + + # Add LLVM Functions -------------------------------------------------------- + if (LLVM_FOUND AND LIBCXXABI_USING_INSTALLED_LLVM) + include(LLVMConfig) # For TARGET_TRIPLE + else() + if (WIN32) + set(LLVM_ON_UNIX 0) + set(LLVM_ON_WIN32 1) + else() + set(LLVM_ON_UNIX 1) + set(LLVM_ON_WIN32 0) + endif() + endif() + if (LLVM_FOUND) + include(AddLLVM OPTIONAL) + include(HandleLLVMOptions OPTIONAL) + endif() + + # LLVM Options -------------------------------------------------------------- + if (NOT DEFINED LLVM_INCLUDE_TESTS) + set(LLVM_INCLUDE_TESTS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_INCLUDE_DOCS) + set(LLVM_INCLUDE_DOCS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_ENABLE_SPHINX) + set(LLVM_ENABLE_SPHINX OFF) + endif() + + # Required LIT Configuration ------------------------------------------------ + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + # Required doc configuration + if (LLVM_ENABLE_SPHINX) + find_package(Sphinx REQUIRED) + endif() + + if (LLVM_ON_UNIX AND NOT APPLE) + set(LLVM_HAVE_LINK_VERSION_SCRIPT 1) + else() + set(LLVM_HAVE_LINK_VERSION_SCRIPT 0) + endif() +endmacro(configure_out_of_tree_llvm) + +configure_out_of_tree_llvm() diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 00000000000..e75002bd8b7 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,18 @@ +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>) + +macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) + +string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) +if( _insource ) + message( SEND_ERROR "${_errorMessage}" ) + message( FATAL_ERROR + "In-source builds are not allowed. + CMake would overwrite the makefiles distributed with libcxxabi. + Please create a directory and run cmake from there, passing the path + to this source directory as the last argument. + This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. + Please delete them." + ) +endif( _insource ) + +endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake index 5541ed41a0f..379b5547749 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake @@ -36,7 +36,7 @@ if (LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) set(MINGW_RUNTIME gcc_s gcc) endif() set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 - shell32 user32 kernel32 iconv mingw32 ${MINGW_RUNTIME} + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) endif() @@ -50,7 +50,6 @@ endif () # Check compiler flags check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES) -check_cxx_compiler_flag(-fPIC LIBCXXABI_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fno-exceptions LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fno-rtti LIBCXXABI_HAS_NO_RTTI_FLAG) check_cxx_compiler_flag(-fstrict-aliasing LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG) @@ -82,11 +81,6 @@ check_cxx_compiler_flag(/EHsc LIBCXXABI_HAS_EHSC_FLAG) check_cxx_compiler_flag(/EHs- LIBCXXABI_HAS_NO_EHS_FLAG) check_cxx_compiler_flag(/EHa- LIBCXXABI_HAS_NO_EHA_FLAG) check_cxx_compiler_flag(/GR- LIBCXXABI_HAS_NO_GR_FLAG) -check_cxx_compiler_flag(-std=c++11 LIBCXXABI_HAS_STD_CXX11) - -if(LIBCXXABI_HAS_STD_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -endif() # Check libraries check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt b/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt index d844b7fb718..adcc412880c 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt @@ -52,36 +52,32 @@ if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) endif() -# Generate library list -set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES}) - if (LIBCXXABI_ENABLE_THREADS) - append_if(libraries LIBCXXABI_HAS_PTHREAD_LIB pthread) + add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) endif() -append_if(libraries LIBCXXABI_HAS_C_LIB c) +add_library_flags_if(LIBCXXABI_HAS_C_LIB c) if (LIBCXXABI_USE_LLVM_UNWINDER) # Prefer using the in-tree version of libunwind, either shared or static. If # none are found fall back to using -lunwind. # FIXME: Is it correct to prefer the static version of libunwind? if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND libraries unwind_shared) + list(APPEND LIBCXXABI_LIBRARIES unwind_shared) elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND libraries unwind_static) + list(APPEND LIBCXXABI_LIBRARIES unwind_static) else() - list(APPEND libraries unwind) + list(APPEND LIBCXXABI_LIBRARIES unwind) endif() else() - append_if(libraries LIBCXXABI_HAS_GCC_S_LIB gcc_s) + add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) endif() if (MINGW) # MINGW_LIBRARIES is defined in config-ix.cmake - list(APPEND libraries ${MINGW_LIBRARIES}) + list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) endif() # Setup flags. -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_FPIC_FLAG -fPIC) -append_if(LIBCXXABI_LINK_FLAGS LIBCXXABI_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs) +add_link_flags_if_supported(-nodefaultlibs) set(LIBCXXABI_SHARED_LINK_FLAGS) @@ -101,9 +97,9 @@ if ( APPLE ) endif() endif() -string(REPLACE ";" " " LIBCXXABI_COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_SHARED_LINK_FLAGS "${LIBCXXABI_SHARED_LINK_FLAGS}") +split_list(LIBCXXABI_COMPILE_FLAGS) +split_list(LIBCXXABI_LINK_FLAGS) +split_list(LIBCXXABI_SHARED_LINK_FLAGS) # FIXME: libc++abi.so will not link when modules are enabled because it depends # on symbols defined in libc++.so which has not yet been built. @@ -113,37 +109,64 @@ endif() # Add a object library that contains the compiled source files. add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - set_target_properties(cxxabi_objects - PROPERTIES - COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + COMPILE_FLAGS + "${LIBCXXABI_COMPILE_FLAGS}" + POSITION_INDEPENDENT_CODE + ON) set(LIBCXXABI_TARGETS) # Build the shared library. if (LIBCXXABI_ENABLE_SHARED) add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>) - target_link_libraries(cxxabi_shared ${libraries}) + target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_shared - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - VERSION "1.0" - SOVERSION "1" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON + SOVERSION + "1" + VERSION + "1.0") list(APPEND LIBCXXABI_TARGETS "cxxabi_shared") endif() # Build the static library. if (LIBCXXABI_ENABLE_STATIC) add_library(cxxabi_static STATIC $<TARGET_OBJECTS:cxxabi_objects>) - target_link_libraries(cxxabi_static ${libraries}) + target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_static - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON) list(APPEND LIBCXXABI_TARGETS "cxxabi_static") endif() @@ -151,8 +174,8 @@ endif() add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS}) install(TARGETS ${LIBCXXABI_TARGETS} - LIBRARY DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ARCHIVE DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi ) if (NOT CMAKE_CONFIGURATION_TYPES) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp index d8734fbbf9d..7d173189835 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp @@ -13,8 +13,8 @@ #include <vector> #include <algorithm> -#include <string> #include <numeric> +#include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> @@ -41,75 +41,1669 @@ enum success }; -template <class C> - const char* parse_type(const char* first, const char* last, C& db); -template <class C> - const char* parse_encoding(const char* first, const char* last, C& db); -template <class C> - const char* parse_name(const char* first, const char* last, C& db, - bool* ends_with_template_args = 0); -template <class C> - const char* parse_expression(const char* first, const char* last, C& db); -template <class C> - const char* parse_template_args(const char* first, const char* last, C& db); -template <class C> - const char* parse_operator_name(const char* first, const char* last, C& db); -template <class C> - const char* parse_unqualified_name(const char* first, const char* last, C& db); -template <class C> - const char* parse_decltype(const char* first, const char* last, C& db); - -template <class C> -void -print_stack(const C& db) +class StringView { + const char *First; + const char *Last; + +public: + template <size_t N> + StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} + StringView(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + StringView() : First(nullptr), Last(nullptr) {} + + StringView substr(size_t From, size_t To) { + if (To >= size()) + To = size() - 1; + if (From >= size()) + From = size() - 1; + return StringView(First + From, First + To); + } + + StringView dropFront(size_t N) const { + if (N >= size()) + N = size() - 1; + return StringView(First + N, Last); + } + + bool startsWith(StringView Str) const { + if (Str.size() > size()) + return false; + return std::equal(Str.begin(), Str.end(), begin()); + } + + const char &operator[](size_t Idx) const { return *(begin() + Idx); } + + const char *begin() const { return First; } + const char *end() const { return Last; } + size_t size() const { return static_cast<size_t>(Last - First); } +}; + +bool operator==(const StringView &LHS, const StringView &RHS) { + return LHS.size() == RHS.size() && + std::equal(LHS.begin(), LHS.end(), RHS.begin()); +} + +// Stream that AST nodes write their string representation into after the AST +// has been parsed. +class OutputStream { + char *Buffer; + size_t CurrentPosition; + size_t BufferCapacity; + + // Ensure there is at least n more positions in buffer. + void grow(size_t N) { + if (N + CurrentPosition >= BufferCapacity) { + BufferCapacity *= 2; + if (BufferCapacity < N + CurrentPosition) + BufferCapacity = N + CurrentPosition; + Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); + } + } + +public: + OutputStream(char *StartBuf, size_t Size) + : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} + + OutputStream &operator+=(StringView R) { + size_t Size = R.size(); + if (Size == 0) + return *this; + grow(Size); + memmove(Buffer + CurrentPosition, R.begin(), Size); + CurrentPosition += Size; + return *this; + } + + OutputStream &operator+=(char C) { + grow(1); + Buffer[CurrentPosition++] = C; + return *this; + } + + // Offset of position in buffer, used for building stream_string_view. + typedef unsigned StreamPosition; + + // StringView into a stream, used for caching the ast nodes. + class StreamStringView { + StreamPosition First, Last; + + friend class OutputStream; + + public: + StreamStringView() : First(0), Last(0) {} + + StreamStringView(StreamPosition First_, StreamPosition Last_) + : First(First_), Last(Last_) {} + + bool empty() const { return First == Last; } + }; + + OutputStream &operator+=(StreamStringView &s) { + size_t Sz = static_cast<size_t>(s.Last - s.First); + if (Sz == 0) + return *this; + grow(Sz); + memmove(Buffer + CurrentPosition, Buffer + s.First, Sz); + CurrentPosition += Sz; + return *this; + } + + StreamPosition getCurrentPosition() const { + return static_cast<StreamPosition>(CurrentPosition); + } + + StreamStringView makeStringViewFromPastPosition(StreamPosition Pos) { + return StreamStringView(Pos, getCurrentPosition()); + } + + char back() const { + return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + } + + bool empty() const { return CurrentPosition == 0; } + + char *getBuffer() { return Buffer; } + char *getBufferEnd() { return Buffer + CurrentPosition - 1; } + size_t getBufferCapacity() { return BufferCapacity; } +}; + +// 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 { + KDotSuffix, + KVendorExtQualType, + KQualType, + KConversionOperatorType, + KPostfixQualifiedType, + KNameType, + KObjCProtoName, + KPointerType, + KLValueReferenceType, + KRValueReferenceType, + KPointerToMemberType, + KArrayType, + KFunctionType, + KTopLevelFunctionDecl, + KFunctionQualType, + KFunctionRefQualType, + KLiteralOperator, + KSpecialName, + KCtorVtableSpecialName, + KQualifiedName, + KEmptyName, + KVectorType, + KTemplateParams, + KNameWithTemplateArgs, + KGlobalQualifiedName, + KStdQualifiedName, + KExpandedSpecialSubstitution, + KSpecialSubstitution, + KCtorDtorName, + KDtorName, + KUnnamedTypeName, + KLambdaTypeName, + KExpr, + }; + + const Kind K; + +private: + // If this Node has any RHS part, potentally many Nodes further down. + const unsigned HasRHSComponent : 1; + const unsigned HasFunction : 1; + const unsigned HasArray : 1; + +public: + Node(Kind K_, bool HasRHS_ = false, bool HasFunction_ = false, + bool HasArray_ = false) + : K(K_), HasRHSComponent(HasRHS_), HasFunction(HasFunction_), + HasArray(HasArray_) {} + + bool hasRHSComponent() const { return HasRHSComponent; } + bool hasArray() const { return HasArray; } + bool hasFunction() const { return HasFunction; } + + void print(OutputStream &s) const { + printLeft(s); + if (hasRHSComponent()) + printRight(s); + } + + // Print the "left" side of this Node into OutputStream. + virtual void printLeft(OutputStream &) const = 0; + + // Print the "right". This distinction is necessary to represent C++ types + // that appear on the RHS of their subtype, such as arrays or functions. + // Since most types don't have such a component, provide a default + // implemenation. + virtual void printRight(OutputStream &) const {} + + virtual StringView getBaseName() const { return StringView(); } + + // Silence compiler warnings, this dtor will never be called. + virtual ~Node() = default; +}; + +class NodeArray { + Node **Elements; + size_t NumElements; + +public: + NodeArray() : NumElements(0) {} + NodeArray(Node **Elements_, size_t NumElements_) + : Elements(Elements_), NumElements(NumElements_) {} + + bool empty() const { return NumElements == 0; } + size_t size() const { return NumElements; } + + void printWithSeperator(OutputStream &S, StringView Seperator) const { + for (size_t Idx = 0; Idx != NumElements; ++Idx) { + if (Idx) + S += Seperator; + Elements[Idx]->print(S); + } + } +}; + +class DotSuffix final : public Node { + const Node *Prefix; + const StringView Suffix; + +public: + DotSuffix(Node *Prefix_, StringView Suffix_) + : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} + + void printLeft(OutputStream &s) const override { + Prefix->print(s); + s += " ("; + s += Suffix; + s += ")"; + } +}; + +class VendorExtQualType final : public Node { + const Node *Ext; + const Node *Ty; + +public: + VendorExtQualType(Node *Ext_, Node *Ty_) + : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + Ext->print(S); + S += " "; + Ty->printLeft(S); + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +enum Qualifiers { + QualNone = 0, + QualConst = 0x1, + QualVolatile = 0x2, + QualRestrict = 0x4, +}; + +void addQualifiers(Qualifiers &Q1, Qualifiers Q2) { + Q1 = static_cast<Qualifiers>(Q1 | Q2); +} + +class QualType : public Node { +protected: + const Qualifiers Quals; + const Node *Child; + + void printQuals(OutputStream &S) const { + if (Quals & QualConst) + S += " const"; + if (Quals & QualVolatile) + S += " volatile"; + if (Quals & QualRestrict) + S += " restrict"; + } + +public: + QualType(Node *Child_, Qualifiers Quals_) + : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + QualType(Node::Kind ChildKind_, Node *Child_, Qualifiers Quals_) + : Node(ChildKind_, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + Child->printLeft(S); + printQuals(S); + } + + void printRight(OutputStream &S) const override { Child->printRight(S); } +}; + +class ConversionOperatorType final : public Node { + const Node *Ty; + +public: + ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + S += "operator "; + Ty->print(S); + } +}; + +class PostfixQualifiedType final : public Node { + const Node *Ty; + const StringView Postfix; + +public: + PostfixQualifiedType(Node *Ty_, StringView Postfix_) + : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} + + void printLeft(OutputStream &s) const override { + Ty->printLeft(s); + s += Postfix; + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +class NameType final : public Node { + const StringView Name; + +public: + NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + + StringView getName() const { return Name; } + StringView getBaseName() const override { return Name; } + + void printLeft(OutputStream &s) const override { s += Name; } +}; + +class ObjCProtoName : public Node { + Node *Ty; + Node *Protocol; + + friend class PointerType; + +public: + ObjCProtoName(Node *Ty_, Node *Protocol_) + : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + + bool isObjCObject() const { + return Ty->K == KNameType && + static_cast<NameType *>(Ty)->getName() == "objc_object"; + } + + void printLeft(OutputStream &S) const override { + Ty->printLeft(S); + S += "<"; + Protocol->printLeft(S); + S += ">"; + } +}; + +class PointerType final : public Node { + const Node *Pointee; + +public: + PointerType(Node *Pointee_) + : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. + if (Pointee->K != KObjCProtoName || + !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "("; + s += "*"; + } else { + const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); + s += "id<"; + objcProto->Protocol->print(s); + s += ">"; + } + } + + void printRight(OutputStream &s) const override { + if (Pointee->K != KObjCProtoName || + !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } + } +}; + +class LValueReferenceType final : public Node { + const Node *Pointee; + +public: + LValueReferenceType(Node *Pointee_) + : Node(KLValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&"; + else + s += "&"; + } + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class RValueReferenceType final : public Node { + const Node *Pointee; + +public: + RValueReferenceType(Node *Pointee_) + : Node(KRValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&&"; + else + s += "&&"; + } + + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class PointerToMemberType final : public Node { + const Node *ClassType; + const Node *MemberType; + +public: + PointerToMemberType(Node *ClassType_, Node *MemberType_) + : Node(KPointerToMemberType, MemberType_->hasRHSComponent()), + ClassType(ClassType_), MemberType(MemberType_) {} + + void printLeft(OutputStream &s) const override { + MemberType->printLeft(s); + if (MemberType->hasArray() || MemberType->hasFunction()) + s += "("; + else + s += " "; + ClassType->print(s); + s += "::*"; + } + + void printRight(OutputStream &s) const override { + if (MemberType->hasArray() || MemberType->hasFunction()) + s += ")"; + MemberType->printRight(s); + } +}; + +class NodeOrString { + const void *First; + const void *Second; + +public: + /* implicit */ NodeOrString(StringView Str) { + const char *FirstChar = Str.begin(); + const char *SecondChar = Str.end(); + if (SecondChar == nullptr) { + assert(FirstChar == SecondChar); + ++FirstChar, ++SecondChar; + } + First = static_cast<const void *>(FirstChar); + Second = static_cast<const void *>(SecondChar); + } + + /* implicit */ NodeOrString(Node *N) + : First(static_cast<const void *>(N)), Second(nullptr) {} + NodeOrString() : First(nullptr), Second(nullptr) {} + + bool isString() const { return Second && First; } + bool isNode() const { return First && !Second; } + bool isEmpty() const { return !First && !Second; } + + StringView asString() const { + assert(isString()); + return StringView(static_cast<const char *>(First), + static_cast<const char *>(Second)); + } + + const Node *asNode() const { + assert(isNode()); + return static_cast<const Node *>(First); + } +}; + +class ArrayType final : public Node { + Node *Base; + NodeOrString Dimension; + +public: + ArrayType(Node *Base_, NodeOrString Dimension_) + : Node(KArrayType, true, false, true), Base(Base_), Dimension(Dimension_) {} + + // Incomplete array type. + ArrayType(Node *Base_) : Node(KArrayType, true, false, true), Base(Base_) {} + + void printLeft(OutputStream &S) const override { Base->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (S.back() != ']') + S += " "; + S += "["; + if (Dimension.isString()) + S += Dimension.asString(); + else if (Dimension.isNode()) + Dimension.asNode()->print(S); + S += "]"; + Base->printRight(S); + } +}; + +class FunctionType final : public Node { + Node *Ret; + NodeArray Params; + +public: + FunctionType(Node *Ret_, NodeArray Params_) + : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {} + + // Handle C++'s ... quirky decl grammer by using the left & right + // distinction. Consider: + // int (*f(float))(char) {} + // f is a function that takes a float and returns a pointer to a function + // that takes a char and returns an int. If we're trying to print f, start + // by printing out the return types's left, then print our parameters, then + // finally print right of the return type. + void printLeft(OutputStream &S) const override { + Ret->printLeft(S); + S += " "; + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + Ret->printRight(S); + } +}; + +class TopLevelFunctionDecl final : public Node { + const Node *Ret; + const Node *Name; + NodeArray Params; + +public: + TopLevelFunctionDecl(Node *Ret_, Node *Name_, NodeArray Params_) + : Node(KTopLevelFunctionDecl, true, true), Ret(Ret_), Name(Name_), + Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (Ret) { + Ret->printLeft(S); + if (!Ret->hasRHSComponent()) + S += " "; + } + Name->print(S); + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + if (Ret) + Ret->printRight(S); + } +}; + +enum FunctionRefQual : unsigned char { + FrefQualNone, + FrefQualLValue, + FrefQualRValue, +}; + +class FunctionRefQualType : public Node { + Node *Fn; + FunctionRefQual Quals; + + friend class FunctionQualType; + +public: + FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_) + : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {} + + void printQuals(OutputStream &S) const { + if (Quals == FrefQualLValue) + S += " &"; + else + S += " &&"; + } + + void printLeft(OutputStream &S) const override { Fn->printLeft(S); } + + void printRight(OutputStream &S) const override { + Fn->printRight(S); + printQuals(S); + } +}; + +class FunctionQualType final : public QualType { +public: + FunctionQualType(Node *Child_, Qualifiers Quals_) + : QualType(KFunctionQualType, Child_, Quals_) {} + + void printLeft(OutputStream &S) const override { Child->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (Child->K == KFunctionRefQualType) { + auto *RefQuals = static_cast<const FunctionRefQualType *>(Child); + RefQuals->Fn->printRight(S); + printQuals(S); + RefQuals->printQuals(S); + } else { + Child->printRight(S); + printQuals(S); + } + } +}; + +class LiteralOperator : public Node { + const Node *OpName; + +public: + LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {} + + void printLeft(OutputStream &S) const override { + S += "operator\"\" "; + OpName->print(S); + } +}; + +class SpecialName final : public Node { + const StringView Special; + const Node *Child; + +public: + SpecialName(StringView Special_, Node *Child_) + : Node(KSpecialName), Special(Special_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Special; + Child->print(S); + } +}; + +class CtorVtableSpecialName final : public Node { + const Node *FirstType; + const Node *SecondType; + +public: + CtorVtableSpecialName(Node *FirstType_, Node *SecondType_) + : Node(KCtorVtableSpecialName), FirstType(FirstType_), + SecondType(SecondType_) {} + + void printLeft(OutputStream &S) const override { + S += "construction vtable for "; + FirstType->print(S); + S += "-in-"; + SecondType->print(S); + } +}; + +class QualifiedName final : public Node { + // qualifier::name + const Node *Qualifier; + const Node *Name; + + mutable OutputStream::StreamStringView Cache; + +public: + QualifiedName(Node *Qualifier_, Node *Name_) + : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + if (Qualifier->K != KEmptyName) { + Qualifier->print(S); + S += "::"; + } + Name->print(S); + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class EmptyName : public Node { +public: + EmptyName() : Node(KEmptyName) {} + void printLeft(OutputStream &) const override {} +}; + +class VectorType final : public Node { + const Node *BaseType; + const NodeOrString Dimension; + const bool IsPixel; + +public: + VectorType(NodeOrString Dimension_) + : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_), + IsPixel(true) {} + VectorType(Node *BaseType_, NodeOrString Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_), + IsPixel(false) {} + + void printLeft(OutputStream &S) const override { + if (IsPixel) { + S += "pixel vector["; + S += Dimension.asString(); + S += "]"; + } else { + BaseType->print(S); + S += " vector["; + if (Dimension.isNode()) + Dimension.asNode()->print(S); + else if (Dimension.isString()) + S += Dimension.asString(); + S += "]"; + } + } +}; + +class TemplateParams final : public Node { + NodeArray Params; + + mutable OutputStream::StreamStringView Cache; + +public: + TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + + S += "<"; + Params.printWithSeperator(S, ", "); + if (S.back() == '>') + S += " "; + S += ">"; + + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class NameWithTemplateArgs final : public Node { + // name<template_args> + Node *Name; + Node *TemplateArgs; + +public: + NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) + : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Name->print(S); + TemplateArgs->print(S); + } +}; + +class GlobalQualifiedName final : public Node { + Node *Child; + +public: + GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "::"; + Child->print(S); + } +}; + +class StdQualifiedName final : public Node { + Node *Child; + +public: + StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "std::"; + Child->print(S); + } +}; + +enum class SpecialSubKind { + allocator, + basic_string, + string, + istream, + ostream, + iostream, +}; + +class ExpandedSpecialSubstitution final : public Node { + SpecialSubKind SSK; + +public: + ExpandedSpecialSubstitution(SpecialSubKind SSK_) + : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("basic_string"); + case SpecialSubKind::istream: + return StringView("basic_istream"); + case SpecialSubKind::ostream: + return StringView("basic_ostream"); + case SpecialSubKind::iostream: + return StringView("basic_iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::basic_string<char, std::char_traits<char>, " + "std::allocator<char> >"; + break; + case SpecialSubKind::basic_string: + case SpecialSubKind::string: + S += "std::basic_string<char, std::char_traits<char>, " + "std::allocator<char> >"; + break; + case SpecialSubKind::istream: + S += "std::basic_istream<char, std::char_traits<char> >"; + break; + case SpecialSubKind::ostream: + S += "std::basic_ostream<char, std::char_traits<char> >"; + break; + case SpecialSubKind::iostream: + S += "std::basic_iostream<char, std::char_traits<char> >"; + break; + } + } +}; + +class SpecialSubstitution final : public Node { +public: + SpecialSubKind SSK; + + SpecialSubstitution(SpecialSubKind SSK_) + : Node(KSpecialSubstitution), SSK(SSK_) {} + + 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"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + case SpecialSubKind::string: + S += "std::string"; + break; + case SpecialSubKind::istream: + S += "std::istream"; + break; + case SpecialSubKind::ostream: + S += "std::ostream"; + break; + case SpecialSubKind::iostream: + S += "std::iostream"; + break; + } + } +}; + +class CtorDtorName final : public Node { + const Node *Basename; + const bool IsDtor; + +public: + CtorDtorName(Node *Basename_, bool IsDtor_) + : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {} + + void printLeft(OutputStream &S) const override { + if (IsDtor) + S += "~"; + S += Basename->getBaseName(); + } +}; + +class DtorName : public Node { + const Node *Base; + +public: + DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {} + + void printLeft(OutputStream &S) const override { + S += "~"; + Base->printLeft(S); + } +}; + +class UnnamedTypeName : public Node { + const StringView Count; + +public: + UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "'unnamed"; + S += Count; + S += "\'"; + } +}; + +class LambdaTypeName : public Node { + NodeArray Params; + StringView Count; + +public: + LambdaTypeName(NodeArray Params_, StringView Count_) + : Node(KLambdaTypeName), Params(Params_), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "\'lambda"; + S += Count; + S += "\'("; + Params.printWithSeperator(S, ", "); + S += ")"; + } +}; + +// -- Expression Nodes -- + +struct Expr : public Node { + Expr() : Node(KExpr) {} +}; + +class BinaryExpr : public Expr { + const Node *LHS; + const StringView InfixOperator; + const Node *RHS; + +public: + BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_) + : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + // might be a template argument expression, then we need to disambiguate + // with parens. + if (InfixOperator == ">") + S += "("; + + S += "("; + LHS->print(S); + S += ") "; + S += InfixOperator; + S += " ("; + RHS->print(S); + S += ")"; + + if (InfixOperator == ">") + S += ")"; + } +}; + +class ArraySubscriptExpr : public Expr { + const Node *Op1; + const Node *Op2; + +public: + ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Op1->print(S); + S += ")["; + Op2->print(S); + S += "]"; + } +}; + +class PostfixExpr : public Expr { + const Node *Child; + const StringView Operand; + +public: + PostfixExpr(Node *Child_, StringView Operand_) + : Child(Child_), Operand(Operand_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Child->print(S); + S += ")"; + S += Operand; + } +}; + +class ConditionalExpr : public Expr { + const Node *Cond; + const Node *Then; + const Node *Else; + +public: + ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_) + : Cond(Cond_), Then(Then_), Else(Else_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Cond->print(S); + S += ") ? ("; + Then->print(S); + S += ") : ("; + Else->print(S); + S += ")"; + } +}; + +class MemberExpr : public Expr { + const Node *LHS; + const StringView Kind; + const Node *RHS; + +public: + MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_) + : LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + LHS->print(S); + S += Kind; + RHS->print(S); + } +}; + +class EnclosingExpr : public Expr { + const StringView Prefix; + const Node *Infix; + const StringView Postfix; + +public: + EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) + : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + Infix->print(S); + S += Postfix; + } +}; + +class CastExpr : public Expr { + // cast_kind<to>(from) + const StringView CastKind; + const Node *To; + const Node *From; + +public: + CastExpr(StringView CastKind_, Node *To_, Node *From_) + : CastKind(CastKind_), To(To_), From(From_) {} + + void printLeft(OutputStream &S) const override { + S += CastKind; + S += "<"; + To->printLeft(S); + S += ">("; + From->printLeft(S); + S += ")"; + } +}; + +class SizeofParamPackExpr : public Expr { + NodeArray Args; + +public: + SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {} + + void printLeft(OutputStream &S) const override { + S += "sizeof...("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class CallExpr : public Expr { + const Node *Callee; + NodeArray Args; + +public: + CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {} + + void printLeft(OutputStream &S) const override { + Callee->print(S); + S += "("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class NewExpr : public Expr { + // new (expr_list) type(init_list) + NodeArray ExprList; + Node *Type; + NodeArray InitList; + bool IsGlobal; // ::operator new ? + bool IsArray; // new[] ? +public: + NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, + bool IsArray_) + : ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::operator "; + S += "new"; + if (IsArray) + S += "[]"; + if (!ExprList.empty()) { + S += "("; + ExprList.printWithSeperator(S, ", "); + S += ")"; + } + Type->print(S); + if (!InitList.empty()) { + S += "("; + InitList.printWithSeperator(S, ", "); + S += ")"; + } + } +}; + +class DeleteExpr : public Expr { + Node *Op; + bool IsGlobal; + bool IsArray; + +public: + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) + : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::"; + S += "delete"; + if (IsArray) + S += "[] "; + Op->print(S); + } +}; + +class PrefixExpr : public Expr { + StringView Prefix; + Node *Child; + +public: + PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + S += "("; + Child->print(S); + S += ")"; + } +}; + +class FunctionParam : public Expr { + StringView Number; + +public: + FunctionParam(StringView Number_) : Number(Number_) {} + + void printLeft(OutputStream &S) const override { + S += "fp"; + S += Number; + } +}; + +class ExprList : public Expr { + NodeArray SubExprs; + +public: + ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + SubExprs.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ConversionExpr : public Expr { + NodeArray Expressions; + NodeArray Types; + +public: + ConversionExpr(NodeArray Expressions_, NodeArray Types_) + : Expressions(Expressions_), Types(Types_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Expressions.printWithSeperator(S, ", "); + S += ")("; + Types.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ThrowExpr : public Expr { + const Node *Op; + +public: + ThrowExpr(Node *Op_) : Op(Op_) {} + + void printLeft(OutputStream &S) const override { + S += "throw "; + Op->print(S); + } +}; + +class BoolExpr : public Expr { + bool Value; + +public: + BoolExpr(bool Value_) : Value(Value_) {} + + void printLeft(OutputStream &S) const override { + S += Value ? StringView("true") : StringView("false"); + } +}; + +class IntegerCastExpr : public Expr { + // ty(integer) + Node *Ty; + StringView Integer; + +public: + IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Ty->print(S); + S += ")"; + S += Integer; + } +}; + +class IntegerExpr : public Expr { + StringView Type; + StringView Value; + +public: + IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {} + + void printLeft(OutputStream &S) const override { + if (Type.size() > 3) { + S += "("; + S += Type; + S += ")"; + } + + if (Value[0] == 'n') { + S += "-"; + S += Value.dropFront(1); + } else + S += Value; + + if (Type.size() <= 3) + S += Type; + } +}; + +template <class Float> struct FloatData; + +template <class Float> class FloatExpr : public Expr { + const StringView Contents; + +public: + FloatExpr(StringView Contents_) : Contents(Contents_) {} + + void printLeft(OutputStream &s) const override { + const char *first = Contents.begin(); + const char *last = Contents.end() + 1; + + const size_t N = FloatData<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) > N) { + last = first + N; + union { + Float value; + char buf[sizeof(Float)]; + }; + const char *t = first; + char *e = buf; + for (; t != last; ++t, ++e) { + unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') + : static_cast<unsigned>(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') + : static_cast<unsigned>(*t - 'a' + 10); + *e = static_cast<char>((d1 << 4) + d0); + } +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[FloatData<Float>::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); + s += StringView(num, num + n); + } + } +}; + +class BumpPointerAllocator { + struct BlockMeta { + BlockMeta* Next; + size_t Current; + }; + + static constexpr size_t AllocSize = 4096; + static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); + + alignas(16) char InitialBuffer[AllocSize]; + BlockMeta* BlockList = nullptr; + + void grow() { + char* NewMeta = new char[AllocSize]; + BlockList = new (NewMeta) BlockMeta{BlockList, 0}; + } + + void* allocateMassive(size_t NBytes) { + NBytes += sizeof(BlockMeta); + BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(new char[NBytes]); + BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; + return static_cast<void*>(NewMeta + 1); + } + +public: + BumpPointerAllocator() + : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} + + void* allocate(size_t N) { + N = (N + 15u) & ~15u; + if (N + BlockList->Current >= UsableAllocSize) { + if (N > UsableAllocSize) + return allocateMassive(N); + grow(); + } + BlockList->Current += N; + return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + + BlockList->Current - N); + } + + ~BumpPointerAllocator() { + while (BlockList) { + BlockMeta* Tmp = BlockList; + BlockList = BlockList->Next; + if (reinterpret_cast<char*>(Tmp) != InitialBuffer) + delete[] reinterpret_cast<char*>(Tmp); + } + } +}; + +template <class T, size_t N> +class PODSmallVector { + static_assert(std::is_pod<T>::value, + "T is required to be a plain old data type"); + + T* First; + T* Last; + T* Cap; + T Inline[N]; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T))); + std::copy(First, Last, Tmp); + First = Tmp; + } else + First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); + 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); + } +}; + +// Substitution table. This type is used to track the substitutions that are +// known by the parser. +template <size_t Size> +class SubstitutionTable { + // Substitutions hold the actual entries in the table, and PackIndices tells + // us which entries are members of which pack. For example, if the + // substitutions we're tracking are: {int, {float, FooBar}, char}, with + // {float, FooBar} being a parameter pack, we represent the substitutions as: + // Substitutions: int, float, FooBar, char + // PackIndices: 0, 1, 3 + // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and + // PackIndices[I + 1] holds the offset of the end. + PODSmallVector<Node*, Size> Substitutions; + PODSmallVector<unsigned, Size> PackIndices; + +public: + // Add a substitution that represents a single name to the table. This is + // modeled as a parameter pack with just one element. + void pushSubstitution(Node* Entry) { + pushPack(); + pushSubstitutionIntoPack(Entry); + } + + // Add a new empty pack to the table. Subsequent calls to + // pushSubstitutionIntoPack() will add to this pack. + void pushPack() { + PackIndices.push_back(static_cast<unsigned>(Substitutions.size())); + } + void pushSubstitutionIntoPack(Node* Entry) { + assert(!PackIndices.empty() && "No pack to push substitution into!"); + Substitutions.push_back(Entry); + } + + // Remove the last pack from the table. + void popPack() { + unsigned Last = PackIndices.back(); + PackIndices.pop_back(); + Substitutions.dropBack(Last); + } + + // For use in a range-for loop. + struct NodeRange { + Node** First; + Node** Last; + Node** begin() { return First; } + Node** end() { return Last; } + }; + + // Retrieve the Nth substitution. This is represented as a range, as the + // substitution could be referring to a parameter pack. + NodeRange nthSubstitution(size_t N) { + assert(PackIndices[N] <= Substitutions.size()); + // The Nth parameter pack starts at offset PackIndices[N], and ends at + // PackIndices[N + 1]. + Node** Begin = Substitutions.begin() + PackIndices[N]; + Node** End; + if (N + 1 != PackIndices.size()) { + assert(PackIndices[N + 1] <= Substitutions.size()); + End = Substitutions.begin() + PackIndices[N + 1]; + } else + End = Substitutions.end(); + assert(Begin <= End); + return NodeRange{Begin, End}; + } + + size_t size() const { return PackIndices.size(); } + bool empty() const { return PackIndices.empty(); } + void clear() { + Substitutions.clear(); + PackIndices.clear(); + } +}; + +struct Db { - fprintf(stderr, "---------\n"); - fprintf(stderr, "names:\n"); - for (auto& s : db.names) - fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - fprintf(stderr, "subs:\n"); - for (auto& v : db.subs) + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser colapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector<Node*, 32> Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 42nd entry in this table. + SubstitutionTable<32> Subs; + + // Template parameter table. Like the above, but referenced like "T42_". + // This has a smaller size compared to Subs and Names because it can be + // stored on the stack. + SubstitutionTable<4> TemplateParams; + + Qualifiers CV = QualNone; + FunctionRefQual RefQuals = FrefQualNone; + unsigned EncodingDepth = 0; + bool ParsedCtorDtorCV = false; + bool TagTemplates = true; + bool FixForwardReferences = false; + bool TryToParseTemplateArgs = true; + + BumpPointerAllocator ASTAllocator; + + template <class T, class... Args> T* make(Args&& ...args) { - if (i >= 0) - fprintf(stderr, "S%i_ = {", i); - else - fprintf(stderr, "S_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward<Args>(args)...); } - fprintf(stderr, "template_param:\n"); - for (auto& t : db.template_param) + + template <class It> NodeArray makeNodeArray(It begin, It end) { - fprintf(stderr, "--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - fprintf(stderr, "T%i_ = {", i); - else - fprintf(stderr, "T_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } + size_t sz = static_cast<size_t>(end - begin); + void* mem = ASTAllocator.allocate(sizeof(Node*) * sz); + Node** data = new (mem) Node*[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); } - fprintf(stderr, "---------\n\n"); -} -template <class C> -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - fprintf(stderr, "%s: ", msg); - for (; first != last; ++first) - fprintf(stderr, "%c", *first); - fprintf(stderr, "\n"); - print_stack(db); -} + NodeArray popTrailingNodeArray(size_t FromPosition) + { + assert(FromPosition <= Names.size()); + NodeArray res = makeNodeArray( + Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } +}; + +const char* parse_type(const char* first, const char* last, Db& db); +const char* parse_encoding(const char* first, const char* last, Db& db); +const char* parse_name(const char* first, const char* last, Db& db, + bool* ends_with_template_args = 0); +const char* parse_expression(const char* first, const char* last, Db& db); +const char* parse_template_args(const char* first, const char* last, Db& db); +const char* parse_operator_name(const char* first, const char* last, Db& db); +const char* parse_unqualified_name(const char* first, const char* last, Db& db); +const char* parse_decltype(const char* first, const char* last, Db& db); // <number> ::= [n] <non-negative decimal integer> @@ -139,30 +1733,30 @@ parse_number(const char* first, const char* last) } template <class Float> -struct float_data; +struct FloatData; template <> -struct float_data<float> +struct FloatData<float> { static const size_t mangled_size = 8; static const size_t max_demangled_size = 24; static constexpr const char* spec = "%af"; }; -constexpr const char* float_data<float>::spec; +constexpr const char* FloatData<float>::spec; template <> -struct float_data<double> +struct FloatData<double> { static const size_t mangled_size = 16; static const size_t max_demangled_size = 32; static constexpr const char* spec = "%a"; }; -constexpr const char* float_data<double>::spec; +constexpr const char* FloatData<double>::spec; template <> -struct float_data<long double> +struct FloatData<long double> { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ defined(__wasm__) @@ -176,55 +1770,35 @@ struct float_data<long double> static constexpr const char* spec = "%LaL"; }; -constexpr const char* float_data<long double>::spec; +constexpr const char* FloatData<long double>::spec; -template <class Float, class C> +template <class Float> const char* -parse_floating_number(const char* first, const char* last, C& db) +parse_floating_number(const char* first, const char* last, Db& db) { - const size_t N = float_data<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) + const size_t N = FloatData<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) <= N) + return first; + last = first + N; + const char* t = first; + for (; t != last; ++t) { - last = first + N; - union - { - Float value; - char buf[sizeof(Float)]; - }; - const char* t = first; - char* e = buf; - for (; t != last; ++t, ++e) - { - if (!isxdigit(*t)) - return first; - unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : - static_cast<unsigned>(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : - static_cast<unsigned>(*t - 'a' + 10); - *e = static_cast<char>((d1 << 4) + d0); - } - if (*t == 'E') - { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[float_data<Float>::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), float_data<Float>::spec, value); - if (static_cast<std::size_t>(n) >= sizeof(num)) - return first; - db.names.push_back(typename C::String(num, static_cast<std::size_t>(n))); - first = t+1; - } + if (!isxdigit(*t)) + return first; + } + if (*t == 'E') + { + db.Names.push_back( + db.make<FloatExpr<Float>>(StringView(first, t))); + first = t + 1; } return first; } // <source-name> ::= <positive length number> <identifier> -template <class C> const char* -parse_source_name(const char* first, const char* last, C& db) +parse_source_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -241,11 +1815,11 @@ parse_source_name(const char* first, const char* last, C& db) } if (static_cast<size_t>(last - t) >= n) { - typename C::String r(t, n); + StringView r(t, t + n); if (r.substr(0, 10) == "_GLOBAL__N") - db.names.push_back("(anonymous namespace)"); + db.Names.push_back(db.make<NameType>("(anonymous namespace)")); else - db.names.push_back(std::move(r)); + db.Names.push_back(db.make<NameType>(r)); first = t + n; } } @@ -264,9 +1838,8 @@ parse_source_name(const char* first, const char* last, C& db) // <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > -template <class C> const char* -parse_substitution(const char* first, const char* last, C& db) +parse_substitution(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -275,34 +1848,39 @@ parse_substitution(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("std::allocator"); + db.Names.push_back( + db.make<SpecialSubstitution>( + SpecialSubKind::allocator)); first += 2; break; case 'b': - db.names.push_back("std::basic_string"); + db.Names.push_back( + db.make<SpecialSubstitution>(SpecialSubKind::basic_string)); first += 2; break; case 's': - db.names.push_back("std::string"); + db.Names.push_back( + db.make<SpecialSubstitution>( + SpecialSubKind::string)); first += 2; break; case 'i': - db.names.push_back("std::istream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream)); first += 2; break; case 'o': - db.names.push_back("std::ostream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream)); first += 2; break; case 'd': - db.names.push_back("std::iostream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream)); first += 2; break; case '_': - if (!db.subs.empty()) + if (!db.Subs.empty()) { - for (const auto& n : db.subs.front()) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(0)) + db.Names.push_back(n); first += 2; } break; @@ -326,10 +1904,10 @@ parse_substitution(const char* first, const char* last, C& db) if (t == last || *t != '_') return first; ++sub; - if (sub < db.subs.size()) + if (sub < db.Subs.size()) { - for (const auto& n : db.subs[sub]) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(sub)) + db.Names.push_back(n); first = t+1; } } @@ -372,96 +1950,95 @@ parse_substitution(const char* first, const char* last, C& db) // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) // ::= u <source-name> # vendor extended type -template <class C> const char* -parse_builtin_type(const char* first, const char* last, C& db) +parse_builtin_type(const char* first, const char* last, Db& db) { if (first != last) { switch (*first) { case 'v': - db.names.push_back("void"); + db.Names.push_back(db.make<NameType>("void")); ++first; break; case 'w': - db.names.push_back("wchar_t"); + db.Names.push_back(db.make<NameType>("wchar_t")); ++first; break; case 'b': - db.names.push_back("bool"); + db.Names.push_back(db.make<NameType>("bool")); ++first; break; case 'c': - db.names.push_back("char"); + db.Names.push_back(db.make<NameType>("char")); ++first; break; case 'a': - db.names.push_back("signed char"); + db.Names.push_back(db.make<NameType>("signed char")); ++first; break; case 'h': - db.names.push_back("unsigned char"); + db.Names.push_back(db.make<NameType>("unsigned char")); ++first; break; case 's': - db.names.push_back("short"); + db.Names.push_back(db.make<NameType>("short")); ++first; break; case 't': - db.names.push_back("unsigned short"); + db.Names.push_back(db.make<NameType>("unsigned short")); ++first; break; case 'i': - db.names.push_back("int"); + db.Names.push_back(db.make<NameType>("int")); ++first; break; case 'j': - db.names.push_back("unsigned int"); + db.Names.push_back(db.make<NameType>("unsigned int")); ++first; break; case 'l': - db.names.push_back("long"); + db.Names.push_back(db.make<NameType>("long")); ++first; break; case 'm': - db.names.push_back("unsigned long"); + db.Names.push_back(db.make<NameType>("unsigned long")); ++first; break; case 'x': - db.names.push_back("long long"); + db.Names.push_back(db.make<NameType>("long long")); ++first; break; case 'y': - db.names.push_back("unsigned long long"); + db.Names.push_back(db.make<NameType>("unsigned long long")); ++first; break; case 'n': - db.names.push_back("__int128"); + db.Names.push_back(db.make<NameType>("__int128")); ++first; break; case 'o': - db.names.push_back("unsigned __int128"); + db.Names.push_back(db.make<NameType>("unsigned __int128")); ++first; break; case 'f': - db.names.push_back("float"); + db.Names.push_back(db.make<NameType>("float")); ++first; break; case 'd': - db.names.push_back("double"); + db.Names.push_back(db.make<NameType>("double")); ++first; break; case 'e': - db.names.push_back("long double"); + db.Names.push_back(db.make<NameType>("long double")); ++first; break; case 'g': - db.names.push_back("__float128"); + db.Names.push_back(db.make<NameType>("__float128")); ++first; break; case 'z': - db.names.push_back("..."); + db.Names.push_back(db.make<NameType>("...")); ++first; break; case 'u': @@ -477,39 +2054,39 @@ parse_builtin_type(const char* first, const char* last, C& db) switch (first[1]) { case 'd': - db.names.push_back("decimal64"); + db.Names.push_back(db.make<NameType>("decimal64")); first += 2; break; case 'e': - db.names.push_back("decimal128"); + db.Names.push_back(db.make<NameType>("decimal128")); first += 2; break; case 'f': - db.names.push_back("decimal32"); + db.Names.push_back(db.make<NameType>("decimal32")); first += 2; break; case 'h': - db.names.push_back("decimal16"); + db.Names.push_back(db.make<NameType>("decimal16")); first += 2; break; case 'i': - db.names.push_back("char32_t"); + db.Names.push_back(db.make<NameType>("char32_t")); first += 2; break; case 's': - db.names.push_back("char16_t"); + db.Names.push_back(db.make<NameType>("char16_t")); first += 2; break; case 'a': - db.names.push_back("auto"); + db.Names.push_back(db.make<NameType>("auto")); first += 2; break; case 'c': - db.names.push_back("decltype(auto)"); + db.Names.push_back(db.make<NameType>("decltype(auto)")); first += 2; break; case 'n': - db.names.push_back("std::nullptr_t"); + db.Names.push_back(db.make<NameType>("std::nullptr_t")); first += 2; break; } @@ -520,27 +2097,27 @@ parse_builtin_type(const char* first, const char* last, C& db) return first; } -// <CV-qualifiers> ::= [r] [V] [K] +// <CV-Qualifiers> ::= [r] [V] [K] const char* -parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) +parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv) { - cv = 0; + cv = QualNone; if (first != last) { if (*first == 'r') { - cv |= 4; + addQualifiers(cv, QualRestrict); ++first; } if (*first == 'V') { - cv |= 2; + addQualifiers(cv, QualVolatile); ++first; } if (*first == 'K') { - cv |= 1; + addQualifiers(cv, QualConst); ++first; } } @@ -550,9 +2127,8 @@ parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) // <template-param> ::= T_ # first template parameter // ::= T <parameter-2 non-negative number> _ -template <class C> const char* -parse_template_param(const char* first, const char* last, C& db) +parse_template_param(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -560,19 +2136,17 @@ parse_template_param(const char* first, const char* last, C& db) { if (first[1] == '_') { - if (db.template_param.empty()) - return first; - if (!db.template_param.back().empty()) + if (!db.TemplateParams.empty()) { - for (auto& t : db.template_param.back().front()) - db.names.push_back(t); + for (Node *t : db.TemplateParams.nthSubstitution(0)) + db.Names.push_back(t); first += 2; } else { - db.names.push_back("T_"); + db.Names.push_back(db.make<NameType>("T_")); first += 2; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } else if (isdigit(first[1])) @@ -584,20 +2158,21 @@ parse_template_param(const char* first, const char* last, C& db) sub *= 10; sub += static_cast<size_t>(*t - '0'); } - if (t == last || *t != '_' || db.template_param.empty()) + if (t == last || *t != '_') return first; ++sub; - if (sub < db.template_param.back().size()) + if (sub < db.TemplateParams.size()) { - for (auto& temp : db.template_param.back()[sub]) - db.names.push_back(temp); + for (Node *temp : db.TemplateParams.nthSubstitution(sub)) + db.Names.push_back(temp); first = t+1; } else { - db.names.push_back(typename C::String(first, t+1)); + db.Names.push_back( + db.make<NameType>(StringView(first, t + 1))); first = t+1; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } } @@ -607,9 +2182,8 @@ parse_template_param(const char* first, const char* last, C& db) // cc <type> <expression> # const_cast<type> (expression) -template <class C> const char* -parse_const_cast_expr(const char* first, const char* last, C& db) +parse_const_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') { @@ -619,13 +2193,14 @@ parse_const_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "const_cast", db.Names.back(), from_expr); first = t1; } } @@ -635,9 +2210,8 @@ parse_const_cast_expr(const char* first, const char* last, C& db) // dc <type> <expression> # dynamic_cast<type> (expression) -template <class C> const char* -parse_dynamic_cast_expr(const char* first, const char* last, C& db) +parse_dynamic_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') { @@ -647,13 +2221,14 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "dynamic_cast", db.Names.back(), from_expr); first = t1; } } @@ -663,9 +2238,8 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) // rc <type> <expression> # reinterpret_cast<type> (expression) -template <class C> const char* -parse_reinterpret_cast_expr(const char* first, const char* last, C& db) +parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') { @@ -675,13 +2249,14 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "reinterpret_cast", db.Names.back(), from_expr); first = t1; } } @@ -691,9 +2266,8 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) // sc <type> <expression> # static_cast<type> (expression) -template <class C> const char* -parse_static_cast_expr(const char* first, const char* last, C& db) +parse_static_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'c') { @@ -703,11 +2277,12 @@ parse_static_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + auto from_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<CastExpr>( + "static_cast", db.Names.back(), from_expr); first = t1; } } @@ -717,9 +2292,8 @@ parse_static_cast_expr(const char* first, const char* last, C& db) // sp <expression> # pack expansion -template <class C> const char* -parse_pack_expansion(const char* first, const char* last, C& db) +parse_pack_expansion(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { @@ -732,18 +2306,18 @@ parse_pack_expansion(const char* first, const char* last, C& db) // st <type> # sizeof (a type) -template <class C> const char* -parse_sizeof_type_expr(const char* first, const char* last, C& db) +parse_sizeof_type_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -752,18 +2326,18 @@ parse_sizeof_type_expr(const char* first, const char* last, C& db) // sz <expr> # sizeof (a expression) -template <class C> const char* -parse_sizeof_expr_expr(const char* first, const char* last, C& db) +parse_sizeof_expr_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -772,60 +2346,50 @@ parse_sizeof_expr_expr(const char* first, const char* last, C& db) // sZ <template-param> # size of a parameter pack -template <class C> const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) + size_t k1 = db.Names.size(); + if (t != first+2 && k0 <= k1) { - typename C::String tmp("sizeof...("); - size_t k = k0; - if (k != k1) - { - tmp += db.names[k].move_full(); - for (++k; k != k1; ++k) - tmp += ", " + db.names[k].move_full(); - } - tmp += ")"; - for (; k1 != k0; --k1) - db.names.pop_back(); - db.names.push_back(std::move(tmp)); + Node* sizeof_expr = db.make<SizeofParamPackExpr>( + db.popTrailingNodeArray(k0)); + db.Names.push_back(sizeof_expr); first = t; } } return first; } -// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters -template <class C> const char* -parse_function_param(const char* first, const char* last, C& db) +parse_function_param(const char* first, const char* last, Db& db) { if (last - first >= 3 && *first == 'f') { if (first[1] == 'p') { - unsigned cv; + Qualifiers cv; const char* t = parse_cv_qualifiers(first+2, last, cv); const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make<FunctionParam>(StringView(t, t1))); first = t1+1; } } else if (first[1] == 'L') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_number(first+2, last); if (t0 != last && *t0 == 'p') { @@ -834,7 +2398,8 @@ parse_function_param(const char* first, const char* last, C& db) const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make<FunctionParam>(StringView(t, t1))); first = t1+1; } } @@ -845,18 +2410,18 @@ parse_function_param(const char* first, const char* last, C& db) // sZ <function-param> # size of a function parameter pack -template <class C> const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') { const char* t = parse_function_param(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof...(", db.Names.back(), ")"); first = t; } } @@ -866,9 +2431,8 @@ parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db // te <expression> # typeid (expression) // ti <type> # typeid (type) -template <class C> const char* -parse_typeid_expr(const char* first, const char* last, C& db) +parse_typeid_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) { @@ -879,9 +2443,10 @@ parse_typeid_expr(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "typeid(", db.Names.back(), ")"); first = t; } } @@ -890,18 +2455,17 @@ parse_typeid_expr(const char* first, const char* last, C& db) // tw <expression> # throw expression -template <class C> const char* -parse_throw_expr(const char* first, const char* last, C& db) +parse_throw_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && first[1] == 'w') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "throw " + db.names.back().move_full(); + db.Names.back() = db.make<ThrowExpr>(db.Names.back()); first = t; } } @@ -910,9 +2474,8 @@ parse_throw_expr(const char* first, const char* last, C& db) // ds <expression> <expression> # expr.*expr -template <class C> const char* -parse_dot_star_expr(const char* first, const char* last, C& db) +parse_dot_star_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 's') { @@ -922,11 +2485,12 @@ parse_dot_star_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += ".*" + expr; + auto rhs_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<MemberExpr>( + db.Names.back(), ".*", rhs_expr); first = t1; } } @@ -936,9 +2500,8 @@ parse_dot_star_expr(const char* first, const char* last, C& db) // <simple-id> ::= <source-name> [ <template-args> ] -template <class C> const char* -parse_simple_id(const char* first, const char* last, C& db) +parse_simple_id(const char* first, const char* last, Db& db) { if (first != last) { @@ -948,11 +2511,12 @@ parse_simple_id(const char* first, const char* last, C& db) const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>(db.Names.back(), args); } first = t1; } @@ -966,9 +2530,8 @@ parse_simple_id(const char* first, const char* last, C& db) // ::= <decltype> // ::= <substitution> -template <class C> const char* -parse_unresolved_type(const char* first, const char* last, C& db) +parse_unresolved_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -977,18 +2540,18 @@ parse_unresolved_type(const char* first, const char* last, C& db) { case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first && k1 == k0 + 1) { - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } else { for (; k1 != k0; --k1) - db.names.pop_back(); + db.Names.pop_back(); } break; } @@ -996,9 +2559,9 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } break; @@ -1013,10 +2576,11 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_unqualified_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = + db.make<StdQualifiedName>(db.Names.back()); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -1030,9 +2594,8 @@ parse_unresolved_type(const char* first, const char* last, C& db) // <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) // ::= <simple-id> # e.g., ~A<2*N> -template <class C> const char* -parse_destructor_name(const char* first, const char* last, C& db) +parse_destructor_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -1041,9 +2604,9 @@ parse_destructor_name(const char* first, const char* last, C& db) t = parse_simple_id(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "~"); + db.Names.back() = db.make<DtorName>(db.Names.back()); first = t; } } @@ -1058,9 +2621,8 @@ parse_destructor_name(const char* first, const char* last, C& db) // ::= dn <destructor-name> # destructor or pseudo-destructor; // # e.g. ~X or ~X<N-1> -template <class C> const char* -parse_base_unresolved_name(const char* first, const char* last, C& db) +parse_base_unresolved_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -1074,11 +2636,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); } } } @@ -1100,11 +2664,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); } } } @@ -1117,9 +2683,8 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) // <unresolved-qualifier-level> ::= <simple-id> -template <class C> const char* -parse_unresolved_qualifier_level(const char* first, const char* last, C& db) +parse_unresolved_qualifier_level(const char* first, const char* last, Db& db) { return parse_simple_id(first, last, db); } @@ -1134,9 +2699,8 @@ parse_unresolved_qualifier_level(const char* first, const char* last, C& db) // # T::N::x /decltype(p)::N::x // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -template <class C> const char* -parse_unresolved_name(const char* first, const char* last, C& db) +parse_unresolved_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -1152,9 +2716,10 @@ parse_unresolved_name(const char* first, const char* last, C& db) { if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make<GlobalQualifiedName>(db.Names.back()); } first = t2; } @@ -1170,41 +2735,44 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<NameWithTemplateArgs>( + db.Names.back(), args); t = t1; if (t == last) { - db.names.pop_back(); + db.Names.pop_back(); return first; } } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } else @@ -1217,25 +2785,28 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); t = t1; } t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } else @@ -1246,33 +2817,37 @@ parse_unresolved_name(const char* first, const char* last, C& db) t = t1; if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make<GlobalQualifiedName>( + db.Names.back()); } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } } @@ -1283,9 +2858,8 @@ parse_unresolved_name(const char* first, const char* last, C& db) // dt <expression> <unresolved-name> # expr.name -template <class C> const char* -parse_dot_expr(const char* first, const char* last, C& db) +parse_dot_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 't') { @@ -1295,13 +2869,13 @@ parse_dot_expr(const char* first, const char* last, C& db) const char* t1 = parse_unresolved_name(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += "." + name; + db.Names.back() = db.make<MemberExpr>(db.Names.back(), ".", name); first = t1; } } @@ -1311,51 +2885,31 @@ parse_dot_expr(const char* first, const char* last, C& db) // cl <expression>+ E # call -template <class C> const char* -parse_call_expr(const char* first, const char* last, C& db) +parse_call_expr(const char* first, const char* last, Db& db) { if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') { const char* t = parse_expression(first+2, last, db); - if (t != first+2) + if (t == last || t == first + 2 || db.Names.empty()) + return first; + Node* callee = db.Names.back(); + db.Names.pop_back(); + size_t args_begin = db.Names.size(); + while (*t != 'E') { - if (t == last) - return first; - if (db.names.empty()) - return first; - db.names.back().first += db.names.back().second; - db.names.back().second = typename C::String(); - db.names.back().first.append("("); - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_expr) - { - db.names.back().first.append(", "); - first_expr = false; - } - db.names.back().first.append(tmp); - } - t = t1; - } - ++t; - if (db.names.empty()) + const char* t1 = parse_expression(t, last, db); + if (t1 == last || t1 == t) return first; - db.names.back().first.append(")"); - first = t; + t = t1; } + if (db.Names.size() < args_begin) + return first; + ++t; + CallExpr* the_call = db.make<CallExpr>( + callee, db.popTrailingNodeArray(args_begin)); + db.Names.push_back(the_call); + first = t; } return first; } @@ -1366,9 +2920,8 @@ parse_call_expr(const char* first, const char* last, C& db) // [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) // <initializer> ::= pi <expression>* E # parenthesized initialization -template <class C> const char* -parse_new_expr(const char* first, const char* last, C& db) +parse_new_expr(const char* first, const char* last, Db& db) { if (last - first >= 4) { @@ -1385,31 +2938,18 @@ parse_new_expr(const char* first, const char* last, C& db) t += 2; if (t == last) return first; - bool has_expr_list = false; - bool first_expr = true; + size_t first_expr_in_list = db.Names.size(); + NodeArray ExprList, init_list; while (*t != '_') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - has_expr_list = true; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } + if (first_expr_in_list > db.Names.size()) + return first; + ExprList = db.popTrailingNodeArray(first_expr_in_list); ++t; const char* t1 = parse_type(t, last, db); if (t1 == t || t1 == last) @@ -1420,65 +2960,25 @@ parse_new_expr(const char* first, const char* last, C& db) { t += 2; has_init = true; - first_expr = true; + size_t init_list_begin = db.Names.size(); while (*t != 'E') { t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } - } - if (*t != 'E') - return first; - typename C::String init_list; - if (has_init) - { - if (db.names.empty()) + if (init_list_begin > db.Names.size()) return first; - init_list = db.names.back().move_full(); - db.names.pop_back(); + init_list = db.popTrailingNodeArray(init_list_begin); } - if (db.names.empty()) + if (*t != 'E' || db.Names.empty()) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - typename C::String expr_list; - if (has_expr_list) - { - if (db.names.empty()) - return first; - expr_list = db.names.back().move_full(); - db.names.pop_back(); - } - typename C::String r; - if (parsed_gs) - r = "::"; - if (is_array) - r += "[] "; - else - r += " "; - if (has_expr_list) - r += "(" + expr_list + ") "; - r += type; - if (has_init) - r += " (" + init_list + ")"; - db.names.push_back(std::move(r)); + auto type = db.Names.back(); + db.Names.pop_back(); + db.Names.push_back( + db.make<NewExpr>(ExprList, type, init_list, + parsed_gs, is_array)); first = t+1; } } @@ -1488,18 +2988,19 @@ parse_new_expr(const char* first, const char* last, C& db) // cv <type> <expression> # conversion with one argument // cv <type> _ <expression>* E # conversion with a different number of arguments -template <class C> const char* -parse_conversion_expr(const char* first, const char* last, C& db) +parse_conversion_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; + size_t type_begin = db.Names.size(); const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2 && t != last) { + size_t expr_list_begin = db.Names.size(); if (*t != '_') { const char* t1 = parse_expression(t, last, db); @@ -1512,41 +3013,30 @@ parse_conversion_expr(const char* first, const char* last, C& db) ++t; if (t == last) return first; - if (*t == 'E') - db.names.emplace_back(); - else + if (*t != 'E') { - bool first_expr = true; while (*t != 'E') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } } ++t; } - if (db.names.size() < 2) + if (db.Names.size() < expr_list_begin || + type_begin > expr_list_begin) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; + NodeArray expressions = db.makeNodeArray( + db.Names.begin() + (long)expr_list_begin, db.Names.end()); + NodeArray types = db.makeNodeArray( + db.Names.begin() + (long)type_begin, + db.Names.begin() + (long)expr_list_begin); + auto* conv_expr = db.make<ConversionExpr>( + types, expressions); + db.Names.dropBack(type_begin); + db.Names.push_back(conv_expr); first = t; } } @@ -1555,9 +3045,8 @@ parse_conversion_expr(const char* first, const char* last, C& db) // pt <expression> <expression> # expr->name -template <class C> const char* -parse_arrow_expr(const char* first, const char* last, C& db) +parse_arrow_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'p' && first[1] == 't') { @@ -1567,12 +3056,12 @@ parse_arrow_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "->"; - db.names.back().first += tmp; + auto tmp = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<MemberExpr>( + db.Names.back(), "->", tmp); first = t1; } } @@ -1585,9 +3074,8 @@ parse_arrow_expr(const char* first, const char* last, C& db) // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E -template <class C> const char* -parse_function_type(const char* first, const char* last, C& db) +parse_function_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'F') { @@ -1601,17 +3089,19 @@ parse_function_type(const char* first, const char* last, C& db) return first; } const char* t1 = parse_type(t, last, db); - if (t1 != t) + if (t1 != t && !db.Names.empty()) { + Node* ret_type = db.Names.back(); + db.Names.pop_back(); + size_t params_begin = db.Names.size(); t = t1; - typename C::String sig("("); - int ref_qual = 0; + FunctionRefQual RefQuals = FrefQualNone; while (true) { if (t == last) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } if (*t == 'E') @@ -1626,45 +3116,30 @@ parse_function_type(const char* first, const char* last, C& db) } if (*t == 'R' && t+1 != last && t[1] == 'E') { - ref_qual = 1; + RefQuals = FrefQualLValue; ++t; continue; } if (*t == 'O' && t+1 != last && t[1] == 'E') { - ref_qual = 2; + RefQuals = FrefQualRValue; ++t; continue; } - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 == t || t1 == last) + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k1 < k0) return first; - for (size_t k = k0; k < k1; ++k) - { - if (sig.size() > 1) - sig += ", "; - sig += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) - db.names.pop_back(); t = t1; } - sig += ")"; - switch (ref_qual) - { - case 1: - sig += " &"; - break; - case 2: - sig += " &&"; - break; - } - if (db.names.empty()) + if (db.Names.empty() || params_begin > db.Names.size()) return first; - db.names.back().first += " "; - db.names.back().second.insert(0, sig); + Node* fty = db.make<FunctionType>( + ret_type, db.popTrailingNodeArray(params_begin)); + if (RefQuals) + fty = db.make<FunctionRefQualType>(fty, RefQuals); + db.Names.push_back(fty); first = t; } } @@ -1674,9 +3149,8 @@ parse_function_type(const char* first, const char* last, C& db) // <pointer-to-member-type> ::= M <class type> <member type> -template <class C> const char* -parse_pointer_to_member_type(const char* first, const char* last, C& db) +parse_pointer_to_member_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'M') { @@ -1686,21 +3160,13 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto func = std::move(db.names.back()); - db.names.pop_back(); - auto class_type = std::move(db.names.back()); - if (!func.second.empty() && func.second.front() == '(') - { - db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; - db.names.back().second = ")" + std::move(func.second); - } - else - { - db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; - db.names.back().second = std::move(func.second); - } + auto func = std::move(db.Names.back()); + db.Names.pop_back(); + auto ClassType = std::move(db.Names.back()); + db.Names.back() = + db.make<PointerToMemberType>(ClassType, func); first = t2; } } @@ -1711,9 +3177,8 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) // <array-type> ::= A <positive dimension number> _ <element type> // ::= A [<dimension expression>] _ <element type> -template <class C> const char* -parse_array_type(const char* first, const char* last, C& db) +parse_array_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'A' && first+1 != last) { @@ -1722,11 +3187,9 @@ parse_array_type(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " []"); + db.Names.back() = db.make<ArrayType>(db.Names.back()); first = t; } } @@ -1738,11 +3201,11 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t+1, last, db); if (t2 != t+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); + db.Names.back() = + db.make<ArrayType>(db.Names.back(), + StringView(first + 1, t)); first = t2; } } @@ -1755,15 +3218,13 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(++t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = std::move(db.names.back()); - db.names.pop_back(); - auto expr = std::move(db.names.back()); - db.names.back().first = std::move(type.first); - if (type.second.substr(0, 2) == " [") - type.second.erase(0, 1); - db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); + auto base_type = std::move(db.Names.back()); + db.Names.pop_back(); + auto dimension_expr = std::move(db.Names.back()); + db.Names.back() = + db.make<ArrayType>(base_type, dimension_expr); first = t2; } } @@ -1775,9 +3236,8 @@ parse_array_type(const char* first, const char* last, C& db) // <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) // ::= DT <expression> E # decltype of an expression (C++0x) -template <class C> const char* -parse_decltype(const char* first, const char* last, C& db) +parse_decltype(const char* first, const char* last, Db& db) { if (last - first >= 4 && first[0] == 'D') { @@ -1789,9 +3249,10 @@ parse_decltype(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2 && t != last && *t == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "decltype(", db.Names.back(), ")"); first = t+1; } } @@ -1808,9 +3269,8 @@ parse_decltype(const char* first, const char* last, C& db) // <extended element type> ::= <element type> // ::= p # AltiVec vector pixel -template <class C> const char* -parse_vector_type(const char* first, const char* last, C& db) +parse_vector_type(const char* first, const char* last, Db& db) { if (last - first > 3 && first[0] == 'D' && first[1] == 'v') { @@ -1828,33 +3288,36 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t1 = parse_type(t, last, db); if (t1 != t) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + db.Names.back() = + db.make<VectorType>(db.Names.back(), + StringView(num, num + sz)); first = t1; } } else { ++t; - db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + db.Names.push_back( + db.make<VectorType>(StringView(num, num + sz))); first = t; } } } else { - typename C::String num; + Node* num = nullptr; const char* t1 = first+2; if (*t1 != '_') { const char* t = parse_expression(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - num = db.names.back().move_full(); - db.names.pop_back(); + num = db.Names.back(); + db.Names.pop_back(); t1 = t; } } @@ -1863,11 +3326,17 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t = parse_type(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + num + "]"; + if (num) + db.Names.back() = + db.make<VectorType>(db.Names.back(), num); + else + db.Names.back() = + db.make<VectorType>(db.Names.back(), StringView()); first = t; - } + } else if (num) + db.Names.push_back(num); } } } @@ -1883,7 +3352,7 @@ parse_vector_type(const char* first, const char* last, C& db) // ::= <template-template-param> <template-args> // ::= <decltype> // ::= <substitution> -// ::= <CV-qualifiers> <type> +// ::= <CV-Qualifiers> <type> // ::= P <type> # pointer-to // ::= R <type> # reference-to // ::= O <type> # rvalue reference-to (C++0x) @@ -1897,9 +3366,8 @@ parse_vector_type(const char* first, const char* last, C& db) // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 // <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> -template <class C> const char* -parse_type(const char* first, const char* last, C& db) +parse_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -1909,52 +3377,30 @@ parse_type(const char* first, const char* last, C& db) case 'V': case 'K': { - unsigned cv = 0; + Qualifiers cv = QualNone; const char* t = parse_cv_qualifiers(first, last, cv); if (t != first) { bool is_function = *t == 'F'; - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t1 != t) { if (is_function) - db.subs.pop_back(); - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.popPack(); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (is_function) - { - size_t p = db.names[k].second.size(); - if (db.names[k].second[p - 2] == '&' && - db.names[k].second[p - 1] == '&') - p -= 2; - else if (db.names[k].second.back() == '&') - p -= 1; - if (cv & 1) - { - db.names[k].second.insert(p, " const"); - p += 6; - } - if (cv & 2) - { - db.names[k].second.insert(p, " volatile"); - p += 9; - } - if (cv & 4) - db.names[k].second.insert(p, " restrict"); - } - else - { - if (cv & 1) - db.names[k].first.append(" const"); - if (cv & 2) - db.names[k].first.append(" volatile"); - if (cv & 4) - db.names[k].first.append(" restrict"); + if (cv) { + if (is_function) + db.Names[k] = db.make<FunctionQualType>( + db.Names[k], cv); + else + db.Names[k] = + db.make<QualType>(db.Names[k], cv); } - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t1; } @@ -1976,77 +3422,69 @@ parse_type(const char* first, const char* last, C& db) t = parse_array_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'C': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" complex"); + db.Names.back() = db.make<PostfixQualifiedType>( + db.Names.back(), " complex"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'F': t = parse_function_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'G': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" imaginary"); + db.Names.back() = db.make<PostfixQualifiedType>( + db.Names.back(), " imaginary"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'M': t = parse_pointer_to_member_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'O': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make<RValueReferenceType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2054,34 +3492,16 @@ parse_type(const char* first, const char* last, C& db) } case 'P': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") - { - db.names[k].first.append("*"); - } - else - { - db.names[k].first.replace(0, 11, "id"); - } - db.subs.back().push_back(db.names[k]); + db.Names[k] = db.make<PointerType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2089,27 +3509,17 @@ parse_type(const char* first, const char* last, C& db) } case 'R': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make<LValueReferenceType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2117,23 +3527,25 @@ parse_type(const char* first, const char* last, C& db) } case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - if (db.try_to_parse_template_args && k1 == k0+1) + db.Subs.pushSubstitutionIntoPack(db.Names[k]); + if (db.TryToParseTemplateArgs && k1 == k0+1) { const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), args); + db.Subs.pushSubstitution(db.Names.back()); t = t1; } } @@ -2150,29 +3562,30 @@ parse_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.back().first.substr(0, 9) != "objcproto") + auto type = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KNameType || + !static_cast<NameType*>(db.Names.back())->getName().startsWith("objcproto")) { - db.names.back() = type + " " + db.names.back().move_full(); + db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back()); } else { - auto proto = db.names.back().move_full(); - db.names.pop_back(); - t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); - if (t != proto.data() + 9) + auto* proto = static_cast<NameType*>(db.Names.back()); + db.Names.pop_back(); + t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db); + if (t != proto->getName().begin() + 9) { - db.names.back() = type + "<" + db.names.back().move_full() + ">"; + db.Names.back() = db.make<ObjCProtoName>(type, db.Names.back()); } else { - db.names.push_back(type + " " + proto); + db.Names.push_back(db.make<VendorExtQualType>(type, proto)); } } - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t2; } } @@ -2184,9 +3597,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2198,17 +3611,22 @@ parse_type(const char* first, const char* last, C& db) first = t; // Parsed a substitution. If the substitution is a // <template-param> it might be followed by <template-args>. - t = parse_template_args(first, last, db); - if (t != first) + if (db.TryToParseTemplateArgs) { - if (db.names.size() < 2) - return first; - auto template_args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += template_args; - // Need to create substitution for <template-template-param> <template-args> - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; + t = parse_template_args(first, last, db); + if (t != first) + { + if (db.Names.size() < 2) + return first; + auto template_args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), template_args); + // Need to create substitution for <template-template-param> <template-args> + db.Subs.pushSubstitution(db.Names.back()); + first = t; + } } } } @@ -2220,14 +3638,14 @@ parse_type(const char* first, const char* last, C& db) { case 'p': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+2, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+2) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); first = t; return first; } @@ -2238,9 +3656,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } @@ -2249,16 +3667,16 @@ parse_type(const char* first, const char* last, C& db) t = parse_vector_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } break; } } - // drop through + _LIBCPP_FALLTHROUGH(); default: // must check for builtin-types before class-enum-types to avoid // ambiguities with operator-names @@ -2272,9 +3690,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2340,9 +3758,8 @@ parse_type(const char* first, const char* last, C& db) // ::= rS # >>= // ::= v <digit> <source-name> # vendor extended operator -template <class C> const char* -parse_operator_name(const char* first, const char* last, C& db) +parse_operator_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -2352,20 +3769,20 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator&&"); + db.Names.push_back(db.make<NameType>("operator&&")); first += 2; break; case 'd': case 'n': - db.names.push_back("operator&"); + db.Names.push_back(db.make<NameType>("operator&")); first += 2; break; case 'N': - db.names.push_back("operator&="); + db.Names.push_back(db.make<NameType>("operator&=")); first += 2; break; case 'S': - db.names.push_back("operator="); + db.Names.push_back(db.make<NameType>("operator=")); first += 2; break; } @@ -2374,29 +3791,30 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'l': - db.names.push_back("operator()"); + db.Names.push_back(db.make<NameType>("operator()")); first += 2; break; case 'm': - db.names.push_back("operator,"); + db.Names.push_back(db.make<NameType>("operator,")); first += 2; break; case 'o': - db.names.push_back("operator~"); + db.Names.push_back(db.make<NameType>("operator~")); first += 2; break; case 'v': { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); - db.parsed_ctor_dtor_cv = true; + db.Names.back() = + db.make<ConversionOperatorType>(db.Names.back()); + db.ParsedCtorDtorCV = true; first = t; } } @@ -2407,23 +3825,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator delete[]"); + db.Names.push_back(db.make<NameType>("operator delete[]")); first += 2; break; case 'e': - db.names.push_back("operator*"); + db.Names.push_back(db.make<NameType>("operator*")); first += 2; break; case 'l': - db.names.push_back("operator delete"); + db.Names.push_back(db.make<NameType>("operator delete")); first += 2; break; case 'v': - db.names.push_back("operator/"); + db.Names.push_back(db.make<NameType>("operator/")); first += 2; break; case 'V': - db.names.push_back("operator/="); + db.Names.push_back(db.make<NameType>("operator/=")); first += 2; break; } @@ -2432,15 +3850,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator^"); + db.Names.push_back(db.make<NameType>("operator^")); first += 2; break; case 'O': - db.names.push_back("operator^="); + db.Names.push_back(db.make<NameType>("operator^=")); first += 2; break; case 'q': - db.names.push_back("operator=="); + db.Names.push_back(db.make<NameType>("operator==")); first += 2; break; } @@ -2449,11 +3867,11 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator>="); + db.Names.push_back(db.make<NameType>("operator>=")); first += 2; break; case 't': - db.names.push_back("operator>"); + db.Names.push_back(db.make<NameType>("operator>")); first += 2; break; } @@ -2461,7 +3879,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'i': if (first[1] == 'x') { - db.names.push_back("operator[]"); + db.Names.push_back(db.make<NameType>("operator[]")); first += 2; } break; @@ -2469,7 +3887,7 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator<="); + db.Names.push_back(db.make<NameType>("operator<=")); first += 2; break; case 'i': @@ -2477,23 +3895,24 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator\"\" "); + db.Names.back() = + db.make<LiteralOperator>(db.Names.back()); first = t; } } break; case 's': - db.names.push_back("operator<<"); + db.Names.push_back(db.make<NameType>("operator<<")); first += 2; break; case 'S': - db.names.push_back("operator<<="); + db.Names.push_back(db.make<NameType>("operator<<=")); first += 2; break; case 't': - db.names.push_back("operator<"); + db.Names.push_back(db.make<NameType>("operator<")); first += 2; break; } @@ -2502,23 +3921,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'i': - db.names.push_back("operator-"); + db.Names.push_back(db.make<NameType>("operator-")); first += 2; break; case 'I': - db.names.push_back("operator-="); + db.Names.push_back(db.make<NameType>("operator-=")); first += 2; break; case 'l': - db.names.push_back("operator*"); + db.Names.push_back(db.make<NameType>("operator*")); first += 2; break; case 'L': - db.names.push_back("operator*="); + db.Names.push_back(db.make<NameType>("operator*=")); first += 2; break; case 'm': - db.names.push_back("operator--"); + db.Names.push_back(db.make<NameType>("operator--")); first += 2; break; } @@ -2527,23 +3946,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator new[]"); + db.Names.push_back(db.make<NameType>("operator new[]")); first += 2; break; case 'e': - db.names.push_back("operator!="); + db.Names.push_back(db.make<NameType>("operator!=")); first += 2; break; case 'g': - db.names.push_back("operator-"); + db.Names.push_back(db.make<NameType>("operator-")); first += 2; break; case 't': - db.names.push_back("operator!"); + db.Names.push_back(db.make<NameType>("operator!")); first += 2; break; case 'w': - db.names.push_back("operator new"); + db.Names.push_back(db.make<NameType>("operator new")); first += 2; break; } @@ -2552,15 +3971,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator||"); + db.Names.push_back(db.make<NameType>("operator||")); first += 2; break; case 'r': - db.names.push_back("operator|"); + db.Names.push_back(db.make<NameType>("operator|")); first += 2; break; case 'R': - db.names.push_back("operator|="); + db.Names.push_back(db.make<NameType>("operator|=")); first += 2; break; } @@ -2569,27 +3988,27 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator->*"); + db.Names.push_back(db.make<NameType>("operator->*")); first += 2; break; case 'l': - db.names.push_back("operator+"); + db.Names.push_back(db.make<NameType>("operator+")); first += 2; break; case 'L': - db.names.push_back("operator+="); + db.Names.push_back(db.make<NameType>("operator+=")); first += 2; break; case 'p': - db.names.push_back("operator++"); + db.Names.push_back(db.make<NameType>("operator++")); first += 2; break; case 's': - db.names.push_back("operator+"); + db.Names.push_back(db.make<NameType>("operator+")); first += 2; break; case 't': - db.names.push_back("operator->"); + db.Names.push_back(db.make<NameType>("operator->")); first += 2; break; } @@ -2597,7 +4016,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'q': if (first[1] == 'u') { - db.names.push_back("operator?"); + db.Names.push_back(db.make<NameType>("operator?")); first += 2; } break; @@ -2605,19 +4024,19 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator%"); + db.Names.push_back(db.make<NameType>("operator%")); first += 2; break; case 'M': - db.names.push_back("operator%="); + db.Names.push_back(db.make<NameType>("operator%=")); first += 2; break; case 's': - db.names.push_back("operator>>"); + db.Names.push_back(db.make<NameType>("operator>>")); first += 2; break; case 'S': - db.names.push_back("operator>>="); + db.Names.push_back(db.make<NameType>("operator>>=")); first += 2; break; } @@ -2628,9 +4047,10 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); + db.Names.back() = + db.make<ConversionOperatorType>(db.Names.back()); first = t; } } @@ -2640,25 +4060,14 @@ parse_operator_name(const char* first, const char* last, C& db) return first; } -template <class C> const char* -parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) +parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) { const char* t = parse_number(first, last); if (t != first && t != last && *t == 'E') { - if (lit.size() > 3) - db.names.push_back("(" + lit + ")"); - else - db.names.emplace_back(); - if (*first == 'n') - { - db.names.back().first += '-'; - ++first; - } - db.names.back().first.append(first, t); - if (lit.size() <= 3) - db.names.back().first += lit; + db.Names.push_back( + db.make<IntegerExpr>(lit, StringView(first, t))); first = t+1; } return first; @@ -2671,9 +4080,8 @@ parse_integer_literal(const char* first, const char* last, const typename C::Str // ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) // ::= L <mangled-name> E # external name -template <class C> const char* -parse_expr_primary(const char* first, const char* last, C& db) +parse_expr_primary(const char* first, const char* last, Db& db) { if (last - first >= 4 && *first == 'L') { @@ -2692,11 +4100,11 @@ parse_expr_primary(const char* first, const char* last, C& db) switch (first[2]) { case '0': - db.names.push_back("false"); + db.Names.push_back(db.make<BoolExpr>(0)); first += 4; break; case '1': - db.names.push_back("true"); + db.Names.push_back(db.make<BoolExpr>(1)); first += 4; break; } @@ -2839,9 +4247,10 @@ parse_expr_primary(const char* first, const char* last, C& db) ; if (n != t && n != last && *n == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + db.Names.back() = db.make<IntegerCastExpr>( + db.Names.back(), StringView(t, n)); first = n+1; break; } @@ -2858,65 +4267,22 @@ parse_expr_primary(const char* first, const char* last, C& db) return first; } -template <class String> -String -base_name(String& s) +Node* maybe_change_special_sub_name(Node* inp, Db& db) { - if (s.empty()) - return s; - if (s == "std::string") - { - s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"; - return "basic_string"; - } - if (s == "std::istream") - { - s = "std::basic_istream<char, std::char_traits<char> >"; - return "basic_istream"; - } - if (s == "std::ostream") - { - s = "std::basic_ostream<char, std::char_traits<char> >"; - return "basic_ostream"; - } - if (s == "std::iostream") - { - s = "std::basic_iostream<char, std::char_traits<char> >"; - return "basic_iostream"; - } - const char* const pf = s.data(); - const char* pe = pf + s.size(); - if (pe[-1] == '>') + if (inp->K != Node::KSpecialSubstitution) + return inp; + auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK; + switch (Kind) { - unsigned c = 1; - while (true) - { - if (--pe == pf) - return String(); - if (pe[-1] == '<') - { - if (--c == 0) - { - --pe; - break; - } - } - else if (pe[-1] == '>') - ++c; - } + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + return db.make<ExpandedSpecialSubstitution>(Kind); + default: + break; } - if (pe - pf <= 1) - return String(); - const char* p0 = pe - 1; - for (; p0 != pf; --p0) - { - if (*p0 == ':') - { - ++p0; - break; - } - } - return String(p0, pe); + return inp; } // <ctor-dtor-name> ::= C1 # complete object constructor @@ -2928,11 +4294,10 @@ base_name(String& s) // ::= D2 # base object destructor // extension ::= D5 # ? -template <class C> const char* -parse_ctor_dtor_name(const char* first, const char* last, C& db) +parse_ctor_dtor_name(const char* first, const char* last, Db& db) { - if (last-first >= 2 && !db.names.empty()) + if (last-first >= 2 && !db.Names.empty()) { switch (first[0]) { @@ -2943,11 +4308,14 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '2': case '3': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back(base_name(db.names.back().first)); + db.Names.back() = + maybe_change_special_sub_name(db.Names.back(), db); + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), false)); first += 2; - db.parsed_ctor_dtor_cv = true; + db.ParsedCtorDtorCV = true; break; } break; @@ -2958,11 +4326,12 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '1': case '2': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back("~" + base_name(db.names.back().first)); + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), true)); first += 2; - db.parsed_ctor_dtor_cv = true; + db.ParsedCtorDtorCV = true; break; } break; @@ -2978,9 +4347,8 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) // // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -template <class C> const char* -parse_unnamed_type_name(const char* first, const char* last, C& db) +parse_unnamed_type_name(const char* first, const char* last, Db& db) { if (last - first > 2 && first[0] == 'U') { @@ -2989,106 +4357,63 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) { case 't': { - db.names.push_back(typename C::String("'unnamed")); const char* t0 = first+2; if (t0 == last) - { - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.append(t0, t1); + count = StringView(t0, t1); t0 = t1; } - db.names.back().first.push_back('\''); if (t0 == last || *t0 != '_') - { - db.names.pop_back(); return first; - } + db.Names.push_back(db.make<UnnamedTypeName>(count)); first = t0 + 1; } break; case 'l': { - size_t lambda_pos = db.names.size(); - db.names.push_back(typename C::String("'lambda'(")); + size_t begin_pos = db.Names.size(); const char* t0 = first+2; + NodeArray lambda_params; if (first[2] == 'v') { - db.names.back().first += ')'; ++t0; } else { - bool is_first_it = true; while (true) { - long k0 = static_cast<long>(db.names.size()); const char* t1 = parse_type(t0, last, db); - long k1 = static_cast<long>(db.names.size()); if (t1 == t0) break; - if (k0 >= k1) - return first; - // If the call to parse_type above found a pack expansion - // substitution, then multiple names could have been - // inserted into the name table. Walk through the names, - // appending each onto the lambda's parameter list. - std::for_each(db.names.begin() + k0, db.names.begin() + k1, - [&](typename C::sub_type::value_type &pair) { - if (pair.empty()) - return; - auto &lambda = db.names[lambda_pos].first; - if (!is_first_it) - lambda.append(", "); - is_first_it = false; - lambda.append(pair.move_full()); - }); - db.names.erase(db.names.begin() + k0, db.names.end()); t0 = t1; } - if (is_first_it) - { - if (!db.names.empty()) - db.names.pop_back(); + if (db.Names.size() < begin_pos) return first; - } - if (db.names.empty() || db.names.size() - 1 != lambda_pos) - return first; - db.names.back().first.append(")"); + lambda_params = db.popTrailingNodeArray(begin_pos); } if (t0 == last || *t0 != 'E') - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } + return first; ++t0; if (t0 == last) - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); + count = StringView(t0, t1); t0 = t1; } if (t0 == last || *t0 != '_') - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + db.Names.push_back(db.make<LambdaTypeName>(lambda_params, count)); first = t0 + 1; } break; @@ -3102,9 +4427,8 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) // ::= <source-name> // ::= <unnamed-type-name> -template <class C> const char* -parse_unqualified_name(const char* first, const char* last, C& db) +parse_unqualified_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -3149,9 +4473,8 @@ parse_unqualified_name(const char* first, const char* last, C& db) // ::= St <unqualified-name> # ::std:: // extension ::= StL<unqualified-name> -template <class C> const char* -parse_unscoped_name(const char* first, const char* last, C& db) +parse_unscoped_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3169,9 +4492,10 @@ parse_unscoped_name(const char* first, const char* last, C& db) { if (St) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); + db.Names.back() = + db.make<StdQualifiedName>(db.Names.back()); } first = t1; } @@ -3181,18 +4505,18 @@ parse_unscoped_name(const char* first, const char* last, C& db) // at <type> # alignof (a type) -template <class C> const char* -parse_alignof_type(const char* first, const char* last, C& db) +parse_alignof_type(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("alignof (", db.Names.back(), ")"); first = t; } } @@ -3201,57 +4525,55 @@ parse_alignof_type(const char* first, const char* last, C& db) // az <expression> # alignof (a expression) -template <class C> const char* -parse_alignof_expr(const char* first, const char* last, C& db) +parse_alignof_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("alignof (", db.Names.back(), ")"); first = t; } } return first; } -template <class C> const char* -parse_noexcept_expression(const char* first, const char* last, C& db) +parse_noexcept_expression(const char* first, const char* last, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("noexcept (", db.Names.back(), ")"); first = t1; } return first; } -template <class C> const char* -parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_prefix_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = op + "(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<PrefixExpr>(op, db.Names.back()); first = t1; } return first; } -template <class C> const char* -parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_binary_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) @@ -3259,22 +4581,14 @@ parse_binary_expression(const char* first, const char* last, const typename C::S const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - auto& nm = db.names.back().first; - nm.clear(); - if (op == ">") - nm += '('; - nm += "(" + op1 + ") " + op + " (" + op2 + ")"; - if (op == ">") - nm += ')'; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = db.make<BinaryExpr>(op1, op, op2); first = t2; } - else if(!db.names.empty()) - db.names.pop_back(); } return first; } @@ -3319,9 +4633,8 @@ parse_binary_expression(const char* first, const char* last, const typename C::S // # objectless nonstatic member reference // ::= <expr-primary> -template <class C> const char* -parse_expression(const char* first, const char* last, C& db) +parse_expression(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3411,10 +4724,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete[] " + db.names.back().move_full(); + db.Names.back() = db.make<DeleteExpr>( + db.Names.back(), parsed_gs, /*is_array=*/true); first = t1; } } @@ -3432,10 +4745,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete " + db.names.back().move_full(); + db.Names.back() = db.make<DeleteExpr>( + db.Names.back(), parsed_gs, /*is_array=*/false); first = t1; } } @@ -3504,16 +4817,17 @@ parse_expression(const char* first, const char* last, C& db) const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ")[" + op2 + "]"; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make<ArraySubscriptExpr>(op1, op2); first = t2; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3577,9 +4891,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")--"; + db.Names.back() = + db.make<PostfixExpr>(db.Names.back(), "--"); first = t1; } } @@ -3667,9 +4982,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")++"; + db.Names.back() = + db.make<PostfixExpr>(db.Names.back(), "++"); first = t1; } } @@ -3696,26 +5012,27 @@ parse_expression(const char* first, const char* last, C& db) const char* t3 = parse_expression(t2, last, db); if (t3 != t2) { - if (db.names.size() < 3) + if (db.Names.size() < 3) return first; - auto op3 = db.names.back().move_full(); - db.names.pop_back(); - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; + auto op3 = db.Names.back(); + db.Names.pop_back(); + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make<ConditionalExpr>(op1, op2, op3); first = t3; } else { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - db.names.pop_back(); - db.names.pop_back(); + db.Names.pop_back(); + db.Names.pop_back(); } } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3788,7 +5105,7 @@ parse_expression(const char* first, const char* last, C& db) first = parse_typeid_expr(first, last, db); break; case 'r': - db.names.push_back("throw"); + db.Names.push_back(db.make<NameType>("throw")); first += 2; break; case 'w': @@ -3817,9 +5134,8 @@ parse_expression(const char* first, const char* last, C& db) // ::= J <template-arg>* E # argument pack // ::= LZ <encoding> E # extension -template <class C> const char* -parse_template_arg(const char* first, const char* last, C& db) +parse_template_arg(const char* first, const char* last, Db& db) { if (first != last) { @@ -3870,57 +5186,52 @@ parse_template_arg(const char* first, const char* last, C& db) // <template-args> ::= I <template-arg>* E // extension, the abi says <template-arg>+ -template <class C> const char* -parse_template_args(const char* first, const char* last, C& db) +parse_template_args(const char* first, const char* last, Db& db) { if (last - first >= 2 && *first == 'I') { - if (db.tag_templates) - db.template_param.back().clear(); + if (db.TagTemplates) + db.TemplateParams.clear(); const char* t = first+1; - typename C::String args("<"); + size_t begin_idx = db.Names.size(); while (*t != 'E') { - if (db.tag_templates) - db.template_param.emplace_back(db.names.get_allocator()); - size_t k0 = db.names.size(); - const char* t1 = parse_template_arg(t, last, db); - size_t k1 = db.names.size(); - if (db.tag_templates) - db.template_param.pop_back(); - if (t1 == t || t1 == last) - return first; - if (db.tag_templates) + if (db.TagTemplates) { - db.template_param.back().emplace_back(db.names.get_allocator()); + auto TmpParams = std::move(db.TemplateParams); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + db.TemplateParams = std::move(TmpParams); + + if (t1 == t || t1 == last || k0 > k1) + return first; + db.TemplateParams.pushPack(); for (size_t k = k0; k < k1; ++k) - db.template_param.back().back().push_back(db.names[k]); - } - for (size_t k = k0; k < k1; ++k) - { - if (args.size() > 1) - args += ", "; - args += db.names[k].move_full(); + db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]); + t = t1; + continue; } - for (; k1 > k0; --k1) - if (!db.names.empty()) - db.names.pop_back(); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k0 > k1) + return first; t = t1; } + if (begin_idx > db.Names.size()) + return first; first = t + 1; - if (args.back() != '>') - args += ">"; - else - args += " >"; - db.names.push_back(std::move(args)); - + TemplateParams* tp = db.make<TemplateParams>( + db.popTrailingNodeArray(begin_idx)); + db.Names.push_back(tp); } return first; } -// <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> @@ -3935,39 +5246,35 @@ parse_template_args(const char* first, const char* last, C& db) // ::= <template-param> // ::= <substitution> -template <class C> const char* -parse_nested_name(const char* first, const char* last, C& db, +parse_nested_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'N') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_cv_qualifiers(first+1, last, cv); if (t0 == last) return first; - db.ref = 0; + db.RefQuals = FrefQualNone; if (*t0 == 'R') { - db.ref = 1; + db.RefQuals = FrefQualLValue; ++t0; } else if (*t0 == 'O') { - db.ref = 2; + db.RefQuals = FrefQualRValue; ++t0; } - db.names.emplace_back(); + db.Names.push_back(db.make<EmptyName>()); if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') { t0 += 2; - db.names.back().first = "std"; + db.Names.back() = db.make<NameType>("std"); } if (t0 == last) - { - db.names.pop_back(); return first; - } bool pop_subs = false; bool component_ends_with_template_args = false; while (*t0 != 'E') @@ -3982,17 +5289,18 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_substitution(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) { - db.names.back().first += "::" + name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); } else - db.names.back().first = name; + db.Names.back() = name; pop_subs = true; t0 = t1; } @@ -4003,15 +5311,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_param(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4024,15 +5333,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_decltype(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4043,12 +5353,13 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - db.names.back().first += name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto name = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<NameWithTemplateArgs>( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; component_ends_with_template_args = true; } @@ -4064,15 +5375,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_unqualified_name(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4081,9 +5393,9 @@ parse_nested_name(const char* first, const char* last, C& db, } } first = t0 + 1; - db.cv = cv; - if (pop_subs && !db.subs.empty()) - db.subs.pop_back(); + db.CV = cv; + if (pop_subs && !db.Subs.empty()) + db.Subs.popPack(); if (ends_with_template_args) *ends_with_template_args = component_ends_with_template_args; } @@ -4132,9 +5444,8 @@ parse_discriminator(const char* first, const char* last) // := Z <function encoding> E s [<discriminator>] // := Z <function encoding> Ed [ <parameter number> ] _ <entity name> -template <class C> const char* -parse_local_name(const char* first, const char* last, C& db, +parse_local_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'Z') @@ -4146,9 +5457,10 @@ parse_local_name(const char* first, const char* last, C& db, { case 's': first = parse_discriminator(t+1, last); - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append("::string literal"); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), db.make<NameType>("string literal")); break; case 'd': if (++t != last) @@ -4161,18 +5473,18 @@ parse_local_name(const char* first, const char* last, C& db, ends_with_template_args); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); first = t1; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -4184,17 +5496,17 @@ parse_local_name(const char* first, const char* last, C& db, { // parse but ignore discriminator first = parse_discriminator(t1, last); - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } break; } @@ -4211,9 +5523,8 @@ parse_local_name(const char* first, const char* last, C& db, // <unscoped-template-name> ::= <unscoped-name> // ::= <substitution> -template <class C> const char* -parse_name(const char* first, const char* last, C& db, +parse_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (last - first >= 2) @@ -4247,20 +5558,22 @@ parse_name(const char* first, const char* last, C& db, { if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args> { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4278,13 +5591,15 @@ parse_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4354,9 +5669,8 @@ parse_call_offset(const char* first, const char* last) // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first // extension ::= GR <object name> # reference temporary for object -template <class C> const char* -parse_special_name(const char* first, const char* last, C& db) +parse_special_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -4371,9 +5685,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "vtable for "); + db.Names.back() = + db.make<SpecialName>("vtable for ", db.Names.back()); first = t; } break; @@ -4382,9 +5697,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "VTT for "); + db.Names.back() = + db.make<SpecialName>("VTT for ", db.Names.back()); first = t; } break; @@ -4393,9 +5709,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo for "); + db.Names.back() = + db.make<SpecialName>("typeinfo for ", db.Names.back()); first = t; } break; @@ -4404,9 +5721,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo name for "); + db.Names.back() = + db.make<SpecialName>("typeinfo name for ", db.Names.back()); first = t; } break; @@ -4422,9 +5740,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "covariant return thunk to "); + db.Names.back() = + db.make<SpecialName>("covariant return thunk to ", + db.Names.back()); first = t; } } @@ -4440,15 +5760,14 @@ parse_special_name(const char* first, const char* last, C& db) const char* t1 = parse_type(++t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto left = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto left = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first = "construction vtable for " + - std::move(left) + "-in-" + - db.names.back().move_full(); + db.Names.back() = db.make<CtorVtableSpecialName>( + left, db.Names.back()); first = t1; } } @@ -4459,9 +5778,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first + 2, last, db); if (t != first + 2) { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "thread-local wrapper routine for "); + if (db.Names.empty()) + return first; + db.Names.back() = + db.make<SpecialName>("thread-local wrapper routine for ", + db.Names.back()); first = t; } break; @@ -4470,9 +5791,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first + 2, last, db); if (t != first + 2) { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "thread-local initialization routine for "); + if (db.Names.empty()) + return first; + db.Names.back() = db.make<SpecialName>( + "thread-local initialization routine for ", db.Names.back()); first = t; } break; @@ -4485,16 +5807,20 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t0, last, db); if (t != t0) { - if (db.names.empty()) + if (db.Names.empty()) return first; if (first[1] == 'v') { - db.names.back().first.insert(0, "virtual thunk to "); + db.Names.back() = + db.make<SpecialName>("virtual thunk to ", + db.Names.back()); first = t; } else { - db.names.back().first.insert(0, "non-virtual thunk to "); + db.Names.back() = + db.make<SpecialName>("non-virtual thunk to ", + db.Names.back()); first = t; } } @@ -4510,9 +5836,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "guard variable for "); + db.Names.back() = + db.make<SpecialName>("guard variable for ", db.Names.back()); first = t; } break; @@ -4521,9 +5848,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "reference temporary for "); + db.Names.back() = + db.make<SpecialName>("reference temporary for ", + db.Names.back()); first = t; } break; @@ -4558,19 +5887,18 @@ public: // ::= <data name> // ::= <special-name> -template <class C> const char* -parse_encoding(const char* first, const char* last, C& db) +parse_encoding(const char* first, const char* last, Db& db) { if (first != last) { - save_value<decltype(db.encoding_depth)> su(db.encoding_depth); - ++db.encoding_depth; - save_value<decltype(db.tag_templates)> sb(db.tag_templates); - if (db.encoding_depth > 1) - db.tag_templates = true; - save_value<decltype(db.parsed_ctor_dtor_cv)> sp(db.parsed_ctor_dtor_cv); - db.parsed_ctor_dtor_cv = false; + save_value<decltype(db.EncodingDepth)> su(db.EncodingDepth); + ++db.EncodingDepth; + save_value<decltype(db.TagTemplates)> sb(db.TagTemplates); + if (db.EncodingDepth > 1) + db.TagTemplates = true; + save_value<decltype(db.ParsedCtorDtorCV)> sp(db.ParsedCtorDtorCV); + db.ParsedCtorDtorCV = false; switch (*first) { case 'G': @@ -4582,96 +5910,72 @@ parse_encoding(const char* first, const char* last, C& db) bool ends_with_template_args = false; const char* t = parse_name(first, last, db, &ends_with_template_args); - unsigned cv = db.cv; - unsigned ref = db.ref; + if (db.Names.empty()) + return first; + Qualifiers cv = db.CV; + FunctionRefQual ref = db.RefQuals; if (t != first) { if (t != last && *t != 'E' && *t != '.') { - save_value<bool> sb2(db.tag_templates); - db.tag_templates = false; + save_value<bool> sb2(db.TagTemplates); + db.TagTemplates = false; const char* t2; - typename C::String ret2; - if (db.names.empty()) + if (db.Names.empty()) return first; - const typename C::String& nm = db.names.back().first; - if (nm.empty()) + if (!db.Names.back()) return first; - if (!db.parsed_ctor_dtor_cv && ends_with_template_args) + Node* return_type = nullptr; + if (!db.ParsedCtorDtorCV && ends_with_template_args) { t2 = parse_type(t, last, db); if (t2 == t) return first; - if (db.names.size() < 2) + if (db.Names.size() < 1) return first; - auto ret1 = std::move(db.names.back().first); - ret2 = std::move(db.names.back().second); - if (ret2.empty()) - ret1 += ' '; - db.names.pop_back(); - if (db.names.empty()) - return first; - - db.names.back().first.insert(0, ret1); + return_type = db.Names.back(); + db.Names.pop_back(); t = t2; } - db.names.back().first += '('; + + Node* result = nullptr; + if (t != last && *t == 'v') { ++t; + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make<TopLevelFunctionDecl>( + return_type, name, NodeArray()); } else { - bool first_arg = true; + size_t params_begin = db.Names.size(); while (true) { - size_t k0 = db.names.size(); t2 = parse_type(t, last, db); - size_t k1 = db.names.size(); if (t2 == t) break; - if (k1 > k0) - { - typename C::String tmp; - for (size_t k = k0; k < k1; ++k) - { - if (!tmp.empty()) - tmp += ", "; - tmp += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) { - if (db.names.empty()) - return first; - db.names.pop_back(); - } - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_arg) - db.names.back().first += ", "; - else - first_arg = false; - db.names.back().first += tmp; - } - } t = t2; } + if (db.Names.size() < params_begin) + return first; + NodeArray params = + db.popTrailingNodeArray(params_begin); + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make<TopLevelFunctionDecl>( + return_type, name, params); } - if (db.names.empty()) - return first; - db.names.back().first += ')'; - if (cv & 1) - db.names.back().first.append(" const"); - if (cv & 2) - db.names.back().first.append(" volatile"); - if (cv & 4) - db.names.back().first.append(" restrict"); - if (ref == 1) - db.names.back().first.append(" &"); - else if (ref == 2) - db.names.back().first.append(" &&"); - db.names.back().first += ret2; + if (ref != FrefQualNone) + result = db.make<FunctionRefQualType>(result, ref); + if (cv != QualNone) + result = db.make<FunctionQualType>(result, cv); + db.Names.push_back(result); first = t; } else @@ -4688,12 +5992,12 @@ parse_encoding(const char* first, const char* last, C& db) // _block_invoke<decimal-digit>+ // _block_invoke_<decimal-digit>+ -template <class C> const char* -parse_block_invoke(const char* first, const char* last, C& db) +parse_block_invoke(const char* first, const char* last, Db& db) { if (last - first >= 13) { + // FIXME: strcmp? const char test[] = "_block_invoke"; const char* t = first; for (int i = 0; i < 13; ++i, ++t) @@ -4714,9 +6018,11 @@ parse_block_invoke(const char* first, const char* last, C& db) while (t != last && isdigit(*t)) ++t; } - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "invocation function for block in "); + db.Names.back() = + db.make<SpecialName>("invocation function for block in ", + db.Names.back()); first = t; } return first; @@ -4725,15 +6031,15 @@ parse_block_invoke(const char* first, const char* last, C& db) // extension // <dot-suffix> := .<anything and everything> -template <class C> const char* -parse_dot_suffix(const char* first, const char* last, C& db) +parse_dot_suffix(const char* first, const char* last, Db& db) { if (first != last && *first == '.') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " (" + typename C::String(first, last) + ")"; + db.Names.back() = + db.make<DotSuffix>(db.Names.back(), StringView(first, last)); first = last; } return first; @@ -4745,9 +6051,8 @@ parse_dot_suffix(const char* first, const char* last, C& db) // <mangled-name> ::= _Z<encoding> // ::= <type> -template <class C> void -demangle(const char* first, const char* last, C& db, int& status) +demangle(const char* first, const char* last, Db& db, int& status) { if (first >= last) { @@ -4790,217 +6095,10 @@ demangle(const char* first, const char* last, C& db, int& status) if (t != last) status = invalid_mangled_name; } - if (status == success && db.names.empty()) + if (status == success && db.Names.empty()) status = invalid_mangled_name; } -template <std::size_t N> -class arena -{ - static const std::size_t alignment = 16; - alignas(alignment) char buf_[N]; - char* ptr_; - - std::size_t - align_up(std::size_t n) noexcept - {return (n + (alignment-1)) & ~(alignment-1);} - - bool - pointer_in_buffer(char* p) noexcept - {return buf_ <= p && p <= buf_ + N;} - -public: - arena() noexcept : ptr_(buf_) {} - ~arena() {ptr_ = nullptr;} - arena(const arena&) = delete; - arena& operator=(const arena&) = delete; - - char* allocate(std::size_t n); - void deallocate(char* p, std::size_t n) noexcept; - - static constexpr std::size_t size() {return N;} - std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);} - void reset() {ptr_ = buf_;} -}; - -template <std::size_t N> -char* -arena<N>::allocate(std::size_t n) -{ - n = align_up(n); - if (static_cast<std::size_t>(buf_ + N - ptr_) >= n) - { - char* r = ptr_; - ptr_ += n; - return r; - } - return static_cast<char*>(std::malloc(n)); -} - -template <std::size_t N> -void -arena<N>::deallocate(char* p, std::size_t n) noexcept -{ - if (pointer_in_buffer(p)) - { - n = align_up(n); - if (p + n == ptr_) - ptr_ = p; - } - else - std::free(p); -} - -template <class T, std::size_t N> -class short_alloc -{ - arena<N>& a_; -public: - typedef T value_type; - -public: - template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;}; - - short_alloc(arena<N>& a) noexcept : a_(a) {} - template <class U> - short_alloc(const short_alloc<U, N>& a) noexcept - : a_(a.a_) {} - short_alloc(const short_alloc&) = default; - short_alloc& operator=(const short_alloc&) = delete; - - T* allocate(std::size_t n) - { - return reinterpret_cast<T*>(a_.allocate(n*sizeof(T))); - } - void deallocate(T* p, std::size_t n) noexcept - { - a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T)); - } - - template <class T1, std::size_t N1, class U, std::size_t M> - friend - bool - operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept; - - template <class U, std::size_t M> friend class short_alloc; -}; - -template <class T, std::size_t N, class U, std::size_t M> -inline -bool -operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept -{ - return N == M && &x.a_ == &y.a_; -} - -template <class T, std::size_t N, class U, std::size_t M> -inline -bool -operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept -{ - return !(x == y); -} - -template <class T> -class malloc_alloc -{ -public: - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - malloc_alloc() = default; - template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {} - - T* allocate(std::size_t n) - { - return static_cast<T*>(std::malloc(n*sizeof(T))); - } - void deallocate(T* p, std::size_t) noexcept - { - std::free(p); - } - - template <class U> struct rebind { using other = malloc_alloc<U>; }; - template <class U, class... Args> - void construct(U* p, Args&&... args) - { - ::new ((void*)p) U(std::forward<Args>(args)...); - } - void destroy(T* p) - { - p->~T(); - } -}; - -template <class T, class U> -inline -bool -operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept -{ - return true; -} - -template <class T, class U> -inline -bool -operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept -{ - return !(x == y); -} - -const size_t bs = 4 * 1024; -template <class T> using Alloc = short_alloc<T, bs>; -template <class T> using Vector = std::vector<T, Alloc<T>>; - -template <class StrT> -struct string_pair -{ - StrT first; - StrT second; - - string_pair() = default; - string_pair(StrT f) : first(std::move(f)) {} - string_pair(StrT f, StrT s) - : first(std::move(f)), second(std::move(s)) {} - template <size_t N> - string_pair(const char (&s)[N]) : first(s, N-1) {} - - size_t size() const {return first.size() + second.size();} - bool empty() const { return first.empty() && second.empty(); } - StrT full() const {return first + second;} - StrT move_full() {return std::move(first) + std::move(second);} -}; - -struct Db -{ - typedef std::basic_string<char, std::char_traits<char>, - malloc_alloc<char>> String; - typedef Vector<string_pair<String>> sub_type; - typedef Vector<sub_type> template_param_type; - sub_type names; - template_param_type subs; - Vector<template_param_type> template_param; - unsigned cv = 0; - unsigned ref = 0; - unsigned encoding_depth = 0; - bool parsed_ctor_dtor_cv = false; - bool tag_templates = true; - bool fix_forward_references = false; - bool try_to_parse_template_args = true; - - template <size_t N> - Db(arena<N>& ar) : - names(ar), - subs(0, names, ar), - template_param(0, subs, ar) - {} -}; - } // unnamed namespace extern "C" _LIBCXXABI_FUNC_VIS char * @@ -5013,48 +6111,42 @@ __cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) { } size_t internal_size = buf != nullptr ? *n : 0; - arena<bs> a; - Db db(a); - db.template_param.emplace_back(a); + Db db; int internal_status = success; size_t len = std::strlen(mangled_name); demangle(mangled_name, mangled_name + len, db, internal_status); - if (internal_status == success && db.fix_forward_references && - !db.template_param.empty() && !db.template_param.front().empty()) + + if (internal_status == success && db.FixForwardReferences && + !db.TemplateParams.empty()) { - db.fix_forward_references = false; - db.tag_templates = false; - db.names.clear(); - db.subs.clear(); + db.FixForwardReferences = false; + db.TagTemplates = false; + db.Names.clear(); + db.Subs.clear(); demangle(mangled_name, mangled_name + len, db, internal_status); - if (db.fix_forward_references) + if (db.FixForwardReferences) internal_status = invalid_mangled_name; } + if (internal_status == success) { - size_t sz = db.names.back().size() + 1; - if (sz > internal_size) + if (!buf) { - char* newbuf = static_cast<char*>(std::realloc(buf, sz)); - if (newbuf == nullptr) - { - internal_status = memory_alloc_failure; - buf = nullptr; - } - else - { - buf = newbuf; - if (n != nullptr) - *n = sz; - } + internal_size = 1024; + buf = static_cast<char*>(std::malloc(internal_size)); } - if (buf != nullptr) + + if (buf) { - db.names.back().first += db.names.back().second; - std::memcpy(buf, db.names.back().first.data(), sz-1); - buf[sz-1] = char(0); + OutputStream s(buf, internal_size); + db.Names.back()->print(s); + s += '\0'; + if (n) *n = s.getCurrentPosition(); + buf = s.getBuffer(); } + else + internal_status = memory_alloc_failure; } else buf = nullptr; diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp index 0794444bcc5..e6ed0931ceb 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp @@ -19,6 +19,10 @@ #include "cxa_handlers.hpp" #include "fallback_malloc.h" +#if __has_feature(address_sanitizer) +extern "C" void __asan_handle_no_return(void); +#endif + // +---------------------------+-----------------------------+---------------+ // | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | // +---------------------------+-----------------------------+---------------+ @@ -217,6 +221,12 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + +#if __has_feature(address_sanitizer) + // Inform the ASan runtime that now might be a good time to clean stuff up. + __asan_handle_no_return(); +#endif + #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp index eaac21734f9..c641e0225f8 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp @@ -56,7 +56,7 @@ namespace { std::__libcpp_tls_key key_; std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - void destruct_ (void *p) { + void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { __free_with_fallback ( p ); if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) abort_message("cannot zero out thread value for __cxa_get_globals()"); diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h b/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h new file mode 100644 index 00000000000..bc131aeb5ae --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h @@ -0,0 +1,131 @@ +//===------------------------ __refstring ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of +// duplicating the file in libc++abi we should require that the libc++ sources +// are available when building libc++abi. + +#ifndef _LIBCPPABI_REFSTRING_H +#define _LIBCPPABI_REFSTRING_H + +#include <__config> +#include <stdexcept> +#include <cstddef> +#include <cstring> +#ifdef __APPLE__ +#include <dlfcn.h> +#include <mach-o/dyld.h> +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __refstring_imp { namespace { +typedef int count_t; + +struct _Rep_base { + std::size_t len; + std::size_t cap; + count_t count; +}; + +inline _Rep_base* rep_from_data(const char *data_) noexcept { + char *data = const_cast<char *>(data_); + return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); +} + +inline char * data_from_rep(_Rep_base *rep) noexcept { + char *data = reinterpret_cast<char *>(rep); + return data + sizeof(*rep); +} + +#if defined(__APPLE__) +inline +const char* compute_gcc_empty_string_storage() _NOEXCEPT +{ + void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); + if (handle == nullptr) + return nullptr; + void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); + if (sym == nullptr) + return nullptr; + return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); +} + +inline +const char* +get_gcc_empty_string_storage() _NOEXCEPT +{ + static const char* p = compute_gcc_empty_string_storage(); + return p; +} +#endif + +}} // namespace __refstring_imp + +using namespace __refstring_imp; + +inline +__libcpp_refstring::__libcpp_refstring(const char* msg) { + std::size_t len = strlen(msg); + _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); + rep->len = len; + rep->cap = len; + rep->count = 0; + char *data = data_from_rep(rep); + std::memcpy(data, msg, len + 1); + __imp_ = data; +} + +inline +__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT + : __imp_(s.__imp_) +{ + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); +} + +inline +__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { + bool adjust_old_count = __uses_refcount(); + struct _Rep_base *old_rep = rep_from_data(__imp_); + __imp_ = s.__imp_; + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); + if (adjust_old_count) + { + if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0) + { + ::operator delete(old_rep); + } + } + return *this; +} + +inline +__libcpp_refstring::~__libcpp_refstring() { + if (__uses_refcount()) { + _Rep_base* rep = rep_from_data(__imp_); + if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0) { + ::operator delete(rep); + } + } +} + +inline +bool __libcpp_refstring::__uses_refcount() const { +#ifdef __APPLE__ + return __imp_ != get_gcc_empty_string_storage(); +#else + return true; +#endif +} + +_LIBCPP_END_NAMESPACE_STD + +#endif //_LIBCPPABI_REFSTRING_H diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp index 58a2b0df6c0..08e2b45fa86 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp @@ -229,7 +229,7 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type, if (thrown_class_type == 0) return false; // bullet 2 - __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -427,7 +427,7 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); if (thrown_class_type == 0) return false; - __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -633,7 +633,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, // be returned. const void* dst_ptr = 0; // Initialize info struct for this search. - __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; + __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; // Find out if we can use a giant short cut in the search if (is_equal(dynamic_type, dst_type, false)) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp index bd6789ef227..e3b7cd40658 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "__refstring" +#include "include/refstring.h" #include "stdexcept" #include "new" #include <cstdlib> diff --git a/chromium/buildtools/third_party/libunwind/BUILD.gn b/chromium/buildtools/third_party/libunwind/BUILD.gn index 4f61b45adbe..0f2345673fd 100644 --- a/chromium/buildtools/third_party/libunwind/BUILD.gn +++ b/chromium/buildtools/third_party/libunwind/BUILD.gn @@ -11,7 +11,10 @@ config("libunwind_config") { source_set("libunwind") { visibility = [ "//buildtools/third_party/libc++abi" ] - if (libcpp_is_static) { + + # On desktop Linux, libunwind symbols conflict with glibc's, so + # always make them hidden, even for component builds. + if (libcpp_is_static || !is_fuchsia) { defines = [ "_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS" ] } sources = [ @@ -30,11 +33,13 @@ source_set("libunwind") { ] configs -= [ "//build/config/compiler:chromium_code", + "//build/config/compiler:no_exceptions", "//build/config/compiler:no_rtti", - "//build/config/gcc:no_exceptions", + "//build/config/coverage:default_coverage", ] configs += [ "//build/config/compiler:no_chromium_code", + "//build/config/compiler:exceptions", "//build/config/compiler:rtti", "//buildtools/third_party/libc++:config", diff --git a/chromium/buildtools/third_party/libunwind/README.chromium b/chromium/buildtools/third_party/libunwind/README.chromium index 75b57e66424..d787e87ad6b 100644 --- a/chromium/buildtools/third_party/libunwind/README.chromium +++ b/chromium/buildtools/third_party/libunwind/README.chromium @@ -3,7 +3,7 @@ URL: https://llvm.org/svn/llvm-project/libunwind/trunk/ Version: 1.0 License: MIT, University of Illinois/NCSA Open Source License License File: trunk/LICENSE.TXT -Security Critical: no +Security Critical: yes Description: diff --git a/chromium/buildtools/third_party/libunwind/trunk/CMakeLists.txt b/chromium/buildtools/third_party/libunwind/trunk/CMakeLists.txt index 032df560f2c..eef7479dfdf 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/CMakeLists.txt +++ b/chromium/buildtools/third_party/libunwind/trunk/CMakeLists.txt @@ -133,6 +133,8 @@ option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON) option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF) option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS}) +set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") @@ -162,7 +164,22 @@ set(CMAKE_MODULE_PATH set(LIBUNWIND_COMPILER ${CMAKE_CXX_COMPILER}) set(LIBUNWIND_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) +if (LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) +else() + set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX}) +endif() + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) + +set(LIBUNWIND_INSTALL_PREFIX "" CACHE STRING + "Define libunwind destination prefix.") + +if (NOT LIBUNWIND_INSTALL_PREFIX MATCHES "^$|.*/") + message(FATAL_ERROR "LIBUNWIND_INSTALL_PREFIX has to end with \"/\".") +endif() set(LIBUNWIND_C_FLAGS "") set(LIBUNWIND_CXX_FLAGS "") @@ -321,3 +338,5 @@ add_subdirectory(src) if (LIBUNWIND_INCLUDE_DOCS) add_subdirectory(docs) endif() + +add_subdirectory(test) diff --git a/chromium/buildtools/third_party/libunwind/trunk/cmake/config-ix.cmake b/chromium/buildtools/third_party/libunwind/trunk/cmake/config-ix.cmake index 40a5dd1f443..2d4da649f6d 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/cmake/config-ix.cmake +++ b/chromium/buildtools/third_party/libunwind/trunk/cmake/config-ix.cmake @@ -29,6 +29,19 @@ if (LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) elseif (LIBUNWIND_HAS_GCC_S_LIB) list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) endif () + if (MINGW) + # Mingw64 requires quite a few "C" runtime libraries in order for basic + # programs to link successfully with -nodefaultlibs. + if (LIBUNWIND_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) + endif() if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") endif () @@ -39,7 +52,6 @@ endif () # Check compiler flags check_c_compiler_flag(-funwind-tables LIBUNWIND_HAS_FUNWIND_TABLES) -check_cxx_compiler_flag(-fPIC LIBUNWIND_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fno-exceptions LIBUNWIND_HAS_NO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fno-rtti LIBUNWIND_HAS_NO_RTTI_FLAG) check_cxx_compiler_flag(-fstrict-aliasing LIBUNWIND_HAS_FSTRICT_ALIASING_FLAG) diff --git a/chromium/buildtools/third_party/libunwind/trunk/docs/conf.py b/chromium/buildtools/third_party/libunwind/trunk/docs/conf.py index 5a2f0709eb2..29c95f37b3c 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/docs/conf.py +++ b/chromium/buildtools/third_party/libunwind/trunk/docs/conf.py @@ -47,9 +47,9 @@ copyright = u'2011-2017, LLVM Project' # built documents. # # The short X.Y version. -version = '5.0' +version = '6.0' # The full version, including alpha/beta/rc tags. -release = '5.0' +release = '6.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/chromium/buildtools/third_party/libunwind/trunk/docs/index.rst b/chromium/buildtools/third_party/libunwind/trunk/docs/index.rst index 7e0b600a332..831bd0e1f58 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/docs/index.rst +++ b/chromium/buildtools/third_party/libunwind/trunk/docs/index.rst @@ -15,7 +15,7 @@ that never materialized (e.g. remote unwinding). The unwinder has two levels of API. The high level APIs are the `_Unwind_*` functions which implement functionality required by `__cxa_*` exception -funcionts. The low level APIs are the `unw_*` functions which are an interface +functions. The low level APIs are the `unw_*` functions which are an interface defined by the old HP libunwind project. Getting Started with libunwind @@ -44,12 +44,15 @@ libunwind is known to work on the following platforms: ============ ==================== ============ ======================== OS Arch Compilers Unwind Info ============ ==================== ============ ======================== -Mac OS X i386, x86_64 Clang, GCC DWARF CFI +Any i386, x86_64, ARM Clang SjLj +Bare Metal ARM Clang, GCC EHABI +FreeBSD i386, x86_64, ARM64 Clang DWARF CFI iOS ARM Clang SjLj -Linux i386, x86_64 Clang, GCC DWARF CFI Linux ARM Clang, GCC EHABI -Bare Metal ARM Clang, GCC EHABI +Linux i386, x86_64, ARM64 Clang, GCC DWARF CFI +Mac OS X i386, x86_64 Clang, GCC DWARF CFI NetBSD x86_64 Clang, GCC DWARF CFI +Windows i386, x86_64 Clang DWARF CFI ============ ==================== ============ ======================== The following minimum compiler versions are strongly recommended. diff --git a/chromium/buildtools/third_party/libunwind/trunk/include/__libunwind_config.h b/chromium/buildtools/third_party/libunwind/trunk/include/__libunwind_config.h index 83f4f471256..6d69085d83a 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/include/__libunwind_config.h +++ b/chromium/buildtools/third_party/libunwind/trunk/include/__libunwind_config.h @@ -15,42 +15,54 @@ #define _LIBUNWIND_ARM_EHABI #endif +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 95 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 31 + #if defined(_LIBUNWIND_IS_NATIVE_ONLY) # if defined(__i386__) # define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_CONTEXT_SIZE 8 -# define _LIBUNWIND_CURSOR_SIZE 19 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 9 +# define _LIBUNWIND_CURSOR_SIZE 15 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 # elif defined(__x86_64__) # define _LIBUNWIND_TARGET_X86_64 1 -# define _LIBUNWIND_CONTEXT_SIZE 21 -# define _LIBUNWIND_CURSOR_SIZE 33 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 17 +# if defined(_WIN64) +# define _LIBUNWIND_CONTEXT_SIZE 54 +# define _LIBUNWIND_CURSOR_SIZE 66 +# else +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 # elif defined(__ppc__) # define _LIBUNWIND_TARGET_PPC 1 # define _LIBUNWIND_CONTEXT_SIZE 117 -# define _LIBUNWIND_CURSOR_SIZE 128 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 113 +# define _LIBUNWIND_CURSOR_SIZE 124 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC # elif defined(__aarch64__) # define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_CONTEXT_SIZE 66 # define _LIBUNWIND_CURSOR_SIZE 78 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 96 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 # elif defined(__arm__) # define _LIBUNWIND_TARGET_ARM 1 # if defined(__ARM_WMMX) -# define _LIBUNWIND_CONTEXT_SIZE 60 -# define _LIBUNWIND_CURSOR_SIZE 67 +# define _LIBUNWIND_CONTEXT_SIZE 61 +# define _LIBUNWIND_CURSOR_SIZE 68 # else # define _LIBUNWIND_CONTEXT_SIZE 42 # define _LIBUNWIND_CURSOR_SIZE 49 # endif -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 96 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM # elif defined(__or1k__) # define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_CONTEXT_SIZE 16 -# define _LIBUNWIND_CURSOR_SIZE 28 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K # else # error "Unsupported architecture." # endif @@ -63,7 +75,7 @@ # define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_CONTEXT_SIZE 128 # define _LIBUNWIND_CURSOR_SIZE 140 -# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 120 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 119 #endif // _LIBUNWIND_IS_NATIVE_ONLY #endif // ____LIBUNWIND_CONFIG_H__ diff --git a/chromium/buildtools/third_party/libunwind/trunk/include/libunwind.h b/chromium/buildtools/third_party/libunwind/trunk/include/libunwind.h index cd090375962..04840440d88 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/include/libunwind.h +++ b/chromium/buildtools/third_party/libunwind/trunk/include/libunwind.h @@ -72,11 +72,10 @@ typedef struct unw_cursor_t unw_cursor_t; typedef struct unw_addr_space *unw_addr_space_t; typedef int unw_regnum_t; +typedef uintptr_t unw_word_t; #if defined(_LIBUNWIND_ARM_EHABI) -typedef uint32_t unw_word_t; typedef uint64_t unw_fpreg_t; #else -typedef uint64_t unw_word_t; typedef double unw_fpreg_t; #endif @@ -188,7 +187,24 @@ enum { UNW_X86_64_R12 = 12, UNW_X86_64_R13 = 13, UNW_X86_64_R14 = 14, - UNW_X86_64_R15 = 15 + UNW_X86_64_R15 = 15, + UNW_X86_64_RIP = 16, + UNW_X86_64_XMM0 = 17, + UNW_X86_64_XMM1 = 18, + UNW_X86_64_XMM2 = 19, + UNW_X86_64_XMM3 = 20, + UNW_X86_64_XMM4 = 21, + UNW_X86_64_XMM5 = 22, + UNW_X86_64_XMM6 = 23, + UNW_X86_64_XMM7 = 24, + UNW_X86_64_XMM8 = 25, + UNW_X86_64_XMM9 = 26, + UNW_X86_64_XMM10 = 27, + UNW_X86_64_XMM11 = 28, + UNW_X86_64_XMM12 = 29, + UNW_X86_64_XMM13 = 30, + UNW_X86_64_XMM14 = 31, + UNW_X86_64_XMM15 = 32, }; diff --git a/chromium/buildtools/third_party/libunwind/trunk/include/unwind.h b/chromium/buildtools/third_party/libunwind/trunk/include/unwind.h index fc7d122ab12..0ab87dd615b 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/include/unwind.h +++ b/chromium/buildtools/third_party/libunwind/trunk/include/unwind.h @@ -100,7 +100,7 @@ struct _Unwind_Control_Block { } pr_cache; long long int :0; /* Enforce the 8-byte alignment */ -}; +} __attribute__((__aligned__(8))); typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (_Unwind_State state, @@ -122,7 +122,7 @@ struct _Unwind_Exception { _Unwind_Exception *exc); uintptr_t private_1; // non-zero means forced unwind uintptr_t private_2; // holds sp that phase1 found for phase2 to use -#ifndef __LP64__ +#if __SIZEOF_POINTER__ == 4 // The implementation of _Unwind_Exception uses an attribute mode on the // above fields which has the side effect of causing this whole struct to // round up to 32 bytes in size. To be more explicit, we add pad fields diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/AddressSpace.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/AddressSpace.hpp index 2ed52a5583c..32428400526 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/AddressSpace.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/AddressSpace.hpp @@ -18,7 +18,7 @@ #include <stdlib.h> #include <string.h> -#ifndef _LIBUNWIND_IS_BAREMETAL +#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) #include <dlfcn.h> #endif @@ -35,6 +35,80 @@ namespace libunwind { #include "EHHeaderParser.hpp" #include "Registers.hpp" +#ifdef __APPLE__ + + struct dyld_unwind_sections + { + const struct mach_header* mh; + const void* dwarf_section; + uintptr_t dwarf_section_length; + const void* compact_unwind_section; + uintptr_t compact_unwind_section_length; + }; + #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ + && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ + || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); + #else + // In 10.6.x and earlier, we need to implement this functionality. Note + // that this requires a newer version of libmacho (from cctools) than is + // present in libSystem on 10.6.x (for getsectiondata). + static inline bool _dyld_find_unwind_sections(void* addr, + dyld_unwind_sections* info) { + // Find mach-o image containing address. + Dl_info dlinfo; + if (!dladdr(addr, &dlinfo)) + return false; +#if __LP64__ + const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; +#else + const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; +#endif + + // Initialize the return struct + info->mh = (const struct mach_header *)mh; + info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); + info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); + + if (!info->dwarf_section) { + info->dwarf_section_length = 0; + } + + if (!info->compact_unwind_section) { + info->compact_unwind_section_length = 0; + } + + return true; + } + #endif + +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. +extern char __exidx_start; +extern char __exidx_end; + +#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +// ELF-based systems may use dl_iterate_phdr() to access sections +// containing unwinding information. The ElfW() macro for pointer-size +// independent ELF header traversal is not provided by <link.h> on some +// systems (e.g., FreeBSD). On these systems the data structures are +// just called Elf_XXX. Define ElfW() locally. +#ifndef _WIN32 +#include <link.h> +#else +#include <windows.h> +#include <psapi.h> +#endif +#if !defined(ElfW) +#define ElfW(type) Elf_##type +#endif + +#endif + namespace libunwind { /// Used by findUnwindSections() to return info about needed sections. @@ -68,13 +142,8 @@ struct UnwindInfoSections { /// making local unwinds fast. class __attribute__((visibility("hidden"))) LocalAddressSpace { public: -#ifdef __LP64__ - typedef uint64_t pint_t; - typedef int64_t sint_t; -#else - typedef uint32_t pint_t; - typedef int32_t sint_t; -#endif + typedef uintptr_t pint_t; + typedef intptr_t sint_t; uint8_t get8(pint_t addr) { uint8_t val; memcpy(&val, (void *)addr, sizeof(val)); @@ -120,7 +189,7 @@ public: }; inline uintptr_t LocalAddressSpace::getP(pint_t addr) { -#ifdef __LP64__ +#if __SIZEOF_POINTER__ == 8 return get64(addr); #else return get32(addr); @@ -265,75 +334,6 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, return result; } -#ifdef __APPLE__ - - struct dyld_unwind_sections - { - const struct mach_header* mh; - const void* dwarf_section; - uintptr_t dwarf_section_length; - const void* compact_unwind_section; - uintptr_t compact_unwind_section_length; - }; - #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ - && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ - || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) - // In 10.7.0 or later, libSystem.dylib implements this function. - extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); - #else - // In 10.6.x and earlier, we need to implement this functionality. Note - // that this requires a newer version of libmacho (from cctools) than is - // present in libSystem on 10.6.x (for getsectiondata). - static inline bool _dyld_find_unwind_sections(void* addr, - dyld_unwind_sections* info) { - // Find mach-o image containing address. - Dl_info dlinfo; - if (!dladdr(addr, &dlinfo)) - return false; -#if __LP64__ - const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; -#else - const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; -#endif - - // Initialize the return struct - info->mh = (const struct mach_header *)mh; - info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); - info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); - - if (!info->dwarf_section) { - info->dwarf_section_length = 0; - } - - if (!info->compact_unwind_section) { - info->compact_unwind_section_length = 0; - } - - return true; - } - #endif - -#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) - -// When statically linked on bare-metal, the symbols for the EH table are looked -// up without going through the dynamic loader. -extern char __exidx_start; -extern char __exidx_end; - -#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) - -// ELF-based systems may use dl_iterate_phdr() to access sections -// containing unwinding information. The ElfW() macro for pointer-size -// independent ELF header traversal is not provided by <link.h> on some -// systems (e.g., FreeBSD). On these systems the data structures are -// just called Elf_XXX. Define ElfW() locally. -#include <link.h> -#if !defined(ElfW) -#define ElfW(type) Elf_##type -#endif - -#endif - inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ @@ -356,6 +356,51 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, info.arm_section, info.arm_section_length); if (info.arm_section && info.arm_section_length) return true; +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + HMODULE mods[1024]; + HANDLE process = GetCurrentProcess(); + DWORD needed; + + if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) + return false; + + for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { + PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; + PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); + PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; + PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); + bool found_obj = false; + bool found_hdr = false; + + info.dso_base = (uintptr_t)mods[i]; + for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { + uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; + uintptr_t end = begin + pish->Misc.VirtualSize; + if (!strncmp((const char *)pish->Name, ".text", + IMAGE_SIZEOF_SHORT_NAME)) { + if (targetAddr >= begin && targetAddr < end) + found_obj = true; + } else if (!strncmp((const char *)pish->Name, ".eh_frame", + IMAGE_SIZEOF_SHORT_NAME)) { + // FIXME: This section name actually is truncated, ideally we + // should locate and check the full long name instead. + info.dwarf_section = begin; + info.dwarf_section_length = pish->Misc.VirtualSize; + found_hdr = true; + } + if (found_obj && found_hdr) + return true; + } + } + return false; +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \ + (__ANDROID_API__ < 21) + int length = 0; + info.arm_section = + (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); + info.arm_section_length = (uintptr_t)length; + if (info.arm_section && info.arm_section_length) + return true; #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) struct dl_iterate_cb_data { LocalAddressSpace *addressSpace; @@ -478,7 +523,7 @@ inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { -#ifndef _LIBUNWIND_IS_BAREMETAL +#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) Dl_info dyldInfo; if (dladdr((void *)addr, &dyldInfo)) { if (dyldInfo.dli_sname != NULL) { diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/CMakeLists.txt b/chromium/buildtools/third_party/libunwind/trunk/src/CMakeLists.txt index 0c78523f965..17550d9ef8a 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/CMakeLists.txt +++ b/chromium/buildtools/third_party/libunwind/trunk/src/CMakeLists.txt @@ -30,8 +30,8 @@ set(LIBUNWIND_HEADERS DwarfParser.hpp libunwind_ext.h Registers.hpp + RWMutex.hpp UnwindCursor.hpp - unwind_ext.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/libunwind.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/unwind.h) @@ -58,7 +58,6 @@ if (LIBUNWIND_ENABLE_THREADS) endif() # Setup flags. -append_if(LIBUNWIND_COMPILE_FLAGS LIBUNWIND_HAS_FPIC_FLAG -fPIC) append_if(LIBUNWIND_CXX_FLAGS LIBUNWIND_HAS_NO_RTTI_FLAG -fno-rtti) append_if(LIBUNWIND_LINK_FLAGS LIBUNWIND_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs) @@ -101,7 +100,8 @@ add_library(unwind_objects OBJECT ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) set_target_properties(unwind_objects PROPERTIES - COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}") + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + POSITION_INDEPENDENT_CODE ON) set(LIBUNWIND_TARGETS) @@ -133,6 +133,6 @@ endif() add_custom_target(unwind DEPENDS ${LIBUNWIND_TARGETS}) install(TARGETS ${LIBUNWIND_TARGETS} - LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} - ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) + LIBRARY DESTINATION ${LIBUNWIND_INSTALL_PREFIX}lib${LIBUNWIND_LIBDIR_SUFFIX} + ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_PREFIX}lib${LIBUNWIND_LIBDIR_SUFFIX}) diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/DwarfInstructions.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/DwarfInstructions.hpp index a4286330157..bd1448b2842 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/DwarfInstructions.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/DwarfInstructions.hpp @@ -167,7 +167,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, R newRegisters = registers; pint_t returnAddress = 0; const int lastReg = R::lastDwarfRegNum(); - assert((int)CFI_Parser<A>::kMaxRegisterNumber > lastReg && + assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg && "register range too large"); assert(lastReg >= (int)cieInfo.returnAddressRegister && "register range does not contain return address register"); diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/DwarfParser.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/DwarfParser.hpp index 3c98d304fda..95af7a6ffa0 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/DwarfParser.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/DwarfParser.hpp @@ -87,7 +87,7 @@ public: uint32_t codeOffsetAtStackDecrement; bool registersInOtherRegisters; bool sameValueUsed; - RegisterLocation savedRegisters[kMaxRegisterNumber]; + RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; }; struct PrologInfoStackEntry { @@ -605,6 +605,13 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, break; case DW_CFA_val_offset: reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterOffsetFromCFA; @@ -668,6 +675,12 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, switch (opcode & 0xC0) { case DW_CFA_offset: reg = operand; + if (reg > kMaxRegisterNumber) { + fprintf(stderr, "malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; @@ -682,6 +695,12 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, break; case DW_CFA_restore: reg = operand; + if (reg > kMaxRegisterNumber) { + fprintf(stderr, "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } results->savedRegisters[reg] = initialState.savedRegisters[reg]; _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", static_cast<uint64_t>(operand)); diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/EHHeaderParser.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/EHHeaderParser.hpp index c66af211998..9bdaf5505ff 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/EHHeaderParser.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/EHHeaderParser.hpp @@ -67,7 +67,9 @@ void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, ehHdrInfo.eh_frame_ptr = addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); ehHdrInfo.fde_count = - addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); + fde_count_enc == DW_EH_PE_omit + ? 0 + : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); ehHdrInfo.table = p; } diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/RWMutex.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/RWMutex.hpp new file mode 100644 index 00000000000..50a78a57b08 --- /dev/null +++ b/chromium/buildtools/third_party/libunwind/trunk/src/RWMutex.hpp @@ -0,0 +1,77 @@ +//===----------------------------- Registers.hpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// Abstract interface to shared reader/writer log, hiding platform and +// configuration differences. +// +//===----------------------------------------------------------------------===// + +#ifndef __RWMUTEX_HPP__ +#define __RWMUTEX_HPP__ + +#if defined(_WIN32) +#include <windows.h> +#elif !defined(_LIBUNWIND_HAS_NO_THREADS) +#include <pthread.h> +#endif + +namespace libunwind { + +#if defined(_LIBUNWIND_HAS_NO_THREADS) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return true; } + bool unlock_shared() { return true; } + bool lock() { return true; } + bool unlock() { return true; } +}; + +#elif defined(_WIN32) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + AcquireSRWLockShared(&_lock); + return true; + } + bool unlock_shared() { + ReleaseSRWLockShared(&_lock); + return true; + } + bool lock() { + AcquireSRWLockExclusive(&_lock); + return true; + } + bool unlock() { + ReleaseSRWLockExclusive(&_lock); + return true; + } + +private: + SRWLOCK _lock = SRWLOCK_INIT; +}; + +#else + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; } + bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; } + bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; } + bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#endif + +} // namespace libunwind + +#endif // __RWMUTEX_HPP__ diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/Registers.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/Registers.hpp index ff57c6076fe..0c4fecb8ab7 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/Registers.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/Registers.hpp @@ -44,7 +44,7 @@ public: void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 8; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } uint32_t getSP() const { return _registers.__esp; } void setSP(uint32_t value) { _registers.__esp = value; } @@ -245,12 +245,12 @@ public: bool validFloatRegister(int) const { return false; } double getFloatRegister(int num) const; void setFloatRegister(int num, double value); - bool validVectorRegister(int) const { return false; } + bool validVectorRegister(int) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 16; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } uint64_t getSP() const { return _registers.__rsp; } void setSP(uint64_t value) { _registers.__rsp = value; } @@ -292,8 +292,14 @@ private: uint64_t __cs; uint64_t __fs; uint64_t __gs; +#if defined(_WIN64) + uint64_t __padding; // 16-byte align +#endif }; GPRs _registers; +#if defined(_WIN64) + v128 _xmm[16]; +#endif }; inline Registers_x86_64::Registers_x86_64(const void *registers) { @@ -458,6 +464,38 @@ inline const char *Registers_x86_64::getRegisterName(int regNum) { return "r14"; case UNW_X86_64_R15: return "r15"; + case UNW_X86_64_XMM0: + return "xmm0"; + case UNW_X86_64_XMM1: + return "xmm1"; + case UNW_X86_64_XMM2: + return "xmm2"; + case UNW_X86_64_XMM3: + return "xmm3"; + case UNW_X86_64_XMM4: + return "xmm4"; + case UNW_X86_64_XMM5: + return "xmm5"; + case UNW_X86_64_XMM6: + return "xmm6"; + case UNW_X86_64_XMM7: + return "xmm7"; + case UNW_X86_64_XMM8: + return "xmm8"; + case UNW_X86_64_XMM9: + return "xmm9"; + case UNW_X86_64_XMM10: + return "xmm10"; + case UNW_X86_64_XMM11: + return "xmm11"; + case UNW_X86_64_XMM12: + return "xmm12"; + case UNW_X86_64_XMM13: + return "xmm13"; + case UNW_X86_64_XMM14: + return "xmm14"; + case UNW_X86_64_XMM15: + return "xmm15"; default: return "unknown register"; } @@ -471,12 +509,34 @@ inline void Registers_x86_64::setFloatRegister(int, double) { _LIBUNWIND_ABORT("no x86_64 float registers"); } -inline v128 Registers_x86_64::getVectorRegister(int) const { +inline bool Registers_x86_64::validVectorRegister(int regNum) const { +#if defined(_WIN64) + if (regNum < UNW_X86_64_XMM0) + return false; + if (regNum > UNW_X86_64_XMM15) + return false; + return true; +#else + return false; +#endif +} + +inline v128 Registers_x86_64::getVectorRegister(int regNum) const { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + return _xmm[regNum - UNW_X86_64_XMM0]; +#else _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif } -inline void Registers_x86_64::setVectorRegister(int, v128) { +inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + _xmm[regNum - UNW_X86_64_XMM0] = value; +#else _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif } #endif // _LIBUNWIND_TARGET_X86_64 @@ -500,7 +560,7 @@ public: void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 112; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } uint64_t getSP() const { return _registers.__r1; } void setSP(uint32_t value) { _registers.__r1 = value; } @@ -1066,7 +1126,7 @@ public: void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 95; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } uint64_t getSP() const { return _registers.__sp; } void setSP(uint64_t value) { _registers.__sp = value; } @@ -1815,7 +1875,7 @@ public: void setVectorRegister(int num, v128 value); const char *getRegisterName(int num); void jumpto(); - static int lastDwarfRegNum() { return 31; } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } uint64_t getSP() const { return _registers.__r[1]; } void setSP(uint32_t value) { _registers.__r[1] = value; } diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-EHABI.cpp b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-EHABI.cpp index 109b27281eb..f37732c6ac8 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-EHABI.cpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-EHABI.cpp @@ -14,6 +14,7 @@ #if defined(_LIBUNWIND_ARM_EHABI) +#include <inttypes.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> @@ -468,11 +469,11 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t pc; unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " - "lsda=0x%llX, personality=0x%llX", - static_cast<void *>(exception_object), (long long)pc, - (long long)frameInfo.start_ip, functionName, - (long long)frameInfo.lsda, (long long)frameInfo.handler); + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + static_cast<void *>(exception_object), pc, + frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, ask it if it will want to stop at @@ -584,11 +585,11 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " - "lsda=0x%llX, personality=0x%llX", - static_cast<void *>(exception_object), (long long)frameInfo.start_ip, - functionName, (long long)sp, (long long)frameInfo.lsda, - (long long)frameInfo.handler); + "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + static_cast<void *>(exception_object), frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. @@ -627,9 +628,9 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " - "user code with ip=0x%llX, sp=0x%llX", + "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, static_cast<void *>(exception_object), - (long long)pc, (long long)sp); + pc, sp); } { diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-sjlj.c b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-sjlj.c index f01e65259fc..90cac3f8c76 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-sjlj.c +++ b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind-sjlj.c @@ -17,20 +17,14 @@ #include <stdlib.h> #include "config.h" -#include "unwind_ext.h" -// -// 32-bit iOS uses setjump/longjump based C++ exceptions. -// Other architectures use "zero cost" exceptions. -// -// With SJLJ based exceptions, any function that has a catch clause or needs to -// do any clean up when an exception propagates through it, needs to call -// _Unwind_SjLj_Register() at the start of the function and -// _Unwind_SjLj_Unregister() at the end. The register function is called with -// the address of a block of memory in the function's stack frame. The runtime -// keeps a linked list (stack) of these blocks - one per thread. The calling -// function also sets the personality and lsda fields of the block. -// +/// With SJLJ based exceptions, any function that has a catch clause or needs to +/// do any clean up when an exception propagates through it, needs to call +/// \c _Unwind_SjLj_Register at the start of the function and +/// \c _Unwind_SjLj_Unregister at the end. The register function is called with +/// the address of a block of memory in the function's stack frame. The runtime +/// keeps a linked list (stack) of these blocks - one per thread. The calling +/// function also sets the personality and lsda fields of the block. #if defined(_LIBUNWIND_BUILD_SJLJ_APIS) @@ -39,10 +33,10 @@ struct _Unwind_FunctionContext { struct _Unwind_FunctionContext *prev; // set by calling function before registering to be the landing pad - uintptr_t resumeLocation; + uint32_t resumeLocation; // set by personality handler to be parameters passed to landing pad function - uintptr_t resumeParameters[4]; + uint32_t resumeParameters[4]; // set by calling function before registering __personality_routine personality; // arm offset=24 @@ -53,6 +47,48 @@ struct _Unwind_FunctionContext { void *jbuf[]; }; +#if defined(_LIBUNWIND_HAS_NO_THREADS) +# define _LIBUNWIND_THREAD_LOCAL +#else +# if __STDC_VERSION__ >= 201112L +# define _LIBUNWIND_THREAD_LOCAL _Thread_local +# elif defined(_WIN32) +# define _LIBUNWIND_THREAD_LOCAL __declspec(thread) +# elif defined(__GNUC__) || defined(__clang__) +# define _LIBUNWIND_THREAD_LOCAL __thread +# else +# error Unable to create thread local storage +# endif +#endif + + +#if !defined(FOR_DYLD) + +#if defined(__APPLE__) +#include <System/pthread_machdep.h> +#else +static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; +#endif + +static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { +#if defined(__APPLE__) + return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); +#else + return stack; +#endif +} + +static void +__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { +#if defined(__APPLE__) + _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); +#else + stack = fc; +#endif +} + +#endif + /// Called at start of each function that catches exceptions _LIBUNWIND_EXPORT void diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindCursor.hpp b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindCursor.hpp index 5f9cba9ff76..ab2f542dbdf 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindCursor.hpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindCursor.hpp @@ -16,9 +16,6 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> -#ifndef _LIBUNWIND_HAS_NO_THREADS - #include <pthread.h> -#endif #include <unwind.h> #ifdef __APPLE__ @@ -34,6 +31,7 @@ #include "EHHeaderParser.hpp" #include "libunwind.h" #include "Registers.hpp" +#include "RWMutex.hpp" #include "Unwind-EHABI.h" namespace libunwind { @@ -62,9 +60,7 @@ private: // These fields are all static to avoid needing an initializer. // There is only one instance of this class per process. -#ifndef _LIBUNWIND_HAS_NO_THREADS - static pthread_rwlock_t _lock; -#endif + static RWMutex _lock; #ifdef __APPLE__ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); static bool _registeredForDyldUnloads; @@ -91,10 +87,8 @@ DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64]; template <typename A> typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; -#ifndef _LIBUNWIND_HAS_NO_THREADS template <typename A> -pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER; -#endif +RWMutex DwarfFDECache<A>::_lock; #ifdef __APPLE__ template <typename A> @@ -104,7 +98,7 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false; template <typename A> typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { pint_t result = 0; - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); for (entry *p = _buffer; p < _bufferUsed; ++p) { if ((mh == p->mh) || (mh == 0)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) { @@ -113,7 +107,7 @@ typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { } } } - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared()); return result; } @@ -121,7 +115,7 @@ template <typename A> void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) { #if !defined(_LIBUNWIND_NO_HEAP) - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); if (_bufferUsed >= _bufferEnd) { size_t oldSize = (size_t)(_bufferEnd - _buffer); size_t newSize = oldSize * 4; @@ -145,13 +139,13 @@ void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, _registeredForDyldUnloads = true; } #endif - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); #endif } template <typename A> void DwarfFDECache<A>::removeAllIn(pint_t mh) { - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); entry *d = _buffer; for (const entry *s = _buffer; s < _bufferUsed; ++s) { if (s->mh != mh) { @@ -161,7 +155,7 @@ void DwarfFDECache<A>::removeAllIn(pint_t mh) { } } _bufferUsed = d; - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } #ifdef __APPLE__ @@ -174,11 +168,11 @@ void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { template <typename A> void DwarfFDECache<A>::iterateCacheEntries(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); for (entry *p = _buffer; p < _bufferUsed; ++p) { (*func)(p->ip_start, p->ip_end, p->fde, p->mh); } - _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) @@ -744,14 +738,21 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection( EHABISectionIterator<A>::begin(_addressSpace, sects); EHABISectionIterator<A> end = EHABISectionIterator<A>::end(_addressSpace, sects); + if (begin == end) + return false; EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc); - if (itNextPC == begin || itNextPC == end) + if (itNextPC == begin) return false; EHABISectionIterator<A> itThisPC = itNextPC - 1; pint_t thisPC = itThisPC.functionAddress(); - pint_t nextPC = itNextPC.functionAddress(); + // If an exception is thrown from a function, corresponding to the last entry + // in the table, we don't really know the function extent and have to choose a + // value for nextPC. Choosing max() will allow the range check during trace to + // succeed. + pint_t nextPC = (itNextPC == end) ? std::numeric_limits<pint_t>::max() + : itNextPC.functionAddress(); pint_t indexDataAddr = itThisPC.dataAddress(); if (indexDataAddr == 0) diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1-gcc-ext.c b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1-gcc-ext.c index f8c1fb4d1c0..10619ba431d 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1-gcc-ext.c +++ b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1-gcc-ext.c @@ -164,8 +164,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { unw_get_proc_name(&cursor, functionName, 512, &offset); unw_get_proc_info(&cursor, &frame); _LIBUNWIND_TRACE_UNWINDING( - " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p", - (long long)frame.start_ip, functionName, (long long)frame.lsda, + " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p", + frame.start_ip, functionName, frame.lsda, (void *)&cursor); } @@ -206,8 +206,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, UNW_REG_SP, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIx64, - (void *)context, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR, + (void *)context, result); return (uintptr_t)result; } diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1.c b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1.c index 19116fad7a4..518577b1d50 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1.c +++ b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindLevel1.c @@ -30,7 +30,7 @@ #include "unwind.h" #include "config.h" -#if !defined(_LIBUNWIND_ARM_EHABI) +#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { @@ -76,8 +76,8 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t pc; unw_get_reg(cursor, UNW_REG_IP, &pc); _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64 - ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "", + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", (void *)exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } @@ -86,7 +86,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // this frame. if (frameInfo.handler != 0) { __personality_routine p = - (__personality_routine)(long)(frameInfo.handler); + (__personality_routine)(uintptr_t)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_ojb=%p): calling personality function %p", (void *)exception_object, (void *)(uintptr_t)p); @@ -170,9 +170,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; - _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64 - ", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64 - ", personality=0x%" PRIx64, + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR + ", personality=0x%" PRIxPTR, (void *)exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); @@ -181,7 +181,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = - (__personality_routine)(long)(frameInfo.handler); + (__personality_routine)(uintptr_t)(frameInfo.handler); _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. @@ -213,8 +213,8 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_get_reg(cursor, UNW_REG_IP, &pc); unw_get_reg(cursor, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " - "user code with ip=0x%" PRIx64 - ", sp=0x%" PRIx64, + "user code with ip=0x%" PRIxPTR + ", sp=0x%" PRIxPTR, (void *)exception_object, pc, sp); } unw_resume(cursor); @@ -262,8 +262,8 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, (frameInfo.start_ip + offset > frameInfo.end_ip)) functionName = ".anonymous."; _LIBUNWIND_TRACE_UNWINDING( - "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 - ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, (void *)exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } @@ -467,17 +467,17 @@ _Unwind_GetGR(struct _Unwind_Context *context, int index) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, index, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64, - (void *)context, index, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, + (void *)context, index, result); return (uintptr_t)result; } /// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t value) { - _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64 + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR ")", - (void *)context, index, (uint64_t)value); + (void *)context, index, value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, index, value); } @@ -487,8 +487,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; unw_get_reg(cursor, UNW_REG_IP, &result); - _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64, - (void *)context, (uint64_t)result); + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, + (void *)context, result); return (uintptr_t)result; } @@ -497,10 +497,10 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { /// start executing in the landing pad. _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { - _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")", - (void *)context, (uint64_t)value); + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")", + (void *)context, value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, UNW_REG_IP, value); } -#endif // !defined(_LIBUNWIND_ARM_EHABI) +#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersRestore.S b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersRestore.S index 408ba031b9a..96106de8941 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersRestore.S +++ b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersRestore.S @@ -11,11 +11,17 @@ .text +#if !defined(__USING_SJLJ_EXCEPTIONS__) + #if defined(__i386__) DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # # void libunwind::Registers_x86::jumpto() # +#if defined(_WIN32) +# On windows, the 'this' pointer is passed in ecx instead of on the stack + movl %ecx, %eax +#else # On entry: # + + # +-----------------------+ @@ -25,6 +31,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) # +-----------------------+ <-- SP # + + movl 4(%esp), %eax +#endif # set up eax and ret on new stack location movl 28(%eax), %edx # edx holds new stack pointer subl $8,%edx @@ -58,7 +65,16 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) # # void libunwind::Registers_x86_64::jumpto() # +#if defined(_WIN64) +# On entry, thread_state pointer is in rcx; move it into rdi +# to share restore code below. Since this routine restores and +# overwrites all registers, we can use the same registers for +# pointers and temporaries as on unix even though win64 normally +# mustn't clobber some of them. + movq %rcx, %rdi +#else # On entry, thread_state pointer is in rdi +#endif movq 56(%rdi), %rax # rax holds new stack pointer subq $16, %rax @@ -88,6 +104,25 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) # skip cs # skip fs # skip gs + +#if defined(_WIN64) + movdqu 176(%rdi),%xmm0 + movdqu 192(%rdi),%xmm1 + movdqu 208(%rdi),%xmm2 + movdqu 224(%rdi),%xmm3 + movdqu 240(%rdi),%xmm4 + movdqu 256(%rdi),%xmm5 + movdqu 272(%rdi),%xmm6 + movdqu 288(%rdi),%xmm7 + movdqu 304(%rdi),%xmm8 + movdqu 320(%rdi),%xmm9 + movdqu 336(%rdi),%xmm10 + movdqu 352(%rdi),%xmm11 + movdqu 368(%rdi),%xmm12 + movdqu 384(%rdi),%xmm13 + movdqu 400(%rdi),%xmm14 + movdqu 416(%rdi),%xmm15 +#endif movq 56(%rdi), %rsp # cut back rsp to new location pop %rdi # rdi was saved here earlier ret # rip was saved here @@ -491,5 +526,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) #endif +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + NO_EXEC_STACK_DIRECTIVE diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersSave.S b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersSave.S index 4860e8f497b..873a16e41a2 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersSave.S +++ b/chromium/buildtools/third_party/libunwind/trunk/src/UnwindRegistersSave.S @@ -11,6 +11,8 @@ .text +#if !defined(__USING_SJLJ_EXCEPTIONS__) + #if defined(__i386__) # @@ -61,29 +63,56 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) # thread_state pointer is in rdi # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) - movq %rax, (%rdi) - movq %rbx, 8(%rdi) - movq %rcx, 16(%rdi) - movq %rdx, 24(%rdi) - movq %rdi, 32(%rdi) - movq %rsi, 40(%rdi) - movq %rbp, 48(%rdi) - movq %rsp, 56(%rdi) - addq $8, 56(%rdi) - movq %r8, 64(%rdi) - movq %r9, 72(%rdi) - movq %r10, 80(%rdi) - movq %r11, 88(%rdi) - movq %r12, 96(%rdi) - movq %r13,104(%rdi) - movq %r14,112(%rdi) - movq %r15,120(%rdi) - movq (%rsp),%rsi - movq %rsi,128(%rdi) # store return address as rip +#if defined(_WIN64) +#define PTR %rcx +#define TMP %rdx +#else +#define PTR %rdi +#define TMP %rsi +#endif + + movq %rax, (PTR) + movq %rbx, 8(PTR) + movq %rcx, 16(PTR) + movq %rdx, 24(PTR) + movq %rdi, 32(PTR) + movq %rsi, 40(PTR) + movq %rbp, 48(PTR) + movq %rsp, 56(PTR) + addq $8, 56(PTR) + movq %r8, 64(PTR) + movq %r9, 72(PTR) + movq %r10, 80(PTR) + movq %r11, 88(PTR) + movq %r12, 96(PTR) + movq %r13,104(PTR) + movq %r14,112(PTR) + movq %r15,120(PTR) + movq (%rsp),TMP + movq TMP,128(PTR) # store return address as rip # skip rflags # skip cs # skip fs # skip gs + +#if defined(_WIN64) + movdqu %xmm0,176(PTR) + movdqu %xmm1,192(PTR) + movdqu %xmm2,208(PTR) + movdqu %xmm3,224(PTR) + movdqu %xmm4,240(PTR) + movdqu %xmm5,256(PTR) + movdqu %xmm6,272(PTR) + movdqu %xmm7,288(PTR) + movdqu %xmm8,304(PTR) + movdqu %xmm9,320(PTR) + movdqu %xmm10,336(PTR) + movdqu %xmm11,352(PTR) + movdqu %xmm12,368(PTR) + movdqu %xmm13,384(PTR) + movdqu %xmm14,400(PTR) + movdqu %xmm15,416(PTR) +#endif xorl %eax, %eax # return UNW_ESUCCESS ret @@ -471,5 +500,7 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) l.sw 124(r3), r31 #endif +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + NO_EXEC_STACK_DIRECTIVE diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind_AppleExtras.cpp b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind_AppleExtras.cpp index 471059b4573..39f379c5298 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/Unwind_AppleExtras.cpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/Unwind_AppleExtras.cpp @@ -11,7 +11,6 @@ #include "config.h" #include "AddressSpace.hpp" #include "DwarfParser.hpp" -#include "unwind_ext.h" // private keymgr stuff @@ -183,32 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { } - -#if !defined(FOR_DYLD) && defined(_LIBUNWIND_BUILD_SJLJ_APIS) - -#ifndef _LIBUNWIND_HAS_NO_THREADS - #include <System/pthread_machdep.h> -#else - _Unwind_FunctionContext *fc_ = nullptr; -#endif - -// Accessors to get get/set linked list of frames for sjlj based execeptions. -_LIBUNWIND_HIDDEN -struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { -#ifndef _LIBUNWIND_HAS_NO_THREADS - return (struct _Unwind_FunctionContext *) - _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); -#else - return fc_; -#endif -} - -_LIBUNWIND_HIDDEN -void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { -#ifndef _LIBUNWIND_HAS_NO_THREADS - _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); -#else - fc_ = fc; -#endif -} -#endif diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/assembly.h b/chromium/buildtools/third_party/libunwind/trunk/src/assembly.h index d28cbc930bf..2b2269cc05f 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/assembly.h +++ b/chromium/buildtools/third_party/libunwind/trunk/src/assembly.h @@ -24,12 +24,6 @@ #define SEPARATOR ; #endif -#if defined(__APPLE__) -#define HIDDEN_DIRECTIVE .private_extern -#else -#define HIDDEN_DIRECTIVE .hidden -#endif - #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) @@ -37,6 +31,7 @@ #if defined(__APPLE__) #define SYMBOL_IS_FUNC(name) +#define HIDDEN_SYMBOL(name) .private_extern name #define NO_EXEC_STACK_DIRECTIVE #elif defined(__ELF__) @@ -46,6 +41,7 @@ #else #define SYMBOL_IS_FUNC(name) .type name,@function #endif +#define HIDDEN_SYMBOL(name) .hidden name #if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ defined(__linux__) @@ -54,16 +50,21 @@ #define NO_EXEC_STACK_DIRECTIVE #endif -#else +#elif defined(_WIN32) #define SYMBOL_IS_FUNC(name) \ .def name SEPARATOR \ .scl 2 SEPARATOR \ .type 32 SEPARATOR \ .endef +#define HIDDEN_SYMBOL(name) #define NO_EXEC_STACK_DIRECTIVE +#else + +#error Unsupported target + #endif #define DEFINE_LIBUNWIND_FUNCTION(name) \ @@ -73,7 +74,7 @@ #define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ .globl SYMBOL_NAME(name) SEPARATOR \ - HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \ + HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_NAME(name): diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/config.h b/chromium/buildtools/third_party/libunwind/trunk/src/config.h index ac8d7d98dc3..6706e5a3acc 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/config.h +++ b/chromium/buildtools/third_party/libunwind/trunk/src/config.h @@ -37,6 +37,8 @@ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #endif +#elif defined(_WIN32) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #else #if defined(__ARM_DWARF_EH__) || !defined(__arm__) #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 @@ -91,20 +93,15 @@ fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__) #endif -#if defined(_LIBUNWIND_HAS_NO_THREADS) - // only used with pthread calls, not needed for the single-threaded builds - #define _LIBUNWIND_LOG_NON_ZERO(x) +#if defined(NDEBUG) + #define _LIBUNWIND_LOG_IF_FALSE(x) x #else - #if defined(NDEBUG) - #define _LIBUNWIND_LOG_NON_ZERO(x) x - #else - #define _LIBUNWIND_LOG_NON_ZERO(x) \ - do { \ - int _err = x; \ - if (_err != 0) \ - _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ - } while (0) - #endif + #define _LIBUNWIND_LOG_IF_FALSE(x) \ + do { \ + bool _ret = x; \ + if (!_ret) \ + _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \ + } while (0) #endif // Macros that define away in non-Debug builds diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/libunwind.cpp b/chromium/buildtools/third_party/libunwind/trunk/src/libunwind.cpp index f072d55e0be..c4308170ab6 100644 --- a/chromium/buildtools/third_party/libunwind/trunk/src/libunwind.cpp +++ b/chromium/buildtools/third_party/libunwind/trunk/src/libunwind.cpp @@ -24,6 +24,7 @@ #include <stdlib.h> +#if !defined(__USING_SJLJ_EXCEPTIONS__) #include "AddressSpace.hpp" #include "UnwindCursor.hpp" @@ -173,8 +174,8 @@ _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, /// Set value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t value) { - _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)", - static_cast<void *>(cursor), regNum, (long long)value); + _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")", + static_cast<void *>(cursor), regNum, value); typedef LocalAddressSpace::pint_t pint_t; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { @@ -341,6 +342,7 @@ void _unw_remove_dynamic_fde(unw_word_t fde) { DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); } #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#endif // !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/chromium/buildtools/third_party/libunwind/trunk/src/unwind_ext.h b/chromium/buildtools/third_party/libunwind/trunk/src/unwind_ext.h deleted file mode 100644 index c40ce6a1610..00000000000 --- a/chromium/buildtools/third_party/libunwind/trunk/src/unwind_ext.h +++ /dev/null @@ -1,37 +0,0 @@ -//===-------------------------- unwind_ext.h ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// Extensions to unwind API. -// -//===----------------------------------------------------------------------===// - -#ifndef __UNWIND_EXT__ -#define __UNWIND_EXT__ - -#include "unwind.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// These platform specific functions to get and set the top context are -// implemented elsewhere. - -extern struct _Unwind_FunctionContext * -__Unwind_SjLj_GetTopOfFunctionStack(); - -extern void -__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc); - -#ifdef __cplusplus -} -#endif - -#endif // __UNWIND_EXT__ - - diff --git a/chromium/buildtools/win/gn.exe.sha1 b/chromium/buildtools/win/gn.exe.sha1 index 5fa40b3dd8a..3b11723605e 100644 --- a/chromium/buildtools/win/gn.exe.sha1 +++ b/chromium/buildtools/win/gn.exe.sha1 @@ -1 +1 @@ -a556e2e8f277452c5c54e3136e4ef123625006b5 +b1981c189f40c3ae42b965277ad1bc3449d26d2a |