From: robert Date: Fri, 26 Jan 2024 11:43:33 +0000 (+0000) Subject: import of libcxxabi 16.0.6 X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=8f1d572453a8bab44a2fe956e25efc4124e87e82;p=openbsd import of libcxxabi 16.0.6 --- diff --git a/gnu/llvm/libcxxabi/.clang-format b/gnu/llvm/libcxxabi/.clang-format index 2d1d3bee68f..b4f56c0de98 100644 --- a/gnu/llvm/libcxxabi/.clang-format +++ b/gnu/llvm/libcxxabi/.clang-format @@ -1,6 +1,5 @@ BasedOnStyle: LLVM ---- Language: Cpp AlwaysBreakTemplateDeclarations: true @@ -9,4 +8,8 @@ PointerAlignment: Left # Disable formatting options which may break tests. SortIncludes: false ReflowComments: false ---- + +IndentPPDirectives: AfterHash + +# libc++ has some long names so we need more than the 80 column limit imposed by LLVM style, for sensible formatting +ColumnLimit: 120 diff --git a/gnu/llvm/libcxxabi/CMakeLists.txt b/gnu/llvm/libcxxabi/CMakeLists.txt index 9fb35860d48..8f48d402bc2 100644 --- a/gnu/llvm/libcxxabi/CMakeLists.txt +++ b/gnu/llvm/libcxxabi/CMakeLists.txt @@ -1,20 +1,19 @@ # See www/CMake.html for instructions on how to build libcxxabi with CMake. -if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libcxx") - message(FATAL_ERROR "libc++abi now requires being built in a monorepo layout with libcxx available") -endif() - #=============================================================================== # Setup Project #=============================================================================== cmake_minimum_required(VERSION 3.13.4) +set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") + # Add path for custom modules -set(CMAKE_MODULE_PATH +list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" - ${CMAKE_MODULE_PATH} + "${LLVM_COMMON_CMAKE_UTILS}" + "${LLVM_COMMON_CMAKE_UTILS}/Modules" ) set(CMAKE_FOLDER "libc++") @@ -24,44 +23,7 @@ set(LIBCXXABI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(LIBCXXABI_LIBCXX_PATH "${CMAKE_CURRENT_LIST_DIR}/../libcxx" CACHE PATH "Specify path to libc++ source.") -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXXABI_STANDALONE_BUILD) - project(libcxxabi CXX C) - - set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 11.0.0git) - set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") - set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") - - # Add the CMake module path of libcxx so we can reuse HandleOutOfTreeLLVM.cmake - set(LIBCXXABI_LIBCXX_CMAKE_PATH "${LIBCXXABI_LIBCXX_PATH}/cmake/Modules") - list(APPEND CMAKE_MODULE_PATH "${LIBCXXABI_LIBCXX_CMAKE_PATH}") - - # In a standalone build, we don't have llvm to automatically generate the - # llvm-lit script for us. So we need to provide an explicit directory that - # the configurator should write the script into. - set(LIBCXXABI_STANDALONE_BUILD 1) - set(LLVM_LIT_OUTPUT_DIR "${LIBCXXABI_BINARY_DIR}/bin") - - # Find the LLVM sources and simulate LLVM CMake options. - include(HandleOutOfTreeLLVM) -endif() - -if (LIBCXXABI_STANDALONE_BUILD) - find_package(Python3 COMPONENTS Interpreter) - if(NOT Python3_Interpreter_FOUND) - message(WARNING "Python3 not found, using python2 as a fallback") - find_package(Python2 COMPONENTS Interpreter REQUIRED) - if(Python2_VERSION VERSION_LESS 2.7) - message(SEND_ERROR "Python 2.7 or newer is required") - endif() - - # Treat python2 as python3 - add_executable(Python3::Interpreter IMPORTED) - set_target_properties(Python3::Interpreter PROPERTIES - IMPORTED_LOCATION ${Python2_EXECUTABLE}) - set(Python3_EXECUTABLE ${Python2_EXECUTABLE}) - endif() -endif() +include(GNUInstallDirs) # Require out of source build. include(MacroEnsureOutOfSourceBuild) @@ -106,14 +68,33 @@ option(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS "Build libc++abi with definitions for operator new/delete. These are normally defined in libc++abi, but it is also possible to define them in libc++, in which case the definition in libc++abi should be turned off." ON) -option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS}) +option(LIBCXXABI_BUILD_32_BITS "Build 32 bit multilib libc++abi. This option is not supported anymore when building the runtimes. Please specify a full triple instead." ${LLVM_BUILD_32_BITS}) +if (LIBCXXABI_BUILD_32_BITS) + message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS is not supported anymore when building the runtimes, please specify a full triple instead.") +endif() + 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)") +option(LIBCXXABI_INSTALL_HEADERS "Install the libc++abi headers." ON) option(LIBCXXABI_INSTALL_LIBRARY "Install the libc++abi library." ON) -set(LIBCXXABI_TARGET_TRIPLE "${LLVM_DEFAULT_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.") + +set(LIBCXXABI_SHARED_OUTPUT_NAME "c++abi" CACHE STRING "Output name for the shared libc++abi runtime library.") +set(LIBCXXABI_STATIC_OUTPUT_NAME "c++abi" CACHE STRING "Output name for the static libc++abi runtime library.") + +set(LIBCXXABI_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/c++/v1" CACHE PATH "Path to install the libc++abi headers at.") + +if(LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBCXXABI_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1") +else() + set(LIBCXXABI_GENERATED_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include/c++/v1") +endif() + +# TODO: Remove this after branching for LLVM 15 +if(LIBCXXABI_SYSROOT OR LIBCXXABI_TARGET_TRIPLE OR LIBCXXABI_GCC_TOOLCHAIN) + message(WARNING "LIBCXXABI_SYSROOT, LIBCXXABI_TARGET_TRIPLE and LIBCXXABI_GCC_TOOLCHAIN are not supported anymore, please use the native CMake equivalents instead") +endif() + set(LIBCXXABI_LIBCXX_LIBRARY_PATH "" CACHE PATH "The path to libc++ library.") set(LIBCXXABI_LIBRARY_VERSION "1.0" CACHE STRING "Version of libc++abi. This will be reflected in the name of the shared \ @@ -122,11 +103,9 @@ result in the library being named libc++abi.x.y.dylib, along with the \ usual symlinks pointing to that.") # Default to building a shared library so that the default options still test -# the libc++abi that is being built. There are two problems with testing a -# static libc++abi. In the case of a standalone build, the tests will link the -# system's libc++, which might not have been built against our libc++abi. In the -# case of an in tree build, libc++ will prefer a dynamic libc++abi from the -# system over a static libc++abi from the output directory. +# the libc++abi that is being built. The problem with testing a static libc++abi +# is that libc++ will prefer a dynamic libc++abi from the system over a static +# libc++abi from the output directory. option(LIBCXXABI_ENABLE_SHARED "Build libc++abi as a shared library." ON) option(LIBCXXABI_ENABLE_STATIC "Build libc++abi as a static library." ON) @@ -139,10 +118,10 @@ cmake_dependent_option(LIBCXXABI_INSTALL_SHARED_LIBRARY cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY "Statically link the LLVM unwinder to static library" ON - "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_STATIC" OFF) + "LIBCXXABI_ENABLE_STATIC_UNWINDER" OFF) cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY "Statically link the LLVM unwinder to shared library" ON - "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_SHARED" OFF) + "LIBCXXABI_ENABLE_STATIC_UNWINDER" OFF) option(LIBCXXABI_BAREMETAL "Build libc++abi for baremetal targets." OFF) # The default terminate handler attempts to demangle uncaught exceptions, which @@ -155,29 +134,42 @@ if (NOT LIBCXXABI_ENABLE_SHARED AND NOT LIBCXXABI_ENABLE_STATIC) message(FATAL_ERROR "libc++abi must be built as either a shared or static library.") endif() -# TODO: This is a workaround for the fact that Standalone builds can't use -# targets from the other runtimes (so the cxx-headers target doesn't exist). +# TODO: Remove this, which shouldn't be necessary since we know we're being built +# side-by-side with libc++. set(LIBCXXABI_LIBCXX_INCLUDES "" CACHE PATH "Specify path to libc++ includes.") -if (LIBCXXABI_STANDALONE_BUILD) - if (NOT IS_DIRECTORY ${LIBCXXABI_LIBCXX_INCLUDES}) - message(FATAL_ERROR - "LIBCXXABI_LIBCXX_INCLUDES=${LIBCXXABI_LIBCXX_INCLUDES} is not a valid directory. " - "Please provide the path to where the libc++ headers have been installed.") + +set(LIBCXXABI_HERMETIC_STATIC_LIBRARY_DEFAULT OFF) +if (WIN32) + set(LIBCXXABI_HERMETIC_STATIC_LIBRARY_DEFAULT ON) +endif() +option(LIBCXXABI_HERMETIC_STATIC_LIBRARY + "Do not export any symbols from the static library." ${LIBCXXABI_HERMETIC_STATIC_LIBRARY_DEFAULT}) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-shared-gcc.cfg.in") +elseif(MINGW) + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-mingw.cfg.in") +elseif(WIN32) # clang-cl + if (LIBCXXABI_ENABLE_SHARED) + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-shared-clangcl.cfg.in") + else() + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-static-clangcl.cfg.in") endif() - add_library(cxx-headers INTERFACE) - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") - target_compile_options(cxx-headers INTERFACE /I "${LIBCXXABI_LIBCXX_INCLUDES}") +else() + if (LIBCXXABI_ENABLE_SHARED) + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-shared.cfg.in") else() - target_compile_options(cxx-headers INTERFACE -I "${LIBCXXABI_LIBCXX_INCLUDES}") + set(LIBCXXABI_DEFAULT_TEST_CONFIG "llvm-libc++abi-static.cfg.in") endif() endif() - -option(LIBCXXABI_HERMETIC_STATIC_LIBRARY - "Do not export any symbols from the static library." OFF) - -set(LIBCXXABI_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/lit.site.cfg.in" CACHE STRING - "The Lit testing configuration to use when running the tests.") +set(LIBCXXABI_TEST_CONFIG "${LIBCXXABI_DEFAULT_TEST_CONFIG}" CACHE STRING + "The path to the Lit testing configuration to use when running the tests. + If a relative path is provided, it is assumed to be relative to '/libcxxabi/test/configs'.") +if (NOT IS_ABSOLUTE "${LIBCXXABI_TEST_CONFIG}") + set(LIBCXXABI_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/${LIBCXXABI_TEST_CONFIG}") +endif() +message(STATUS "Using libc++abi testing configuration: ${LIBCXXABI_TEST_CONFIG}") set(LIBCXXABI_TEST_PARAMS "" CACHE STRING "A list of parameters to run the Lit test suite with.") @@ -192,6 +184,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ) +set(LIBCXXABI_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH + "Path where built libc++abi runtime libraries should be installed.") + if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) set(LIBCXXABI_HEADER_DIR ${LLVM_BINARY_DIR}) set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}) @@ -201,14 +196,14 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) string(APPEND LIBCXXABI_LIBRARY_DIR /${LIBCXXABI_LIBDIR_SUBDIR}) string(APPEND LIBCXXABI_INSTALL_LIBRARY_DIR /${LIBCXXABI_LIBDIR_SUBDIR}) endif() -elseif(LLVM_LIBRARY_OUTPUT_INTDIR) - set(LIBCXXABI_HEADER_DIR ${LLVM_BINARY_DIR}) - set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) - set(LIBCXXABI_INSTALL_LIBRARY_DIR lib${LIBCXXABI_LIBDIR_SUFFIX} CACHE PATH - "Path where built libc++abi libraries should be installed.") else() - set(LIBCXXABI_HEADER_DIR ${CMAKE_BINARY_DIR}) - set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) + if(LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBCXXABI_HEADER_DIR ${LLVM_BINARY_DIR}) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) + else() + set(LIBCXXABI_HEADER_DIR ${CMAKE_BINARY_DIR}) + set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) + endif() set(LIBCXXABI_INSTALL_LIBRARY_DIR lib${LIBCXXABI_LIBDIR_SUFFIX} CACHE PATH "Path where built libc++abi libraries should be installed.") endif() @@ -217,22 +212,12 @@ 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. +# By default, libcxx and libcxxabi share a library directory. if (NOT LIBCXXABI_LIBCXX_LIBRARY_PATH) set(LIBCXXABI_LIBCXX_LIBRARY_PATH "${LIBCXXABI_LIBRARY_DIR}" CACHE PATH "The path to libc++ library." FORCE) endif() -# Check that we can build with 32 bits if requested. -if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32) - if (LIBCXXABI_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM - message(STATUS "Building 32 bits executables and libraries.") - endif() -elseif(LIBCXXABI_BUILD_32_BITS) - message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.") -endif() - # Declare libc++abi configuration variables. # They are intended for use as follows: # LIBCXXABI_C_FLAGS: General flags for both the c++ compiler and linker. @@ -246,6 +231,10 @@ set(LIBCXXABI_CXX_FLAGS "") set(LIBCXXABI_COMPILE_FLAGS "") set(LIBCXXABI_LINK_FLAGS "") set(LIBCXXABI_LIBRARIES "") +set(LIBCXXABI_ADDITIONAL_COMPILE_FLAGS "" CACHE STRING + "Additional Compile only flags which can be provided in cache") +set(LIBCXXABI_ADDITIONAL_LIBRARIES "" CACHE STRING + "Additional libraries libc++abi is linked to which can be provided in cache") # Include macros for adding and removing libc++abi flags. include(HandleLibcxxabiFlags) @@ -255,28 +244,21 @@ include(HandleLibcxxabiFlags) #=============================================================================== # Configure target flags -add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") - -if(LIBCXXABI_TARGET_TRIPLE) - add_target_flags_if_supported("--target=${LIBCXXABI_TARGET_TRIPLE}") -elseif(CMAKE_CXX_COMPILER_TARGET) - set(LIBCXXABI_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}") +if(ZOS) + add_target_flags_if_supported("-fzos-le-char-mode=ebcdic") endif() -if(LIBCXX_GCC_TOOLCHAIN) - add_target_flags_if_supported("--gcc-toolchain=${LIBCXXABI_GCC_TOOLCHAIN}") -elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) - set(LIBCXXABI_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") -endif() -if(LIBCXXABI_SYSROOT) - add_target_flags_if_supported("--sysroot=${LIBCXXABI_SYSROOT}") -elseif(CMAKE_SYSROOT) - set(LIBCXXABI_SYSROOT "${CMAKE_SYSROOT}") + +if (${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_target_flags_if_supported("-mdefault-visibility-export-mapping=explicit") + set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF) endif() +add_compile_flags("${LIBCXXABI_ADDITIONAL_COMPILE_FLAGS}") +add_library_flags("${LIBCXXABI_ADDITIONAL_LIBRARIES}") # Configure compiler. Must happen after setting the target flags. include(config-ix) -if (LIBCXXABI_HAS_NOSTDINCXX_FLAG) +if (CXX_SUPPORTS_NOSTDINCXX_FLAG) list(APPEND LIBCXXABI_COMPILE_FLAGS -nostdinc++) # cmake 3.14 and above remove system include paths that are explicitly # passed on the command line. We build with -nostdinc++ and explicitly add @@ -300,18 +282,6 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) # it is being built as part of libcxx. add_definitions(-D_LIBCPP_BUILDING_LIBRARY) -# Disable DLL annotations on Windows for static builds. -if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) - if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_STATIC_ABI_LIBRARY) - # Building libcxxabi statically, but intending for it to be statically - # linked into a shared libcxx; keep dllexport enabled within libcxxabi, - # as the symbols will need to be exported from libcxx. - else() - # Regular static build; disable dllexports. - add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) - endif() -endif() - add_compile_flags_if_supported(-Werror=return-type) # Get warning flags @@ -404,7 +374,6 @@ if (NOT LIBCXXABI_ENABLE_THREADS) " is also set to ON.") endif() add_definitions(-D_LIBCXXABI_HAS_NO_THREADS) - add_definitions(-D_LIBCPP_HAS_NO_THREADS) endif() if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) @@ -472,18 +441,10 @@ if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) add_definitions(-D_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) endif() -# Prevent libc++abi from having library dependencies on libc++ -add_definitions(-D_LIBCPP_DISABLE_EXTERN_TEMPLATE) - if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() -# Define LIBCXXABI_USE_LLVM_UNWINDER for conditional compilation. -if (LIBCXXABI_USE_LLVM_UNWINDER) - add_definitions(-DLIBCXXABI_USE_LLVM_UNWINDER) -endif() - if (LIBCXXABI_SILENT_TERMINATE) add_definitions(-DLIBCXXABI_SILENT_TERMINATE) endif() @@ -496,7 +457,7 @@ if (LIBCXXABI_BAREMETAL) add_definitions(-DLIBCXXABI_BAREMETAL) endif() -if (LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +if (C_SUPPORTS_COMMENT_LIB_PRAGMA) if (LIBCXXABI_HAS_PTHREAD_LIB) add_definitions(-D_LIBCXXABI_LINK_PTHREAD_LIB) endif() @@ -506,6 +467,12 @@ string(REPLACE ";" " " LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXXABI_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBCXXABI_C_FLAGS}") +# On AIX, avoid picking up VMX extensions(i.e. vec_malloc) which would change +# the default alignment of the allocators here. +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") + add_definitions("-D_XOPEN_SOURCE=700") +endif() + #=============================================================================== # Setup Source Code #=============================================================================== @@ -515,7 +482,6 @@ set(LIBCXXABI_LIBUNWIND_INCLUDES "${LIBCXXABI_LIBUNWIND_INCLUDES}" CACHE PATH set(LIBCXXABI_LIBUNWIND_PATH "${LIBCXXABI_LIBUNWIND_PATH}" CACHE PATH "Specify path to libunwind source." FORCE) -include_directories(include) if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) find_path(LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL libunwind.h PATHS ${LIBCXXABI_LIBUNWIND_INCLUDES} @@ -539,6 +505,7 @@ endif() # Add source code. This also contains all of the logic for deciding linker flags # soname, etc... +add_subdirectory(include) add_subdirectory(src) if (LIBCXXABI_INCLUDE_TESTS) diff --git a/gnu/llvm/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake b/gnu/llvm/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake index 512e71a6a78..25d4789a2fd 100644 --- a/gnu/llvm/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake +++ b/gnu/llvm/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake @@ -41,7 +41,7 @@ endmacro(remove_flags) macro(check_flag_supported flag) mangle_name("${flag}" flagname) - check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") endmacro() macro(append_flags DEST) @@ -62,8 +62,8 @@ endmacro() macro(append_flags_if_supported DEST) foreach(flag ${ARGN}) mangle_name("${flag}" flagname) - check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") - append_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${DEST} ${flag}) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + append_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${DEST} ${flag}) endforeach() endmacro() @@ -129,8 +129,8 @@ endmacro() macro(add_target_flags_if_supported) foreach(flag ${ARGN}) mangle_name("${flag}" flagname) - check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") - add_target_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + add_target_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag}) endforeach() endmacro() @@ -156,8 +156,8 @@ endmacro() 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}) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + add_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag}) endforeach() endmacro() @@ -181,8 +181,8 @@ endmacro() 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}) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag}) endforeach() endmacro() @@ -191,8 +191,8 @@ endmacro() 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}) + check_c_compiler_flag("${flag}" "C_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(C_SUPPORTS_${flagname}_FLAG ${flag}) endforeach() endmacro() @@ -216,8 +216,8 @@ endmacro() 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}) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag}) endforeach() endmacro() @@ -240,3 +240,15 @@ endmacro() macro(split_list listname) string(REPLACE ";" " " ${listname} "${${listname}}") endmacro() + +# For each specified flag, add that compile flag to the provided target. +# The flags are added with the given visibility, i.e. PUBLIC|PRIVATE|INTERFACE. +function(target_add_compile_flags_if_supported target visibility) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG") + if (CXX_SUPPORTS_${flagname}_FLAG) + target_compile_options(${target} ${visibility} ${flag}) + endif() + endforeach() +endfunction() diff --git a/gnu/llvm/libcxxabi/cmake/config-ix.cmake b/gnu/llvm/libcxxabi/cmake/config-ix.cmake index 7f1cecbcd25..f4ee8946c1f 100644 --- a/gnu/llvm/libcxxabi/cmake/config-ix.cmake +++ b/gnu/llvm/libcxxabi/cmake/config-ix.cmake @@ -23,24 +23,29 @@ endif () # required for the link to go through. We remove sanitizers from the # configuration checks to avoid spurious link errors. -check_c_compiler_flag(-nostdlib++ LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG) -if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG) +check_cxx_compiler_flag(-nostdlib++ CXX_SUPPORTS_NOSTDLIBXX_FLAG) +if (CXX_SUPPORTS_NOSTDLIBXX_FLAG) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++") else() - check_c_compiler_flag(-nodefaultlibs LIBCXXABI_SUPPORTS_NODEFAULTLIBS_FLAG) - if (LIBCXXABI_SUPPORTS_NODEFAULTLIBS_FLAG) + check_c_compiler_flag(-nodefaultlibs C_SUPPORTS_NODEFAULTLIBS_FLAG) + if (C_SUPPORTS_NODEFAULTLIBS_FLAG) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") endif() endif() -if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG OR LIBCXXABI_SUPPORTS_NODEFAULTLIBS_FLAG) +if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG) if (LIBCXXABI_HAS_C_LIB) list(APPEND CMAKE_REQUIRED_LIBRARIES c) endif () if (LIBCXXABI_USE_COMPILER_RT) - list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) - find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY) - list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") + include(HandleCompilerRT) + find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY + FLAGS "${LIBCXXABI_COMPILE_FLAGS}") + if (LIBCXXABI_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") + else() + message(WARNING "Could not find builtins library from libc++abi") + endif() else () if (LIBCXXABI_HAS_GCC_S_LIB) list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) @@ -66,7 +71,7 @@ if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG OR LIBCXXABI_SUPPORTS_NODEFAULTLIBS_FLAG) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") endif () if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize-coverage=0") endif () endif () @@ -76,13 +81,13 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unknown-pragmas") check_c_source_compiles(" #pragma comment(lib, \"c\") -int main() { return 0; } -" LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +int main(void) { return 0; } +" C_SUPPORTS_COMMENT_LIB_PRAGMA) cmake_pop_check_state() endif() # Check compiler flags -check_cxx_compiler_flag(-nostdinc++ LIBCXXABI_HAS_NOSTDINCXX_FLAG) +check_cxx_compiler_flag(-nostdinc++ CXX_SUPPORTS_NOSTDINCXX_FLAG) # Check libraries if(FUCHSIA) diff --git a/gnu/llvm/libcxxabi/include/CMakeLists.txt b/gnu/llvm/libcxxabi/include/CMakeLists.txt new file mode 100644 index 00000000000..5b1cc254501 --- /dev/null +++ b/gnu/llvm/libcxxabi/include/CMakeLists.txt @@ -0,0 +1,39 @@ +set(files + __cxxabi_config.h + cxxabi.h + ) + +foreach(f ${files}) + set(src "${CMAKE_CURRENT_SOURCE_DIR}/${f}") + set(dst "${LIBCXXABI_GENERATED_INCLUDE_DIR}/${f}") + add_custom_command(OUTPUT ${dst} + DEPENDS ${src} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} + COMMENT "Copying CXXABI header ${f}") + list(APPEND _all_includes "${dst}") +endforeach() + +add_custom_target(generate-cxxabi-headers ALL DEPENDS ${_all_includes}) + +add_library(cxxabi-headers INTERFACE) +add_dependencies(cxxabi-headers generate-cxxabi-headers) +target_include_directories(cxxabi-headers INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}") + +if (LIBCXXABI_INSTALL_HEADERS) + foreach(file ${files}) + get_filename_component(dir ${file} DIRECTORY) + install(FILES ${file} + DESTINATION ${LIBCXXABI_INSTALL_INCLUDE_DIR}/${dir} + COMPONENT cxxabi-headers + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) + endforeach() + + add_custom_target(install-cxxabi-headers + DEPENDS cxxabi-headers + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=cxxabi-headers + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") + # Stripping is a no-op for headers + add_custom_target(install-cxxabi-headers-stripped DEPENDS install-cxxabi-headers) +endif() diff --git a/gnu/llvm/libcxxabi/include/__cxxabi_config.h b/gnu/llvm/libcxxabi/include/__cxxabi_config.h index cffedb88df5..c97dd656e16 100644 --- a/gnu/llvm/libcxxabi/include/__cxxabi_config.h +++ b/gnu/llvm/libcxxabi/include/__cxxabi_config.h @@ -1,4 +1,4 @@ -//===-------------------------- __cxxabi_config.h -------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,7 +10,7 @@ #define ____CXXABI_CONFIG_H #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ - !defined(__ARM_DWARF_EH__) + !defined(__ARM_DWARF_EH__) && !defined(__SEH__) #define _LIBCXXABI_ARM_EHABI #endif @@ -93,8 +93,14 @@ # if !__has_feature(cxx_exceptions) # define _LIBCXXABI_NO_EXCEPTIONS # endif -#elif defined(_LIBCXXABI_COMPILER_GCC) && !__EXCEPTIONS +#elif defined(_LIBCXXABI_COMPILER_GCC) && !defined(__EXCEPTIONS) # define _LIBCXXABI_NO_EXCEPTIONS #endif +#if defined(_WIN32) +#define _LIBCXXABI_DTOR_FUNC __thiscall +#else +#define _LIBCXXABI_DTOR_FUNC +#endif + #endif // ____CXXABI_CONFIG_H diff --git a/gnu/llvm/libcxxabi/include/cxxabi.h b/gnu/llvm/libcxxabi/include/cxxabi.h index 43ce6f5f740..85cb4b36b81 100644 --- a/gnu/llvm/libcxxabi/include/cxxabi.h +++ b/gnu/llvm/libcxxabi/include/cxxabi.h @@ -1,4 +1,4 @@ -//===--------------------------- cxxabi.h ---------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -19,7 +19,7 @@ #include <__cxxabi_config.h> -#define _LIBCPPABI_VERSION 1002 +#define _LIBCPPABI_VERSION 15000 #define _LIBCXXABI_NORETURN __attribute__((noreturn)) #define _LIBCXXABI_ALWAYS_COLD __attribute__((cold)) @@ -47,7 +47,7 @@ __cxa_free_exception(void *thrown_exception) throw(); // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void *thrown_exception, std::type_info *tinfo, - void (*dest)(void *)); + void (_LIBCXXABI_DTOR_FUNC *dest)(void *)); // 2.5.3 Exception Handlers extern _LIBCXXABI_FUNC_VIS void * diff --git a/gnu/llvm/libcxxabi/src/CMakeLists.txt b/gnu/llvm/libcxxabi/src/CMakeLists.txt index f07d4334916..58df59a5725 100644 --- a/gnu/llvm/libcxxabi/src/CMakeLists.txt +++ b/gnu/llvm/libcxxabi/src/CMakeLists.txt @@ -56,8 +56,8 @@ if (MSVC_IDE OR XCODE) endif() endif() -# stdlib_stdexcept.cpp depends on libc++ internals. -include_directories("${LIBCXXABI_LIBCXX_PATH}") +# Some files depend on libc++ internals. +include_directories("${LIBCXXABI_LIBCXX_PATH}/src") if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) @@ -77,32 +77,13 @@ else() add_library_flags_if(LIBCXXABI_HAS_C_LIB c) endif() -if (LIBCXXABI_USE_COMPILER_RT) - find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY) - list(APPEND LIBCXXABI_SHARED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") -endif () - -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_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_static) - else() - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind) - endif() - if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - # We handle this by directly merging libunwind objects into libc++abi. - else() - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind) - endif() -else() +if (NOT LIBCXXABI_USE_COMPILER_RT) + add_library_flags_if(LIBCXXABI_HAS_GCC_LIB gcc) +endif() +if (NOT LIBCXXABI_USE_LLVM_UNWINDER) add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) endif() + if (MINGW) # MINGW_LIBRARIES is defined in config-ix.cmake list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) @@ -111,17 +92,20 @@ if (ANDROID AND ANDROID_PLATFORM_LEVEL LESS 21) list(APPEND LIBCXXABI_LIBRARIES android_support) endif() -if (NOT LIBCXXABI_USE_COMPILER_RT) - add_library_flags_if(LIBCXXABI_HAS_GCC_LIB gcc) -endif () - # Setup flags. -if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG) +if (CXX_SUPPORTS_NOSTDLIBXX_FLAG) add_link_flags_if_supported(-nostdlib++) else() add_link_flags_if_supported(-nodefaultlibs) endif() +if (CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG AND LIBCXXABI_USE_LLVM_UNWINDER) + # If we're linking directly against the libunwind that we're building + # in the same invocation, don't try to link in the toolchain's + # default libunwind (which may be missing still). + add_link_flags_if_supported(--unwindlib=none) +endif() + if ( APPLE ) if (LLVM_USE_SANITIZER) if (("${LLVM_USE_SANITIZER}" STREQUAL "Address") OR @@ -136,7 +120,8 @@ if ( APPLE ) message(WARNING "LLVM_USE_SANITIZER=${LLVM_USE_SANITIZER} is not supported on OS X") endif() if (LIBFILE) - find_compiler_rt_dir(LIBDIR) + find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY) + get_filename_component(LIBDIR "${LIBCXXABI_BUILTINS_LIBRARY}" DIRECTORY) if (NOT IS_DIRECTORY "${LIBDIR}") message(FATAL_ERROR "Cannot find compiler-rt directory on OS X required for LLVM_USE_SANITIZER") endif() @@ -174,26 +159,56 @@ if (NOT TARGET pstl::ParallelSTL) endif() # Build the shared library. -if (LIBCXXABI_ENABLE_SHARED) - add_library(cxxabi_shared SHARED ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - target_link_libraries(cxxabi_shared PRIVATE cxx-headers ${LIBCXXABI_SHARED_LIBRARIES} ${LIBCXXABI_LIBRARIES}) - if (TARGET pstl::ParallelSTL) - target_link_libraries(cxxabi_shared PUBLIC pstl::ParallelSTL) +add_library(cxxabi_shared_objects OBJECT EXCLUDE_FROM_ALL ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) +if (LIBCXXABI_USE_LLVM_UNWINDER) + if (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY) + target_link_libraries(cxxabi_shared_objects PUBLIC unwind_shared_objects) # propagate usage requirements + target_sources(cxxabi_shared_objects PUBLIC $) + else() + target_link_libraries(cxxabi_shared_objects PUBLIC unwind_shared) endif() +endif() +target_link_libraries(cxxabi_shared_objects PRIVATE cxx-headers ${LIBCXXABI_BUILTINS_LIBRARY} ${LIBCXXABI_SHARED_LIBRARIES} ${LIBCXXABI_LIBRARIES}) +target_link_libraries(cxxabi_shared_objects PUBLIC cxxabi-headers) +set_target_properties(cxxabi_shared_objects + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED OFF + COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" + DEFINE_SYMBOL "" +) +if (CMAKE_POSITION_INDEPENDENT_CODE OR NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE) + set_target_properties(cxxabi_shared_objects PROPERTIES POSITION_INDEPENDENT_CODE ON) # must set manually because it's an object library +endif() + +if (LIBCXXABI_ENABLE_SHARED) + add_library(cxxabi_shared SHARED) set_target_properties(cxxabi_shared PROPERTIES - CXX_EXTENSIONS OFF - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED OFF - COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME "c++abi" + OUTPUT_NAME "${LIBCXXABI_SHARED_OUTPUT_NAME}" SOVERSION "1" VERSION "${LIBCXXABI_LIBRARY_VERSION}" - DEFINE_SYMBOL "" - POSITION_INDEPENDENT_CODE ON ) + if (ZOS) + add_custom_command(TARGET cxxabi_shared POST_BUILD + COMMAND + ${LIBCXXABI_LIBCXX_PATH}/utils/zos_rename_dll_side_deck.sh + $ $ "${LIBCXXABI_DLL_NAME}" + COMMENT "Rename dll name inside the side deck file" + WORKING_DIRECTORY $ + ) + endif () + + target_link_libraries(cxxabi_shared + PUBLIC cxxabi_shared_objects + PRIVATE ${LIBCXXABI_SHARED_LIBRARIES} ${LIBCXXABI_LIBRARIES}) + if (TARGET pstl::ParallelSTL) + target_link_libraries(cxxabi_shared PUBLIC pstl::ParallelSTL) + endif() + list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_shared") if (LIBCXXABI_INSTALL_SHARED_LIBRARY) list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared") @@ -230,61 +245,59 @@ if (LIBCXXABI_ENABLE_SHARED) endif() # Build the static library. +add_library(cxxabi_static_objects OBJECT EXCLUDE_FROM_ALL ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) +if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) + target_link_libraries(cxxabi_static_objects PUBLIC unwind_static_objects) # propagate usage requirements + target_sources(cxxabi_static_objects PUBLIC $) +endif() +target_link_libraries(cxxabi_static_objects PRIVATE cxx-headers ${LIBCXXABI_STATIC_LIBRARIES} ${LIBCXXABI_LIBRARIES}) +target_link_libraries(cxxabi_static_objects PUBLIC cxxabi-headers) +set_target_properties(cxxabi_static_objects + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED OFF + COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" +) + +if(LIBCXXABI_HERMETIC_STATIC_LIBRARY) + target_add_compile_flags_if_supported(cxxabi_static_objects PRIVATE -fvisibility=hidden) + # If the hermetic library doesn't define the operator new/delete functions + # then its code shouldn't declare them with hidden visibility. They might + # actually be provided by a shared library at link time. + if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) + target_add_compile_flags_if_supported(cxxabi_static_objects PRIVATE -fvisibility-global-new-delete-hidden) + endif() + # _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS can be defined in libcxx's + # __config_site too. Define it in the same way here, to avoid redefinition + # conflicts. + target_compile_definitions(cxxabi_static_objects + PRIVATE + _LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS + _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=) +endif() + if (LIBCXXABI_ENABLE_STATIC) - add_library(cxxabi_static STATIC ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - target_link_libraries(cxxabi_static PRIVATE cxx-headers ${LIBCXXABI_STATIC_LIBRARIES} ${LIBCXXABI_LIBRARIES}) - if (TARGET pstl::ParallelSTL) - target_link_libraries(cxxabi_static PUBLIC pstl::ParallelSTL) + add_library(cxxabi_static STATIC) + if (LIBCXXABI_USE_LLVM_UNWINDER AND NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) + target_link_libraries(cxxabi_static PUBLIC unwind_static) endif() set_target_properties(cxxabi_static PROPERTIES - CXX_EXTENSIONS OFF - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED OFF - COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - POSITION_INDEPENDENT_CODE ON + OUTPUT_NAME "${LIBCXXABI_STATIC_OUTPUT_NAME}" ) - - if(LIBCXXABI_HERMETIC_STATIC_LIBRARY) - append_flags_if_supported(CXXABI_STATIC_LIBRARY_FLAGS -fvisibility=hidden) - # If the hermetic library doesn't define the operator new/delete functions - # then its code shouldn't declare them with hidden visibility. They might - # actually be provided by a shared library at link time. - if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) - append_flags_if_supported(CXXABI_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden) - endif() - target_compile_options(cxxabi_static PRIVATE ${CXXABI_STATIC_LIBRARY_FLAGS}) - target_compile_definitions(cxxabi_static - PRIVATE - _LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS - _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) + target_link_libraries(cxxabi_static + PUBLIC cxxabi_static_objects + PRIVATE ${LIBCXXABI_STATIC_LIBRARIES} ${LIBCXXABI_LIBRARIES}) + if (TARGET pstl::ParallelSTL) + target_link_libraries(cxxabi_static PUBLIC pstl::ParallelSTL) endif() list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_static") if (LIBCXXABI_INSTALL_STATIC_LIBRARY) list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_static") endif() - - if (APPLE) - set(MERGE_ARCHIVES_LIBTOOL "--use-libtool" "--libtool" "${CMAKE_LIBTOOL}") - endif() - - # Merge the libc++abi.a and libunwind.a into one. - if(LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) - add_custom_command(TARGET cxxabi_static POST_BUILD - COMMAND ${Python3_EXECUTABLE} ${LIBCXXABI_LIBCXX_PATH}/utils/merge_archives.py - ARGS - -o "$" - --ar "${CMAKE_AR}" - ${MERGE_ARCHIVES_LIBTOOL} - "$" - "$" - WORKING_DIRECTORY ${LIBCXXABI_BUILD_DIR} - DEPENDS unwind_static - ) - endif() endif() # Add a meta-target for both libraries. @@ -294,12 +307,13 @@ if (LIBCXXABI_INSTALL_LIBRARY) install(TARGETS ${LIBCXXABI_INSTALL_TARGETS} LIBRARY DESTINATION ${LIBCXXABI_INSTALL_LIBRARY_DIR} COMPONENT cxxabi ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_LIBRARY_DIR} COMPONENT cxxabi + RUNTIME DESTINATION ${LIBCXXABI_INSTALL_RUNTIME_DIR} COMPONENT cxxabi ) endif() if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY) add_custom_target(install-cxxabi - DEPENDS cxxabi + DEPENDS cxxabi install-cxxabi-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=cxxabi -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") diff --git a/gnu/llvm/libcxxabi/src/abort_message.cpp b/gnu/llvm/libcxxabi/src/abort_message.cpp index ad44063facb..859a5031b93 100644 --- a/gnu/llvm/libcxxabi/src/abort_message.cpp +++ b/gnu/llvm/libcxxabi/src/abort_message.cpp @@ -1,4 +1,4 @@ -//===------------------------- abort_message.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/abort_message.h b/gnu/llvm/libcxxabi/src/abort_message.h index 83f956f74f6..f1d5c12e252 100644 --- a/gnu/llvm/libcxxabi/src/abort_message.h +++ b/gnu/llvm/libcxxabi/src/abort_message.h @@ -1,4 +1,4 @@ -//===-------------------------- abort_message.h-----------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/aix_state_tab_eh.inc b/gnu/llvm/libcxxabi/src/aix_state_tab_eh.inc new file mode 100644 index 00000000000..128a0ab34af --- /dev/null +++ b/gnu/llvm/libcxxabi/src/aix_state_tab_eh.inc @@ -0,0 +1,718 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// This file implements the personality and helper functions for the state +// table based EH used by IBM legacy compilers xlC and xlclang++ on AIX. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#if !__has_cpp_attribute(clang::optnone) +#error This file requires clang::optnone attribute support +#endif + +/* + The legacy IBM xlC and xlclang++ compilers use the state table for EH + instead of the range table. Destructors, or addresses of the possible catch + sites or cleanup code are specified in the state table which is a finite + state machine (FSM). Each function that has a state table also has an + autolocal state variable. The state variable represents the current state + of the function for EH and is found through the traceback table of the + function during unwinding, which is located at the end of each function. + The FSM is an array of state entries. Each state entry has the following + fields: + + * offset/address/pointer - the offset used to locate the object, or the + address of a global object, or the address of the next state if it is an + old conditional state change entry; + * dtor/landing pad - address of the destructor function to invoke, + or address of the catch block or cleanup code in the user code to branch to; + * element count/action flag - the number of elements or the flag for actions; + * element size - if the object is an array this is the size of one element + of the array; + * flags - flags used to control how fields in the entry are interpreted; + * next state - the state to execute next after the action for this state is + performed. The value of zero indicates the end of the state for this + function. + + The following is the description of 'element count/action flag' field. ++-----------------------------------------------------------------------------+ +| value | description | action | ++-------+------------------------+--------------------------------------------+ +| > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for | +| | | each member of the array | ++-------+------------------------+--------------------------------------------+ +| 1, 0 | object is a scalar | calls dtor for the object | ++-------+------------------------+--------------------------------------------+ +| -1 | begin catch | branches to the handler which performes | +| | | catch-match. If there is no catch that | +| | | matches the exception it will be rethrown | ++-------+------------------------+--------------------------------------------+ +| -2 | end catch | ends current catch block and continues | +| | | attempting to catch the exception | ++-------+------------------------+--------------------------------------------+ +| -3 | delete the object | calls the delete function of the object | ++-------+------------------------+--------------------------------------------+ +| -4 | cleanup label | branches to the user code for cleaning up | ++-------+------------------------+--------------------------------------------+ +*/ + +namespace __cxxabiv1 { + +extern "C" { + +// Macros for debugging the state table parsing. +#ifdef NDEBUG +# define _LIBCXXABI_TRACE_STATETAB(msg, ...) +# define _LIBCXXABI_TRACE_STATETAB0(msg) +# define _LIBCXXABI_TRACE_STATETAB1(msg) +# define _LIBCXXABI_TRACING_STATETAB 0 +#else +static bool state_tab_dbg() { + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL); + checked = true; + } + return log; +} + +# define _LIBCXXABI_TRACE_STATETAB(msg, ...) \ + do { \ + if (state_tab_dbg()) \ + fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \ + } while (0) +# define _LIBCXXABI_TRACE_STATETAB0(msg) \ + do { \ + if (state_tab_dbg()) \ + fprintf(stderr, "libcxxabi: " msg); \ + } while (0) +# define _LIBCXXABI_TRACE_STATETAB1(msg) \ + do { \ + if (state_tab_dbg()) \ + fprintf(stderr, msg); \ + } while (0) + +# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg() +#endif // NDEBUG + +namespace __state_table_eh { + +using destruct_f = void (*)(void*); + +// Definition of flags for the state table entry field 'action flag'. +enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 }; + +// Definition of flags for the state table entry field 'flags'. +enum FSMEntryFlag : int16_t { + indirect = 0x100, // Object was thrown from a function where + // the return value optimization was used. + oldConditionalStateChange = 0x400, // State table entry is an indirect state + // change, dereference the address in + // offset as int for the target state. + // This is deprecated. This indicates + // the address is direct. (static local). + conditionalStateChange = 0x800, // State table entry is an indirect state + // change, dereference the address in + // offset as int for the target state. + // The temporary is an automatic. State + // change is used in cases such as + // (b?(T1(),foo()):(T2(),foo())),throw 42; + // which causes a conditional state change + // so that we know if T1 or T2 need to be + // destroyed. + thisFlag = 0x01, // The address of the object for the + // cleanup action is based on the + // StateVariable::thisValue. + vBaseFlag = 0x02, // The object is of a virtual base class. + globalObj = 0x04 // FSMEntry::address is the address of + // a global object. +}; + +namespace { +// The finite state machine to be walked. +struct FSMEntry { + union { + // Offset of the object within its stack frame or containing object. + intptr_t offset; + // Address of a global object. + intptr_t address; + // Address of the next state if it is an old conditional state change entry. + intptr_t nextStatePtr; + }; + union { + // Address of the destructor function. + void (*destructor)(void*, size_t); + // The address of the catch block or cleanup code. + void* landingPad; + }; + union { + // The flag for actions (when the value is negative). + FSMEntryCount actionFlag; + // The element count (when the value is positive or zero). + size_t elementCount; + }; + size_t elemSize; + FSMEntryFlag flags; + uint16_t nextState; +}; + +struct FSM { + uint32_t magic; // Magic number of the state table. + int32_t numberOfStates; + FSMEntry table[1]; // Actually table[numberOfStates]. +}; + +// The state variable on the stack. +struct StateVariable { + int32_t state; + struct FSM* table; + intptr_t thisValue; + int32_t ignoreVBasePtrs; +}; +} // namespace + +// State table magic number +enum FSMMagic : uint32_t { + number = 0xbeefdead, // State table generated by xlC compiler. + number2 = 0xbeeedead, // State table generated by early version xlC compiler. + number3 = 0x1cedbeef // State table generated by xlclang++ compiler. +}; + +constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free + // virtual bases, don't delete object. + +static void invoke_destructor(FSMEntry* fsmEntry, void* addr) { + _LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast(fsmEntry)); + try { + if (fsmEntry->elementCount == 1) { + _LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n"); + (*fsmEntry->destructor)(addr, dtorArgument); + _LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n"); + } else { + _LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n"); + __cxa_vec_cleanup(addr, reinterpret_cast(fsmEntry->elementCount), fsmEntry->elemSize, + reinterpret_cast(fsmEntry->destructor)); + _LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n"); + } + } catch (...) { + _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n"); + std::terminate(); + } +} + +static void invoke_delete(FSMEntry* fsmEntry, void* addr) { + char* objectAddress = *reinterpret_cast(addr); + + _LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast(objectAddress), + reinterpret_cast(fsmEntry)); + try { + _LIBCXXABI_TRACE_STATETAB0("..calling delete()\n"); + // 'destructor' holds a function pointer to delete(). + (*fsmEntry->destructor)(objectAddress, fsmEntry->elemSize); + _LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n"); + } catch (...) { + _LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n"); + std::terminate(); + } +} + +// Get the frame address of the current function from its traceback table +// which is at the end of each function. +static uintptr_t get_frame_addr(_Unwind_Context* context) { + int framePointerReg = 1; // default frame pointer == SP. + uint32_t* p = reinterpret_cast(_Unwind_GetIP(context)); + + // Keep looking forward until a word of 0 is found. The traceback + // table starts at the following word. + while (*p) + ++p; + tbtable* TBTable = reinterpret_cast(p + 1); + + p = reinterpret_cast(&TBTable->tb_ext); + + // Skip field parminfo if it exists. + if (TBTable->tb.fixedparms || TBTable->tb.floatparms) + ++p; + + // Skip field tb_offset if it exists. + if (TBTable->tb.has_tboff) + ++p; + + // Skip field hand_mask if it exists. + if (TBTable->tb.int_hndl) + ++p; + + // Skip fields ctl_info and ctl_info_disp if they exist. + if (TBTable->tb.has_ctl) + p += 1 + *p; + + // Skip fields name_len and name if exist. + if (TBTable->tb.name_present) { + const uint16_t name_len = *reinterpret_cast(p); + p = reinterpret_cast(reinterpret_cast(p) + name_len + sizeof(uint16_t)); + } + + if (TBTable->tb.uses_alloca) + framePointerReg = *reinterpret_cast(p); + + return _Unwind_GetGR(context, framePointerReg); +} + +// Calculate the object address from the FSM entry. +static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) { + void* addr; + if (fsmEntry->flags & FSMEntryFlag::globalObj) { + addr = reinterpret_cast(fsmEntry->address); + _LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr); + } else if (fsmEntry->flags & FSMEntryFlag::thisFlag) { + addr = reinterpret_cast(state->thisValue + fsmEntry->offset); + _LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : " + "state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n", + fsmEntry->offset, state->thisValue, addr); + } else if (fsmEntry->flags & FSMEntryFlag::indirect) { + addr = reinterpret_cast( + *reinterpret_cast(get_frame_addr(context) + static_cast(fsmEntry->offset))); + _LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n", + addr, fsmEntry->offset); + } else { + addr = reinterpret_cast(get_frame_addr(context) + static_cast(fsmEntry->offset)); + _LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n", + addr); + } + return addr; +} + +static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception, + _Unwind_Exception* unwind_exception, _Unwind_Context* context) { + // Initialize results to found nothing but an error. + results.ttypeIndex = 0; + results.actionRecord = 0; + results.languageSpecificData = 0; + results.landingPad = 0; + results.adjustedPtr = 0; + results.reason = _URC_FATAL_PHASE1_ERROR; + + // Check for consistent actions. + if (actions & _UA_SEARCH_PHASE) { + // Do Phase 1 + if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) { + // None of these flags should be set during Phase 1. + // Client error + results.reason = _URC_FATAL_PHASE1_ERROR; + return; + } + } else if (actions & _UA_CLEANUP_PHASE) { + if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) { + // _UA_HANDLER_FRAME should only be set if phase 1 found a handler. + // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened. + // Client error + results.reason = _URC_FATAL_PHASE2_ERROR; + return; + } + } else { + // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set. + // Client error + results.reason = _URC_FATAL_PHASE1_ERROR; + return; + } + + if (_LIBCXXABI_TRACING_STATETAB) { + _LIBCXXABI_TRACE_STATETAB1("\n"); + _LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions); + + if (_UA_SEARCH_PHASE & actions) + _LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE "); + if (_UA_CLEANUP_PHASE & actions) + _LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE "); + if (_UA_HANDLER_FRAME & actions) + _LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME "); + if (_UA_FORCE_UNWIND & actions) + _LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND "); + _LIBCXXABI_TRACE_STATETAB1(")\n"); + _LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast(unwind_exception), + reinterpret_cast(context)); + } + + // Start scan by getting state table address. + StateVariable* const state = reinterpret_cast(_Unwind_GetLanguageSpecificData(context)); + if (state->state <= 0) { + // The state is not correct - give up on this routine. + _LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state); + results.reason = _URC_CONTINUE_UNWIND; + return; + } + // Parse the state table. + FSM* const fsm = state->table; + FSMEntry* currFSMEntry; + + if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) { + // Something is wrong with the state table we found. + if (_UA_SEARCH_PHASE & actions) { + _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n"); + results.reason = _URC_FATAL_PHASE1_ERROR; + } else if (_UA_CLEANUP_PHASE & actions) { + _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n"); + results.reason = _URC_FATAL_PHASE2_ERROR; + } else { + // We should never get here. + _LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n"); + results.reason = _URC_FATAL_PHASE2_ERROR; + } + return; + } + + if (_LIBCXXABI_TRACING_STATETAB) { + // Print the state table for debugging purposes. + _LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs); + _LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates); + // Print out the FSM table. + _LIBCXXABI_TRACE_STATETAB0("FSM table:\n"); + _LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad", + "count", "el_size", "flags", "next"); + for (int i = 0; i < fsm->numberOfStates; i++) { + currFSMEntry = &fsm->table[i]; + _LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld " + "%7ld %#7x %7d\n", + reinterpret_cast(&currFSMEntry), i + 1, currFSMEntry->offset, + reinterpret_cast(currFSMEntry->destructor), + currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags, + currFSMEntry->nextState); + } + } + + if (_UA_SEARCH_PHASE & actions) { + // Start walking the state table. Use a local copy of state->state so when + // we return from search phase we don't change the state number. + int currState = state->state; + + while (currState > 0) { + currFSMEntry = &fsm->table[currState - 1]; + _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags); + + if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) { + // Found a catch handler. + if (fsm->magic == FSMMagic::number) { + _LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n"); + // xlC catch handlers cannot be entered because they use a + // proprietary EH runtime that is not interoperable. + results.reason = _URC_FATAL_PHASE1_ERROR; + return; + } + // xlclang++ compiled frames use CXA-abi EH calls and any catch + // block will include a catch(...) block so it is safe to assume that + // the handler is found without checking the catch match. The + // catch(...) block will rethrow the exception if there isn't a + // match. + _LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n"); + results.reason = _URC_HANDLER_FOUND; + return; + } + if (currFSMEntry->actionFlag == FSMEntryCount::terminate) { + _LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n"); + results.reason = _URC_HANDLER_FOUND; + return; + } + if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) { + // Deprecated conditional expression. + currState = *reinterpret_cast(currFSMEntry->nextStatePtr); + _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference " + "currFSMEntry->nextStatePtr(%ld), set state=%d\n", + currFSMEntry->nextStatePtr, currState); + continue; // We are done this iteration of the loop, since + // we changed a state. + } + if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) { + void* addr = compute_addr_from_table(currFSMEntry, state, context); + currState = *reinterpret_cast(addr); + _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference " + "addr(%p), set state=%d\n", addr, currState); + continue; // We are done this iteration of the loop, since we + // changed the state. + } + // Go to the next state. + currState = currFSMEntry->nextState; + } + _LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n"); + results.reason = _URC_CONTINUE_UNWIND; + return; + } + if (_UA_CLEANUP_PHASE & actions) { + // Start walking the state table. + while (state->state > 0) { + currFSMEntry = &fsm->table[state->state - 1]; + + if (currFSMEntry->actionFlag == FSMEntryCount::terminate) { + _LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n"); + std::terminate(); + } + // Perform action according to the currFSMEntry->actionFlag, + // except when flag is FSMEntryFlag::conditionalStateChange or + // FSMEntryFlag::oldConditionalStateChange. + _LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags); + if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) { + state->state = *reinterpret_cast(currFSMEntry->nextStatePtr); + _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference " + "currFSMEntry->nextStatePtr(%ld), set state=%d\n", + currFSMEntry->nextStatePtr, state->state); + continue; // We are done with this iteration of the loop, since we changed a state. + } + if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) { + // A conditional state table entry holds the address of a local + // that holds the next state. + void* addr = compute_addr_from_table(currFSMEntry, state, context); + state->state = *reinterpret_cast(addr); + _LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference " + "addr(%p), set state=%d\n", addr, state->state); + continue; // We are done with this iteration of the loop, since we changed a state. + } + if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch || + currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) { + + _LIBCXXABI_TRACE_STATETAB( + "FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n", + (currFSMEntry->actionFlag == FSMEntryCount::beginCatch + ? "beginCatch" + : (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")), + currFSMEntry->landingPad, *reinterpret_cast(currFSMEntry->landingPad)); + + state->state = currFSMEntry->nextState; + results.landingPad = reinterpret_cast(*reinterpret_cast(currFSMEntry->landingPad)); + results.reason = _URC_HANDLER_FOUND; + return; + } + if (currFSMEntry->elementCount > 0) { + if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) { + _LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n"); + } else { + // We need to invoke the virtual base destructor. This must be + // a frame from the legacy xlC compiler as the xlclang++ compiler + // generates inline cleanup code rather than specifying + // the destructor via the state table. + void* addr = compute_addr_from_table(currFSMEntry, state, context); + + // An extra indirect to get to the object according to the object + // model used by the xlC compiler. + addr = reinterpret_cast(*reinterpret_cast(addr)); + _LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr); + invoke_destructor(currFSMEntry, addr); + } + } else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) { + void* addr = compute_addr_from_table(currFSMEntry, state, context); + if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) { + // We need to invoke the virtual base delete function. This must be + // a frame from the legacy xlC compiler as the xlclang++ compiler + // generates inline cleanup code rather than specifying + // the delete function via the state table. + + // An extra indirect to get to the object according to the object + // model used by the xlC compiler. + addr = reinterpret_cast(*reinterpret_cast(addr)); + } + _LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr); + invoke_delete(currFSMEntry, addr); + } else { + _LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n", + currFSMEntry->elementCount); + } // End of action switching. + + // Go to next state. + state->state = currFSMEntry->nextState; + } + _LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n"); + results.reason = _URC_CONTINUE_UNWIND; + return; + } + _LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n"); + // It is possible that no state table entry specify how to handle + // this exception. By spec, terminate it immediately. + call_terminate(native_exception, unwind_exception); +} + +// Personality routine for EH using the state table. +_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code +__xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception* unwind_exception, _Unwind_Context* context) { + if (version != 1 || unwind_exception == 0 || context == 0) + return _URC_FATAL_PHASE1_ERROR; + + bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); + scan_results results; + scan_state_tab(results, actions, native_exception, unwind_exception, context); + if (actions & _UA_SEARCH_PHASE) { + // Phase 1 search: All we're looking for in phase 1 is a handler that + // halts unwinding + return results.reason; + } + if (actions & _UA_CLEANUP_PHASE) { + // Phase 2 cleanup: + if (results.reason == _URC_HANDLER_FOUND) { + // Store the address of unwind_exception in the stack field + // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of + // the caller of the function containing the landing pad (within the link + // area for the call to the latter) for __xlc_exception_handle() + // to retrieve when it is called by the landing pad. + uintptr_t *currentSP = reinterpret_cast(_Unwind_GetGR(context, 1)); + uintptr_t *callersSP = reinterpret_cast(currentSP[0]); + callersSP[3] = reinterpret_cast(unwind_exception); + _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast(unwind_exception), reinterpret_cast(callersSP)); + // Jump to the handler. + _Unwind_SetIP(context, results.landingPad); + return _URC_INSTALL_CONTEXT; + } + // Did not find a handler. Return the results of the scan. Normally + // _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR. + return results.reason; + } + // We were called improperly: neither a phase 1 or phase 2 search. + return _URC_FATAL_PHASE1_ERROR; +} +} // namespace __state_table_eh + +// The following are EH helper functions for xlclang++ compiled code. + +// __xlc_catch_matchv2 +// Check whether the thrown object matches the catch handler's exception +// declaration. If there is a match, the function returns true with adjusted +// address of the thrown object. Otherwise, returns false. +_LIBCXXABI_FUNC_VIS bool +__xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) { + _LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast(exceptionObject)); + + if (!__isOurExceptionClass(exceptionObject)) { + _LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n"); + return false; + } + + __cxa_exception* exceptionHeader = 0; + + if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) { + // Walk to the __cxa_dependent_exception primary exception for the + // exception object and its type_info. + __cxa_dependent_exception* dependentExceptionHeader = + reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1; + exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1; + _LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n", + reinterpret_cast(exceptionObject), + reinterpret_cast(&exceptionHeader->unwindHeader)); + exceptionObject = &exceptionHeader->unwindHeader; + } else { + _LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast(exceptionObject)); + exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1; + } + + void* thrownObject = reinterpret_cast(exceptionObject + 1); + std::type_info* throwTypeInfo = exceptionHeader->exceptionType; + + // Get the type info for the thrown type and this catch clause and + // see if the catch caluse can catch that type. + + __cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo); + __cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo); + _LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n", + reinterpret_cast(exceptionObject), thrownObject, reinterpret_cast(throwType), + throwType->name(), reinterpret_cast(catchType), catchType->name()); + if (catchType->can_catch(throwType, thrownObject)) { + exceptionHeader->adjustedPtr = thrownObject; + obj = thrownObject; + _LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject); + return true; + } + _LIBCXXABI_TRACE_STATETAB0("No match\n"); + return false; +} + +// __xlc_throw_badexception +// This function is for xlclang++. It allocates and throws a bad_exception. +// During unwinding for this bad_exception, the previous exception which is +// not matching the throw spec will be cleaned up. Thus having the same +// effect as replace the top most exception (which is bad) with a bad_exception. +_LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { + _LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__); + void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception; + __cxa_throw(newexception, const_cast(&typeid(std::bad_exception)), 0); +} + +// force_a_stackframe +// This function is called by __xlc_exception_handle() to ensure a stack frame +// is created for __xlc_exception_handle(). +__attribute__((noinline, optnone)) +static void force_a_stackframe() {} + +// __xlc_exception_handle +// This function is for xlclang++. It returns the address of the exception +// object stored in the reserved field in the stack of the caller of the +// function that calls __xlc_exception_handle() (within the link area for the +// call to the latter). The address is stored by the personality routine for +// xlclang++ compiled code. The implementation of __xlc_exception_handle() +// assumes a stack frame is created for it. The following ensures this +// assumption holds true: 1) a call to force_a_stackframe() is made inside +// __xlc_exception_handle() to make it non-leaf; and 2) optimizations are +// disabled for this function with attribute 'optnone'. Note: this function +// may not work as expected if these are changed. +__attribute__((optnone)) +_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { + // Make a call to force_a_stackframe() so that the compiler creates a stack + // frame for this function. + force_a_stackframe(); + + // Get the SP of this function, i.e., __xlc_exception_handle(). + uintptr_t *lastStack; + asm("mr %0, 1" : "=r"(lastStack)); + // Get the SP of the caller of __xlc_exception_handle(). + uintptr_t *callerStack = reinterpret_cast(lastStack[0]); + // Get the SP of the caller of the caller. + uintptr_t *callerStack2 = reinterpret_cast(callerStack[0]); + uintptr_t exceptionObject = callerStack2[3]; + _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast(exceptionObject), reinterpret_cast(callerStack2)); + return exceptionObject; +} + +// xlclang++ may generate calls to __Deleted_Virtual. +_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); } + +// __catchThrownException is called during AIX library initialization and +// termination to handle exceptions. An implementation is also provided in +// libC.a(shrcore.o). This implementation is provided for applications that +// link with -lc++ (the xlclang++ or ibm-clang++ link default.) +_LIBCXXABI_FUNC_VIS int +__catchThrownException(void (*cdfunc)(void), // function which may fail + void (*cleanup)(void*), // cleanup function + void* cleanuparg, // parameter to cleanup function + int action) { // control exception throwing and termination + enum Action : int { None = 0, Rethrow = 1, Terminate = 2 }; + if (!cdfunc) + return 0; + if (action == Action::Rethrow && !cleanup) { + // No cleanup and rethrow is effectively no-op. + // Avoid the catch handler when possible to allow exceptions generated + // from xlC binaries to flow through. + (*cdfunc)(); + return 0; + } + try { + (*cdfunc)(); + } catch (...) { + if (action == Action::Terminate) + std::terminate(); + if (cleanup) + (*cleanup)(cleanuparg); + if (action == Action::Rethrow) + throw; + assert(action == Action::None); + return -1; // FAILED + } + return 0; +} + +} // extern "C" + +} // __cxxabiv1 diff --git a/gnu/llvm/libcxxabi/src/cxa_aux_runtime.cpp b/gnu/llvm/libcxxabi/src/cxa_aux_runtime.cpp index 0ed1a722795..a42990c7eff 100644 --- a/gnu/llvm/libcxxabi/src/cxa_aux_runtime.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_aux_runtime.cpp @@ -1,4 +1,4 @@ -//===------------------------ cxa_aux_runtime.cpp -------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_default_handlers.cpp b/gnu/llvm/libcxxabi/src/cxa_default_handlers.cpp index c059a653d45..7bcfca069fb 100644 --- a/gnu/llvm/libcxxabi/src/cxa_default_handlers.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_default_handlers.cpp @@ -1,85 +1,89 @@ -//===------------------------- cxa_default_handlers.cpp -------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // -// This file implements the default terminate_handler and unexpected_handler. +// This file implements the default terminate_handler, unexpected_handler and +// new_handler. //===----------------------------------------------------------------------===// #include +#include #include #include "abort_message.h" #include "cxxabi.h" #include "cxa_handlers.h" #include "cxa_exception.h" #include "private_typeinfo.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ #if !defined(LIBCXXABI_SILENT_TERMINATE) -_LIBCPP_SAFE_STATIC -static const char* cause = "uncaught"; +static constinit const char* cause = "uncaught"; + +#ifndef _LIBCXXABI_NO_EXCEPTIONS +// Demangle the given string, or return the string as-is in case of an error. +static std::unique_ptr demangle(char const* str) +{ +#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE) + if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr)) + return {result, [](char const* p) { std::free(const_cast(p)); }}; +#endif + return {str, [](char const*) { /* nothing to free */ }}; +} __attribute__((noreturn)) static void demangling_terminate_handler() { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - // If there might be an uncaught exception using namespace __cxxabiv1; __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals) + + // If there is no uncaught exception, just note that we're terminating + if (!globals) + abort_message("terminating"); + + __cxa_exception* exception_header = globals->caughtExceptions; + if (!exception_header) + abort_message("terminating"); + + _Unwind_Exception* unwind_exception = + reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; + + // If we're terminating due to a foreign exception + if (!__isOurExceptionClass(unwind_exception)) + abort_message("terminating due to %s foreign exception", cause); + + void* thrown_object = + __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ? + ((__cxa_dependent_exception*)exception_header)->primaryException : + exception_header + 1; + const __shim_type_info* thrown_type = + static_cast(exception_header->exceptionType); + auto name = demangle(thrown_type->name()); + // If the uncaught exception can be caught with std::exception& + const __shim_type_info* catch_type = + static_cast(&typeid(std::exception)); + if (catch_type->can_catch(thrown_type, thrown_object)) { - __cxa_exception* exception_header = globals->caughtExceptions; - // If there is an uncaught exception - if (exception_header) - { - _Unwind_Exception* unwind_exception = - reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; - if (__isOurExceptionClass(unwind_exception)) - { - void* thrown_object = - __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)exception_header)->primaryException : - exception_header + 1; - const __shim_type_info* thrown_type = - static_cast(exception_header->exceptionType); -#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE) - // Try to get demangled name of thrown_type - int status; - char buf[1024]; - size_t len = sizeof(buf); - const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); - if (status != 0) - name = thrown_type->name(); -#else - const char* name = thrown_type->name(); -#endif - // If the uncaught exception can be caught with std::exception& - const __shim_type_info* catch_type = - static_cast(&typeid(std::exception)); - if (catch_type->can_catch(thrown_type, thrown_object)) - { - // Include the what() message from the exception - const std::exception* e = static_cast(thrown_object); - abort_message("terminating with %s exception of type %s: %s", - cause, name, e->what()); - } - else - // Else just note that we're terminating with an exception - abort_message("terminating with %s exception of type %s", - cause, name); - } - else - // Else we're terminating with a foreign exception - abort_message("terminating with %s foreign exception", cause); - } + // Include the what() message from the exception + const std::exception* e = static_cast(thrown_object); + abort_message("terminating due to %s exception of type %s: %s", cause, name.get(), e->what()); } -#endif - // Else just note that we're terminating + else + { + // Else just note that we're terminating due to an exception + abort_message("terminating due to %s exception of type %s", cause, name.get()); + } +} +#else // !_LIBCXXABI_NO_EXCEPTIONS +__attribute__((noreturn)) +static void demangling_terminate_handler() +{ abort_message("terminating"); } +#endif // !_LIBCXXABI_NO_EXCEPTIONS __attribute__((noreturn)) static void demangling_unexpected_handler() @@ -90,19 +94,22 @@ static void demangling_unexpected_handler() static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler; static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler; -#else +#else // !LIBCXXABI_SILENT_TERMINATE static constexpr std::terminate_handler default_terminate_handler = ::abort; static constexpr std::terminate_handler default_unexpected_handler = std::terminate; -#endif +#endif // !LIBCXXABI_SILENT_TERMINATE // // Global variables that hold the pointers to the current handler // _LIBCXXABI_DATA_VIS -_LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_terminate_handler; +constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler; + +_LIBCXXABI_DATA_VIS +constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; _LIBCXXABI_DATA_VIS -_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; +constinit std::new_handler __cxa_new_handler = nullptr; namespace std { @@ -125,4 +132,10 @@ set_terminate(terminate_handler func) noexcept _AO_Acq_Rel); } +new_handler +set_new_handler(new_handler handler) noexcept +{ + return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); +} + } diff --git a/gnu/llvm/libcxxabi/src/cxa_demangle.cpp b/gnu/llvm/libcxxabi/src/cxa_demangle.cpp index 3045f6edb30..7baac680074 100644 --- a/gnu/llvm/libcxxabi/src/cxa_demangle.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_demangle.cpp @@ -1,4 +1,4 @@ -//===-------------------------- cxa_demangle.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -173,6 +173,50 @@ struct DumpVisitor { return printStr("TemplateParamKind::Template"); } } + void print(Node::Prec P) { + switch (P) { + case Node::Prec::Primary: + return printStr("Node::Prec::Primary"); + case Node::Prec::Postfix: + return printStr("Node::Prec::Postfix"); + case Node::Prec::Unary: + return printStr("Node::Prec::Unary"); + case Node::Prec::Cast: + return printStr("Node::Prec::Cast"); + case Node::Prec::PtrMem: + return printStr("Node::Prec::PtrMem"); + case Node::Prec::Multiplicative: + return printStr("Node::Prec::Multiplicative"); + case Node::Prec::Additive: + return printStr("Node::Prec::Additive"); + case Node::Prec::Shift: + return printStr("Node::Prec::Shift"); + case Node::Prec::Spaceship: + return printStr("Node::Prec::Spaceship"); + case Node::Prec::Relational: + return printStr("Node::Prec::Relational"); + case Node::Prec::Equality: + return printStr("Node::Prec::Equality"); + case Node::Prec::And: + return printStr("Node::Prec::And"); + case Node::Prec::Xor: + return printStr("Node::Prec::Xor"); + case Node::Prec::Ior: + return printStr("Node::Prec::Ior"); + case Node::Prec::AndIf: + return printStr("Node::Prec::AndIf"); + case Node::Prec::OrIf: + return printStr("Node::Prec::OrIf"); + case Node::Prec::Conditional: + return printStr("Node::Prec::Conditional"); + case Node::Prec::Assign: + return printStr("Node::Prec::Assign"); + case Node::Prec::Comma: + return printStr("Node::Prec::Comma"); + case Node::Prec::Default: + return printStr("Node::Prec::Default"); + } + } void newLine() { printStr("\n"); @@ -342,21 +386,18 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { int InternalStatus = demangle_success; Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; - Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) - InternalStatus = demangle_memory_alloc_failure; else { + OutputBuffer O(Buf, N); assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; + AST->print(O); + O += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); + *N = O.getCurrentPosition(); + Buf = O.getBuffer(); } if (Status) diff --git a/gnu/llvm/libcxxabi/src/cxa_exception.cpp b/gnu/llvm/libcxxabi/src/cxa_exception.cpp index 510827a37bb..9cb2bf88881 100644 --- a/gnu/llvm/libcxxabi/src/cxa_exception.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_exception.cpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_exception.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -17,7 +17,7 @@ #include "cxa_exception.h" #include "cxa_handlers.h" #include "fallback_malloc.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ #if __has_feature(address_sanitizer) #include @@ -254,7 +254,7 @@ will call terminate, assuming that there was no handler for the exception. */ void -__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { +__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { __cxa_eh_globals *globals = __cxa_get_globals(); __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -341,8 +341,11 @@ unwinding with _Unwind_Resume. According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any register, thus we have to write this function in assembly so that we can save {r1, r2, r3}. We don't have to save r0 because it is the return value and the -first argument to _Unwind_Resume(). In addition, we are saving r4 in order to -align the stack to 16 bytes, even though it is a callee-save register. +first argument to _Unwind_Resume(). The function also saves/restores r4 to +keep the stack aligned and to provide a temp register. _Unwind_Resume never +returns and we need to keep the original lr so just branch to it. When +targeting bare metal, the function also clobbers ip/r12 to hold the address of +_Unwind_Resume, which may be too far away for an ordinary branch. */ __attribute__((used)) static _Unwind_Exception * __cxa_end_cleanup_impl() @@ -372,18 +375,28 @@ __cxa_end_cleanup_impl() return &exception_header->unwindHeader; } -asm ( - " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" +asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" " .globl __cxa_end_cleanup\n" " .type __cxa_end_cleanup,%function\n" "__cxa_end_cleanup:\n" +#if defined(__ARM_FEATURE_BTI_DEFAULT) + " bti\n" +#endif " push {r1, r2, r3, r4}\n" + " mov r4, lr\n" " bl __cxa_end_cleanup_impl\n" + " mov lr, r4\n" +#if defined(LIBCXXABI_BAREMETAL) + " ldr r4, =_Unwind_Resume\n" + " mov ip, r4\n" +#endif " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); +#if defined(LIBCXXABI_BAREMETAL) + " bx ip\n" +#else + " b _Unwind_Resume\n" +#endif + " .popsection"); #endif // defined(_LIBCXXABI_ARM_EHABI) /* @@ -431,6 +444,14 @@ __cxa_begin_catch(void* unwind_arg) throw() ( static_cast<_Unwind_Exception*>(unwind_exception) ); + +#if defined(__MVS__) + // Remove the exception object from the linked list of exceptions that the z/OS unwinder + // maintains before adding it to the libc++abi list of caught exceptions. + // The libc++abi will manage the lifetime of the exception from this point forward. + _UnwindZOS_PopException(); +#endif + if (native_exception) { // Increment the handler count, removing the flag about being rethrown diff --git a/gnu/llvm/libcxxabi/src/cxa_exception.h b/gnu/llvm/libcxxabi/src/cxa_exception.h index 601be4e4046..49dde28b258 100644 --- a/gnu/llvm/libcxxabi/src/cxa_exception.h +++ b/gnu/llvm/libcxxabi/src/cxa_exception.h @@ -1,4 +1,4 @@ -//===------------------------- cxa_exception.h ----------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -34,7 +34,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // in the beginning of the struct, rather than before unwindHeader. void *reserve; - // This is a new field to support C++ 0x exception_ptr. + // This is a new field to support C++11 exception_ptr. // For binary compatibility it is at the start of this // struct which is prepended to the object thrown in // __cxa_allocate_exception. @@ -43,7 +43,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // Manage the exception object itself. std::type_info *exceptionType; - void (*exceptionDestructor)(void *); + void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; @@ -63,9 +63,9 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { #endif #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI) - // This is a new field to support C++ 0x exception_ptr. + // This is a new field to support C++11 exception_ptr. // For binary compatibility it is placed where the compiler - // previously adding padded to 64-bit align unwindHeader. + // previously added padding to 64-bit align unwindHeader. size_t referenceCount; #endif _Unwind_Exception unwindHeader; @@ -81,7 +81,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception { #endif std::type_info *exceptionType; - void (*exceptionDestructor)(void *); + void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; diff --git a/gnu/llvm/libcxxabi/src/cxa_exception_storage.cpp b/gnu/llvm/libcxxabi/src/cxa_exception_storage.cpp index 24ff55e39d2..3a3233a1b92 100644 --- a/gnu/llvm/libcxxabi/src/cxa_exception_storage.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_exception_storage.cpp @@ -1,4 +1,4 @@ -//===--------------------- cxa_exception_storage.cpp ----------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,25 +21,24 @@ extern "C" { static __cxa_eh_globals eh_globals; __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } - } -} +} // extern "C" +} // namespace __cxxabiv1 #elif defined(HAS_THREAD_LOCAL) namespace __cxxabiv1 { - namespace { - __cxa_eh_globals * __globals () { + __cxa_eh_globals *__globals() { static thread_local __cxa_eh_globals eh_globals; return &eh_globals; - } } +} // namespace extern "C" { - __cxa_eh_globals * __cxa_get_globals () { return __globals (); } - __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } - } -} + __cxa_eh_globals *__cxa_get_globals() { return __globals(); } + __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } +} // extern "C" +} // namespace __cxxabiv1 #else @@ -59,47 +58,46 @@ namespace { std::__libcpp_tls_key key_; std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { - __free_with_fallback ( p ); - if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) + 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()"); - } + } - void construct_ () { - if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) + void construct_() { + if (0 != std::__libcpp_tls_create(&key_, destruct_)) abort_message("cannot create thread specific key for __cxa_get_globals()"); - } -} + } +} // namespace extern "C" { - __cxa_eh_globals * __cxa_get_globals () { - // Try to get the globals for this thread - __cxa_eh_globals* retVal = __cxa_get_globals_fast (); - - // If this is the first time we've been asked for these globals, create them - if ( NULL == retVal ) { - retVal = static_cast<__cxa_eh_globals*> - (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); - if ( NULL == retVal ) + __cxa_eh_globals *__cxa_get_globals() { + // Try to get the globals for this thread + __cxa_eh_globals *retVal = __cxa_get_globals_fast(); + + // If this is the first time we've been asked for these globals, create them + if (NULL == retVal) { + retVal = static_cast<__cxa_eh_globals*>( + __calloc_with_fallback(1, sizeof(__cxa_eh_globals))); + if (NULL == retVal) abort_message("cannot allocate __cxa_eh_globals"); - if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) + if (0 != std::__libcpp_tls_set(key_, retVal)) abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); - } - return retVal; } + return retVal; + } // Note that this implementation will reliably return NULL if not // preceded by a call to __cxa_get_globals(). This is an extension // to the Itanium ABI and is taken advantage of in several places in // libc++abi. - __cxa_eh_globals * __cxa_get_globals_fast () { - // First time through, create the key. + __cxa_eh_globals *__cxa_get_globals_fast() { + // First time through, create the key. if (0 != std::__libcpp_execute_once(&flag_, construct_)) abort_message("execute once failure in __cxa_get_globals_fast()"); -// static int init = construct_(); return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); - } + } +} // extern "C" +} // namespace __cxxabiv1 -} -} #endif diff --git a/gnu/llvm/libcxxabi/src/cxa_guard.cpp b/gnu/llvm/libcxxabi/src/cxa_guard.cpp index 5d1cf235cc5..fc1fa905119 100644 --- a/gnu/llvm/libcxxabi/src/cxa_guard.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_guard.cpp @@ -1,4 +1,4 @@ -//===---------------------------- cxa_guard.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_handlers.cpp b/gnu/llvm/libcxxabi/src/cxa_handlers.cpp index bcaf4f1f6f0..344250dde0c 100644 --- a/gnu/llvm/libcxxabi/src/cxa_handlers.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_handlers.cpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_handlers.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // // // This file implements the functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. +// unexpected_handler, and new_handler. //===----------------------------------------------------------------------===// #include @@ -17,7 +17,7 @@ #include "cxa_handlers.h" #include "cxa_exception.h" #include "private_typeinfo.h" -#include "include/atomic_support.h" +#include "include/atomic_support.h" // from libc++ namespace std { @@ -92,16 +92,6 @@ terminate() noexcept __terminate(get_terminate()); } -extern "C" { -new_handler __cxa_new_handler = 0; -} - -new_handler -set_new_handler(new_handler handler) noexcept -{ - return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); -} - new_handler get_new_handler() noexcept { diff --git a/gnu/llvm/libcxxabi/src/cxa_handlers.h b/gnu/llvm/libcxxabi/src/cxa_handlers.h index da113b82db3..3d8dc6b2de9 100644 --- a/gnu/llvm/libcxxabi/src/cxa_handlers.h +++ b/gnu/llvm/libcxxabi/src/cxa_handlers.h @@ -1,4 +1,4 @@ -//===------------------------- cxa_handlers.h -----------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_noexception.cpp b/gnu/llvm/libcxxabi/src/cxa_noexception.cpp index 73e0b2ae03f..4a803f72e19 100644 --- a/gnu/llvm/libcxxabi/src/cxa_noexception.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_noexception.cpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_exception.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_personality.cpp b/gnu/llvm/libcxxabi/src/cxa_personality.cpp index 91b584eb8c8..b28c58df6a2 100644 --- a/gnu/llvm/libcxxabi/src/cxa_personality.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_personality.cpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_exception.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,6 +22,15 @@ #include "private_typeinfo.h" #include "unwind.h" +// TODO: This is a temporary workaround for libc++abi to recognize that it's being +// built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION +// in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove +// this workaround, it won't be possible to build libc++abi against libunwind headers +// from LLVM 14 and before anymore. +#if defined(____LIBUNWIND_CONFIG_H__) && !defined(_LIBUNWIND_VERSION) +# define _LIBUNWIND_VERSION +#endif + #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) #include #include @@ -613,7 +622,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, results.reason = _URC_FATAL_PHASE1_ERROR; return; } - // Start scan by getting exception table address + // Start scan by getting exception table address. const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); if (lsda == 0) { @@ -903,6 +912,8 @@ static _Unwind_Reason_Code __gxx_personality_imp _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code #ifdef __USING_SJLJ_EXCEPTIONS__ __gxx_personality_sj0 +#elif defined(__MVS__) +__zos_cxx_personality_v2 #else __gxx_personality_v0 #endif @@ -1004,13 +1015,18 @@ extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, _Unwind_Context* context) { - if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK) - return _URC_FAILURE; + switch (__gnu_unwind_frame(unwind_exception, context)) { + case _URC_OK: return _URC_CONTINUE_UNWIND; + case _URC_END_OF_STACK: + return _URC_END_OF_STACK; + default: + return _URC_FAILURE; + } } // ARM register names -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) +#if !defined(_LIBUNWIND_VERSION) static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block #endif static const uint32_t REG_SP = 13; @@ -1045,7 +1061,7 @@ __gxx_personality_v0(_Unwind_State state, bool native_exception = __isOurExceptionClass(unwind_exception); -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) +#if !defined(_LIBUNWIND_VERSION) // Copy the address of _Unwind_Control_Block to r12 so that // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can // return correct address. @@ -1107,9 +1123,16 @@ __gxx_personality_v0(_Unwind_State state, } // Either we didn't do a phase 1 search (due to forced unwinding), or - // phase 1 reported no catching-handlers. + // phase 1 reported no catching-handlers. // Search for a (non-catching) cleanup - scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context); + if (is_force_unwinding) + scan_eh_tab( + results, + static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND), + native_exception, unwind_exception, context); + else + scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, + unwind_exception, context); if (results.reason == _URC_HANDLER_FOUND) { // Found a non-catching handler @@ -1284,3 +1307,9 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1( } // extern "C" } // __cxxabiv1 + +#if defined(_AIX) +// Include implementation of the personality and helper functions for the +// state table based EH used by IBM legacy compilers xlC and xlclang++ on AIX. +# include "aix_state_tab_eh.inc" +#endif diff --git a/gnu/llvm/libcxxabi/src/cxa_thread_atexit.cpp b/gnu/llvm/libcxxabi/src/cxa_thread_atexit.cpp index a940eaf2f9c..665f9e55694 100644 --- a/gnu/llvm/libcxxabi/src/cxa_thread_atexit.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_thread_atexit.cpp @@ -1,4 +1,4 @@ -//===----------------------- cxa_thread_atexit.cpp ------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_vector.cpp b/gnu/llvm/libcxxabi/src/cxa_vector.cpp index 325bbf22d20..099f9f0c1e9 100644 --- a/gnu/llvm/libcxxabi/src/cxa_vector.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_vector.cpp @@ -1,4 +1,4 @@ -//===-------------------------- cxa_vector.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/cxa_virtual.cpp b/gnu/llvm/libcxxabi/src/cxa_virtual.cpp index 9214c1f3e29..c868672e00a 100644 --- a/gnu/llvm/libcxxabi/src/cxa_virtual.cpp +++ b/gnu/llvm/libcxxabi/src/cxa_virtual.cpp @@ -1,4 +1,4 @@ -//===-------------------------- cxa_virtual.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/demangle/ItaniumDemangle.h b/gnu/llvm/libcxxabi/src/demangle/ItaniumDemangle.h index 36d5d1adeca..66213c63f2f 100644 --- a/gnu/llvm/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/gnu/llvm/libcxxabi/src/demangle/ItaniumDemangle.h @@ -6,145 +6,218 @@ // //===----------------------------------------------------------------------===// // -// Generic itanium demangler library. This file has two byte-per-byte identical -// copies in the source tree, one in libcxxabi, and the other in llvm. +// Generic itanium demangler library. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// #ifndef DEMANGLE_ITANIUMDEMANGLE_H #define DEMANGLE_ITANIUMDEMANGLE_H -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include #include #include #include #include #include -#include +#include +#include #include -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(SyntheticTemplateParamName) \ - X(TypeTemplateParamDecl) \ - X(NonTypeTemplateParamDecl) \ - X(TemplateTemplateParamDecl) \ - X(TemplateParamPackDecl) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(SubobjectExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(PointerToMemberConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(BoolExpr) \ - X(StringLiteral) \ - X(LambdaExpr) \ - X(EnumLiteral) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - DEMANGLE_NAMESPACE_BEGIN +template class PODSmallVector { + static_assert(std::is_pod::value, + "T is required to be a plain old data type"); + + T *First = nullptr; + T *Last = nullptr; + T *Cap = nullptr; + T Inline[N] = {0}; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto *Tmp = static_cast(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector &) = delete; + PODSmallVector &operator=(const PODSmallVector &) = delete; + + PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector &operator=(PODSmallVector &&Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void push_back(const T &Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T *begin() { return First; } + T *end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast(Last - First); } + T &back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T &operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + // Base class of all AST nodes. The AST is built by the parser, then is // traversed by the printLeft/Right functions to produce a demangled string. class Node { public: enum Kind : unsigned char { -#define ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR +#define NODE(NodeKind) K##NodeKind, +#include "ItaniumNodes.def" }; /// Three-way bool to track a cached value. Unknown is possible if this node /// has an unexpanded parameter pack below it that may affect this cache. enum class Cache : unsigned char { Yes, No, Unknown, }; + /// Operator precedence for expression nodes. Used to determine required + /// parens in expression emission. + enum class Prec { + Primary, + Postfix, + Unary, + Cast, + PtrMem, + Multiplicative, + Additive, + Shift, + Spaceship, + Relational, + Equality, + And, + Xor, + Ior, + AndIf, + OrIf, + Conditional, + Assign, + Comma, + Default, + }; + private: Kind K; + Prec Precedence : 6; + // FIXME: Make these protected. public: /// Tracks if this node has a component on its right side, in which case we /// need to call printRight. - Cache RHSComponentCache; + Cache RHSComponentCache : 2; /// Track if this node is a (possibly qualified) array type. This can affect /// how we format the output string. - Cache ArrayCache; + Cache ArrayCache : 2; /// Track if this node is a (possibly qualified) function type. This can /// affect how we format the output string. - Cache FunctionCache; + Cache FunctionCache : 2; public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} + Node(Kind K_, Prec Precedence_ = Prec::Primary, + Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_), + ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {} + Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_, + FunctionCache_) {} /// Visit the most-derived object corresponding to this object. template void visit(Fn F) const; @@ -155,50 +228,63 @@ public: // would construct an equivalent node. //template void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + Prec getPrecedence() const { return Precedence; } + + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } + virtual bool hasArraySlow(OutputBuffer &) const { return false; } + virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } - - void print(OutputStream &S) const { - printLeft(S); + virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } + + // Print this node as an expression operand, surrounding it in parentheses if + // its precedence is [Strictly] weaker than P. + void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default, + bool StrictlyWorse = false) const { + bool Paren = + unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse); + if (Paren) + OB.printOpen(); + print(OB); + if (Paren) + OB.printClose(); + } + + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // Print the "left" side of this Node into OutputBuffer. + virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. - virtual void printRight(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -227,19 +313,19 @@ public: Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + OB += ", "; + size_t AfterComma = OB.getCurrentPosition(); + Elements[Idx]->printAsOperand(OB, Node::Prec::Comma); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -254,9 +340,7 @@ struct NodeArrayNode : Node { template void match(Fn F) const { F(Array); } - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } + void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { @@ -269,11 +353,11 @@ public: template void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + void printLeft(OutputBuffer &OB) const override { + Prefix->print(OB); + OB += " ("; + OB += Suffix; + OB += ")"; } }; @@ -286,14 +370,18 @@ public: VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} + const Node *getTy() const { return Ty; } + StringView getExt() const { return Ext; } + const Node *getTA() const { return TA; } + template void match(Fn F) const { F(Ty, Ext, TA); } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += " "; + OB += Ext; if (TA != nullptr) - TA->print(S); + TA->print(OB); } }; @@ -319,13 +407,13 @@ protected: const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -334,24 +422,27 @@ public: Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} + Qualifiers getQuals() const { return Quals; } + const Node *getChild() const { return Child; } + template void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -363,9 +454,9 @@ public: template void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; @@ -374,14 +465,14 @@ class PostfixQualifiedType final : public Node { const StringView Postfix; public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) + PostfixQualifiedType(const Node *Ty_, StringView Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; @@ -396,7 +487,27 @@ public: StringView getName() const { return Name; } StringView getBaseName() const override { return Name; } - void printLeft(OutputStream &s) const override { s += Name; } + void printLeft(OutputBuffer &OB) const override { OB += Name; } +}; + +class BitIntType final : public Node { + const Node *Size; + bool Signed; + +public: + BitIntType(const Node *Size_, bool Signed_) + : Node(KBitIntType), Size(Size_), Signed(Signed_) {} + + template void match(Fn F) const { F(Size, Signed); } + + void printLeft(OutputBuffer &OB) const override { + if (!Signed) + OB += "unsigned "; + OB += "_BitInt"; + OB.printOpen(); + Size->printAsOperand(OB); + OB.printClose(); + } }; class ElaboratedTypeSpefType : public Node { @@ -408,10 +519,10 @@ public: template void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; @@ -426,11 +537,11 @@ struct AbiTagAttr : Node { template void match(Fn F) const { F(Base, Tag); } - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Base->printLeft(OB); + OB += "[abi:"; + OB += Tag; + OB += "]"; } }; @@ -442,10 +553,10 @@ public: template void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; @@ -466,11 +577,11 @@ public: static_cast(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -482,36 +593,38 @@ public: : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} + const Node *getPointee() const { return Pointee; } + template void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -531,15 +644,30 @@ class ReferenceType : public Node { // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any // other combination collapses to a lvalue ref. - std::pair collapse(OutputStream &S) const { + // + // A combination of a TemplateForwardReference and a back-ref Substitution + // from an ill-formed string may have created a cycle; use cycle detection to + // avoid looping forever. + std::pair collapse(OutputBuffer &OB) const { auto SoFar = std::make_pair(RK, Pointee); + // Track the chain of nodes for the Floyd's 'tortoise and hare' + // cycle-detection algorithm, since getSyntaxNode(S) is impure + PODSmallVector Prev; for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); + const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast(SN); SoFar.second = RT->Pointee; SoFar.first = std::min(SoFar.first, RT->RK); + + // The middle of Prev is the 'slow' pointer moving at half speed + Prev.push_back(SoFar.second); + if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { + // Cycle detected + SoFar.second = nullptr; + break; + } } return SoFar; } @@ -551,31 +679,35 @@ public: template void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + ScopedOverride SavePrinting(Printing, true); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + Collapsed.second->printLeft(OB); + if (Collapsed.second->hasArray(OB)) + OB += " "; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + ScopedOverride SavePrinting(Printing, true); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -590,24 +722,24 @@ public: template void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; + OB += " "; + ClassType->print(OB); + OB += "::*"; } - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; @@ -624,19 +756,19 @@ public: template void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; if (Dimension) - Dimension->print(S); - S += "]"; - Base->printRight(S); + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -660,8 +792,8 @@ public: F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: @@ -670,32 +802,32 @@ public: // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -707,10 +839,11 @@ public: template void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept"; + OB.printOpen(); + E->printAsOperand(OB); + OB.printClose(); } }; @@ -722,10 +855,11 @@ public: template void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw"; + OB.printOpen(); + Types.printWithComma(OB); + OB.printClose(); } }; @@ -756,41 +890,41 @@ public: NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -803,9 +937,9 @@ public: template void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; @@ -819,9 +953,9 @@ public: template void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -836,11 +970,11 @@ public: template void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -855,10 +989,50 @@ struct NestedName : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qual->print(OB); + OB += "::"; + Name->print(OB); + } +}; + +struct ModuleName : Node { + ModuleName *Parent; + Node *Name; + bool IsPartition; + + ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) + : Node(KModuleName), Parent(Parent_), Name(Name_), + IsPartition(IsPartition_) {} + + template void match(Fn F) const { + F(Parent, Name, IsPartition); + } + + void printLeft(OutputBuffer &OB) const override { + if (Parent) + Parent->print(OB); + if (Parent || IsPartition) + OB += IsPartition ? ':' : '.'; + Name->print(OB); + } +}; + +struct ModuleEntity : Node { + ModuleName *Module; + Node *Name; + + ModuleEntity(ModuleName *Module_, Node *Name_) + : Node(KModuleEntity), Module(Module_), Name(Name_) {} + + template void match(Fn F) const { F(Module, Name); } + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + OB += '@'; + Module->print(OB); } }; @@ -871,10 +1045,10 @@ struct LocalName : Node { template void match(Fn F) const { F(Encoding, Entity); } - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); + void printLeft(OutputBuffer &OB) const override { + Encoding->print(OB); + OB += "::"; + Entity->print(OB); } }; @@ -891,10 +1065,10 @@ public: StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -903,18 +1077,20 @@ class VectorType final : public Node { const Node *Dimension; public: - VectorType(const Node *BaseType_, Node *Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} + VectorType(const Node *BaseType_, const Node *Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} + + const Node *getBaseType() const { return BaseType; } + const Node *getDimension() const { return Dimension; } template void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; if (Dimension) - Dimension->print(S); - S += "]"; + Dimension->print(OB); + OB += "]"; } }; @@ -927,11 +1103,26 @@ public: template void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - Dimension->print(S); - S += "]"; + OB += "pixel vector["; + Dimension->print(OB); + OB += "]"; + } +}; + +class BinaryFPType final : public Node { + const Node *Dimension; + +public: + BinaryFPType(const Node *Dimension_) + : Node(KBinaryFPType), Dimension(Dimension_) {} + + template void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -953,20 +1144,20 @@ public: template void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -980,13 +1171,9 @@ public: template void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -1000,15 +1187,15 @@ public: template void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1025,15 +1212,14 @@ public: template void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1046,14 +1232,12 @@ public: template void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1067,11 +1251,12 @@ public: class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits::max()) { - S.CurrentPackMax = static_cast(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits::max()) { + OB.CurrentPackMax = static_cast(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1094,38 +1279,38 @@ public: template void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + const Node *getSyntaxNode(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1144,8 +1329,8 @@ public: NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1162,35 +1347,35 @@ public: const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + ScopedOverride SavePackIdx(OB.CurrentPackIndex, Max); + ScopedOverride SavePackMax(OB.CurrentPackMax, Max); + size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. - Child->print(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1205,12 +1390,11 @@ public: NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + Params.printWithComma(OB); + OB += ">"; } }; @@ -1252,42 +1436,42 @@ struct ForwardTemplateReference : Node { // special handling. template void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; - SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + ScopedOverride SavePrinting(Printing, true); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); + ScopedOverride SavePrinting(Printing, true); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); + ScopedOverride SavePrinting(Printing, true); + Ref->printRight(OB); } }; @@ -1303,9 +1487,9 @@ struct NameWithTemplateArgs : Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + TemplateArgs->print(OB); } }; @@ -1320,24 +1504,9 @@ public: StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1350,15 +1519,25 @@ enum class SpecialSubKind { iostream, }; -class ExpandedSpecialSubstitution final : public Node { +class SpecialSubstitution; +class ExpandedSpecialSubstitution : public Node { +protected: SpecialSubKind SSK; + ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) + : Node(K_), SSK(SSK_) {} public: ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} + inline ExpandedSpecialSubstitution(SpecialSubstitution const *); template void match(Fn F) const { F(SSK); } +protected: + bool isInstantiation() const { + return unsigned(SSK) >= unsigned(SpecialSubKind::string); + } + StringView getBaseName() const override { switch (SSK) { case SpecialSubKind::allocator: @@ -1377,82 +1556,44 @@ public: DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream >"; - break; +private: + void printLeft(OutputBuffer &OB) const override { + OB << "std::" << getBaseName(); + if (isInstantiation()) { + OB << ""; + if (SSK == SpecialSubKind::string) + OB << ", std::allocator"; + OB << ">"; } } }; -class SpecialSubstitution final : public Node { +class SpecialSubstitution final : public ExpandedSpecialSubstitution { public: - SpecialSubKind SSK; - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} template void match(Fn F) const { F(SSK); } StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); + auto SV = ExpandedSpecialSubstitution::getBaseName (); + if (isInstantiation()) { + // The instantiations are typedefs that drop the "basic_" prefix. + assert(SV.startsWith("basic_")); + SV = SV.dropFront(sizeof("basic_") - 1); } - DEMANGLE_UNREACHABLE; + return SV; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::string"; - break; - case SpecialSubKind::istream: - S += "std::istream"; - break; - case SpecialSubKind::ostream: - S += "std::ostream"; - break; - case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } + void printLeft(OutputBuffer &OB) const override { + OB << "std::" << getBaseName(); } }; +inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( + SpecialSubstitution const *SS) + : ExpandedSpecialSubstitution(SS->SSK) {} + class CtorDtorName final : public Node { const Node *Basename; const bool IsDtor; @@ -1465,10 +1606,10 @@ public: template void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1480,9 +1621,9 @@ public: template void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; @@ -1494,10 +1635,10 @@ public: template void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; @@ -1516,22 +1657,23 @@ public: F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1543,10 +1685,10 @@ public: template void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen('['); + Bindings.printWithComma(OB); + OB.printClose(']'); } }; @@ -1558,28 +1700,31 @@ class BinaryExpr : public Node { const Node *RHS; public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { - } - - template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; + BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_, + Prec Prec_) + : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), + RHS(RHS_) {} + + template void match(Fn F) const { + F(LHS, InfixOperator, RHS, getPrecedence()); + } + + void printLeft(OutputBuffer &OB) const override { + bool ParenAll = OB.isGtInsideTemplateArgs() && + (InfixOperator == ">" || InfixOperator == ">>"); + if (ParenAll) + OB.printOpen(); + // Assignment is right associative, with special LHS precedence. + bool IsAssign = getPrecedence() == Prec::Assign; + LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign); + // No space before comma operator + if (!(InfixOperator == ",")) + OB += " "; + OB += InfixOperator; + OB += " "; + RHS->printAsOperand(OB, getPrecedence(), IsAssign); + if (ParenAll) + OB.printClose(); } }; @@ -1588,17 +1733,18 @@ class ArraySubscriptExpr : public Node { const Node *Op2; public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) + : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} - template void match(Fn F) const { F(Op1, Op2); } + template void match(Fn F) const { + F(Op1, Op2, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Op1->printAsOperand(OB, getPrecedence()); + OB.printOpen('['); + Op2->printAsOperand(OB); + OB.printClose(']'); } }; @@ -1607,16 +1753,16 @@ class PostfixExpr : public Node { const StringView Operator; public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_) + : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} - template void match(Fn F) const { F(Child, Operator); } + template void match(Fn F) const { + F(Child, Operator, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + Child->printAsOperand(OB, getPrecedence(), true); + OB += Operator; } }; @@ -1626,19 +1772,20 @@ class ConditionalExpr : public Node { const Node *Else; public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, + Prec Prec_) + : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} - template void match(Fn F) const { F(Cond, Then, Else); } + template void match(Fn F) const { + F(Cond, Then, Else, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Cond->printAsOperand(OB, getPrecedence()); + OB += " ? "; + Then->printAsOperand(OB); + OB += " : "; + Else->printAsOperand(OB, Prec::Assign, true); } }; @@ -1648,15 +1795,17 @@ class MemberExpr : public Node { const Node *RHS; public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_) + : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - template void match(Fn F) const { F(LHS, Kind, RHS); } + template void match(Fn F) const { + F(LHS, Kind, RHS, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + void printLeft(OutputBuffer &OB) const override { + LHS->printAsOperand(OB, getPrecedence(), true); + OB += Kind; + RHS->printAsOperand(OB, getPrecedence(), false); } }; @@ -1677,20 +1826,20 @@ public: F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); } - void printLeft(OutputStream &S) const override { - SubExpr->print(S); - S += ".<"; - Type->print(S); - S += " at offset "; + void printLeft(OutputBuffer &OB) const override { + SubExpr->print(OB); + OB += ".<"; + Type->print(OB); + OB += " at offset "; if (Offset.empty()) { - S += "0"; + OB += "0"; } else if (Offset[0] == 'n') { - S += "-"; - S += Offset.dropFront(); + OB += "-"; + OB += Offset.dropFront(); } else { - S += Offset; + OB += Offset; } - S += ">"; + OB += ">"; } }; @@ -1700,16 +1849,20 @@ class EnclosingExpr : public Node { const StringView Postfix; public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} + EnclosingExpr(StringView Prefix_, const Node *Infix_, + Prec Prec_ = Prec::Primary) + : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} - template void match(Fn F) const { F(Prefix, Infix, Postfix); } + template void match(Fn F) const { + F(Prefix, Infix, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB.printOpen(); + Infix->print(OB); + OB.printClose(); + OB += Postfix; } }; @@ -1720,18 +1873,24 @@ class CastExpr : public Node { const Node *From; public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_) - : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} + CastExpr(StringView CastKind_, const Node *To_, const Node *From_, Prec Prec_) + : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} - template void match(Fn F) const { F(CastKind, To, From); } + template void match(Fn F) const { + F(CastKind, To, From, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + { + ScopedOverride LT(OB.GtIsGt, 0); + OB += "<"; + To->printLeft(OB); + OB += ">"; + } + OB.printOpen(); + From->printAsOperand(OB); + OB.printClose(); } }; @@ -1744,11 +1903,12 @@ public: template void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof..."; + OB.printOpen(); ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB.printClose(); } }; @@ -1757,16 +1917,18 @@ class CallExpr : public Node { NodeArray Args; public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) + : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} - template void match(Fn F) const { F(Callee, Args); } + template void match(Fn F) const { + F(Callee, Args, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB.printOpen(); + Args.printWithComma(OB); + OB.printClose(); } }; @@ -1779,33 +1941,32 @@ class NewExpr : public Node { bool IsArray; // new[] ? public: NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} + bool IsArray_, Prec Prec_) + : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), + InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); + F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::"; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB.printOpen(); + ExprList.printWithComma(OB); + OB.printClose(); } - Type->print(S); + OB += " "; + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB.printOpen(); + InitList.printWithComma(OB); + OB.printClose(); } - } }; @@ -1815,18 +1976,22 @@ class DeleteExpr : public Node { bool IsArray; public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) + : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} - template void match(Fn F) const { F(Op, IsGlobal, IsArray); } + template void match(Fn F) const { + F(Op, IsGlobal, IsArray, getPrecedence()); + } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[]"; + OB += ' '; + Op->print(OB); } }; @@ -1835,16 +2000,16 @@ class PrefixExpr : public Node { Node *Child; public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_) + : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} - template void match(Fn F) const { F(Prefix, Child); } + template void match(Fn F) const { + F(Prefix, Child, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Child->printAsOperand(OB, getPrecedence()); } }; @@ -1856,9 +2021,9 @@ public: template void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1867,17 +2032,20 @@ class ConversionExpr : public Node { NodeArray Expressions; public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) + : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} - template void match(Fn F) const { F(Type, Expressions); } + template void match(Fn F) const { + F(Type, Expressions, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Type->print(OB); + OB.printClose(); + OB.printOpen(); + Expressions.printWithComma(OB); + OB.printClose(); } }; @@ -1888,18 +2056,21 @@ class PointerToMemberConversionExpr : public Node { public: PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, - StringView Offset_) - : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_), - Offset(Offset_) {} + StringView Offset_, Prec Prec_) + : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), + SubExpr(SubExpr_), Offset(Offset_) {} - template void match(Fn F) const { F(Type, SubExpr, Offset); } + template void match(Fn F) const { + F(Type, SubExpr, Offset, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - SubExpr->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Type->print(OB); + OB.printClose(); + OB.printOpen(); + SubExpr->print(OB); + OB.printClose(); } }; @@ -1912,12 +2083,12 @@ public: template void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1931,18 +2102,18 @@ public: template void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1956,15 +2127,15 @@ public: template void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1983,43 +2154,35 @@ public: F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB.printOpen(); + ParameterPackExpansion(Pack).print(OB); + OB.printClose(); }; - S += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } + OB.printOpen(); + // Either '[init op ]... op pack' or 'pack op ...[ op init]' + // Refactored to '[(init|pack) op ]...[ op (pack|init)]' + // Fold expr operands are cast-expressions + if (!IsLeftFold || Init != nullptr) { + // '(init|pack) op ' + if (IsLeftFold) + Init->printAsOperand(OB, Prec::Cast, true); + else + PrintPack(); + OB << " " << OperatorName << " "; + } + OB << "..."; + if (IsLeftFold || Init != nullptr) { + // ' op (init|pack)' + OB << " " << OperatorName << " "; + if (IsLeftFold) + PrintPack(); + else + Init->printAsOperand(OB, Prec::Cast, true); } - S += ')'; + OB.printClose(); } }; @@ -2031,9 +2194,9 @@ public: template void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2045,8 +2208,8 @@ public: template void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? StringView("true") : StringView("false"); } }; @@ -2058,10 +2221,10 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2073,11 +2236,11 @@ public: template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast(Type)->printDeclarator(S); - S += "{...}"; + static_cast(Type)->printDeclarator(OB); + OB += "{...}"; } }; @@ -2092,15 +2255,15 @@ public: template void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S << "("; - Ty->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Ty->print(OB); + OB.printClose(); if (Integer[0] == 'n') - S << "-" << Integer.dropFront(1); + OB << "-" << Integer.dropFront(1); else - S << Integer; + OB << Integer; } }; @@ -2114,21 +2277,21 @@ public: template void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB.printOpen(); + OB += Type; + OB.printClose(); } if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); + OB += '-'; + OB += Value.dropFront(1); } else - S += Value; + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2158,7 +2321,7 @@ public: template void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { const char *first = Contents.begin(); const char *last = Contents.end() + 1; @@ -2184,7 +2347,7 @@ public: #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); + OB += StringView(num, num + n); } } }; @@ -2198,159 +2361,38 @@ using LongDoubleLiteral = FloatLiteralImpl; template void Node::visit(Fn F) const { switch (K) { -#define CASE(X) case K ## X: return F(static_cast(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE +#define NODE(X) \ + case K##X: \ + return F(static_cast(this)); +#include "ItaniumNodes.def" } assert(0 && "unknown mangling node kind"); } /// Determine the kind of a node from its type. template struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ +#define NODE(X) \ + template <> struct NodeKind { \ + static constexpr Node::Kind Kind = Node::K##X; \ + static constexpr const char *name() { return #X; } \ }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef SPECIALIZATION +#include "ItaniumNodes.def" -#undef FOR_EACH_NODE_KIND +template struct AbstractManglingParser { + const char *First; + const char *Last; -template -class PODSmallVector { - static_assert(std::is_pod::value, - "T is required to be a plain old data type"); + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser collapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector Names; - T* First = nullptr; - T* Last = nullptr; - T* Cap = nullptr; - T Inline[N] = {0}; + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 44nd entry (base-36) in this + // table. + PODSmallVector Subs; - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - -template struct AbstractManglingParser { - const char *First; - const char *Last; - - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser collapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector Names; - - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector Subs; - - using TemplateParamList = PODSmallVector; + using TemplateParamList = PODSmallVector; class ScopedTemplateParamList { AbstractManglingParser *Parser; @@ -2450,7 +2492,7 @@ template struct AbstractManglingParser { char consume() { return First != Last ? *First++ : '\0'; } - char look(unsigned Lookahead = 0) { + char look(unsigned Lookahead = 0) const { if (static_cast(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; @@ -2472,17 +2514,16 @@ template struct AbstractManglingParser { /// Parse the production. Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); + Node *parsePrefixExpr(StringView Kind, Node::Prec Prec); + Node *parseBinaryExpr(StringView Kind, Node::Prec Prec); Node *parseIntegerLiteral(StringView Lit); Node *parseExprPrimary(); template Node *parseFloatingLiteral(); Node *parseFunctionParam(); - Node *parseNewExpr(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); - Node *parsePointerToMemberConversionExpr(); + Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); /// Parse the production. @@ -2530,17 +2571,80 @@ template struct AbstractManglingParser { Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); + bool parseModuleNameOpt(ModuleName *&Module); + Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); + Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); Node *parseAbiTags(Node *N); + struct OperatorInfo { + enum OIKind : unsigned char { + Prefix, // Prefix unary: @ expr + Postfix, // Postfix unary: expr @ + Binary, // Binary: lhs @ rhs + Array, // Array index: lhs [ rhs ] + Member, // Member access: lhs @ rhs + New, // New + Del, // Delete + Call, // Function call: expr (expr*) + CCast, // C cast: (type)expr + Conditional, // Conditional: expr ? expr : expr + NameOnly, // Overload only, not allowed in expression. + // Below do not have operator names + NamedCast, // Named cast, @(expr) + OfIdOp, // alignof, sizeof, typeid + + Unnameable = NamedCast, + }; + char Enc[2]; // Encoding + OIKind Kind; // Kind of operator + bool Flag : 1; // Entry-specific flag + Node::Prec Prec : 7; // Precedence + const char *Name; // Spelling + + public: + constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P, + const char *N) + : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {} + + public: + bool operator<(const OperatorInfo &Other) const { + return *this < Other.Enc; + } + bool operator<(const char *Peek) const { + return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]); + } + bool operator==(const char *Peek) const { + return Enc[0] == Peek[0] && Enc[1] == Peek[1]; + } + bool operator!=(const char *Peek) const { return !this->operator==(Peek); } + + public: + StringView getSymbol() const { + StringView Res = Name; + if (Kind < Unnameable) { + assert(Res.startsWith("operator") && + "operator name does not start with 'operator'"); + Res = Res.dropFront(sizeof("operator") - 1); + Res.consumeFront(' '); + } + return Res; + } + StringView getName() const { return Name; } + OIKind getKind() const { return Kind; } + bool getFlag() const { return Flag; } + Node::Prec getPrecedence() const { return Prec; } + }; + static const OperatorInfo Ops[]; + static const size_t NumOps; + const OperatorInfo *parseOperatorEncoding(); + /// Parse the production. - Node *parseUnresolvedName(); + Node *parseUnresolvedName(bool Global); Node *parseSimpleId(); Node *parseBaseUnresolvedName(); Node *parseUnresolvedType(); @@ -2561,41 +2665,35 @@ const char* parse_discriminator(const char* first, const char* last); // ::= template Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') return getDerived().parseLocalName(State); - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); - } + Node *Result = nullptr; + bool IsSubst = false; - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) return nullptr; - // ::= + if (look() == 'I') { - Subs.push_back(N); + // ::= + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by . + return nullptr; } - // ::= - return N; + + return Result; } // := Z E [] @@ -2636,34 +2734,63 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { // ::= // ::= St # ::std:: -// extension ::= StL +// [*] extension template Node * -AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) +AbstractManglingParser::parseUnscopedName(NameState *State, + bool *IsSubst) { + + Node *Std = nullptr; + if (consumeIf("St")) { + Std = make("std"); + if (Std == nullptr) return nullptr; - return make(R); } - return getDerived().parseUnqualifiedName(State); + + Node *Res = nullptr; + ModuleName *Module = nullptr; + if (look() == 'S') { + Node *S = getDerived().parseSubstitution(); + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) + Module = static_cast(S); + else if (IsSubst && Std == nullptr) { + Res = S; + *IsSubst = true; + } else { + return nullptr; + } + } + + if (Res == nullptr || Std != nullptr) { + Res = getDerived().parseUnqualifiedName(State, Std, Module); + } + + return Res; } -// ::= [abi-tags] -// ::= -// ::= -// ::= -// ::= DC + E # structured binding declaration +// ::= [] L? [] +// ::= [] [] +// ::= [] L? [] +// ::= [] L? [] +// # structured binding declaration +// ::= [] L? DC + E template -Node * -AbstractManglingParser::parseUnqualifiedName(NameState *State) { - // s are special-cased in parseNestedName(). +Node *AbstractManglingParser::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + + consumeIf('L'); + Node *Result; - if (look() == 'U') - Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } else if (look() == 'U') { + Result = getDerived().parseUnnamedTypeName(State); + } else if (consumeIf("DC")) { + // Structured binding size_t BindingsBegin = Names.size(); do { Node *Binding = getDerived().parseSourceName(State); @@ -2672,13 +2799,46 @@ AbstractManglingParser::parseUnqualifiedName(NameState *State) { Names.push_back(Binding); } while (!consumeIf('E')); Result = make(popTrailingNodeArray(BindingsBegin)); - } else + } else if (look() == 'C' || look() == 'D') { + // A . + if (Scope == nullptr || Module != nullptr) + return nullptr; + Result = getDerived().parseCtorDtorName(Scope, State); + } else { Result = getDerived().parseOperatorName(State); + } + + if (Result != nullptr && Module != nullptr) + Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); + if (Result != nullptr && Scope != nullptr) + Result = make(Scope, Result); + return Result; } +// ::= +// ::= +// ::= # passed in by caller +// ::= W +// ::= W P +template +bool AbstractManglingParser::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast(make(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // ::= Ut [] _ // ::= // @@ -2700,7 +2860,7 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { return make(Count); } if (consumeIf("Ul")) { - SwapAndRestore SwapParams(ParsingLambdaParamsAtLevel, + ScopedOverride SwapParams(ParsingLambdaParamsAtLevel, TemplateParams.size()); ScopedTemplateParamList LambdaTemplateParams(this); @@ -2778,284 +2938,162 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return make(Name); } -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= li # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v # vendor extended operator +// Operator encodings template -Node * -AbstractManglingParser::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make("operator&&"); - case 'd': - case 'n': - First += 2; - return make("operator&"); - case 'N': - First += 2; - return make("operator&="); - case 'S': - First += 2; - return make("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make("operator()"); - case 'm': - First += 2; - return make("operator,"); - case 'o': - First += 2; - return make("operator~"); - // ::= cv # (cast) - case 'v': { - First += 2; - SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); - // If we're parsing an encoding, State != nullptr and the conversion - // operators' could have a that refers to some - // s further ahead in the mangled name. - SwapAndRestore SavePermit(PermitForwardTemplateReferences, - PermitForwardTemplateReferences || - State != nullptr); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (State) State->CtorDtorConversion = true; - return make(Ty); - } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make("operator delete[]"); - case 'e': - First += 2; - return make("operator*"); - case 'l': - First += 2; - return make("operator delete"); - case 'v': - First += 2; - return make("operator/"); - case 'V': - First += 2; - return make("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make("operator^"); - case 'O': - First += 2; - return make("operator^="); - case 'q': - First += 2; - return make("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make("operator>="); - case 't': - First += 2; - return make("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make("operator<="); - // ::= li # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make(SN); - } - case 's': - First += 2; - return make("operator<<"); - case 'S': - First += 2; - return make("operator<<="); - case 't': - First += 2; - return make("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make("operator-"); - case 'I': - First += 2; - return make("operator-="); - case 'l': - First += 2; - return make("operator*"); - case 'L': - First += 2; - return make("operator*="); - case 'm': - First += 2; - return make("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make("operator new[]"); - case 'e': - First += 2; - return make("operator!="); - case 'g': - First += 2; - return make("operator-"); - case 't': - First += 2; - return make("operator!"); - case 'w': - First += 2; - return make("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make("operator||"); - case 'r': - First += 2; - return make("operator|"); - case 'R': - First += 2; - return make("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make("operator->*"); - case 'l': - First += 2; - return make("operator+"); - case 'L': - First += 2; - return make("operator+="); - case 'p': - First += 2; - return make("operator++"); - case 's': - First += 2; - return make("operator+"); - case 't': - First += 2; - return make("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make("operator?"); - } +const typename AbstractManglingParser< + Derived, Alloc>::OperatorInfo AbstractManglingParser::Ops[] = { + // Keep ordered by encoding + {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, + {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, + {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, + {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, + {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, + {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "}, + {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, + "operator co_await"}, + {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "}, + {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, + {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, + {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, + {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, + {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast + {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, + {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, + "operator delete[]"}, + {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"}, + {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, + {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, + "operator delete"}, + {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator.*"}, + {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix, + "operator."}, + {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"}, + {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="}, + {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"}, + {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="}, + {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="}, + {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"}, + {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"}, + {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="}, + {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="}, + {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"}, + {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"}, + {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="}, + {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="}, + {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"}, + {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator*"}, + {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"}, + {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary, + "operator new[]"}, + {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, + {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, + {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, + {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"}, + {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, + {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, + {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, + {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="}, + {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"}, + {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator->*"}, + {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"}, + {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"}, + {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix, + "operator->"}, + {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional, + "operator?"}, + {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="}, + {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="}, + {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, + "reinterpret_cast"}, + {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator%"}, + {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, + {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"}, + {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, + {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, + {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "}, + {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, + "typeid "}, + {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "}, +}; +template +const size_t AbstractManglingParser::NumOps = sizeof(Ops) / + sizeof(Ops[0]); + +// If the next 2 chars are an operator encoding, consume them and return their +// OperatorInfo. Otherwise return nullptr. +template +const typename AbstractManglingParser::OperatorInfo * +AbstractManglingParser::parseOperatorEncoding() { + if (numLeft() < 2) return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make("operator%"); - case 'M': - First += 2; - return make("operator%="); - case 's': - First += 2; - return make("operator>>"); - case 'S': - First += 2; - return make("operator>>="); - } + + // We can't use lower_bound as that can link to symbols in the C++ library, + // and this must remain independant of that. + size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. + while (upper != lower) { + size_t middle = (upper + lower) / 2; + if (Ops[middle] < First) + lower = middle + 1; + else + upper = middle; + } + if (Ops[lower] != First) return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make("operator<=>"); + + First += 2; + return &Ops[lower]; +} + +// ::= See parseOperatorEncoding() +// ::= li # operator "" +// ::= v # vendor extended operator +template +Node * +AbstractManglingParser::parseOperatorName(NameState *State) { + if (const auto *Op = parseOperatorEncoding()) { + if (Op->getKind() == OperatorInfo::CCast) { + // ::= cv # (cast) + ScopedOverride SaveTemplate(TryToParseTemplateArgs, false); + // If we're parsing an encoding, State != nullptr and the conversion + // operators' could have a that refers to some + // s further ahead in the mangled name. + ScopedOverride SavePermit(PermitForwardTemplateReferences, + PermitForwardTemplateReferences || + State != nullptr); + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) + return nullptr; + if (State) State->CtorDtorConversion = true; + return make(Ty); } - return nullptr; - // ::= v # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; + + if (Op->getKind() >= OperatorInfo::Unnameable) + /* Not a nameable operator. */ + return nullptr; + if (Op->getKind() == OperatorInfo::Member && !Op->getFlag()) + /* Not a nameable MemberExpr */ + return nullptr; + + return make(Op->getName()); + } + + if (consumeIf("li")) { + // ::= li # operator "" + Node *SN = getDerived().parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make(SN); + } + + if (consumeIf('v')) { + // ::= v # vendor extended operator + if (look() >= '0' && look() <= '9') { + First++; Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; @@ -3063,6 +3101,7 @@ AbstractManglingParser::parseOperatorName(NameState *State) { } return nullptr; } + return nullptr; } @@ -3081,19 +3120,11 @@ Node * AbstractManglingParser::parseCtorDtorName(Node *&SoFar, NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } + // Expand the special substitution. + SoFar = make( + static_cast(SoFar)); + if (!SoFar) + return nullptr; } if (consumeIf('C')) { @@ -3122,8 +3153,10 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, return nullptr; } -// ::= N [] [] E -// ::= N [] [] E +// ::= N [] [] +// E +// ::= N [] [] +// E // // ::= // ::= @@ -3132,7 +3165,7 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, // ::= # empty // ::= // ::= -// extension ::= L +// [*] extension // // := [] M // @@ -3152,90 +3185,76 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { - consumeIf('L'); // extension - - // := [] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // ::= if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'I') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) + if (TA == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically cannot be generated by a + // C++ entity. There will always be [something like] a name between + // them. return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } + if (State) + State->EndsWithTemplateArgs = true; + SoFar = make(SoFar, TA); + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else { + ModuleName *Module = nullptr; + + if (look() == 'S') { + // ::= + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast(S); + } else if (SoFar != nullptr) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } - // Parse an thats actually a . - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; + // ::= [] + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } - // ::= - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); + + // No longer used. + // := [] M + consumeIf('M'); } if (SoFar == nullptr || Subs.empty()) @@ -3330,6 +3349,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // ::= [gs] # x or (with "gs") ::x // ::= [gs] sr + E // # A::x, N::y, A::z; "gs" means leading "::" +// [gs] has been parsed by caller. // ::= sr # T::x / decltype(p)::x // extension ::= sr // # T::N::x /decltype(p)::N::x @@ -3337,7 +3357,7 @@ Node *AbstractManglingParser::parseBaseUnresolvedName() { // // ::= template -Node *AbstractManglingParser::parseUnresolvedName() { +Node *AbstractManglingParser::parseUnresolvedName(bool Global) { Node *SoFar = nullptr; // srN [] * E @@ -3371,8 +3391,6 @@ Node *AbstractManglingParser::parseUnresolvedName() { return make(SoFar, Base); } - bool Global = consumeIf("gs"); - // [gs] # x or (with "gs") ::x if (!consumeIf("sr")) { SoFar = getDerived().parseBaseUnresolvedName(); @@ -3602,7 +3620,7 @@ Node *AbstractManglingParser::parseDecltype() { return nullptr; if (!consumeIf('E')) return nullptr; - return make("decltype(", E, ")"); + return make("decltype", E); } // ::= A _ @@ -3688,8 +3706,8 @@ Node *AbstractManglingParser::parseQualifiedType() { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); StringView Proto; { - SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); + ScopedOverride SaveFirst(First, ProtoSourceName.begin()), + SaveLast(Last, ProtoSourceName.end()); Proto = parseBareSourceName(); } if (Proto.empty()) @@ -3884,6 +3902,32 @@ Node *AbstractManglingParser::parseType() { case 'h': First += 2; return make("half"); + // ::= DF _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(DimensionNumber); + } + // ::= DB _ # C23 signed _BitInt(N) + // ::= DB _ # C23 signed _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + // ::= DU _ # C23 unsigned _BitInt(N) + case 'B': + case 'U': { + bool Signed = look(1) == 'B'; + First += 2; + Node *Size = std::isdigit(look()) ? make(parseNumber()) + : getDerived().parseExpr(); + if (!Size) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(Size, Signed); + } // ::= Di # char32_t case 'i': First += 2; @@ -4031,9 +4075,10 @@ Node *AbstractManglingParser::parseType() { } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -4046,17 +4091,19 @@ Node *AbstractManglingParser::parseType() { // If this is followed by some , and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else if (IsSubst) { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } @@ -4076,22 +4123,24 @@ Node *AbstractManglingParser::parseType() { } template -Node *AbstractManglingParser::parsePrefixExpr(StringView Kind) { +Node *AbstractManglingParser::parsePrefixExpr(StringView Kind, + Node::Prec Prec) { Node *E = getDerived().parseExpr(); if (E == nullptr) return nullptr; - return make(Kind, E); + return make(Kind, E, Prec); } template -Node *AbstractManglingParser::parseBinaryExpr(StringView Kind) { +Node *AbstractManglingParser::parseBinaryExpr(StringView Kind, + Node::Prec Prec) { Node *LHS = getDerived().parseExpr(); if (LHS == nullptr) return nullptr; Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(LHS, Kind, RHS); + return make(LHS, Kind, RHS, Prec); } template @@ -4146,43 +4195,6 @@ Node *AbstractManglingParser::parseFunctionParam() { return nullptr; } -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization -template -Node *AbstractManglingParser::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make(ExprList, Ty, NodeArray(), Global, IsArray); -} - // cv # conversion with one argument // cv _ * E # conversion with a different number of arguments template @@ -4191,7 +4203,7 @@ Node *AbstractManglingParser::parseConversionExpr() { return nullptr; Node *Ty; { - SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); Ty = getDerived().parseType(); } @@ -4308,7 +4320,7 @@ Node *AbstractManglingParser::parseExprPrimary() { return nullptr; } case 'D': - if (consumeIf("DnE")) + if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E'))) return make("nullptr"); return nullptr; case 'T': @@ -4395,55 +4407,38 @@ Node *AbstractManglingParser::parseFoldExpr() { if (!consumeIf('f')) return nullptr; - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else + bool IsLeftFold = false, HasInitializer = false; + switch (look()) { + default: return nullptr; + case 'L': + IsLeftFold = true; + HasInitializer = true; + break; + case 'R': + HasInitializer = true; + break; + case 'l': + IsLeftFold = true; + break; + case 'r': + break; + } ++First; - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; - - Node *Pack = getDerived().parseExpr(), *Init = nullptr; + const auto *Op = parseOperatorEncoding(); + if (!Op) + return nullptr; + if (!(Op->getKind() == OperatorInfo::Binary + || (Op->getKind() == OperatorInfo::Member + && Op->getName().back() == '*'))) + return nullptr; + + Node *Pack = getDerived().parseExpr(); if (Pack == nullptr) return nullptr; + + Node *Init = nullptr; if (HasInitializer) { Init = getDerived().parseExpr(); if (Init == nullptr) @@ -4453,14 +4448,16 @@ Node *AbstractManglingParser::parseFoldExpr() { if (IsLeftFold && Init) std::swap(Pack, Init); - return make(IsLeftFold, OperatorName, Pack, Init); + return make(IsLeftFold, Op->getSymbol(), Pack, Init); } // ::= mc [] E // // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 template -Node *AbstractManglingParser::parsePointerToMemberConversionExpr() { +Node * +AbstractManglingParser::parsePointerToMemberConversionExpr( + Node::Prec Prec) { Node *Ty = getDerived().parseType(); if (!Ty) return nullptr; @@ -4470,7 +4467,7 @@ Node *AbstractManglingParser::parsePointerToMemberConversionExpr StringView Offset = getDerived().parseNumber(true); if (!consumeIf('E')) return nullptr; - return make(Ty, Expr, Offset); + return make(Ty, Expr, Offset, Prec); } // ::= so [] * [p] E @@ -4547,316 +4544,127 @@ Node *AbstractManglingParser::parseSubobjectExpr() { template Node *AbstractManglingParser::parseExpr() { bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - switch (*First) { - case 'L': - return getDerived().parseExprPrimary(); - case 'T': - return getDerived().parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a . - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return getDerived().parseBinaryExpr("&&"); - case 'd': - First += 2; - return getDerived().parsePrefixExpr("&"); - case 'n': - First += 2; - return getDerived().parseBinaryExpr("&"); - case 'N': - First += 2; - return getDerived().parseBinaryExpr("&="); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ty = getDerived().parseExpr(); - if (Ty == nullptr) - return nullptr; - return make("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc # const_cast(expression) - case 'c': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("const_cast", Ty, Ex); - } - // cl + E # call - case 'l': { - First += 2; - Node *Callee = getDerived().parseExpr(); - if (Callee == nullptr) - return Callee; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - return make(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr(","); - case 'o': - First += 2; - return getDerived().parsePrefixExpr("~"); - case 'v': - return getDerived().parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; + const auto *Op = parseOperatorEncoding(); + if (Op) { + auto Sym = Op->getSymbol(); + switch (Op->getKind()) { + case OperatorInfo::Binary: + // Binary operator: lhs @ rhs + return getDerived().parseBinaryExpr(Sym, Op->getPrecedence()); + case OperatorInfo::Prefix: + // Prefix unary operator: @ expr + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); + case OperatorInfo::Postfix: { + // Postfix unary operator: expr @ + if (consumeIf('_')) + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return getDerived().parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - return make(E, Global, /*is_array=*/false); - } - case 'n': - return getDerived().parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make(LHS, ".*", RHS); - } - case 't': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) return nullptr; - return make(LHS, ".", RHS); - } - case 'v': - First += 2; - return getDerived().parseBinaryExpr("/"); - case 'V': - First += 2; - return getDerived().parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return getDerived().parseBinaryExpr("^"); - case 'O': - First += 2; - return getDerived().parseBinaryExpr("^="); - case 'q': - First += 2; - return getDerived().parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr(">="); - case 't': - First += 2; - return getDerived().parseBinaryExpr(">"); + return make(Ex, Sym, Op->getPrecedence()); } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; + case OperatorInfo::Array: { + // Array Index: lhs [ rhs ] Node *Base = getDerived().parseExpr(); if (Base == nullptr) return nullptr; Node *Index = getDerived().parseExpr(); if (Index == nullptr) - return Index; - return make(Base, Index); + return nullptr; + return make(Base, Index, Op->getPrecedence()); } - case 'l': { - First += 2; + case OperatorInfo::Member: { + // Member access lhs @ rhs + Node *LHS = getDerived().parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = getDerived().parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, Sym, RHS, Op->getPrecedence()); + } + case OperatorInfo::New: { + // New + // # new (expr-list) type [(init)] + // [gs] nw * _ [pi *] E + // # new[] (expr-list) type [(init)] + // [gs] na * _ [pi *] E + size_t Exprs = Names.size(); + while (!consumeIf('_')) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + Names.push_back(Ex); + } + NodeArray ExprList = popTrailingNodeArray(Exprs); + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) + return nullptr; + bool HaveInits = consumeIf("pi"); size_t InitsBegin = Names.size(); while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) + if (!HaveInits) return nullptr; - Names.push_back(E); + Node *Init = getDerived().parseExpr(); + if (Init == nullptr) + return Init; + Names.push_back(Init); } - return make(nullptr, popTrailingNodeArray(InitsBegin)); - } - } - return nullptr; - case 'l': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr("<="); - case 's': - First += 2; - return getDerived().parseBinaryExpr("<<"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("<<="); - case 't': - First += 2; - return getDerived().parseBinaryExpr("<"); + NodeArray Inits = popTrailingNodeArray(InitsBegin); + return make(ExprList, Ty, Inits, Global, + /*IsArray=*/Op->getFlag(), Op->getPrecedence()); } - return nullptr; - case 'm': - switch (First[1]) { - case 'c': - First += 2; - return parsePointerToMemberConversionExpr(); - case 'i': - First += 2; - return getDerived().parseBinaryExpr("-"); - case 'I': - First += 2; - return getDerived().parseBinaryExpr("-="); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("*"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("*="); - case 'm': - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("--"); + case OperatorInfo::Del: { + // Delete Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return nullptr; - return make(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return getDerived().parseNewExpr(); - case 'e': - First += 2; - return getDerived().parseBinaryExpr("!="); - case 'g': - First += 2; - return getDerived().parsePrefixExpr("-"); - case 't': - First += 2; - return getDerived().parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("noexcept (", Ex, ")"); - } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return getDerived().parseUnresolvedName(); - case 'o': - First += 2; - return getDerived().parseBinaryExpr("||"); - case 'r': - First += 2; - return getDerived().parseBinaryExpr("|"); - case 'R': - First += 2; - return getDerived().parseBinaryExpr("|="); + return make(Ex, Global, /*IsArray=*/Op->getFlag(), + Op->getPrecedence()); } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return getDerived().parseBinaryExpr("->*"); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("+"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("++"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make(Ex, "++"); + case OperatorInfo::Call: { + // Function Call + Node *Callee = getDerived().parseExpr(); + if (Callee == nullptr) + return nullptr; + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); + } + return make(Callee, popTrailingNodeArray(ExprsBegin), + Op->getPrecedence()); } - case 's': - First += 2; - return getDerived().parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = getDerived().parseExpr(); - if (L == nullptr) + case OperatorInfo::CCast: { + // C Cast: (type)expr + Node *Ty; + { + ScopedOverride SaveTemp(TryToParseTemplateArgs, false); + Ty = getDerived().parseType(); + } + if (Ty == nullptr) return nullptr; - Node *R = getDerived().parseExpr(); - if (R == nullptr) + + size_t ExprsBegin = Names.size(); + bool IsMany = consumeIf('_'); + while (!consumeIf('E')) { + Node *E = getDerived().parseExpr(); + if (E == nullptr) + return E; + Names.push_back(E); + if (!IsMany) + break; + } + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + if (!IsMany && Exprs.size() != 1) return nullptr; - return make(L, "->", R); + return make(Ty, Exprs, Op->getPrecedence()); } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; + case OperatorInfo::Conditional: { + // Conditional operator: expr ? expr : expr Node *Cond = getDerived().parseExpr(); if (Cond == nullptr) return nullptr; @@ -4866,147 +4674,120 @@ Node *AbstractManglingParser::parseExpr() { Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make(Cond, LHS, RHS); - } - return nullptr; - case 'r': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("reinterpret_cast", T, Ex); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr("%"); - case 'M': - First += 2; - return getDerived().parseBinaryExpr("%="); - case 's': - First += 2; - return getDerived().parseBinaryExpr(">>"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("static_cast", T, Ex); - } - case 'o': - First += 2; - return parseSubobjectExpr(); - case 'p': { - First += 2; - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make(Child); + return make(Cond, LHS, RHS, Op->getPrecedence()); } - case 'r': - return getDerived().parseUnresolvedName(); - case 't': { - First += 2; + case OperatorInfo::NamedCast: { + // Named cast operation, @(expr) Node *Ty = getDerived().parseType(); if (Ty == nullptr) - return Ty; - return make("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; + return nullptr; Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make("sizeof (", Ex, ")"); + return nullptr; + return make(Sym, Ty, Ex, Op->getPrecedence()); } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make(R); - } else if (look() == 'f') { - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make("sizeof... (", FP, ")"); - } - return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make(popTrailingNodeArray(ArgsBegin)); - if (!Pack) + case OperatorInfo::OfIdOp: { + // [sizeof/alignof/typeid] ( | ) + Node *Arg = + Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); + if (!Arg) return nullptr; - return make("sizeof... (", Pack, ")"); + return make(Sym, Arg, Op->getPrecedence()); } + case OperatorInfo::NameOnly: { + // Not valid as an expression operand. + return nullptr; } - return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make("typeid (", Ex, ")"); } - case 'i': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make("typeid (", Ty, ")"); + DEMANGLE_UNREACHABLE; + } + + if (numLeft() < 2) + return nullptr; + + if (look() == 'L') + return getDerived().parseExprPrimary(); + if (look() == 'T') + return getDerived().parseTemplateParam(); + if (look() == 'f') { + // Disambiguate a fold expression from a . + if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) + return getDerived().parseFunctionParam(); + return getDerived().parseFoldExpr(); + } + if (consumeIf("il")) { + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); } - case 'l': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + return make(nullptr, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("mc")) + return parsePointerToMemberConversionExpr(Node::Prec::Unary); + if (consumeIf("nx")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return Ex; + return make("noexcept ", Ex, Node::Prec::Unary); + } + if (consumeIf("so")) + return parseSubobjectExpr(); + if (consumeIf("sp")) { + Node *Child = getDerived().parseExpr(); + if (Child == nullptr) + return nullptr; + return make(Child); + } + if (consumeIf("sZ")) { + if (look() == 'T') { + Node *R = getDerived().parseTemplateParam(); + if (R == nullptr) return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make(Ty, popTrailingNodeArray(InitsBegin)); + return make(R); } - case 'r': - First += 2; - return make("throw"); - case 'w': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) + Node *FP = getDerived().parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make("sizeof... ", FP); + } + if (consumeIf("sP")) { + size_t ArgsBegin = Names.size(); + while (!consumeIf('E')) { + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) return nullptr; - return make(Ex); + Names.push_back(Arg); } + auto *Pack = make(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make("sizeof... ", Pack); + } + if (consumeIf("tl")) { + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) + return nullptr; + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); } - return nullptr; - case 'u': { - ++First; + return make(Ty, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("tr")) + return make("throw"); + if (consumeIf("tw")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(Ex); + } + if (consumeIf('u')) { Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); if (!Name) return nullptr; @@ -5015,45 +4796,36 @@ Node *AbstractManglingParser::parseExpr() { // interpreted as node 'short' or 'ellipsis'. However, neither // __uuidof(short) nor __uuidof(...) can actually appear, so there is no // actual conflict here. + bool IsUUID = false; + Node *UUID = nullptr; if (Name->getBaseName() == "__uuidof") { - if (numLeft() < 2) - return nullptr; - if (*First == 't') { - ++First; - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - return make(Name, makeNodeArray(&Ty, &Ty + 1)); - } - if (*First == 'z') { - ++First; - Node *Ex = getDerived().parseExpr(); - if (!Ex) - return nullptr; - return make(Name, makeNodeArray(&Ex, &Ex + 1)); + if (consumeIf('t')) { + UUID = getDerived().parseType(); + IsUUID = true; + } else if (consumeIf('z')) { + UUID = getDerived().parseExpr(); + IsUUID = true; } } size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseTemplateArg(); - if (E == nullptr) - return E; - Names.push_back(E); + if (IsUUID) { + if (UUID == nullptr) + return nullptr; + Names.push_back(UUID); + } else { + while (!consumeIf('E')) { + Node *E = getDerived().parseTemplateArg(); + if (E == nullptr) + return E; + Names.push_back(E); + } } - return make(Name, popTrailingNodeArray(ExprsBegin)); - } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return getDerived().parseUnresolvedName(); + return make(Name, popTrailingNodeArray(ExprsBegin), + Node::Prec::Postfix); } - return nullptr; + + // Only unresolved names remain. + return getDerived().parseUnresolvedName(Global); } // ::= h _ @@ -5086,14 +4858,17 @@ bool AbstractManglingParser::parseCallOffset() { // # second call-offset is result adjustment // ::= T // # base is the nominal target function of thunk -// ::= GV # Guard variable for one-time initialization +// # Guard variable for one-time initialization +// ::= GV // # No // ::= TW # Thread-local wrapper // ::= TH # Thread-local initialization // ::= GR _ # First temporary // ::= GR _ # Subsequent temporaries -// extension ::= TC _ # construction vtable for second-in-first +// # construction vtable for second-in-first +// extension ::= TC _ // extension ::= GR # reference temporary for object +// extension ::= GI # module global initializer template Node *AbstractManglingParser::parseSpecialName() { switch (look()) { @@ -5220,6 +4995,16 @@ Node *AbstractManglingParser::parseSpecialName() { return nullptr; return make("reference temporary for ", Name); } + // GI v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make("initializer for module ", Module); + } } } return nullptr; @@ -5334,7 +5119,7 @@ template <> struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) + defined(__wasm__) || defined(__riscv) || defined(__loongarch__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; @@ -5399,43 +5184,41 @@ bool AbstractManglingParser::parseSeqId(size_t *Out) { // ::= Si # ::std::basic_istream > // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > +// The St case is handled specially in parseNestedName. template Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S')) return nullptr; - if (std::islower(look())) { - Node *SpecialSub; + if (look() >= 'a' && look() <= 'z') { + SpecialSubKind Kind; switch (look()) { case 'a': - ++First; - SpecialSub = make(SpecialSubKind::allocator); + Kind = SpecialSubKind::allocator; break; case 'b': - ++First; - SpecialSub = make(SpecialSubKind::basic_string); + Kind = SpecialSubKind::basic_string; break; - case 's': - ++First; - SpecialSub = make(SpecialSubKind::string); + case 'd': + Kind = SpecialSubKind::iostream; break; case 'i': - ++First; - SpecialSub = make(SpecialSubKind::istream); + Kind = SpecialSubKind::istream; break; case 'o': - ++First; - SpecialSub = make(SpecialSubKind::ostream); + Kind = SpecialSubKind::ostream; break; - case 'd': - ++First; - SpecialSub = make(SpecialSubKind::iostream); + case 's': + Kind = SpecialSubKind::string; break; default: return nullptr; } + ++First; + auto *SpecialSub = make(Kind); if (!SpecialSub) return nullptr; + // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. diff --git a/gnu/llvm/libcxxabi/src/demangle/ItaniumNodes.def b/gnu/llvm/libcxxabi/src/demangle/ItaniumNodes.def new file mode 100644 index 00000000000..f615cb9fadb --- /dev/null +++ b/gnu/llvm/libcxxabi/src/demangle/ItaniumNodes.def @@ -0,0 +1,95 @@ +//===------------------------- ItaniumNodes.def ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Define the demangler's node names + +#ifndef NODE +#error Define NODE to handle nodes +#endif + +NODE(NodeArrayNode) +NODE(DotSuffix) +NODE(VendorExtQualType) +NODE(QualType) +NODE(ConversionOperatorType) +NODE(PostfixQualifiedType) +NODE(ElaboratedTypeSpefType) +NODE(NameType) +NODE(AbiTagAttr) +NODE(EnableIfAttr) +NODE(ObjCProtoName) +NODE(PointerType) +NODE(ReferenceType) +NODE(PointerToMemberType) +NODE(ArrayType) +NODE(FunctionType) +NODE(NoexceptSpec) +NODE(DynamicExceptionSpec) +NODE(FunctionEncoding) +NODE(LiteralOperator) +NODE(SpecialName) +NODE(CtorVtableSpecialName) +NODE(QualifiedName) +NODE(NestedName) +NODE(LocalName) +NODE(ModuleName) +NODE(ModuleEntity) +NODE(VectorType) +NODE(PixelVectorType) +NODE(BinaryFPType) +NODE(BitIntType) +NODE(SyntheticTemplateParamName) +NODE(TypeTemplateParamDecl) +NODE(NonTypeTemplateParamDecl) +NODE(TemplateTemplateParamDecl) +NODE(TemplateParamPackDecl) +NODE(ParameterPack) +NODE(TemplateArgumentPack) +NODE(ParameterPackExpansion) +NODE(TemplateArgs) +NODE(ForwardTemplateReference) +NODE(NameWithTemplateArgs) +NODE(GlobalQualifiedName) +NODE(ExpandedSpecialSubstitution) +NODE(SpecialSubstitution) +NODE(CtorDtorName) +NODE(DtorName) +NODE(UnnamedTypeName) +NODE(ClosureTypeName) +NODE(StructuredBindingName) +NODE(BinaryExpr) +NODE(ArraySubscriptExpr) +NODE(PostfixExpr) +NODE(ConditionalExpr) +NODE(MemberExpr) +NODE(SubobjectExpr) +NODE(EnclosingExpr) +NODE(CastExpr) +NODE(SizeofParamPackExpr) +NODE(CallExpr) +NODE(NewExpr) +NODE(DeleteExpr) +NODE(PrefixExpr) +NODE(FunctionParam) +NODE(ConversionExpr) +NODE(PointerToMemberConversionExpr) +NODE(InitListExpr) +NODE(FoldExpr) +NODE(ThrowExpr) +NODE(BoolExpr) +NODE(StringLiteral) +NODE(LambdaExpr) +NODE(EnumLiteral) +NODE(IntegerLiteral) +NODE(FloatLiteral) +NODE(DoubleLiteral) +NODE(LongDoubleLiteral) +NODE(BracedExpr) +NODE(BracedRangeExpr) + +#undef NODE diff --git a/gnu/llvm/libcxxabi/src/demangle/README.txt b/gnu/llvm/libcxxabi/src/demangle/README.txt index 514ff6dd16f..76470f61f95 100644 --- a/gnu/llvm/libcxxabi/src/demangle/README.txt +++ b/gnu/llvm/libcxxabi/src/demangle/README.txt @@ -4,41 +4,50 @@ Itanium Name Demangler Library Introduction ------------ -This directory contains the generic itanium name demangler library. The main -purpose of the library is to demangle C++ symbols, i.e. convert the string -"_Z1fv" into "f()". You can also use the CRTP base ManglingParser to perform -some simple analysis on the mangled name, or (in LLVM) use the opaque -ItaniumPartialDemangler to query the demangled AST. +This directory contains the generic itanium name demangler +library. The main purpose of the library is to demangle C++ symbols, +i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP +base ManglingParser to perform some simple analysis on the mangled +name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the +demangled AST. Why are there multiple copies of the this library in the source tree? --------------------------------------------------------------------- -This directory is mirrored between libcxxabi/demangle and -llvm/include/llvm/Demangle. The simple reason for this is that both projects -need to demangle symbols, but neither can depend on each other. libcxxabi needs -the demangler to implement __cxa_demangle, which is part of the itanium ABI -spec. LLVM needs a copy for a bunch of places, but doesn't want to use the -system's __cxa_demangle because it a) might not be available (i.e., on Windows), -and b) probably isn't that up-to-date on the latest language features. - -The copy of the demangler in LLVM has some extra stuff that aren't needed in -libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), which depend on the -shared generic components. Despite these differences, we want to keep the "core" -generic demangling library identical between both copies to simplify development -and testing. - -If you're working on the generic library, then do the work first in libcxxabi, -then run the cp-to-llvm.sh script in src/demangle. This script takes as an -argument the path to llvm, and re-copies the changes you made to libcxxabi over. -Note that this script just blindly overwrites all changes to the generic library -in llvm, so be careful. - -Because the core demangler needs to work in libcxxabi, everything needs to be -declared in an anonymous namespace (see DEMANGLE_NAMESPACE_BEGIN), and you can't -introduce any code that depends on the libcxx dylib. - -Hopefully, when LLVM becomes a monorepo, we can de-duplicate this code, and have -both LLVM and libcxxabi depend on a shared demangler library. +The canonical sources are in libcxxabi/src/demangle and some of the +files are copied to llvm/include/llvm/Demangle. The simple reason for +this comes from before the monorepo, and both [sub]projects need to +demangle symbols, but neither can depend on each other. + +* libcxxabi needs the demangler to implement __cxa_demangle, which is + part of the itanium ABI spec. + +* LLVM needs a copy for a bunch of places, and cannot rely on the + system's __cxa_demangle because it a) might not be available (i.e., + on Windows), and b) may not be up-to-date on the latest language + features. + +The copy of the demangler in LLVM has some extra stuff that aren't +needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), +which depend on the shared generic components. Despite these +differences, we want to keep the "core" generic demangling library +identical between both copies to simplify development and testing. + +If you're working on the generic library, then do the work first in +libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This +script takes as an optional argument the path to llvm, and copies the +changes you made to libcxxabi over. Note that this script just +blindly overwrites all changes to the generic library in llvm, so be +careful. + +Because the core demangler needs to work in libcxxabi, everything +needs to be declared in an anonymous namespace (see +DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that +depends on the libcxx dylib. + +FIXME: Now that LLVM is a monorepo, it should be possible to +de-duplicate this code, and have both LLVM and libcxxabi depend on a +shared demangler library. Testing ------- diff --git a/gnu/llvm/libcxxabi/src/demangle/StringView.h b/gnu/llvm/libcxxabi/src/demangle/StringView.h index 1e4d3803f06..90890e37711 100644 --- a/gnu/llvm/libcxxabi/src/demangle/StringView.h +++ b/gnu/llvm/libcxxabi/src/demangle/StringView.h @@ -7,6 +7,9 @@ //===----------------------------------------------------------------------===// // // FIXME: Use std::string_view instead when we support C++17. +// There are two copies of this file in the source tree. The one under +// libcxxabi is the original and the one under llvm is the copy. Use +// cp-to-llvm.sh to update the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// @@ -14,7 +17,6 @@ #define DEMANGLE_STRINGVIEW_H #include "DemangleConfig.h" -#include #include #include @@ -38,15 +40,16 @@ public: StringView substr(size_t Pos, size_t Len = npos) const { assert(Pos <= size()); - return StringView(begin() + Pos, std::min(Len, size() - Pos)); + if (Len > size() - Pos) + Len = size() - Pos; + return StringView(begin() + Pos, Len); } size_t find(char C, size_t From = 0) const { - size_t FindBegin = std::min(From, size()); // Avoid calling memchr with nullptr. - if (FindBegin < size()) { + if (From < size()) { // Just forward to memchr, which is faster than a hand-rolled loop. - if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) + if (const void *P = ::memchr(First + From, C, size() - From)) return size_t(static_cast(P) - First); } return npos; @@ -98,7 +101,7 @@ public: bool startsWith(StringView Str) const { if (Str.size() > size()) return false; - return std::equal(Str.begin(), Str.end(), begin()); + return std::strncmp(Str.begin(), begin(), Str.size()) == 0; } const char &operator[](size_t Idx) const { return *(begin() + Idx); } @@ -111,7 +114,7 @@ public: inline bool operator==(const StringView &LHS, const StringView &RHS) { return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); + std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; } DEMANGLE_NAMESPACE_END diff --git a/gnu/llvm/libcxxabi/src/demangle/Utility.h b/gnu/llvm/libcxxabi/src/demangle/Utility.h index 846a5f0818e..c9b211b5441 100644 --- a/gnu/llvm/libcxxabi/src/demangle/Utility.h +++ b/gnu/llvm/libcxxabi/src/demangle/Utility.h @@ -6,7 +6,10 @@ // //===----------------------------------------------------------------------===// // -// Provide some utility classes for use in the demangler(s). +// Provide some utility classes for use in the demangler. +// There are two copies of this file in the source tree. The one in libcxxabi +// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update +// the copy. See README.txt for more details. // //===----------------------------------------------------------------------===// @@ -14,123 +17,158 @@ #define DEMANGLE_UTILITY_H #include "StringView.h" +#include #include #include #include -#include +#include #include DEMANGLE_NAMESPACE_BEGIN // Stream that AST nodes write their string representation into after the AST // has been parsed. -class OutputStream { +class OutputBuffer { char *Buffer = nullptr; size_t CurrentPosition = 0; size_t BufferCapacity = 0; - // Ensure there is at least n more positions in buffer. + // Ensure there are at least N more positions in the buffer. void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { + size_t Need = N + CurrentPosition; + if (Need > BufferCapacity) { + // Reduce the number of reallocations, with a bit of hysteresis. The + // number here is chosen so the first allocation will more-than-likely not + // allocate more than 1K. + Need += 1024 - 32; BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; + if (BufferCapacity < Need) + BufferCapacity = Need; Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); } } - void writeUnsigned(uint64_t N, bool isNeg = false) { - // Handle special case... - if (N == 0) { - *this << '0'; - return; - } - - char Temp[21]; - char *TempPtr = std::end(Temp); + OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { + std::array Temp; + char *TempPtr = Temp.data() + Temp.size(); - while (N) { + // Output at least one character. + do { *--TempPtr = char('0' + N % 10); N /= 10; - } + } while (N); - // Add negative sign... + // Add negative sign. if (isNeg) *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); + + return operator+=(StringView(TempPtr, Temp.data() + Temp.size())); } public: - OutputStream(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; - void reset(char *Buffer_, size_t BufferCapacity_) { - CurrentPosition = 0; - Buffer = Buffer_; - BufferCapacity = BufferCapacity_; - } + OutputBuffer(char *StartBuf, size_t Size) + : Buffer(StartBuf), BufferCapacity(Size) {} + OutputBuffer(char *StartBuf, size_t *SizePtr) + : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} + OutputBuffer() = default; + // Non-copyable + OutputBuffer(const OutputBuffer &) = delete; + OutputBuffer &operator=(const OutputBuffer &) = delete; + + operator StringView() const { return StringView(Buffer, CurrentPosition); } /// If a ParameterPackExpansion (or similar type) is encountered, the offset /// into the pack that we're currently printing. unsigned CurrentPackIndex = std::numeric_limits::max(); unsigned CurrentPackMax = std::numeric_limits::max(); - OutputStream &operator+=(StringView R) { - size_t Size = R.size(); - if (Size == 0) - return *this; - grow(Size); - std::memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; + /// When zero, we're printing template args and '>' needs to be parenthesized. + /// Use a counter so we can simply increment inside parentheses. + unsigned GtIsGt = 1; + + bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } + + void printOpen(char Open = '(') { + GtIsGt++; + *this += Open; + } + void printClose(char Close = ')') { + GtIsGt--; + *this += Close; + } + + OutputBuffer &operator+=(StringView R) { + if (size_t Size = R.size()) { + grow(Size); + std::memcpy(Buffer + CurrentPosition, R.begin(), Size); + CurrentPosition += Size; + } return *this; } - OutputStream &operator+=(char C) { + OutputBuffer &operator+=(char C) { grow(1); Buffer[CurrentPosition++] = C; return *this; } - OutputStream &operator<<(StringView R) { return (*this += R); } + OutputBuffer &prepend(StringView R) { + size_t Size = R.size(); - OutputStream &operator<<(char C) { return (*this += C); } + grow(Size); + std::memmove(Buffer + Size, Buffer, CurrentPosition); + std::memcpy(Buffer, R.begin(), Size); + CurrentPosition += Size; - OutputStream &operator<<(long long N) { - if (N < 0) - writeUnsigned(static_cast(-N), true); - else - writeUnsigned(static_cast(N)); return *this; } - OutputStream &operator<<(unsigned long long N) { - writeUnsigned(N, false); - return *this; + OutputBuffer &operator<<(StringView R) { return (*this += R); } + + OutputBuffer &operator<<(char C) { return (*this += C); } + + OutputBuffer &operator<<(long long N) { + return writeUnsigned(static_cast(std::abs(N)), N < 0); } - OutputStream &operator<<(long N) { + OutputBuffer &operator<<(unsigned long long N) { + return writeUnsigned(N, false); + } + + OutputBuffer &operator<<(long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned long N) { + OutputBuffer &operator<<(unsigned long N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(int N) { + OutputBuffer &operator<<(int N) { return this->operator<<(static_cast(N)); } - OutputStream &operator<<(unsigned int N) { + OutputBuffer &operator<<(unsigned int N) { return this->operator<<(static_cast(N)); } + void insert(size_t Pos, const char *S, size_t N) { + assert(Pos <= CurrentPosition); + if (N == 0) + return; + grow(N); + std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos); + std::memcpy(Buffer + Pos, S, N); + CurrentPosition += N; + } + size_t getCurrentPosition() const { return CurrentPosition; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } char back() const { - return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + assert(CurrentPosition); + return Buffer[CurrentPosition - 1]; } bool empty() const { return CurrentPosition == 0; } @@ -140,52 +178,22 @@ public: size_t getBufferCapacity() const { return BufferCapacity; } }; -template class SwapAndRestore { - T &Restore; - T OriginalValue; - bool ShouldRestore = true; +template class ScopedOverride { + T &Loc; + T Original; public: - SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} - - SwapAndRestore(T &Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); - } - ~SwapAndRestore() { - if (ShouldRestore) - Restore = std::move(OriginalValue); - } + ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} - void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } - - void restoreNow(bool Force) { - if (!Force && !ShouldRestore) - return; - - Restore = std::move(OriginalValue); - ShouldRestore = false; + ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { + Loc_ = std::move(NewVal); } + ~ScopedOverride() { Loc = std::move(Original); } - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; + ScopedOverride(const ScopedOverride &) = delete; + ScopedOverride &operator=(const ScopedOverride &) = delete; }; -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, - size_t InitSize) { - size_t BufferSize; - if (Buf == nullptr) { - Buf = static_cast(std::malloc(InitSize)); - if (Buf == nullptr) - return false; - BufferSize = InitSize; - } else - BufferSize = *N; - - S.reset(Buf, BufferSize); - return true; -} - DEMANGLE_NAMESPACE_END #endif diff --git a/gnu/llvm/libcxxabi/src/demangle/cp-to-llvm.sh b/gnu/llvm/libcxxabi/src/demangle/cp-to-llvm.sh index 808abbcd99b..d1474655b1c 100755 --- a/gnu/llvm/libcxxabi/src/demangle/cp-to-llvm.sh +++ b/gnu/llvm/libcxxabi/src/demangle/cp-to-llvm.sh @@ -5,7 +5,8 @@ set -e -FILES="ItaniumDemangle.h StringView.h Utility.h README.txt" +cd $(dirname $0) +HDRS="ItaniumDemangle.h ItaniumNodes.def StringView.h Utility.h" LLVM_DEMANGLE_DIR=$1 if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then @@ -21,7 +22,15 @@ read -p "This will overwrite the copies of $FILES in $LLVM_DEMANGLE_DIR; are you echo if [[ $ANSWER =~ ^[Yy]$ ]]; then - for I in $FILES ; do - cp $I $LLVM_DEMANGLE_DIR/$I + cp -f README.txt $LLVM_DEMANGLE_DIR + chmod -w $LLVM_DEMANGLE_DIR/README.txt + for I in $HDRS ; do + rm -f $LLVM_DEMANGLE_DIR/$I + dash=$(echo "$I---------------------------" | cut -c -27 |\ + sed 's|[^-]*||') + sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- mode:c++;eval:(read-only-mode) -*-===//|' \ + -e '2s|^// *$|// Do not edit! See README.txt.|' \ + $I >$LLVM_DEMANGLE_DIR/$I + chmod -w $LLVM_DEMANGLE_DIR/$I done fi diff --git a/gnu/llvm/libcxxabi/src/fallback_malloc.cpp b/gnu/llvm/libcxxabi/src/fallback_malloc.cpp index f3d7937793c..591efbefc8a 100644 --- a/gnu/llvm/libcxxabi/src/fallback_malloc.cpp +++ b/gnu/llvm/libcxxabi/src/fallback_malloc.cpp @@ -1,4 +1,4 @@ -//===------------------------ fallback_malloc.cpp -------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,6 +15,7 @@ #endif #endif +#include #include // for malloc, calloc, free #include // for memset #include // for std::__libcpp_aligned_{alloc,free} @@ -33,10 +34,9 @@ namespace { // When POSIX threads are not available, make the mutex operations a nop #ifndef _LIBCXXABI_HAS_NO_THREADS -_LIBCPP_SAFE_STATIC -static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER; +static _LIBCPP_CONSTINIT std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER; #else -static void* heap_mutex = 0; +static _LIBCPP_CONSTINIT void* heap_mutex = 0; #endif class mutexor { @@ -64,11 +64,28 @@ char heap[HEAP_SIZE] __attribute__((aligned)); typedef unsigned short heap_offset; typedef unsigned short heap_size; +// On both 64 and 32 bit targets heap_node should have the following properties +// Size: 4 +// Alignment: 2 struct heap_node { heap_offset next_node; // offset into heap heap_size len; // size in units of "sizeof(heap_node)" }; +// All pointers returned by fallback_malloc must be at least aligned +// as RequiredAligned. Note that RequiredAlignment can be greater than +// alignof(std::max_align_t) on 64 bit systems compiling 32 bit code. +struct FallbackMaxAlignType { +} __attribute__((aligned)); +const size_t RequiredAlignment = alignof(FallbackMaxAlignType); + +static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0, + "The required alignment must be evenly divisible by the sizeof(heap_node)"); + +// The number of heap_node's that can fit in a chunk of memory with the size +// of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4. +const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / sizeof(heap_node); + static const heap_node* list_end = (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap static heap_node* freelist = NULL; @@ -83,10 +100,23 @@ heap_offset offset_from_node(const heap_node* ptr) { sizeof(heap_node)); } +// Return a pointer to the first address, 'A', in `heap` that can actually be +// used to represent a heap_node. 'A' must be aligned so that +// '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this +// address should be 12 bytes after the first 16 byte boundary. +heap_node* getFirstAlignedNodeInHeap() { + heap_node* node = (heap_node*)heap; + const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node); + size_t boundaryOffset = reinterpret_cast(node) % RequiredAlignment; + size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset; + size_t NElemOffset = requiredOffset / sizeof(heap_node); + return node + NElemOffset; +} + void init_heap() { - freelist = (heap_node*)heap; + freelist = getFirstAlignedNodeInHeap(); freelist->next_node = offset_from_node(list_end); - freelist->len = HEAP_SIZE / sizeof(heap_node); + freelist->len = static_cast(list_end - freelist); } // How big a chunk we allocate @@ -110,23 +140,44 @@ void* fallback_malloc(size_t len) { for (p = freelist, prev = 0; p && p != list_end; prev = p, p = node_from_offset(p->next_node)) { - if (p->len > nelems) { // chunk is larger, shorten, and return the tail - heap_node* q; + // Check the invariant that all heap_nodes pointers 'p' are aligned + // so that 'p + 1' has an alignment of at least RequiredAlignment + assert(reinterpret_cast(p + 1) % RequiredAlignment == 0); + + // Calculate the number of extra padding elements needed in order + // to split 'p' and create a properly aligned heap_node from the tail + // of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems' + // will be a multiple of NodesPerAlignment. + size_t aligned_nelems = nelems; + if (p->len > nelems) { + heap_size remaining_len = static_cast(p->len - nelems); + aligned_nelems += remaining_len % NodesPerAlignment; + } - p->len = static_cast(p->len - nelems); + // chunk is larger and we can create a properly aligned heap_node + // from the tail. In this case we shorten 'p' and return the tail. + if (p->len > aligned_nelems) { + heap_node* q; + p->len = static_cast(p->len - aligned_nelems); q = p + p->len; q->next_node = 0; - q->len = static_cast(nelems); - return (void*)(q + 1); + q->len = static_cast(aligned_nelems); + void* ptr = q + 1; + assert(reinterpret_cast(ptr) % RequiredAlignment == 0); + return ptr; } - if (p->len == nelems) { // exact size match + // The chunk is the exact size or the chunk is larger but not large + // enough to split due to alignment constraints. + if (p->len >= nelems) { if (prev == 0) freelist = node_from_offset(p->next_node); else prev->next_node = p->next_node; p->next_node = 0; - return (void*)(p + 1); + void* ptr = p + 1; + assert(reinterpret_cast(ptr) % RequiredAlignment == 0); + return ptr; } } return NULL; // couldn't find a spot big enough diff --git a/gnu/llvm/libcxxabi/src/fallback_malloc.h b/gnu/llvm/libcxxabi/src/fallback_malloc.h index 57808545197..816e691ed23 100644 --- a/gnu/llvm/libcxxabi/src/fallback_malloc.h +++ b/gnu/llvm/libcxxabi/src/fallback_malloc.h @@ -1,4 +1,4 @@ -//===------------------------- fallback_malloc.h --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/private_typeinfo.cpp b/gnu/llvm/libcxxabi/src/private_typeinfo.cpp index 86e187fecb5..e1086661c01 100644 --- a/gnu/llvm/libcxxabi/src/private_typeinfo.cpp +++ b/gnu/llvm/libcxxabi/src/private_typeinfo.cpp @@ -1,4 +1,4 @@ -//===----------------------- private_typeinfo.cpp -------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/private_typeinfo.h b/gnu/llvm/libcxxabi/src/private_typeinfo.h index b99039cb567..622e09cc242 100644 --- a/gnu/llvm/libcxxabi/src/private_typeinfo.h +++ b/gnu/llvm/libcxxabi/src/private_typeinfo.h @@ -1,4 +1,4 @@ -//===------------------------ private_typeinfo.h --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/stdlib_exception.cpp b/gnu/llvm/libcxxabi/src/stdlib_exception.cpp index 5f9e643548b..b1fc21f412a 100644 --- a/gnu/llvm/libcxxabi/src/stdlib_exception.cpp +++ b/gnu/llvm/libcxxabi/src/stdlib_exception.cpp @@ -1,4 +1,4 @@ -//===---------------------------- exception.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/stdlib_new_delete.cpp b/gnu/llvm/libcxxabi/src/stdlib_new_delete.cpp index 1091b82f642..4a664e15a50 100644 --- a/gnu/llvm/libcxxabi/src/stdlib_new_delete.cpp +++ b/gnu/llvm/libcxxabi/src/stdlib_new_delete.cpp @@ -1,4 +1,4 @@ -//===--------------------- stdlib_new_delete.cpp --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/gnu/llvm/libcxxabi/src/stdlib_stdexcept.cpp b/gnu/llvm/libcxxabi/src/stdlib_stdexcept.cpp index 0ca378dcde0..92f7a6e076c 100644 --- a/gnu/llvm/libcxxabi/src/stdlib_stdexcept.cpp +++ b/gnu/llvm/libcxxabi/src/stdlib_stdexcept.cpp @@ -1,4 +1,4 @@ -//===------------------------ stdexcept.cpp -------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,9 +12,7 @@ #include #include #include - -// This includes an implementation file from libc++. -#include "src/include/refstring.h" +#include "include/refstring.h" // from libc++ static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); diff --git a/gnu/llvm/libcxxabi/src/stdlib_typeinfo.cpp b/gnu/llvm/libcxxabi/src/stdlib_typeinfo.cpp index b282cc7c61b..6e5499628d1 100644 --- a/gnu/llvm/libcxxabi/src/stdlib_typeinfo.cpp +++ b/gnu/llvm/libcxxabi/src/stdlib_typeinfo.cpp @@ -1,4 +1,4 @@ -//===----------------------------- typeinfo.cpp ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information.