From 5d8cd81596041f638e071dc78898874dcae4aae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Fri, 25 Feb 2022 12:10:28 +0100 Subject: [PATCH 1/2] Update to llvm 14 2fe5bf57172cebf5a3f0b3f82552cf5c2122eca2 --- .arcconfig | 4 - .clang-format | 12 - CMakeLists.txt | 177 ++- cmake/Modules/HandleCompilerRT.cmake | 64 - cmake/Modules/HandleLibcxxabiFlags.cmake | 11 + cmake/config-ix.cmake | 27 +- include/__cxxabi_config.h | 4 +- include/cxxabi.h | 2 +- src/CMakeLists.txt | 89 +- src/abort_message.cpp | 2 +- src/abort_message.h | 2 +- src/cxa_aux_runtime.cpp | 2 +- src/cxa_default_handlers.cpp | 24 +- src/cxa_demangle.cpp | 14 +- src/cxa_exception.cpp | 34 +- src/cxa_exception.h | 4 +- src/cxa_exception_storage.cpp | 70 +- src/cxa_guard.cpp | 2 +- src/cxa_guard_impl.h | 442 ++++--- src/cxa_handlers.cpp | 30 +- src/cxa_handlers.h | 6 +- src/cxa_noexception.cpp | 2 +- src/cxa_personality.cpp | 271 ++-- src/cxa_thread_atexit.cpp | 35 +- src/cxa_vector.cpp | 2 +- src/cxa_virtual.cpp | 2 +- src/demangle/ItaniumDemangle.h | 1530 +++++++++++----------- src/demangle/README.txt | 71 +- src/demangle/StringView.h | 28 +- src/demangle/Utility.h | 65 +- src/demangle/cp-to-llvm.sh | 15 +- src/fallback_malloc.cpp | 2 +- src/fallback_malloc.h | 2 +- src/include/atomic_support.h | 180 --- src/private_typeinfo.cpp | 6 +- src/private_typeinfo.h | 4 +- src/stdlib_exception.cpp | 22 +- src/stdlib_new_delete.cpp | 54 +- src/stdlib_stdexcept.cpp | 26 +- src/stdlib_typeinfo.cpp | 14 +- 40 files changed, 1681 insertions(+), 1672 deletions(-) delete mode 100644 .arcconfig delete mode 100644 .clang-format delete mode 100644 cmake/Modules/HandleCompilerRT.cmake delete mode 100644 src/include/atomic_support.h diff --git a/.arcconfig b/.arcconfig deleted file mode 100644 index 08cd16e..0000000 --- a/.arcconfig +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repository.callsign" : "CXXA", - "conduit_uri" : "https://reviews.llvm.org/" -} diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 2d1d3be..0000000 --- a/.clang-format +++ /dev/null @@ -1,12 +0,0 @@ -BasedOnStyle: LLVM - ---- -Language: Cpp - -AlwaysBreakTemplateDeclarations: true -PointerAlignment: Left - -# Disable formatting options which may break tests. -SortIncludes: false -ReflowComments: false ---- diff --git a/CMakeLists.txt b/CMakeLists.txt index 146749f..8e8cdf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,23 +10,27 @@ endif() cmake_minimum_required(VERSION 3.13.4) -if(POLICY CMP0042) - cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default -endif() +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++") + set(LIBCXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 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) + message(WARNING "The Standalone build is deprecated in this release. Please use one of the ways " + "described at https://libcxx.llvm.org/BuildingLibcxx.html for building libc++abi.") + project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) @@ -34,21 +38,21 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXXABI_STANDALONE_B 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}") + set(LIBCXXABI_STANDALONE_BUILD TRUE) # 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") +endif() + +# Must go below project(..) +include(GNUInstallDirs) +if (LIBCXXABI_STANDALONE_BUILD) # 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") @@ -84,13 +88,13 @@ option(LIBCXXABI_ENABLE_EXCEPTIONS When disabled, libc++abi does not support stack unwinding and other exceptions-related features." ON) option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) -option(LIBCXXABI_ENABLE_PIC "Build Position-Independent Code, even in static library" ON) option(LIBCXXABI_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." OFF) option(LIBCXXABI_ENABLE_STATIC_UNWINDER "Statically link the LLVM unwinder." OFF) option(LIBCXXABI_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF) option(LIBCXXABI_ENABLE_THREADS "Build with threads enabled" ON) option(LIBCXXABI_HAS_PTHREAD_API "Ignore auto-detection and force use of pthread API" OFF) +option(LIBCXXABI_HAS_WIN32_THREAD_API "Ignore auto-detection and force use of win32 thread API" OFF) option(LIBCXXABI_HAS_EXTERNAL_THREAD_API "Build libc++abi with an externalized threading API. This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON." OFF) @@ -108,14 +112,35 @@ 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_LIBRARY "Install the libc++abi library." ON) -set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") -set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") -set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") + +if(NOT CMAKE_SYSROOT AND LIBCXXABI_SYSROOT) + message(WARNING "LIBCXXABI_SYSROOT is deprecated, please use CMAKE_SYSROOT instead") +endif() +if(NOT CMAKE_CXX_COMPILER_TARGET AND LIBCXXABI_TARGET_TRIPLE) + message(WARNING "LIBCXXABI_TARGET_TRIPLE is deprecated, please use CMAKE_CXX_COMPILER_TARGET instead") +endif() +if(NOT CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN AND LIBCXXABI_GCC_TOOLCHAIN) + message(WARNING "LIBCXXABI_GCC_TOOLCHAIN is deprecated, please use CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN instead") +endif() + +if(CMAKE_CXX_COMPILER_TARGET) + set(LIBCXXABI_DEFAULT_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}") +else() + set(LIBCXXABI_DEFAULT_TARGET_TRIPLE "${LLVM_DEFAULT_TARGET_TRIPLE}") +endif() +set(LIBCXXABI_TARGET_TRIPLE "${LIBCXXABI_DEFAULT_TARGET_TRIPLE}" CACHE STRING "Target triple for cross compiling.") +set(LIBCXXABI_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}" CACHE PATH "GCC toolchain for cross compiling.") +set(LIBCXXABI_SYSROOT "${CMAKE_SYSROOT}" CACHE PATH "Sysroot for cross compiling.") + 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 \ @@ -150,20 +175,40 @@ option(LIBCXXABI_BAREMETAL "Build libc++abi for baremetal targets." OFF) # The default terminate handler attempts to demangle uncaught exceptions, which # causes extra I/O and demangling code to be pulled in. option(LIBCXXABI_SILENT_TERMINATE "Set this to make the terminate handler default to a silent alternative" OFF) +option(LIBCXXABI_NON_DEMANGLING_TERMINATE "Set this to make the terminate handler +avoid demangling" OFF) 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() -set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXXABI_LIBCXX_PATH}/include" CACHE PATH +# 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). +set(LIBCXXABI_LIBCXX_INCLUDES "" CACHE PATH "Specify path to libc++ includes.") -message(STATUS "Libc++abi will be using libc++ includes from ${LIBCXXABI_LIBCXX_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.") + 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() + target_compile_options(cxx-headers INTERFACE -I "${LIBCXXABI_LIBCXX_INCLUDES}") + 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.") + "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() set(LIBCXXABI_TEST_PARAMS "" CACHE STRING "A list of parameters to run the Lit test suite with.") @@ -178,23 +223,30 @@ 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_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++) - set(LIBCXXABI_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++) + set(LIBCXXABI_HEADER_DIR ${LLVM_BINARY_DIR}) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}) + set(LIBCXXABI_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE PATH + "Path where built libc++abi libraries should be installed.") if(LIBCXX_LIBDIR_SUBDIR) 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_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) - set(LIBCXXABI_INSTALL_LIBRARY_DIR lib${LIBCXXABI_LIBDIR_SUFFIX}) else() - set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) - set(LIBCXXABI_INSTALL_LIBRARY_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() -set(LIBCXXABI_INSTALL_PREFIX "" CACHE STRING "Define libc++abi destination prefix.") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) @@ -206,15 +258,6 @@ if (NOT LIBCXXABI_LIBCXX_LIBRARY_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. @@ -237,26 +280,17 @@ include(HandleLibcxxabiFlags) #=============================================================================== # Configure target flags -add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") - +if(ZOS) + add_target_flags_if_supported("-fzos-le-char-mode=ebcdic") +endif() if(LIBCXXABI_TARGET_TRIPLE) - add_target_flags("--target=${LIBCXXABI_TARGET_TRIPLE}") -elseif(CMAKE_CXX_COMPILER_TARGET) - set(LIBCXXABI_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}") + add_target_flags_if_supported("--target=${LIBCXXABI_TARGET_TRIPLE}") endif() -if(LIBCXX_GCC_TOOLCHAIN) - add_target_flags("--gcc-toolchain=${LIBCXXABI_GCC_TOOLCHAIN}") -elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) - set(LIBCXXABI_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") +if(LIBCXXABI_GCC_TOOLCHAIN) + add_target_flags_if_supported("--gcc-toolchain=${LIBCXXABI_GCC_TOOLCHAIN}") endif() if(LIBCXXABI_SYSROOT) - add_target_flags("--sysroot=${LIBCXXABI_SYSROOT}") -elseif(CMAKE_SYSROOT) - set(LIBCXXABI_SYSROOT "${CMAKE_SYSROOT}") -endif() - -if (LIBCXXABI_TARGET_TRIPLE) - set(TARGET_TRIPLE "${LIBCXXABI_TARGET_TRIPLE}") + add_target_flags_if_supported("--sysroot=${LIBCXXABI_SYSROOT}") endif() # Configure compiler. Must happen after setting the target flags. @@ -374,6 +408,11 @@ if (NOT LIBCXXABI_ENABLE_THREADS) " be set to ON when LIBCXXABI_ENABLE_THREADS" " is also set to ON.") endif() + if (LIBCXXABI_HAS_WIN32_THREAD_API) + message(FATAL_ERROR "LIBCXXABI_HAS_WIN32_THREAD_API can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) message(FATAL_ERROR "LIBCXXABI_HAS_EXTERNAL_THREAD_API can only" " be set to ON when LIBCXXABI_ENABLE_THREADS" @@ -385,7 +424,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) @@ -394,6 +432,11 @@ if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) " and LIBCXXABI_HAS_PTHREAD_API cannot be both" " set to ON at the same time.") endif() + if (LIBCXXABI_HAS_WIN32_THREAD_API) + message(FATAL_ERROR "The options LIBCXXABI_HAS_EXTERNAL_THREAD_API" + " and LIBCXXABI_HAS_WIN32_THREAD_API cannot be both" + " set to ON at the same time.") + endif() if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) message(FATAL_ERROR "The options LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY" " and LIBCXXABI_HAS_EXTERNAL_THREAD_API cannot be both" @@ -401,6 +444,14 @@ if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) endif() endif() +if (LIBCXXABI_HAS_PTHREAD_API) + if (LIBCXXABI_HAS_WIN32_THREAD_API) + message(FATAL_ERROR "The options LIBCXXABI_HAS_PTHREAD_API" + "and LIBCXXABI_HAS_WIN32_THREAD_API cannot be both" + "set to ON at the same time.") + endif() +endif() + if (LLVM_ENABLE_MODULES) # Ignore that the rest of the modules flags are now unused. add_compile_flags_if_supported(-Wno-unused-command-line-argument) @@ -428,6 +479,10 @@ if (LIBCXXABI_HAS_PTHREAD_API) add_definitions(-D_LIBCPP_HAS_THREAD_API_PTHREAD) endif() +if (LIBCXXABI_HAS_WIN32_THREAD_API) + add_definitions(-D_LIBCPP_HAS_THREAD_API_WIN32) +endif() + if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) add_definitions(-D_LIBCPP_HAS_THREAD_API_EXTERNAL) endif() @@ -439,10 +494,6 @@ endif() # Prevent libc++abi from having library dependencies on libc++ add_definitions(-D_LIBCPP_DISABLE_EXTERN_TEMPLATE) -# Bring back `std::unexpected`, which is removed in C++17, to support -# pre-C++17. -add_definitions(-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) - if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() @@ -456,6 +507,10 @@ if (LIBCXXABI_SILENT_TERMINATE) add_definitions(-DLIBCXXABI_SILENT_TERMINATE) endif() +if (LIBCXXABI_NON_DEMANGLING_TERMINATE) + add_definitions(-DLIBCXXABI_NON_DEMANGLING_TERMINATE) +endif() + if (LIBCXXABI_BAREMETAL) add_definitions(-DLIBCXXABI_BAREMETAL) endif() @@ -470,6 +525,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 #=============================================================================== diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake deleted file mode 100644 index 1f95327..0000000 --- a/cmake/Modules/HandleCompilerRT.cmake +++ /dev/null @@ -1,64 +0,0 @@ -function(find_compiler_rt_library name dest) - if (NOT DEFINED LIBCXXABI_COMPILE_FLAGS) - message(FATAL_ERROR "LIBCXXABI_COMPILE_FLAGS must be defined when using this function") - endif() - set(dest "" PARENT_SCOPE) - set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} - "--rtlib=compiler-rt" "--print-libgcc-file-name") - if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) - list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") - endif() - get_property(LIBCXXABI_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) - string(REPLACE " " ";" LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}") - list(APPEND CLANG_COMMAND ${LIBCXXABI_CXX_FLAGS}) - execute_process( - COMMAND ${CLANG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LIBRARY_FILE - ) - string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) - file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) - string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") - if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") - message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") - set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) - else() - message(STATUS "Failed to find compiler-rt library") - endif() -endfunction() - -function(find_compiler_rt_dir dest) - if (NOT DEFINED LIBCXXABI_COMPILE_FLAGS) - message(FATAL_ERROR "LIBCXXABI_COMPILE_FLAGS must be defined when using this function") - endif() - set(dest "" PARENT_SCOPE) - if (APPLE) - set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} - "-print-file-name=lib") - execute_process( - COMMAND ${CLANG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LIBRARY_DIR - ) - string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) - file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) - set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") - else() - set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} - "--rtlib=compiler-rt" "--print-libgcc-file-name") - execute_process( - COMMAND ${CLANG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LIBRARY_FILE - ) - string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) - file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) - get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) - endif() - if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}") - message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}") - set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE) - else() - message(STATUS "Failed to find compiler-rt directory") - endif() -endfunction() diff --git a/cmake/Modules/HandleLibcxxabiFlags.cmake b/cmake/Modules/HandleLibcxxabiFlags.cmake index 19d6e93..512e71a 100644 --- a/cmake/Modules/HandleLibcxxabiFlags.cmake +++ b/cmake/Modules/HandleLibcxxabiFlags.cmake @@ -123,6 +123,17 @@ macro(add_target_flags_if condition) endif() endmacro() +# Add all the flags supported by the compiler to all of +# 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXXABI_COMPILE_FLAGS' +# and 'LIBCXXABI_LINK_FLAGS'. +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}) + endforeach() +endmacro() + # Add a specified list of flags to both 'LIBCXXABI_COMPILE_FLAGS' and # 'LIBCXXABI_LINK_FLAGS'. macro(add_flags) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 15b5208..efc572e 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -14,22 +14,33 @@ if (NOT LIBCXXABI_USE_COMPILER_RT) endif () endif () -# libc++abi is built with -nodefaultlibs, so we want all our checks to also -# use this option, otherwise we may end up with an inconsistency between +# libc++abi is using -nostdlib++ at the link step when available, +# otherwise -nodefaultlibs is used. We want all our checks to also +# use one of these options, otherwise we may end up with an inconsistency between # the flags we think we require during configuration (if the checks are # performed without -nodefaultlibs) and the flags that are actually # required during compilation (which has the -nodefaultlibs). libc is # required for the link to go through. We remove sanitizers from the # configuration checks to avoid spurious link errors. -check_c_compiler_flag(-nodefaultlibs LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) -if (LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + +check_c_compiler_flag(-nostdlib++ LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG) +if (LIBCXXABI_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) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + endif() +endif() + +if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG OR LIBCXXABI_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) + include(HandleCompilerRT) + find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY + FLAGS "${LIBCXXABI_COMPILE_FLAGS}") list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") else () if (LIBCXXABI_HAS_GCC_S_LIB) @@ -56,7 +67,7 @@ if (LIBCXXABI_HAS_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 () diff --git a/include/__cxxabi_config.h b/include/__cxxabi_config.h index cffedb8..7bc39ad 100644 --- a/include/__cxxabi_config.h +++ b/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. @@ -93,7 +93,7 @@ # 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 diff --git a/include/cxxabi.h b/include/cxxabi.h index 43ce6f5..eaa324d 100644 --- a/include/cxxabi.h +++ b/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. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8e12aa..762649a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,7 +36,8 @@ else() ) endif() -if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)) +if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN) + AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX")) list(APPEND LIBCXXABI_SOURCES cxa_thread_atexit.cpp ) @@ -55,7 +56,8 @@ if (MSVC_IDE OR XCODE) endif() endif() -include_directories("${LIBCXXABI_LIBCXX_INCLUDES}") +# 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) @@ -75,6 +77,11 @@ 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. @@ -109,7 +116,11 @@ if (NOT LIBCXXABI_USE_COMPILER_RT) endif () # Setup flags. -add_link_flags_if_supported(-nodefaultlibs) +if (LIBCXXABI_SUPPORTS_NOSTDLIBXX_FLAG) + add_link_flags_if_supported(-nostdlib++) +else() + add_link_flags_if_supported(-nodefaultlibs) +endif() if ( APPLE ) if (LLVM_USE_SANITIZER) @@ -125,7 +136,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() @@ -165,34 +177,22 @@ endif() # Build the shared library. if (LIBCXXABI_ENABLE_SHARED) add_library(cxxabi_shared SHARED ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - target_link_libraries(cxxabi_shared PRIVATE ${LIBCXXABI_SHARED_LIBRARIES} ${LIBCXXABI_LIBRARIES}) + 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) endif() 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" - SOVERSION - "1" - VERSION - "${LIBCXXABI_LIBRARY_VERSION}" - DEFINE_SYMBOL - "") - - if(LIBCXXABI_ENABLE_PIC) - set_target_properties(cxxabi_shared PROPERTIES POSITION_INDEPENDENT_CODE ON) - endif() + 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" + SOVERSION "1" + VERSION "${LIBCXXABI_LIBRARY_VERSION}" + DEFINE_SYMBOL "" + ) list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_shared") if (LIBCXXABI_INSTALL_SHARED_LIBRARY) @@ -232,28 +232,19 @@ endif() # Build the static library. if (LIBCXXABI_ENABLE_STATIC) add_library(cxxabi_static STATIC ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - target_link_libraries(cxxabi_static PRIVATE ${LIBCXXABI_STATIC_LIBRARIES} ${LIBCXXABI_LIBRARIES}) + 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) 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") - - if(LIBCXXABI_ENABLE_PIC) - set_target_properties(cxxabi_static PROPERTIES POSITION_INDEPENDENT_CODE ON) - endif() + 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" + ) if(LIBCXXABI_HERMETIC_STATIC_LIBRARY) append_flags_if_supported(CXXABI_STATIC_LIBRARY_FLAGS -fvisibility=hidden) @@ -290,6 +281,7 @@ if (LIBCXXABI_ENABLE_STATIC) "$" "$" WORKING_DIRECTORY ${LIBCXXABI_BUILD_DIR} + DEPENDS unwind_static ) endif() endif() @@ -299,8 +291,9 @@ add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS}) if (LIBCXXABI_INSTALL_LIBRARY) install(TARGETS ${LIBCXXABI_INSTALL_TARGETS} - LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}${LIBCXXABI_INSTALL_LIBRARY_DIR} COMPONENT cxxabi - ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}${LIBCXXABI_INSTALL_LIBRARY_DIR} COMPONENT cxxabi + 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() diff --git a/src/abort_message.cpp b/src/abort_message.cpp index ad44063..859a503 100644 --- a/src/abort_message.cpp +++ b/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/src/abort_message.h b/src/abort_message.h index 83f956f..f1d5c12 100644 --- a/src/abort_message.h +++ b/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/src/cxa_aux_runtime.cpp b/src/cxa_aux_runtime.cpp index 0ed1a72..a42990c 100644 --- a/src/cxa_aux_runtime.cpp +++ b/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/src/cxa_default_handlers.cpp b/src/cxa_default_handlers.cpp index d2f823d..e0ccbe1 100644 --- a/src/cxa_default_handlers.cpp +++ b/src/cxa_default_handlers.cpp @@ -1,11 +1,12 @@ -//===------------------------- 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 @@ -15,7 +16,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++ #if !defined(LIBCXXABI_SILENT_TERMINATE) @@ -45,6 +46,7 @@ static void demangling_terminate_handler() 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]; @@ -52,6 +54,9 @@ static void demangling_terminate_handler() 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)); @@ -100,11 +105,14 @@ _LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_ter _LIBCXXABI_DATA_VIS _LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; +_LIBCXXABI_DATA_VIS +_LIBCPP_SAFE_STATIC std::new_handler __cxa_new_handler = 0; + namespace std { unexpected_handler -set_unexpected(unexpected_handler func) _NOEXCEPT +set_unexpected(unexpected_handler func) noexcept { if (func == 0) func = default_unexpected_handler; @@ -113,7 +121,7 @@ set_unexpected(unexpected_handler func) _NOEXCEPT } terminate_handler -set_terminate(terminate_handler func) _NOEXCEPT +set_terminate(terminate_handler func) noexcept { if (func == 0) func = default_terminate_handler; @@ -121,4 +129,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/src/cxa_demangle.cpp b/src/cxa_demangle.cpp index 3045f6e..bee4cfd 100644 --- a/src/cxa_demangle.cpp +++ b/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. @@ -342,21 +342,21 @@ __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; + OutputBuffer O; Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) + else if (!initializeOutputBuffer(Buf, N, O, 1024)) InternalStatus = demangle_memory_alloc_failure; else { 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/src/cxa_exception.cpp b/src/cxa_exception.cpp index ebb05ce..36388d5 100644 --- a/src/cxa_exception.cpp +++ b/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,10 +17,10 @@ #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) -extern "C" void __asan_handle_no_return(void); +#include #endif // +---------------------------+-----------------------------+---------------+ @@ -341,8 +341,10 @@ 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(). In addition, we are saving lr in order to +align the stack to 16 bytes and lr will be used to identify the caller and its +frame information. _Unwind_Resume never return and we need to keep the original +lr so just branch to it. */ __attribute__((used)) static _Unwind_Exception * __cxa_end_cleanup_impl() @@ -372,19 +374,25 @@ __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" - " push {r1, r2, r3, r4}\n" +#if defined(__ARM_FEATURE_BTI_DEFAULT) + " bti\n" +#endif + " push {r1, r2, r3, lr}\n" " bl __cxa_end_cleanup_impl\n" " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); -#endif // defined(_LIBCXXABI_ARM_EHABI) + " mov lr, r4\n" +#if defined(LIBCXXABI_BAREMETAL) + " ldr r4, =_Unwind_Resume\n" + " bx r4\n" +#else + " b _Unwind_Resume\n" +#endif + " .popsection"); +#endif // defined(_LIBCXXABI_ARM_EHABI) /* This routine can catch foreign or native exceptions. If native, the exception diff --git a/src/cxa_exception.h b/src/cxa_exception.h index 8c6c8bc..7a32fb6 100644 --- a/src/cxa_exception.h +++ b/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. @@ -161,4 +161,4 @@ extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * depen } // namespace __cxxabiv1 -#endif // _CXA_EXCEPTION_H +#endif // _CXA_EXCEPTION_H diff --git a/src/cxa_exception_storage.cpp b/src/cxa_exception_storage.cpp index 24ff55e..3a3233a 100644 --- a/src/cxa_exception_storage.cpp +++ b/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/src/cxa_guard.cpp b/src/cxa_guard.cpp index 5d1cf23..fc1fa90 100644 --- a/src/cxa_guard.cpp +++ b/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/src/cxa_guard_impl.h b/src/cxa_guard_impl.h index 6f873f2..5a7cbfd 100644 --- a/src/cxa_guard_impl.h +++ b/src/cxa_guard_impl.h @@ -23,9 +23,15 @@ * the thread currently performing initialization is stored in the second word. * * Guard Object Layout: - * ------------------------------------------------------------------------- - * |a: guard byte | a+1: init byte | a+2 : unused ... | a+4: thread-id ... | - * ------------------------------------------------------------------------ + * --------------------------------------------------------------------------- + * | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... | + * --------------------------------------------------------------------------- + * + * Note that we don't do what the ABI docs suggest (put a mutex in the guard + * object which we acquire in cxa_guard_acquire and release in + * cxa_guard_release). Instead we use the init byte to imitate that behaviour, + * but without actually holding anything mutex related between aquire and + * release/abort. * * Access Protocol: * For each implementation the guard byte is checked and set before accessing @@ -38,28 +44,31 @@ */ #include "__cxxabi_config.h" -#include "include/atomic_support.h" -#include +#include "include/atomic_support.h" // from libc++ #if defined(__has_include) -# if __has_include() -# include -# endif +# if __has_include() +# include +# endif +# if __has_include() +# include +# endif #endif +#include #include #include <__threading_support> #ifndef _LIBCXXABI_HAS_NO_THREADS -#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) -#pragma comment(lib, "pthread") -#endif +# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) +# pragma comment(lib, "pthread") +# endif #endif #if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtautological-pointer-compare" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wtautological-pointer-compare" #elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Waddress" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Waddress" #endif // To make testing possible, this header is included from both cxa_guard.cpp @@ -74,20 +83,20 @@ // defined when including this file. Only `src/cxa_guard.cpp` should define // the former. #ifdef BUILDING_CXA_GUARD -# include "abort_message.h" -# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__) +# include "abort_message.h" +# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__) #elif defined(TESTING_CXA_GUARD) -# define ABORT_WITH_MESSAGE(...) ::abort() +# define ABORT_WITH_MESSAGE(...) ::abort() #else -# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined" +# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined" #endif #if __has_feature(thread_sanitizer) extern "C" void __tsan_acquire(void*); extern "C" void __tsan_release(void*); #else -#define __tsan_acquire(addr) ((void)0) -#define __tsan_release(addr) ((void)0) +# define __tsan_acquire(addr) ((void)0) +# define __tsan_release(addr) ((void)0) #endif namespace __cxxabiv1 { @@ -99,7 +108,7 @@ namespace { // Misc Utilities //===----------------------------------------------------------------------===// -template +template struct LazyValue { LazyValue() : is_init(false) {} @@ -110,7 +119,8 @@ struct LazyValue { } return value; } - private: + +private: T value; bool is_init = false; }; @@ -120,25 +130,19 @@ class AtomicInt { public: using MemoryOrder = std::__libcpp_atomic_order; - explicit AtomicInt(IntType *b) : b_(b) {} + explicit AtomicInt(IntType* b) : b_(b) {} AtomicInt(AtomicInt const&) = delete; AtomicInt& operator=(AtomicInt const&) = delete; - IntType load(MemoryOrder ord) { - return std::__libcpp_atomic_load(b_, ord); - } - void store(IntType val, MemoryOrder ord) { - std::__libcpp_atomic_store(b_, val, ord); - } - IntType exchange(IntType new_val, MemoryOrder ord) { - return std::__libcpp_atomic_exchange(b_, new_val, ord); - } - bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) { + IntType load(MemoryOrder ord) { return std::__libcpp_atomic_load(b_, ord); } + void store(IntType val, MemoryOrder ord) { std::__libcpp_atomic_store(b_, val, ord); } + IntType exchange(IntType new_val, MemoryOrder ord) { return std::__libcpp_atomic_exchange(b_, new_val, ord); } + bool compare_exchange(IntType* expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) { return std::__libcpp_atomic_compare_exchange(b_, expected, desired, ord_success, ord_failure); } private: - IntType *b_; + IntType* b_; }; //===----------------------------------------------------------------------===// @@ -148,8 +152,7 @@ class AtomicInt { #if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) uint32_t PlatformThreadID() { static_assert(sizeof(mach_port_t) == sizeof(uint32_t), ""); - return static_cast( - pthread_mach_thread_np(std::__libcpp_thread_get_current_id())); + return static_cast(pthread_mach_thread_np(std::__libcpp_thread_get_current_id())); } #elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) uint32_t PlatformThreadID() { @@ -160,99 +163,108 @@ uint32_t PlatformThreadID() { constexpr uint32_t (*PlatformThreadID)() = nullptr; #endif - -constexpr bool PlatformSupportsThreadID() { - return +PlatformThreadID != nullptr; -} - //===----------------------------------------------------------------------===// -// GuardBase +// GuardByte //===----------------------------------------------------------------------===// -enum class AcquireResult { - INIT_IS_DONE, - INIT_IS_PENDING, -}; -constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE; -constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING; - static constexpr uint8_t UNSET = 0; static constexpr uint8_t COMPLETE_BIT = (1 << 0); static constexpr uint8_t PENDING_BIT = (1 << 1); static constexpr uint8_t WAITING_BIT = (1 << 2); -template -struct GuardObject { - GuardObject() = delete; - GuardObject(GuardObject const&) = delete; - GuardObject& operator=(GuardObject const&) = delete; +/// Manages reads and writes to the guard byte. +struct GuardByte { + GuardByte() = delete; + GuardByte(GuardByte const&) = delete; + GuardByte& operator=(GuardByte const&) = delete; - explicit GuardObject(uint32_t* g) - : base_address(g), guard_byte_address(reinterpret_cast(g)), - init_byte_address(reinterpret_cast(g) + 1), - thread_id_address(nullptr) {} - - explicit GuardObject(uint64_t* g) - : base_address(g), guard_byte_address(reinterpret_cast(g)), - init_byte_address(reinterpret_cast(g) + 1), - thread_id_address(reinterpret_cast(g) + 1) {} + explicit GuardByte(uint8_t* const guard_byte_address) : guard_byte(guard_byte_address) {} public: - /// Implements __cxa_guard_acquire - AcquireResult cxa_guard_acquire() { - AtomicInt guard_byte(guard_byte_address); - if (guard_byte.load(std::_AO_Acquire) != UNSET) - return INIT_IS_DONE; - return derived()->acquire_init_byte(); - } - - /// Implements __cxa_guard_release - void cxa_guard_release() { - AtomicInt guard_byte(guard_byte_address); - // Store complete first, so that when release wakes other folks, they see - // it as having been completed. - guard_byte.store(COMPLETE_BIT, std::_AO_Release); - derived()->release_init_byte(); + /// The guard byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { + // if guard_byte is non-zero, we have already completed initialization + // (i.e. release has been called) + return guard_byte.load(std::_AO_Acquire) != UNSET; } - /// Implements __cxa_guard_abort - void cxa_guard_abort() { derived()->abort_init_byte(); } + /// The guard byte portion of cxa_guard_release. + void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); } -public: - /// base_address - the address of the original guard object. - void* const base_address; - /// The address of the guard byte at offset 0. - uint8_t* const guard_byte_address; - /// The address of the byte used by the implementation during initialization. - uint8_t* const init_byte_address; - /// An optional address storing an identifier for the thread performing initialization. - /// It's used to detect recursive initialization. - uint32_t* const thread_id_address; + /// The guard byte portion of cxa_guard_abort. + void abort() {} // Nothing to do private: - Derived* derived() { return static_cast(this); } + AtomicInt guard_byte; }; +//===----------------------------------------------------------------------===// +// InitByte Implementations +//===----------------------------------------------------------------------===// +// +// Each initialization byte implementation supports the following methods: +// +// InitByte(uint8_t* _init_byte_address, uint32_t* _thread_id_address) +// Construct the InitByte object, initializing our member variables +// +// bool acquire() +// Called before we start the initialization. Check if someone else has already started, and if +// not to signal our intent to start it ourselves. We determine the current status from the init +// byte, which is one of 4 possible values: +// COMPLETE: Initialization was finished by somebody else. Return true. +// PENDING: Somebody has started the initialization already, set the WAITING bit, +// then wait for the init byte to get updated with a new value. +// (PENDING|WAITING): Somebody has started the initialization already, and we're not the +// first one waiting. Wait for the init byte to get updated. +// UNSET: Initialization hasn't successfully completed, and nobody is currently +// performing the initialization. Set the PENDING bit to indicate our +// intention to start the initialization, and return false. +// The return value indicates whether initialization has already been completed. +// +// void release() +// Called after successfully completing the initialization. Update the init byte to reflect +// that, then if anybody else is waiting, wake them up. +// +// void abort() +// Called after an error is thrown during the initialization. Reset the init byte to UNSET to +// indicate that we're no longer performing the initialization, then if anybody is waiting, wake +// them up so they can try performing the initialization. +// + //===----------------------------------------------------------------------===// // Single Threaded Implementation //===----------------------------------------------------------------------===// -struct InitByteNoThreads : GuardObject { - using GuardObject::GuardObject; +/// InitByteNoThreads - Doesn't use any inter-thread synchronization when +/// managing reads and writes to the init byte. +struct InitByteNoThreads { + InitByteNoThreads() = delete; + InitByteNoThreads(InitByteNoThreads const&) = delete; + InitByteNoThreads& operator=(InitByteNoThreads const&) = delete; - AcquireResult acquire_init_byte() { + explicit InitByteNoThreads(uint8_t* _init_byte_address, uint32_t*) : init_byte_address(_init_byte_address) {} + + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { if (*init_byte_address == COMPLETE_BIT) - return INIT_IS_DONE; + return true; if (*init_byte_address & PENDING_BIT) ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); *init_byte_address = PENDING_BIT; - return INIT_IS_PENDING; + return false; } - void release_init_byte() { *init_byte_address = COMPLETE_BIT; } - void abort_init_byte() { *init_byte_address = UNSET; } -}; + /// The init byte portion of cxa_guard_release. + void release() { *init_byte_address = COMPLETE_BIT; } + /// The init byte portion of cxa_guard_abort. + void abort() { *init_byte_address = UNSET; } +private: + /// The address of the byte used during initialization. + uint8_t* const init_byte_address; +}; //===----------------------------------------------------------------------===// // Global Mutex Implementation @@ -280,9 +292,7 @@ struct LibcppCondVar { LibcppCondVar(LibcppCondVar const&) = delete; LibcppCondVar& operator=(LibcppCondVar const&) = delete; - bool wait(LibcppMutex& mut) { - return std::__libcpp_condvar_wait(&cond, &mut.mutex); - } + bool wait(LibcppMutex& mut) { return std::__libcpp_condvar_wait(&cond, &mut.mutex); } bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); } private: @@ -293,28 +303,25 @@ struct LibcppMutex {}; struct LibcppCondVar {}; #endif // !defined(_LIBCXXABI_HAS_NO_THREADS) - +/// InitByteGlobalMutex - Uses a global mutex and condition variable (common to +/// all static local variables) to manage reads and writes to the init byte. template -struct InitByteGlobalMutex - : GuardObject> { - - using BaseT = typename InitByteGlobalMutex::GuardObject; - using BaseT::BaseT; +struct InitByteGlobalMutex { - explicit InitByteGlobalMutex(uint32_t *g) - : BaseT(g), has_thread_id_support(false) {} - explicit InitByteGlobalMutex(uint64_t *g) - : BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {} + explicit InitByteGlobalMutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address) + : init_byte_address(_init_byte_address), thread_id_address(_thread_id_address), + has_thread_id_support(_thread_id_address != nullptr && GetThreadID != nullptr) {} public: - AcquireResult acquire_init_byte() { + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { LockGuard g("__cxa_guard_acquire"); // Check for possible recursive initialization. if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) { if (*thread_id_address == current_thread_id.get()) - ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); } // Wait until the pending bit is not set. @@ -324,16 +331,17 @@ struct InitByteGlobalMutex } if (*init_byte_address == COMPLETE_BIT) - return INIT_IS_DONE; + return true; if (has_thread_id_support) *thread_id_address = current_thread_id.get(); *init_byte_address = PENDING_BIT; - return INIT_IS_PENDING; + return false; } - void release_init_byte() { + /// The init byte portion of cxa_guard_release. + void release() { bool has_waiting; { LockGuard g("__cxa_guard_release"); @@ -347,7 +355,8 @@ struct InitByteGlobalMutex } } - void abort_init_byte() { + /// The init byte portion of cxa_guard_abort. + void abort() { bool has_waiting; { LockGuard g("__cxa_guard_abort"); @@ -364,8 +373,12 @@ struct InitByteGlobalMutex } private: - using BaseT::init_byte_address; - using BaseT::thread_id_address; + /// The address of the byte used during initialization. + uint8_t* const init_byte_address; + /// An optional address storing an identifier for the thread performing initialization. + /// It's used to detect recursive initialization. + uint32_t* const thread_id_address; + const bool has_thread_id_support; LazyValue current_thread_id; @@ -375,8 +388,7 @@ struct InitByteGlobalMutex LockGuard(LockGuard const&) = delete; LockGuard& operator=(LockGuard const&) = delete; - explicit LockGuard(const char* calling_func) - : calling_func_(calling_func) { + explicit LockGuard(const char* calling_func) : calling_func_(calling_func) { if (global_mutex.lock()) ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func_); } @@ -411,50 +423,40 @@ constexpr void (*PlatformFutexWait)(int*, int) = nullptr; constexpr void (*PlatformFutexWake)(int*) = nullptr; #endif -constexpr bool PlatformSupportsFutex() { - return +PlatformFutexWait != nullptr; -} +constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; } -/// InitByteFutex - Manages initialization using atomics and the futex syscall -/// for waiting and waking. -template -struct InitByteFutex : GuardObject> { - using BaseT = typename InitByteFutex::GuardObject; - - /// ARM Constructor - explicit InitByteFutex(uint32_t *g) : BaseT(g), - init_byte(this->init_byte_address), - has_thread_id_support(this->thread_id_address && GetThreadIDArg), - thread_id(this->thread_id_address) {} +struct InitByteFutex { - /// Itanium Constructor - explicit InitByteFutex(uint64_t *g) : BaseT(g), - init_byte(this->init_byte_address), - has_thread_id_support(this->thread_id_address && GetThreadIDArg), - thread_id(this->thread_id_address) {} + explicit InitByteFutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address) + : init_byte(_init_byte_address), + has_thread_id_support(_thread_id_address != nullptr && GetThreadIDArg != nullptr), + thread_id(_thread_id_address), + base_address(reinterpret_cast(/*_init_byte_address & ~0x3*/ _init_byte_address - 1)) {} public: - AcquireResult acquire_init_byte() { + /// The init byte portion of cxa_guard_acquire. Returns true if + /// initialization has already been completed. + bool acquire() { while (true) { uint8_t last_val = UNSET; - if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, - std::_AO_Acquire)) { + if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, std::_AO_Acquire)) { if (has_thread_id_support) { thread_id.store(current_thread_id.get(), std::_AO_Relaxed); } - return INIT_IS_PENDING; + return false; } if (last_val == COMPLETE_BIT) - return INIT_IS_DONE; + return true; if (last_val & PENDING_BIT) { // Check for recursive initialization if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) { - ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); + ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization"); } if ((last_val & WAITING_BIT) == 0) { @@ -462,11 +464,10 @@ struct InitByteFutex : GuardObject> { // (1) another thread finished the whole thing before we got here // (2) another thread set the waiting bit we were trying to thread // (3) another thread had an exception and failed to finish - if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT, - std::_AO_Acq_Rel, std::_AO_Release)) { + if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT, std::_AO_Acq_Rel, std::_AO_Release)) { // (1) success, via someone else's work! if (last_val == COMPLETE_BIT) - return INIT_IS_DONE; + return true; // (3) someone else, bailed on doing the work, retry from the start! if (last_val == UNSET) @@ -480,30 +481,30 @@ struct InitByteFutex : GuardObject> { } } - void release_init_byte() { + /// The init byte portion of cxa_guard_release. + void release() { uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel); if (old & WAITING_BIT) wake_all(); } - void abort_init_byte() { + /// The init byte portion of cxa_guard_abort. + void abort() { if (has_thread_id_support) thread_id.store(0, std::_AO_Relaxed); - uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel); + uint8_t old = init_byte.exchange(UNSET, std::_AO_Acq_Rel); if (old & WAITING_BIT) wake_all(); } private: /// Use the futex to wait on the current guard variable. Futex expects a - /// 32-bit 4-byte aligned address as the first argument, so we have to use use - /// the base address of the guard variable (not the init byte). - void wait_on_initialization() { - Wait(static_cast(this->base_address), - expected_value_for_futex(PENDING_BIT | WAITING_BIT)); - } - void wake_all() { Wake(static_cast(this->base_address)); } + /// 32-bit 4-byte aligned address as the first argument, so we use the 4-byte + /// aligned address that encompasses the init byte (i.e. the address of the + /// raw guard object that was passed to __cxa_guard_acquire/release/abort). + void wait_on_initialization() { Wait(base_address, expected_value_for_futex(PENDING_BIT | WAITING_BIT)); } + void wake_all() { Wake(base_address); } private: AtomicInt init_byte; @@ -513,6 +514,10 @@ struct InitByteFutex : GuardObject> { AtomicInt thread_id; LazyValue current_thread_id; + /// the 4-byte-aligned address that encompasses the init byte (i.e. the + /// address of the raw guard object). + int* const base_address; + /// Create the expected integer value for futex `wait(int* addr, int expected)`. /// We pass the base address as the first argument, So this function creates /// an zero-initialized integer with `b` copied at the correct offset. @@ -525,6 +530,86 @@ struct InitByteFutex : GuardObject> { static_assert(Wait != nullptr && Wake != nullptr, ""); }; +//===----------------------------------------------------------------------===// +// GuardObject +//===----------------------------------------------------------------------===// + +enum class AcquireResult { + INIT_IS_DONE, + INIT_IS_PENDING, +}; +constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE; +constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING; + +/// Co-ordinates between GuardByte and InitByte. +template +struct GuardObject { + GuardObject() = delete; + GuardObject(GuardObject const&) = delete; + GuardObject& operator=(GuardObject const&) = delete; + +private: + GuardByte guard_byte; + InitByteT init_byte; + +public: + /// ARM Constructor + explicit GuardObject(uint32_t* raw_guard_object) + : guard_byte(reinterpret_cast(raw_guard_object)), + init_byte(reinterpret_cast(raw_guard_object) + 1, nullptr) {} + + /// Itanium Constructor + explicit GuardObject(uint64_t* raw_guard_object) + : guard_byte(reinterpret_cast(raw_guard_object)), + init_byte(reinterpret_cast(raw_guard_object) + 1, reinterpret_cast(raw_guard_object) + 1) { + } + + /// Implements __cxa_guard_acquire. + AcquireResult cxa_guard_acquire() { + // Use short-circuit evaluation to avoid calling init_byte.acquire when + // guard_byte.acquire returns true. (i.e. don't call it when we know from + // the guard byte that initialization has already been completed) + if (guard_byte.acquire() || init_byte.acquire()) + return INIT_IS_DONE; + return INIT_IS_PENDING; + } + + /// Implements __cxa_guard_release. + void cxa_guard_release() { + // Update guard byte first, so if somebody is woken up by init_byte.release + // and comes all the way back around to __cxa_guard_acquire again, they see + // it as having completed initialization. + guard_byte.release(); + init_byte.release(); + } + + /// Implements __cxa_guard_abort. + void cxa_guard_abort() { + guard_byte.abort(); + init_byte.abort(); + } +}; + +//===----------------------------------------------------------------------===// +// Convenience Classes +//===----------------------------------------------------------------------===// + +/// NoThreadsGuard - Manages initialization without performing any inter-thread +/// synchronization. +using NoThreadsGuard = GuardObject; + +/// GlobalMutexGuard - Manages initialization using a global mutex and +/// condition variable. +template +using GlobalMutexGuard = GuardObject>; + +/// FutexGuard - Manages initialization using atomics and the futex syscall for +/// waiting and waking. +template +using FutexGuard = GuardObject>; + //===----------------------------------------------------------------------===// // //===----------------------------------------------------------------------===// @@ -536,31 +621,25 @@ struct GlobalStatic { template _LIBCPP_SAFE_STATIC T GlobalStatic::instance = {}; -enum class Implementation { - NoThreads, - GlobalLock, - Futex -}; +enum class Implementation { NoThreads, GlobalMutex, Futex }; template struct SelectImplementation; template <> struct SelectImplementation { - using type = InitByteNoThreads; + using type = NoThreadsGuard; }; template <> -struct SelectImplementation { - using type = InitByteGlobalMutex< - LibcppMutex, LibcppCondVar, GlobalStatic::instance, - GlobalStatic::instance, PlatformThreadID>; +struct SelectImplementation { + using type = GlobalMutexGuard::instance, + GlobalStatic::instance, PlatformThreadID>; }; template <> struct SelectImplementation { - using type = - InitByteFutex; + using type = FutexGuard; }; // TODO(EricWF): We should prefer the futex implementation when available. But @@ -571,22 +650,21 @@ constexpr Implementation CurrentImplementation = #elif defined(_LIBCXXABI_USE_FUTEX) Implementation::Futex; #else - Implementation::GlobalLock; + Implementation::GlobalMutex; #endif -static_assert(CurrentImplementation != Implementation::Futex - || PlatformSupportsFutex(), "Futex selected but not supported"); +static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(), + "Futex selected but not supported"); -using SelectedImplementation = - SelectImplementation::type; +using SelectedImplementation = SelectImplementation::type; } // end namespace } // end namespace __cxxabiv1 #if defined(__clang__) -# pragma clang diagnostic pop +# pragma clang diagnostic pop #elif defined(__GNUC__) -# pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H diff --git a/src/cxa_handlers.cpp b/src/cxa_handlers.cpp index f520a4d..344250d 100644 --- a/src/cxa_handlers.cpp +++ b/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,13 +17,13 @@ #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 { unexpected_handler -get_unexpected() _NOEXCEPT +get_unexpected() noexcept { return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire); } @@ -44,18 +44,18 @@ unexpected() } terminate_handler -get_terminate() _NOEXCEPT +get_terminate() noexcept { return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire); } void -__terminate(terminate_handler func) _NOEXCEPT +__terminate(terminate_handler func) noexcept { #ifndef _LIBCXXABI_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS func(); // handler should not return abort_message("terminate_handler unexpectedly returned"); @@ -66,12 +66,12 @@ __terminate(terminate_handler func) _NOEXCEPT // handler should not throw exception abort_message("terminate_handler unexpectedly threw an exception"); } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS } __attribute__((noreturn)) void -terminate() _NOEXCEPT +terminate() noexcept { #ifndef _LIBCXXABI_NO_EXCEPTIONS // If there might be an uncaught exception @@ -92,18 +92,8 @@ 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 +get_new_handler() noexcept { return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire); } diff --git a/src/cxa_handlers.h b/src/cxa_handlers.h index a96d7e5..3d8dc6b 100644 --- a/src/cxa_handlers.h +++ b/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. @@ -25,7 +25,7 @@ __unexpected(unexpected_handler func); _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void -__terminate(terminate_handler func) _NOEXCEPT; +__terminate(terminate_handler func) noexcept; } // std @@ -52,4 +52,4 @@ _LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)(); } // extern "C" -#endif // _CXA_HANDLERS_H +#endif // _CXA_HANDLERS_H diff --git a/src/cxa_noexception.cpp b/src/cxa_noexception.cpp index 73e0b2a..4a803f7 100644 --- a/src/cxa_noexception.cpp +++ b/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/src/cxa_personality.cpp b/src/cxa_personality.cpp index 45639ec..f6e135f 100644 --- a/src/cxa_personality.cpp +++ b/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. @@ -88,7 +88,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_EXCEPTIONS__ +---------------------------------------------------------------------+ | Beginning of Action Table ttypeIndex == 0 : cleanup | | ... ttypeIndex > 0 : catch | @@ -241,10 +241,11 @@ readSLEB128(const uint8_t** data) /// @link http://dwarfstd.org/Dwarf3.pdf @unlink /// @param data reference variable holding memory pointer to decode from /// @param encoding dwarf encoding type +/// @param base for adding relative offset, default to 0 /// @returns decoded value static uintptr_t -readEncodedPointer(const uint8_t** data, uint8_t encoding) +readEncodedPointer(const uint8_t** data, uint8_t encoding, uintptr_t base = 0) { uintptr_t result = 0; if (encoding == DW_EH_PE_omit) @@ -295,8 +296,12 @@ readEncodedPointer(const uint8_t** data, uint8_t encoding) if (result) result += (uintptr_t)(*data); break; - case DW_EH_PE_textrel: case DW_EH_PE_datarel: + assert((base != 0) && "DW_EH_PE_datarel is invalid with a base of 0"); + if (result) + result += base; + break; + case DW_EH_PE_textrel: case DW_EH_PE_funcrel: case DW_EH_PE_aligned: default: @@ -348,7 +353,7 @@ static const void* read_target2_value(const void* ptr) static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) + _Unwind_Exception* unwind_exception, uintptr_t /*base*/ = 0) { if (classInfo == 0) { @@ -371,7 +376,7 @@ static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) + _Unwind_Exception* unwind_exception, uintptr_t base = 0) { if (classInfo == 0) { @@ -400,7 +405,8 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, call_terminate(native_exception, unwind_exception); } classInfo -= ttypeIndex; - return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); + return (const __shim_type_info*)readEncodedPointer(&classInfo, + ttypeEncoding, base); } #endif // !defined(_LIBCXXABI_ARM_EHABI) @@ -418,7 +424,8 @@ static bool exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) + void* adjustedPtr, _Unwind_Exception* unwind_exception, + uintptr_t /*base*/ = 0) { if (classInfo == 0) { @@ -463,7 +470,8 @@ static bool exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) + void* adjustedPtr, _Unwind_Exception* unwind_exception, + uintptr_t base = 0) { if (classInfo == 0) { @@ -485,7 +493,8 @@ exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, classInfo, ttypeEncoding, true, - unwind_exception); + unwind_exception, + base); void* tempPtr = adjustedPtr; if (catchType->can_catch(excpType, tempPtr)) return false; @@ -531,6 +540,9 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, { #if defined(__USING_SJLJ_EXCEPTIONS__) #define __builtin_eh_return_data_regno(regno) regno +#elif defined(__ibmxl__) +// IBM xlclang++ compiler does not support __builtin_eh_return_data_regno. +#define __builtin_eh_return_data_regno(regno) regno + 3 #endif _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), reinterpret_cast(unwind_exception)); @@ -610,6 +622,11 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, return; } results.languageSpecificData = lsda; +#if defined(_AIX) + uintptr_t base = _Unwind_GetDataRelBase(context); +#else + uintptr_t base = 0; +#endif // Get the current instruction pointer and offset it before next // instruction in the current frame which threw the exception. uintptr_t ip = _Unwind_GetIP(context) - 1; @@ -628,13 +645,14 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // ip is 1-based index into call site table #else // !__USING_SJLJ_EXCEPTIONS__ uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) +#endif // !defined(_USING_SLJL_EXCEPTIONS__) const uint8_t* classInfo = NULL; // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding // dwarf emission // Parse LSDA header. uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); + const uint8_t* lpStart = + (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); if (lpStart == 0) lpStart = (const uint8_t*)funcStart; uint8_t ttypeEncoding = *lsda++; @@ -673,7 +691,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, uintptr_t landingPad = readULEB128(&callSitePtr); uintptr_t actionEntry = readULEB128(&callSitePtr); if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_EXCEPTIONS__ { // Found the call site containing ip. #ifndef __USING_SJLJ_EXCEPTIONS__ @@ -686,25 +704,19 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, landingPad = (uintptr_t)lpStart + landingPad; #else // __USING_SJLJ_EXCEPTIONS__ ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_EXCEPTIONS__ + results.landingPad = landingPad; if (actionEntry == 0) { // Found a cleanup - // If this is a type 1 or type 2 search, there are no handlers - // If this is a type 3 search, you want to install the cleanup. - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - results.ttypeIndex = 0; // Redundant but clarifying - results.landingPad = landingPad; - results.reason = _URC_HANDLER_FOUND; - return; - } - // No handler here - results.reason = _URC_CONTINUE_UNWIND; + results.reason = actions & _UA_SEARCH_PHASE + ? _URC_CONTINUE_UNWIND + : _URC_HANDLER_FOUND; return; } // Convert 1-based byte offset into const uint8_t* action = actionTableStart + (actionEntry - 1); + bool hasCleanup = false; // Scan action entries until you find a matching handler, cleanup, or the end of action list while (true) { @@ -717,30 +729,21 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, const __shim_type_info* catchType = get_shim_type_info(static_cast(ttypeIndex), classInfo, ttypeEncoding, - native_exception, unwind_exception); + native_exception, unwind_exception, + base); if (catchType == 0) { - // Found catch (...) catches everything, including foreign exceptions - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 2 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } + // Found catch (...) catches everything, including + // foreign exceptions. This is search phase, cleanup + // phase with foreign exception, or forced unwinding. + assert(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME | + _UA_FORCE_UNWIND)); + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.adjustedPtr = + get_thrown_object_ptr(unwind_exception); + results.reason = _URC_HANDLER_FOUND; + return; } // Else this is a catch (T) clause and will never // catch a foreign exception @@ -757,36 +760,25 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, } if (catchType->can_catch(excpType, adjustedPtr)) { - // Found a matching handler - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } + // Found a matching handler. This is either search + // phase or forced unwinding. + assert(actions & + (_UA_SEARCH_PHASE | _UA_FORCE_UNWIND)); + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.adjustedPtr = adjustedPtr; + results.reason = _URC_HANDLER_FOUND; + return; } } // Scan next action ... } else if (ttypeIndex < 0) { - // Found an exception spec. If this is a foreign exception, - // it is always caught. - if (native_exception) - { + // Found an exception specification. + if (actions & _UA_FORCE_UNWIND) { + // Skip if forced unwinding. + } else if (native_exception) { // Does the exception spec catch this native exception? __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; void* adjustedPtr = get_thrown_object_ptr(unwind_exception); @@ -799,79 +791,41 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, } if (exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, excpType, - adjustedPtr, unwind_exception)) + adjustedPtr, + unwind_exception, base)) { - // native exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - } - else - { - // foreign exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 2 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND + // Native exception caught by exception + // specification. + assert(actions & _UA_SEARCH_PHASE); results.ttypeIndex = ttypeIndex; results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); + results.adjustedPtr = adjustedPtr; results.reason = _URC_HANDLER_FOUND; return; } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - // Scan next action ... - } - else // ttypeIndex == 0 - { - // Found a cleanup - // If this is a type 1 search, ignore it and continue scan - // If this is a type 2 search, ignore it and continue scan - // If this is a type 3 search, save state and return _URC_HANDLER_FOUND - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND + } else { + // foreign exception caught by exception spec results.ttypeIndex = ttypeIndex; results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); + results.adjustedPtr = + get_thrown_object_ptr(unwind_exception); results.reason = _URC_HANDLER_FOUND; return; } + // Scan next action ... + } else { + hasCleanup = true; } const uint8_t* temp = action; int64_t actionOffset = readSLEB128(&temp); if (actionOffset == 0) { - // End of action list, no matching handler or cleanup found - results.reason = _URC_CONTINUE_UNWIND; + // End of action list. If this is phase 2 and we have found + // a cleanup (ttypeIndex=0), return _URC_HANDLER_FOUND; + // otherwise return _URC_CONTINUE_UNWIND. + results.reason = hasCleanup && actions & _UA_CLEANUP_PHASE + ? _URC_HANDLER_FOUND + : _URC_CONTINUE_UNWIND; return; } // Go to next action @@ -886,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Possible stack corruption. call_terminate(native_exception, unwind_exception); } -#endif // !__USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_EXCEPTIONS__ } // there might be some tricky cases which break out of this loop // It is possible that no eh table entry specify how to handle @@ -977,6 +931,15 @@ __gxx_personality_v0 // Jump to the handler. set_registers(unwind_exception, context, results); + // Cache base for calculating the address of ttype in + // __cxa_call_unexpected. + if (results.ttypeIndex < 0) { +#if defined(_AIX) + exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context); +#else + exception_header->catchTemp = 0; +#endif + } return _URC_INSTALL_CONTEXT; } @@ -1006,6 +969,16 @@ __gxx_personality_v0 assert(actions & _UA_CLEANUP_PHASE); assert(results.reason == _URC_HANDLER_FOUND); set_registers(unwind_exception, context, results); + // Cache base for calculating the address of ttype in __cxa_call_unexpected. + if (results.ttypeIndex < 0) { + __cxa_exception* exception_header = + (__cxa_exception*)(unwind_exception + 1) - 1; +#if defined(_AIX) + exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context); +#else + exception_header->catchTemp = 0; +#endif + } return _URC_INSTALL_CONTEXT; } @@ -1031,9 +1004,14 @@ 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 @@ -1136,7 +1114,14 @@ __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. // 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 @@ -1180,6 +1165,8 @@ __cxa_call_unexpected(void* arg) __cxa_exception* old_exception_header = 0; int64_t ttypeIndex; const uint8_t* lsda; + uintptr_t base = 0; + if (native_old_exception) { old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; @@ -1193,6 +1180,7 @@ __cxa_call_unexpected(void* arg) #else ttypeIndex = old_exception_header->handlerSwitchValue; lsda = old_exception_header->languageSpecificData; + base = (uintptr_t)old_exception_header->catchTemp; #endif } else @@ -1216,11 +1204,13 @@ __cxa_call_unexpected(void* arg) // Have: // old_exception_header->languageSpecificData // old_exception_header->actionRecord + // old_exception_header->catchTemp, base for calculating ttype // Need // const uint8_t* classInfo // uint8_t ttypeEncoding uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); + const uint8_t* lpStart = + (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); (void)lpStart; // purposefully unused. Just needed to increment lsda. uint8_t ttypeEncoding = *lsda++; if (ttypeEncoding == DW_EH_PE_omit) @@ -1247,7 +1237,8 @@ __cxa_call_unexpected(void* arg) ((__cxa_dependent_exception*)new_exception_header)->primaryException : new_exception_header + 1; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) + excpType, adjustedPtr, + unwind_exception, base)) { // We need to __cxa_end_catch, but for the old exception, // not the new one. This is a little tricky ... @@ -1276,7 +1267,8 @@ __cxa_call_unexpected(void* arg) std::bad_exception be; adjustedPtr = &be; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) + excpType, adjustedPtr, + unwind_exception, base)) { // We need to __cxa_end_catch for both the old exception and the // new exception. Technically we should do it in that order. @@ -1292,6 +1284,15 @@ __cxa_call_unexpected(void* arg) std::__terminate(t_handler); } +#if defined(_AIX) +// Personality routine for EH using the range table. Make it an alias of +// __gxx_personality_v0(). +_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1( + int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception* unwind_exception, _Unwind_Context* context) + __attribute__((__alias__("__gxx_personality_v0"))); +#endif + } // extern "C" } // __cxxabiv1 diff --git a/src/cxa_thread_atexit.cpp b/src/cxa_thread_atexit.cpp index eb64d41..665f9e5 100644 --- a/src/cxa_thread_atexit.cpp +++ b/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. @@ -6,14 +6,6 @@ // //===----------------------------------------------------------------------===// -/** This file was edited for ClickHouse. - * This is needed to avoid linking with "__cxa_thread_atexit_impl" function, that require too new (2.18) glibc library. - * - * Note: "__cxa_thread_atexit_impl" may provide sophisticated implementation to correct destruction of thread-local objects, - * that was created in different DSO. Read https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables - * We simply don't need this implementation, because we don't use thread-local objects from different DSO. - */ - #include "abort_message.h" #include "cxxabi.h" #include <__threading_support> @@ -29,6 +21,15 @@ namespace __cxxabiv1 { using Dtor = void(*)(void*); + extern "C" +#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL + // A weak symbol is used to detect this function's presence in the C library + // at runtime, even if libc++ is built against an older libc + _LIBCXXABI_WEAK +#endif + int __cxa_thread_atexit_impl(Dtor, void*, void*); + +#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL namespace { // This implementation is used if the C library does not provide @@ -103,10 +104,17 @@ namespace { }; } // namespace +#endif // HAVE___CXA_THREAD_ATEXIT_IMPL extern "C" { - _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit_impl(Dtor dtor, void* obj, void* dso_symbol) throw() { + _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() { +#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL + return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); +#else + if (__cxa_thread_atexit_impl) { + return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); + } else { // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for // one-time initialization and __cxa_atexit() for destruction) static DtorsManager manager; @@ -129,11 +137,8 @@ extern "C" { dtors = head; return 0; - } - - int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() - { - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); + } +#endif // HAVE___CXA_THREAD_ATEXIT_IMPL } } // extern "C" diff --git a/src/cxa_vector.cpp b/src/cxa_vector.cpp index 325bbf2..099f9f0 100644 --- a/src/cxa_vector.cpp +++ b/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/src/cxa_virtual.cpp b/src/cxa_virtual.cpp index 9214c1f..c868672 100644 --- a/src/cxa_virtual.cpp +++ b/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/src/demangle/ItaniumDemangle.h b/src/demangle/ItaniumDemangle.h index 6bfc02d..db65c60 100644 --- a/src/demangle/ItaniumDemangle.h +++ b/src/demangle/ItaniumDemangle.h @@ -6,8 +6,10 @@ // //===----------------------------------------------------------------------===// // -// 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. // //===----------------------------------------------------------------------===// @@ -21,12 +23,13 @@ #include "DemangleConfig.h" #include "StringView.h" #include "Utility.h" +#include #include #include #include #include #include -#include +#include #include #define FOR_EACH_NODE_KIND(X) \ @@ -57,6 +60,7 @@ X(LocalName) \ X(VectorType) \ X(PixelVectorType) \ + X(BinaryFPType) \ X(SyntheticTemplateParamName) \ X(TypeTemplateParamDecl) \ X(NonTypeTemplateParamDecl) \ @@ -96,7 +100,6 @@ X(InitListExpr) \ X(FoldExpr) \ X(ThrowExpr) \ - X(UUIDOfExpr) \ X(BoolExpr) \ X(StringLiteral) \ X(LambdaExpr) \ @@ -110,6 +113,126 @@ 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 { @@ -156,50 +279,48 @@ class Node { // would construct an equivalent node. //template void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } + virtual bool hasArraySlow(OutputBuffer &) const { return false; } + virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } + virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } - void print(OutputStream &S) const { - printLeft(S); + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // Print the "left" side of this Node into OutputBuffer. + virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. - virtual void printRight(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -228,19 +349,19 @@ class NodeArray { Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + OB += ", "; + size_t AfterComma = OB.getCurrentPosition(); + Elements[Idx]->print(OB); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -255,9 +376,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 { @@ -270,28 +389,31 @@ class DotSuffix final : public Node { template void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + void printLeft(OutputBuffer &OB) const override { + Prefix->print(OB); + OB += " ("; + OB += Suffix; + OB += ")"; } }; class VendorExtQualType final : public Node { const Node *Ty; StringView Ext; + const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - template void match(Fn F) const { F(Ty, Ext); } + template void match(Fn F) const { F(Ty, Ext, TA); } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += " "; + OB += Ext; + if (TA != nullptr) + TA->print(OB); } }; @@ -317,13 +439,13 @@ class QualType final : public Node { const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -334,22 +456,22 @@ class QualType final : public Node { template void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -361,9 +483,9 @@ class ConversionOperatorType final : public Node { template void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; @@ -377,9 +499,9 @@ class PostfixQualifiedType final : public Node { template void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; @@ -394,7 +516,7 @@ class NameType final : public Node { StringView getName() const { return Name; } StringView getBaseName() const override { return Name; } - void printLeft(OutputStream &s) const override { s += Name; } + void printLeft(OutputBuffer &OB) const override { OB += Name; } }; class ElaboratedTypeSpefType : public Node { @@ -406,10 +528,10 @@ class ElaboratedTypeSpefType : public Node { template void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; @@ -424,11 +546,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 += "]"; } }; @@ -440,10 +562,10 @@ class EnableIfAttr : public Node { template void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; @@ -464,11 +586,11 @@ class ObjCProtoName : public Node { static_cast(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -482,34 +604,34 @@ class PointerType final : public Node { template void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object* into id. if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -529,15 +651,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; } @@ -549,31 +686,35 @@ class ReferenceType : public Node { template void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + Collapsed.second->printLeft(OB); + if (Collapsed.second->hasArray(OB)) + OB += " "; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - std::pair Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + std::pair Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -588,24 +729,24 @@ class PointerToMemberType final : public Node { template void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; + OB += " "; + ClassType->print(OB); + OB += "::*"; } - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; @@ -622,19 +763,19 @@ class ArrayType final : public Node { template void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; if (Dimension) - Dimension->print(S); - S += "]"; - Base->printRight(S); + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -658,8 +799,8 @@ class FunctionType final : public Node { F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: @@ -668,32 +809,32 @@ class FunctionType final : public Node { // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -705,10 +846,10 @@ class NoexceptSpec : public Node { template void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept("; + E->print(OB); + OB += ")"; } }; @@ -720,10 +861,10 @@ class DynamicExceptionSpec : public Node { template void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw("; + Types.printWithComma(OB); + OB += ')'; } }; @@ -754,41 +895,41 @@ class FunctionEncoding final : public Node { NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB += "("; + Params.printWithComma(OB); + OB += ")"; if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -801,9 +942,9 @@ class LiteralOperator : public Node { template void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; @@ -817,9 +958,9 @@ class SpecialName final : public Node { template void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -834,11 +975,11 @@ class CtorVtableSpecialName final : public Node { template void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -853,10 +994,10 @@ 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); } }; @@ -869,10 +1010,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); } }; @@ -889,10 +1030,10 @@ class QualifiedName final : public Node { StringView getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; @@ -907,12 +1048,12 @@ class VectorType final : public Node { template void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; if (Dimension) - Dimension->print(S); - S += "]"; + Dimension->print(OB); + OB += "]"; } }; @@ -925,11 +1066,26 @@ class PixelVectorType final : public Node { template void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - Dimension->print(S); - S += "]"; + OB += "pixel vector["; + Dimension->print(OB); + OB += "]"; + } +}; + +class BinaryFPType final : public Node { + const Node *Dimension; + +public: + BinaryFPType(const Node *Dimension_) + : Node(KBinaryFPType), Dimension(Dimension_) {} + + template void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -951,20 +1107,20 @@ class SyntheticTemplateParamName final : public Node { template void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -978,13 +1134,9 @@ class TypeTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -998,15 +1150,15 @@ class NonTypeTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1023,15 +1175,13 @@ class TemplateTemplateParamDecl final : public Node { template void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1044,14 +1194,12 @@ class TemplateParamPackDecl final : public Node { template void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1065,11 +1213,12 @@ class TemplateParamPackDecl final : public Node { class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits::max()) { - S.CurrentPackMax = static_cast(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits::max()) { + OB.CurrentPackMax = static_cast(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1092,38 +1241,38 @@ class ParameterPack final : public Node { template void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + const Node *getSyntaxNode(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1142,8 +1291,8 @@ class TemplateArgumentPack final : public Node { NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1160,35 +1309,35 @@ class ParameterPackExpansion final : public Node { const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits::max(); - SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + SwapAndRestore SavePackIdx(OB.CurrentPackIndex, Max); + SwapAndRestore SavePackMax(OB.CurrentPackMax, Max); + size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. - Child->print(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a . - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1203,12 +1352,12 @@ class TemplateArgs final : public Node { NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + OB += "<"; + Params.printWithComma(OB); + if (OB.back() == '>') + OB += " "; + OB += ">"; } }; @@ -1250,42 +1399,42 @@ struct ForwardTemplateReference : Node { // special handling. template void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasArray(S); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; SwapAndRestore SavePrinting(Printing, true); - return Ref->hasFunction(S); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; SwapAndRestore SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printLeft(S); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; SwapAndRestore SavePrinting(Printing, true); - Ref->printRight(S); + Ref->printRight(OB); } }; @@ -1301,9 +1450,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); } }; @@ -1318,9 +1467,9 @@ class GlobalQualifiedName final : public Node { StringView getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1333,9 +1482,9 @@ struct StdQualifiedName : Node { 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 += "std::"; + Child->print(OB); } }; @@ -1375,26 +1524,26 @@ class ExpandedSpecialSubstitution final : public Node { DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::basic_string, " - "std::allocator >"; + OB += "std::basic_string, " + "std::allocator >"; break; case SpecialSubKind::istream: - S += "std::basic_istream >"; + OB += "std::basic_istream >"; break; case SpecialSubKind::ostream: - S += "std::basic_ostream >"; + OB += "std::basic_ostream >"; break; case SpecialSubKind::iostream: - S += "std::basic_iostream >"; + OB += "std::basic_iostream >"; break; } } @@ -1427,25 +1576,25 @@ class SpecialSubstitution final : public Node { DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (SSK) { case SpecialSubKind::allocator: - S += "std::allocator"; + OB += "std::allocator"; break; case SpecialSubKind::basic_string: - S += "std::basic_string"; + OB += "std::basic_string"; break; case SpecialSubKind::string: - S += "std::string"; + OB += "std::string"; break; case SpecialSubKind::istream: - S += "std::istream"; + OB += "std::istream"; break; case SpecialSubKind::ostream: - S += "std::ostream"; + OB += "std::ostream"; break; case SpecialSubKind::iostream: - S += "std::iostream"; + OB += "std::iostream"; break; } } @@ -1463,10 +1612,10 @@ class CtorDtorName final : public Node { template void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1478,9 +1627,9 @@ class DtorName : public Node { template void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; @@ -1492,10 +1641,10 @@ class UnnamedTypeName : public Node { template void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; @@ -1514,22 +1663,22 @@ class ClosureTypeName : public Node { F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB += "("; + Params.printWithComma(OB); + OB += ")"; } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1541,10 +1690,10 @@ class StructuredBindingName : public Node { template void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + Bindings.printWithComma(OB); + OB += ']'; } }; @@ -1562,22 +1711,22 @@ class BinaryExpr : public Node { template void match(Fn F) const { F(LHS, InfixOperator, RHS); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // might be a template argument expression, then we need to disambiguate // with parens. if (InfixOperator == ">") - S += "("; + OB += "("; - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; + OB += "("; + LHS->print(OB); + OB += ") "; + OB += InfixOperator; + OB += " ("; + RHS->print(OB); + OB += ")"; if (InfixOperator == ">") - S += ")"; + OB += ")"; } }; @@ -1591,12 +1740,12 @@ class ArraySubscriptExpr : public Node { template void match(Fn F) const { F(Op1, Op2); } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Op1->print(OB); + OB += ")["; + Op2->print(OB); + OB += "]"; } }; @@ -1610,11 +1759,11 @@ class PostfixExpr : public Node { template void match(Fn F) const { F(Child, Operator); } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Child->print(OB); + OB += ")"; + OB += Operator; } }; @@ -1629,14 +1778,14 @@ class ConditionalExpr : public Node { template void match(Fn F) const { F(Cond, Then, Else); } - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Cond->print(OB); + OB += ") ? ("; + Then->print(OB); + OB += ") : ("; + Else->print(OB); + OB += ")"; } }; @@ -1651,10 +1800,10 @@ class MemberExpr : public Node { template void match(Fn F) const { F(LHS, Kind, RHS); } - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + void printLeft(OutputBuffer &OB) const override { + LHS->print(OB); + OB += Kind; + RHS->print(OB); } }; @@ -1675,20 +1824,20 @@ class SubobjectExpr : public Node { F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); } - void printLeft(OutputStream &S) const override { - SubExpr->print(S); - S += ".<"; - Type->print(S); - S += " at offset "; + void printLeft(OutputBuffer &OB) const override { + SubExpr->print(OB); + OB += ".<"; + Type->print(OB); + OB += " at offset "; if (Offset.empty()) { - S += "0"; + OB += "0"; } else if (Offset[0] == 'n') { - S += "-"; - S += Offset.dropFront(); + OB += "-"; + OB += Offset.dropFront(); } else { - S += Offset; + OB += Offset; } - S += ">"; + OB += ">"; } }; @@ -1704,10 +1853,10 @@ class EnclosingExpr : public Node { template void match(Fn F) const { F(Prefix, Infix, Postfix); } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Infix->print(OB); + OB += Postfix; } }; @@ -1723,13 +1872,13 @@ class CastExpr : public Node { template void match(Fn F) const { F(CastKind, To, From); } - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + OB += "<"; + To->printLeft(OB); + OB += ">("; + From->printLeft(OB); + OB += ")"; } }; @@ -1742,11 +1891,11 @@ class SizeofParamPackExpr : public Node { template void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof...("; ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB += ")"; } }; @@ -1760,11 +1909,11 @@ class CallExpr : public Node { template void match(Fn F) const { F(Callee, Args); } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB += "("; + Args.printWithComma(OB); + OB += ")"; } }; @@ -1785,25 +1934,24 @@ class NewExpr : public Node { F(ExprList, Type, InitList, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::operator "; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; + OB += ' '; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB += "("; + ExprList.printWithComma(OB); + OB += ")"; } - Type->print(S); + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB += "("; + InitList.printWithComma(OB); + OB += ")"; } - } }; @@ -1818,13 +1966,13 @@ class DeleteExpr : public Node { template void match(Fn F) const { F(Op, IsGlobal, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[] "; + Op->print(OB); } }; @@ -1838,11 +1986,11 @@ class PrefixExpr : public Node { template void match(Fn F) const { F(Prefix, Child); } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB += "("; + Child->print(OB); + OB += ")"; } }; @@ -1854,9 +2002,9 @@ class FunctionParam : public Node { template void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1870,12 +2018,12 @@ class ConversionExpr : public Node { template void match(Fn F) const { F(Type, Expressions); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + Expressions.printWithComma(OB); + OB += ")"; } }; @@ -1892,12 +2040,12 @@ class PointerToMemberConversionExpr : public Node { template void match(Fn F) const { F(Type, SubExpr, Offset); } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - SubExpr->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "("; + Type->print(OB); + OB += ")("; + SubExpr->print(OB); + OB += ")"; } }; @@ -1910,12 +2058,12 @@ class InitListExpr : public Node { template void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1929,18 +2077,18 @@ class BracedExpr : public Node { template void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1954,15 +2102,15 @@ class BracedRangeExpr : public Node { template void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1981,43 +2129,43 @@ class FoldExpr : public Node { F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB += '('; + ParameterPackExpansion(Pack).print(OB); + OB += ')'; }; - S += '('; + OB += '('; if (IsLeftFold) { // init op ... op pack if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; + Init->print(OB); + OB += ' '; + OB += OperatorName; + OB += ' '; } // ... op pack - S += "... "; - S += OperatorName; - S += ' '; + OB += "... "; + OB += OperatorName; + OB += ' '; PrintPack(); } else { // !IsLeftFold // pack op ... PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; + OB += ' '; + OB += OperatorName; + OB += " ..."; // pack op ... op init if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); + OB += ' '; + OB += OperatorName; + OB += ' '; + Init->print(OB); } } - S += ')'; + OB += ')'; } }; @@ -2029,24 +2177,9 @@ class ThrowExpr : public Node { template void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -// MSVC __uuidof extension, generated by clang in -fms-extensions mode. -class UUIDOfExpr : public Node { - Node *Operand; -public: - UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {} - - template void match(Fn F) const { F(Operand); } - - void printLeft(OutputStream &S) const override { - S << "__uuidof("; - Operand->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2058,8 +2191,8 @@ class BoolExpr : public Node { template void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? StringView("true") : StringView("false"); } }; @@ -2071,10 +2204,10 @@ class StringLiteral : public Node { template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2086,11 +2219,11 @@ class LambdaExpr : public Node { template void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast(Type)->printDeclarator(S); - S += "{...}"; + static_cast(Type)->printDeclarator(OB); + OB += "{...}"; } }; @@ -2105,15 +2238,15 @@ class EnumLiteral : public Node { template void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S << "("; - Ty->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB << "("; + Ty->print(OB); + OB << ")"; if (Integer[0] == 'n') - S << "-" << Integer.dropFront(1); + OB << "-" << Integer.dropFront(1); else - S << Integer; + OB << Integer; } }; @@ -2127,21 +2260,21 @@ class IntegerLiteral : public Node { template void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB += "("; + OB += Type; + OB += ")"; } if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); + OB += "-"; + OB += Value.dropFront(1); } else - S += Value; + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2171,7 +2304,7 @@ template class FloatLiteralImpl : public Node { template void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { const char *first = Contents.begin(); const char *last = Contents.end() + 1; @@ -2197,7 +2330,7 @@ template class FloatLiteralImpl : public Node { #endif char num[FloatData::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData::spec, value); - s += StringView(num, num + n); + OB += StringView(num, num + n); } } }; @@ -2230,125 +2363,6 @@ FOR_EACH_NODE_KIND(SPECIALIZATION) #undef FOR_EACH_NODE_KIND -template -class PODSmallVector { - static_assert(std::is_pod::value, - "T is required to be a plain old data type"); - - T* First = nullptr; - T* Last = nullptr; - T* Cap = nullptr; - T Inline[N] = {0}; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - template struct AbstractManglingParser { const char *First; const char *Last; @@ -2463,7 +2477,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]; @@ -2581,34 +2595,38 @@ Node *AbstractManglingParser::parseName(NameState *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 = look() == 'S' && look(1) != 't'; + if (IsSubst) { + // A substitution must lead to: + // ::= + Result = getDerived().parseSubstitution(); + } else { + // An unscoped name can be one of: + // ::= + // ::= + Result = getDerived().parseUnscopedName(State); } - - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) + if (Result == nullptr) 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 [] @@ -2653,13 +2671,17 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make(R); - } - return getDerived().parseUnqualifiedName(State); + bool IsStd = consumeIf("St"); + if (IsStd) + consumeIf('L'); + + Node *Result = getDerived().parseUnqualifiedName(State); + if (Result == nullptr) + return nullptr; + if (IsStd) + Result = make(Result); + + return Result; } // ::= [abi-tags] @@ -3696,8 +3718,6 @@ Node *AbstractManglingParser::parseQualifiedType() { if (Qual.empty()) return nullptr; - // FIXME parse the optional here! - // extension ::= U # objc-type if (Qual.startsWith("objcproto")) { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); @@ -3715,10 +3735,17 @@ Node *AbstractManglingParser::parseQualifiedType() { return make(Child, Proto); } + Node *TA = nullptr; + if (look() == 'I') { + TA = getDerived().parseTemplateArgs(); + if (TA == nullptr) + return nullptr; + } + Node *Child = getDerived().parseQualifiedType(); if (Child == nullptr) return nullptr; - return make(Child, Qual); + return make(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); @@ -3891,7 +3918,17 @@ Node *AbstractManglingParser::parseType() { // ::= Dh # IEEE 754r half-precision floating point (16 bits) case 'h': First += 2; - return make("decimal16"); + return make("half"); + // ::= DF _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make(DimensionNumber); + } // ::= Di # char32_t case 'i': First += 2; @@ -4039,9 +4076,9 @@ 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') { + Result = getDerived().parseSubstitution(); + if (Result == nullptr) return nullptr; // Sub could be either of: @@ -4058,13 +4095,13 @@ Node *AbstractManglingParser::parseType() { Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else { + // 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; } @@ -5013,6 +5050,43 @@ Node *AbstractManglingParser::parseExpr() { } } return nullptr; + case 'u': { + ++First; + Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); + if (!Name) + return nullptr; + // Special case legacy __uuidof mangling. The 't' and 'z' appear where the + // standard encoding expects a , and would be otherwise be + // interpreted as node 'short' or 'ellipsis'. However, neither + // __uuidof(short) nor __uuidof(...) can actually appear, so there is no + // actual conflict here. + if (Name->getBaseName() == "__uuidof") { + if (numLeft() < 2) + return nullptr; + if (*First == 't') { + ++First; + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + return make(Name, makeNodeArray(&Ty, &Ty + 1)); + } + if (*First == 'z') { + ++First; + Node *Ex = getDerived().parseExpr(); + if (!Ex) + return nullptr; + return make(Name, makeNodeArray(&Ex, &Ex + 1)); + } + } + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseTemplateArg(); + if (E == nullptr) + return E; + Names.push_back(E); + } + return make(Name, popTrailingNodeArray(ExprsBegin)); + } case '1': case '2': case '3': @@ -5024,21 +5098,6 @@ Node *AbstractManglingParser::parseExpr() { case '9': return getDerived().parseUnresolvedName(); } - - if (consumeIf("u8__uuidoft")) { - Node *Ty = getDerived().parseType(); - if (!Ty) - return nullptr; - return make(Ty); - } - - if (consumeIf("u8__uuidofz")) { - Node *Ex = getDerived().parseExpr(); - if (!Ex) - return nullptr; - return make(Ex); - } - return nullptr; } @@ -5221,14 +5280,18 @@ Node *AbstractManglingParser::parseEncoding() { class SaveTemplateParams { AbstractManglingParser *Parser; decltype(TemplateParams) OldParams; + decltype(OuterTemplateParams) OldOuterParams; public: SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { OldParams = std::move(Parser->TemplateParams); + OldOuterParams = std::move(Parser->OuterTemplateParams); Parser->TemplateParams.clear(); + Parser->OuterTemplateParams.clear(); } ~SaveTemplateParams() { Parser->TemplateParams = std::move(OldParams); + Parser->OuterTemplateParams = std::move(OldOuterParams); } } SaveTemplateParams(this); @@ -5386,38 +5449,35 @@ 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/src/demangle/README.txt b/src/demangle/README.txt index 514ff6d..76470f6 100644 --- a/src/demangle/README.txt +++ b/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/src/demangle/StringView.h b/src/demangle/StringView.h index ceb6c79..90890e3 100644 --- a/src/demangle/StringView.h +++ b/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 @@ -36,29 +38,23 @@ class StringView { StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} StringView() : First(nullptr), Last(nullptr) {} - StringView substr(size_t From) const { - return StringView(begin() + From, size() - From); + StringView substr(size_t Pos, size_t Len = npos) const { + assert(Pos <= size()); + 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; } - StringView substr(size_t From, size_t To) const { - if (To >= size()) - To = size() - 1; - if (From >= size()) - From = size() - 1; - return StringView(First + From, First + To); - } - StringView dropFront(size_t N = 1) const { if (N >= size()) N = size(); @@ -105,7 +101,7 @@ class StringView { bool startsWith(StringView Str) const { if (Str.size() > size()) return false; - return std::equal(Str.begin(), Str.end(), begin()); + return std::strncmp(Str.begin(), begin(), Str.size()) == 0; } const char &operator[](size_t Idx) const { return *(begin() + Idx); } @@ -118,7 +114,7 @@ class StringView { inline bool operator==(const StringView &LHS, const StringView &RHS) { return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); + std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0; } DEMANGLE_NAMESPACE_END diff --git a/src/demangle/Utility.h b/src/demangle/Utility.h index 846a5f0..3b27328 100644 --- a/src/demangle/Utility.h +++ b/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,17 +17,18 @@ #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; @@ -48,8 +52,8 @@ class OutputStream { return; } - char Temp[21]; - char *TempPtr = std::end(Temp); + std::array Temp; + char *TempPtr = Temp.data() + Temp.size(); while (N) { *--TempPtr = char('0' + N % 10); @@ -59,13 +63,13 @@ class OutputStream { // Add negative sign... if (isNeg) *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); + this->operator<<(StringView(TempPtr, Temp.data() + Temp.size())); } public: - OutputStream(char *StartBuf, size_t Size) + OutputBuffer(char *StartBuf, size_t Size) : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; + OutputBuffer() = default; void reset(char *Buffer_, size_t BufferCapacity_) { CurrentPosition = 0; Buffer = Buffer_; @@ -77,7 +81,7 @@ class OutputStream { unsigned CurrentPackIndex = std::numeric_limits::max(); unsigned CurrentPackMax = std::numeric_limits::max(); - OutputStream &operator+=(StringView R) { + OutputBuffer &operator+=(StringView R) { size_t Size = R.size(); if (Size == 0) return *this; @@ -87,17 +91,28 @@ class OutputStream { 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 &operator<<(StringView R) { return (*this += R); } - OutputStream &operator<<(char C) { return (*this += C); } + OutputBuffer prepend(StringView R) { + size_t Size = R.size(); + + grow(Size); + std::memmove(Buffer + Size, Buffer, CurrentPosition); + std::memcpy(Buffer, R.begin(), Size); + CurrentPosition += Size; - OutputStream &operator<<(long long N) { + return *this; + } + + OutputBuffer &operator<<(char C) { return (*this += C); } + + OutputBuffer &operator<<(long long N) { if (N < 0) writeUnsigned(static_cast(-N), true); else @@ -105,27 +120,37 @@ class OutputStream { return *this; } - OutputStream &operator<<(unsigned long long N) { + OutputBuffer &operator<<(unsigned long long N) { writeUnsigned(N, false); return *this; } - OutputStream &operator<<(long N) { + 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; } @@ -171,7 +196,7 @@ template class SwapAndRestore { SwapAndRestore &operator=(const SwapAndRestore &) = delete; }; -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, +inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, size_t InitSize) { size_t BufferSize; if (Buf == nullptr) { @@ -182,7 +207,7 @@ inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, } else BufferSize = *N; - S.reset(Buf, BufferSize); + OB.reset(Buf, BufferSize); return true; } diff --git a/src/demangle/cp-to-llvm.sh b/src/demangle/cp-to-llvm.sh index 808abbc..faf6056 100755 --- a/src/demangle/cp-to-llvm.sh +++ b/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 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|^//=*-* .*\.h -*.*=*// *$|//===--- '"$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/src/fallback_malloc.cpp b/src/fallback_malloc.cpp index f3d7937..7e356d9 100644 --- a/src/fallback_malloc.cpp +++ b/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. diff --git a/src/fallback_malloc.h b/src/fallback_malloc.h index 5780854..816e691 100644 --- a/src/fallback_malloc.h +++ b/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/src/include/atomic_support.h b/src/include/atomic_support.h deleted file mode 100644 index 6f9dbf4..0000000 --- a/src/include/atomic_support.h +++ /dev/null @@ -1,180 +0,0 @@ -//===----------------------------------------------------------------------===//// -// -// 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 -// -//===----------------------------------------------------------------------===//// - -// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead -// of duplicating the file in libc++abi we should require that the libc++ -// sources are available when building libc++abi. - -#ifndef ATOMIC_SUPPORT_H -#define ATOMIC_SUPPORT_H - -#include "__config" -#include "memory" // for __libcpp_relaxed_load - -#if defined(__clang__) && __has_builtin(__atomic_load_n) \ - && __has_builtin(__atomic_store_n) \ - && __has_builtin(__atomic_add_fetch) \ - && __has_builtin(__atomic_exchange_n) \ - && __has_builtin(__atomic_compare_exchange_n) \ - && defined(__ATOMIC_RELAXED) \ - && defined(__ATOMIC_CONSUME) \ - && defined(__ATOMIC_ACQUIRE) \ - && defined(__ATOMIC_RELEASE) \ - && defined(__ATOMIC_ACQ_REL) \ - && defined(__ATOMIC_SEQ_CST) -# define _LIBCXXABI_HAS_ATOMIC_BUILTINS -#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407 -# define _LIBCXXABI_HAS_ATOMIC_BUILTINS -#endif - -#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) -# if defined(_LIBCPP_WARNING) - _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported") -# else -# warning Building libc++ without __atomic builtins is unsupported -# endif -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -namespace { - -#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) - -enum __libcpp_atomic_order { - _AO_Relaxed = __ATOMIC_RELAXED, - _AO_Consume = __ATOMIC_CONSUME, - _AO_Acquire = __ATOMIC_ACQUIRE, - _AO_Release = __ATOMIC_RELEASE, - _AO_Acq_Rel = __ATOMIC_ACQ_REL, - _AO_Seq = __ATOMIC_SEQ_CST -}; - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int __order = _AO_Seq) -{ - __atomic_store_n(__dest, __val, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - __atomic_store_n(__dest, __val, _AO_Relaxed); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int __order = _AO_Seq) -{ - return __atomic_load_n(__val, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int __order = _AO_Seq) -{ - return __atomic_add_fetch(__val, __a, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int __order = _AO_Seq) -{ - return __atomic_exchange_n(__target, __value, __order); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -bool __libcpp_atomic_compare_exchange(_ValueType* __val, - _ValueType* __expected, _ValueType __after, - int __success_order = _AO_Seq, - int __fail_order = _AO_Seq) -{ - return __atomic_compare_exchange_n(__val, __expected, __after, true, - __success_order, __fail_order); -} - -#else // _LIBCPP_HAS_NO_THREADS - -enum __libcpp_atomic_order { - _AO_Relaxed, - _AO_Consume, - _AO_Acquire, - _AO_Release, - _AO_Acq_Rel, - _AO_Seq -}; - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int = 0) -{ - *__dest = __val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - *__dest = __val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int = 0) -{ - return *__val; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int = 0) -{ - return *__val += __a; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int = _AO_Seq) -{ - _ValueType old = *__target; - *__target = __value; - return old; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -bool __libcpp_atomic_compare_exchange(_ValueType* __val, - _ValueType* __expected, _ValueType __after, - int = 0, int = 0) -{ - if (*__val == *__expected) { - *__val = __after; - return true; - } - *__expected = *__val; - return false; -} - -#endif // _LIBCPP_HAS_NO_THREADS - -} // end namespace - -_LIBCPP_END_NAMESPACE_STD - -#endif // ATOMIC_SUPPORT_H diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp index c77ad66..e108666 100644 --- a/src/private_typeinfo.cpp +++ b/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. @@ -679,7 +679,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info.number_of_dst_type = 1; dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); } -#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST +#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST // Query the search. if (info.path_dst_ptr_to_static_ptr == public_path) dst_ptr = dynamic_ptr; @@ -707,7 +707,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); } -#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST +#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST // Query the search. switch (info.number_to_static_ptr) { diff --git a/src/private_typeinfo.h b/src/private_typeinfo.h index cf680d6..622e09c 100644 --- a/src/private_typeinfo.h +++ b/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. @@ -248,4 +248,4 @@ class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info } // __cxxabiv1 -#endif // __PRIVATE_TYPEINFO_H_ +#endif // __PRIVATE_TYPEINFO_H_ diff --git a/src/stdlib_exception.cpp b/src/stdlib_exception.cpp index b0cc431..b1fc21f 100644 --- a/src/stdlib_exception.cpp +++ b/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. @@ -14,22 +14,22 @@ namespace std // exception -exception::~exception() _NOEXCEPT +exception::~exception() noexcept { } -const char* exception::what() const _NOEXCEPT +const char* exception::what() const noexcept { return "std::exception"; } // bad_exception -bad_exception::~bad_exception() _NOEXCEPT +bad_exception::~bad_exception() noexcept { } -const char* bad_exception::what() const _NOEXCEPT +const char* bad_exception::what() const noexcept { return "std::bad_exception"; } @@ -37,32 +37,32 @@ const char* bad_exception::what() const _NOEXCEPT // bad_alloc -bad_alloc::bad_alloc() _NOEXCEPT +bad_alloc::bad_alloc() noexcept { } -bad_alloc::~bad_alloc() _NOEXCEPT +bad_alloc::~bad_alloc() noexcept { } const char* -bad_alloc::what() const _NOEXCEPT +bad_alloc::what() const noexcept { return "std::bad_alloc"; } // bad_array_new_length -bad_array_new_length::bad_array_new_length() _NOEXCEPT +bad_array_new_length::bad_array_new_length() noexcept { } -bad_array_new_length::~bad_array_new_length() _NOEXCEPT +bad_array_new_length::~bad_array_new_length() noexcept { } const char* -bad_array_new_length::what() const _NOEXCEPT +bad_array_new_length::what() const noexcept { return "bad_array_new_length"; } diff --git a/src/stdlib_new_delete.cpp b/src/stdlib_new_delete.cpp index 8ef3057..4a664e1 100644 --- a/src/stdlib_new_delete.cpp +++ b/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. @@ -12,8 +12,8 @@ #include #include -#if !defined(_THROW_BAD_ALLOC) || !defined(_NOEXCEPT) || !defined(_LIBCXXABI_WEAK) -#error The _THROW_BAD_ALLOC, _NOEXCEPT, and _LIBCXXABI_WEAK libc++ macros must \ +#if !defined(_THROW_BAD_ALLOC) || !defined(_LIBCXXABI_WEAK) +#error The _THROW_BAD_ALLOC and _LIBCXXABI_WEAK libc++ macros must \ already be defined by libc++. #endif // Implement all new and delete operators as weak definitions @@ -46,20 +46,20 @@ operator new(std::size_t size) _THROW_BAD_ALLOC _LIBCXXABI_WEAK void* -operator new(size_t size, const std::nothrow_t&) _NOEXCEPT +operator new(size_t size, const std::nothrow_t&) noexcept { void* p = nullptr; #ifndef _LIBCXXABI_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS p = ::operator new(size); #ifndef _LIBCXXABI_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS return p; } @@ -72,61 +72,61 @@ operator new[](size_t size) _THROW_BAD_ALLOC _LIBCXXABI_WEAK void* -operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT +operator new[](size_t size, const std::nothrow_t&) noexcept { void* p = nullptr; #ifndef _LIBCXXABI_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS p = ::operator new[](size); #ifndef _LIBCXXABI_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS return p; } _LIBCXXABI_WEAK void -operator delete(void* ptr) _NOEXCEPT +operator delete(void* ptr) noexcept { ::free(ptr); } _LIBCXXABI_WEAK void -operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT +operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } _LIBCXXABI_WEAK void -operator delete(void* ptr, size_t) _NOEXCEPT +operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr) _NOEXCEPT +operator delete[] (void* ptr) noexcept { ::operator delete(ptr); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT +operator delete[] (void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr, size_t) _NOEXCEPT +operator delete[] (void* ptr, size_t) noexcept { ::operator delete[](ptr); } @@ -167,20 +167,20 @@ operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC _LIBCXXABI_WEAK void* -operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { void* p = nullptr; #ifndef _LIBCXXABI_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS p = ::operator new(size, alignment); #ifndef _LIBCXXABI_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS return p; } @@ -193,61 +193,61 @@ operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC _LIBCXXABI_WEAK void* -operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { void* p = nullptr; #ifndef _LIBCXXABI_NO_EXCEPTIONS try { -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS p = ::operator new[](size, alignment); #ifndef _LIBCXXABI_NO_EXCEPTIONS } catch (...) { } -#endif // _LIBCXXABI_NO_EXCEPTIONS +#endif // _LIBCXXABI_NO_EXCEPTIONS return p; } _LIBCXXABI_WEAK void -operator delete(void* ptr, std::align_val_t) _NOEXCEPT +operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } _LIBCXXABI_WEAK void -operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { ::operator delete(ptr, alignment); } _LIBCXXABI_WEAK void -operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT +operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { ::operator delete(ptr, alignment); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT +operator delete[] (void* ptr, std::align_val_t alignment) noexcept { ::operator delete(ptr, alignment); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { ::operator delete[](ptr, alignment); } _LIBCXXABI_WEAK void -operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT +operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept { ::operator delete[](ptr, alignment); } diff --git a/src/stdlib_stdexcept.cpp b/src/stdlib_stdexcept.cpp index 4a464e4..92f7a6e 100644 --- a/src/stdlib_stdexcept.cpp +++ b/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. @@ -6,42 +6,42 @@ // //===----------------------------------------------------------------------===// -#include "../../libcxx/src/include/refstring.h" #include "stdexcept" #include "new" #include #include #include #include +#include "include/refstring.h" // from libc++ static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); namespace std // purposefully not using versioning namespace { -logic_error::~logic_error() _NOEXCEPT {} +logic_error::~logic_error() noexcept {} const char* -logic_error::what() const _NOEXCEPT +logic_error::what() const noexcept { return __imp_.c_str(); } -runtime_error::~runtime_error() _NOEXCEPT {} +runtime_error::~runtime_error() noexcept {} const char* -runtime_error::what() const _NOEXCEPT +runtime_error::what() const noexcept { return __imp_.c_str(); } -domain_error::~domain_error() _NOEXCEPT {} -invalid_argument::~invalid_argument() _NOEXCEPT {} -length_error::~length_error() _NOEXCEPT {} -out_of_range::~out_of_range() _NOEXCEPT {} +domain_error::~domain_error() noexcept {} +invalid_argument::~invalid_argument() noexcept {} +length_error::~length_error() noexcept {} +out_of_range::~out_of_range() noexcept {} -range_error::~range_error() _NOEXCEPT {} -overflow_error::~overflow_error() _NOEXCEPT {} -underflow_error::~underflow_error() _NOEXCEPT {} +range_error::~range_error() noexcept {} +overflow_error::~overflow_error() noexcept {} +underflow_error::~underflow_error() noexcept {} } // std diff --git a/src/stdlib_typeinfo.cpp b/src/stdlib_typeinfo.cpp index dbb9623..6e54996 100644 --- a/src/stdlib_typeinfo.cpp +++ b/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. @@ -19,32 +19,32 @@ type_info::~type_info() // bad_cast -bad_cast::bad_cast() _NOEXCEPT +bad_cast::bad_cast() noexcept { } -bad_cast::~bad_cast() _NOEXCEPT +bad_cast::~bad_cast() noexcept { } const char* -bad_cast::what() const _NOEXCEPT +bad_cast::what() const noexcept { return "std::bad_cast"; } // bad_typeid -bad_typeid::bad_typeid() _NOEXCEPT +bad_typeid::bad_typeid() noexcept { } -bad_typeid::~bad_typeid() _NOEXCEPT +bad_typeid::~bad_typeid() noexcept { } const char* -bad_typeid::what() const _NOEXCEPT +bad_typeid::what() const noexcept { return "std::bad_typeid"; } From 8106144ae5246d21783b80c3a0887b195805b438 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 22 Feb 2020 17:45:34 +0300 Subject: [PATCH 2/2] Merge remote-tracking branch 'origin/clickhouse-avoid-__cxa_thread_atexit_impl' into clickhouse --- src/cxa_thread_atexit.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/cxa_thread_atexit.cpp b/src/cxa_thread_atexit.cpp index 665f9e5..2a55cec 100644 --- a/src/cxa_thread_atexit.cpp +++ b/src/cxa_thread_atexit.cpp @@ -6,6 +6,14 @@ // //===----------------------------------------------------------------------===// +/** This file was edited for ClickHouse. + * This is needed to avoid linking with "__cxa_thread_atexit_impl" function, that require too new (2.18) glibc library. + * + * Note: "__cxa_thread_atexit_impl" may provide sophisticated implementation to correct destruction of thread-local objects, + * that was created in different DSO. Read https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables + * We simply don't need this implementation, because we don't use thread-local objects from different DSO. + */ + #include "abort_message.h" #include "cxxabi.h" #include <__threading_support> @@ -21,15 +29,6 @@ namespace __cxxabiv1 { using Dtor = void(*)(void*); - extern "C" -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL - // A weak symbol is used to detect this function's presence in the C library - // at runtime, even if libc++ is built against an older libc - _LIBCXXABI_WEAK -#endif - int __cxa_thread_atexit_impl(Dtor, void*, void*); - -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL namespace { // This implementation is used if the C library does not provide @@ -104,17 +103,10 @@ namespace { }; } // namespace -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL extern "C" { - _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() { -#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); -#else - if (__cxa_thread_atexit_impl) { - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); - } else { + _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit_impl(Dtor dtor, void* obj, void* dso_symbol) throw() { // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for // one-time initialization and __cxa_atexit() for destruction) static DtorsManager manager; @@ -137,8 +129,11 @@ extern "C" { dtors = head; return 0; - } -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL + } + + int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() + { + return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); } } // extern "C"