From: robert Date: Tue, 11 Sep 2018 18:06:31 +0000 (+0000) Subject: import of libc++abi 6.0.0 X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=8a05a458f6e66ba4e39e97f266f4fbfbbdf85f5b;p=openbsd import of libc++abi 6.0.0 --- diff --git a/lib/libcxxabi/CMakeLists.txt b/lib/libcxxabi/CMakeLists.txt index 300d6da2152..1adbdb33832 100644 --- a/lib/libcxxabi/CMakeLists.txt +++ b/lib/libcxxabi/CMakeLists.txt @@ -1,3 +1,5 @@ +# See www/CMake.html for instructions on how to build libcxxabi with CMake. + #=============================================================================== # Setup Project #=============================================================================== @@ -8,104 +10,37 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default endif() -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - project(libcxxabi) - - # Rely on llvm-config. - set(CONFIG_OUTPUT) - find_program(LLVM_CONFIG "llvm-config") - if(DEFINED LLVM_PATH) - set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") - set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) - set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") - elseif(LLVM_CONFIG) - message(STATUS "Found LLVM_CONFIG as ${LLVM_CONFIG}") - set(CONFIG_COMMAND ${LLVM_CONFIG} - "--includedir" - "--prefix" - "--src-root") - execute_process( - COMMAND ${CONFIG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE CONFIG_OUTPUT - ) - if(NOT HAD_ERROR) - string(REGEX REPLACE - "[ \t]*[\r\n]+[ \t]*" ";" - CONFIG_OUTPUT ${CONFIG_OUTPUT}) - else() - string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") - message(STATUS "${CONFIG_COMMAND_STR}") - message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") - endif() - - list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) - list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) - list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) - - set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") - set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") - set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR}/share/llvm/cmake") - set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py") - else() - message(FATAL_ERROR "llvm-config not found and LLVM_MAIN_SRC_DIR not defined. " - "Reconfigure with -DLLVM_CONFIG=path/to/llvm-config " - "or -DLLVM_PATH=path/to/llvm-source-root.") - endif() +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + ${CMAKE_MODULE_PATH} + ) - if(EXISTS ${LLVM_CMAKE_PATH}) - list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") - include("${LLVM_CMAKE_PATH}/AddLLVM.cmake") - include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake") - else() - message(FATAL_ERROR "Not found: ${LLVM_CMAKE_PATH}") - endif() +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 3.9.0) + set(PACKAGE_VERSION 6.0.0) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") - if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - else() - # Seek installed Lit. - find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit - DOC "Path to lit.py") - endif() - - if(LLVM_LIT) - # Define the default arguments to use with 'lit', and an option for the user - # to override. - set(LIT_ARGS_DEFAULT "-sv") - if (MSVC OR XCODE) - set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") - endif() - set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") - - # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. - if( WIN32 AND NOT CYGWIN ) - set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") - endif() - else() - set(LLVM_INCLUDE_TESTS OFF) - endif() - - set(LIBCXXABI_LIBDIR_SUFFIX "" CACHE STRING - "Define suffix of library directory name (32/64)") - - set(LIBCXXABI_BUILT_STANDALONE 1) -else() - set(LLVM_MAIN_SRC_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "Path to LLVM source tree") - set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py") - set(LIBCXXABI_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX}) + # Find the LLVM sources and simulate LLVM CMake options. + include(HandleOutOfTreeLLVM) endif() +# Require out of source build. +include(MacroEnsureOutOfSourceBuild) +MACRO_ENSURE_OUT_OF_SOURCE_BUILD( + "${PROJECT_NAME} requires an out of source build. Please create a separate + build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there." + ) + #=============================================================================== # Setup CMake Options #=============================================================================== +include(CMakeDependentOption) +include(HandleCompilerRT) # Define options. option(LIBCXXABI_ENABLE_EXCEPTIONS "Use exceptions." ON) @@ -113,10 +48,28 @@ option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode. option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." 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_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) +option(LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY + "Build libc++abi with an externalized threading library. + This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON" OFF) + +# FIXME: This option should default to off. Unfortunatly GCC 4.9 fails to link +# programs to due undefined references to new/delete in libc++abi. Once this +# has been fixed or worked around the default value should be changed. +option(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS + "Build libc++abi with definitions for operator new/delete. Normally libc++ + provides these definitions" ON) option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS}) +option(LIBCXXABI_INCLUDE_TESTS "Generate build targets for the libc++abi unit tests." ${LLVM_INCLUDE_TESTS}) +set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") +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.") @@ -131,17 +84,36 @@ set(LIBCXXABI_LIBCXX_LIBRARY_PATH "" CACHE PATH "The path to libc++ library.") option(LIBCXXABI_ENABLE_SHARED "Build libc++abi as a shared library." ON) option(LIBCXXABI_ENABLE_STATIC "Build libc++abi as a static library." ON) +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) + 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() +if (LLVM_EXTERNAL_LIBCXX_SOURCE_DIR) + set(LIBCXXABI_LIBCXX_SRC_DIRS ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR}) +else() + set(LIBCXXABI_LIBCXX_SRC_DIRS + "${LLVM_MAIN_SRC_DIR}/projects/libcxx" + "${LLVM_MAIN_SRC_DIR}/runtimes/libcxx" + ) +endif() + +set(LIBCXXABI_LIBCXX_INCLUDE_DIRS "") +foreach(dir ${LIBCXXABI_LIBCXX_SRC_DIRS}) + list(APPEND LIBCXXABI_LIBCXX_INCLUDE_DIRS "${dir}/include") +endforeach() + find_path( LIBCXXABI_LIBCXX_INCLUDES vector PATHS ${LIBCXXABI_LIBCXX_INCLUDES} ${LIBCXXABI_LIBCXX_PATH}/include ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBCXX_INCLUDES} - ${LLVM_MAIN_SRC_DIR}/projects/libcxx/include + ${LIBCXXABI_LIBCXX_INCLUDE_DIRS} ${LLVM_INCLUDE_DIR}/c++/v1 ) @@ -150,10 +122,10 @@ set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXXABI_LIBCXX_INCLUDES}" CACHE PATH find_path( LIBCXXABI_LIBCXX_PATH - test/libcxx/__init__.py + utils/libcxx/test/__init__.py PATHS ${LIBCXXABI_LIBCXX_PATH} ${LIBCXXABI_LIBCXX_INCLUDES}/../ - ${LLVM_MAIN_SRC_DIR}/projects/libcxx/ + ${LIBCXXABI_LIBCXX_SRC_DIRS} NO_DEFAULT_PATH ) @@ -179,10 +151,22 @@ set(CMAKE_MODULE_PATH set(LIBCXXABI_COMPILER ${CMAKE_CXX_COMPILER}) set(LIBCXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(LIBCXXABI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) +if (LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) +else() + set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) +endif() + +set(LIBCXXABI_INSTALL_PREFIX "" CACHE STRING + "Define libc++abi destination prefix.") + +if (NOT LIBCXXABI_INSTALL_PREFIX MATCHES "^$|.*/") + message(FATAL_ERROR "LIBCXXABI_INSTALL_PREFIX has to end with \"/\".") +endif() set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) # By default, for non-standalone builds, libcxx and libcxxabi share a library # directory. @@ -200,39 +184,40 @@ elseif(LIBCXXABI_BUILD_32_BITS) message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.") endif() -#=============================================================================== -# Setup Compiler Flags -#=============================================================================== - -# Get required flags. -macro(append_if list condition var) - if (${condition}) - list(APPEND ${list} ${var}) - endif() -endmacro() - -macro(add_target_flags_if condition var) - if (${condition}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${var}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${var}") - list(APPEND LIBCXXABI_LINK_FLAGS ${var}) - endif() -endmacro() +# Declare libc++abi configuration variables. +# They are intended for use as follows: +# LIBCXXABI_C_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_CXX_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_COMPILE_FLAGS: Compile only flags. +# LIBCXXABI_LINK_FLAGS: Linker only flags. +# LIBCXXABI_LIBRARIES: libraries libc++abi is linked to. set(LIBCXXABI_C_FLAGS "") set(LIBCXXABI_CXX_FLAGS "") set(LIBCXXABI_COMPILE_FLAGS "") set(LIBCXXABI_LINK_FLAGS "") +set(LIBCXXABI_LIBRARIES "") + +# Include macros for adding and removing libc++abi flags. +include(HandleLibcxxabiFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== # Configure target flags add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") add_target_flags_if(LIBCXXABI_TARGET_TRIPLE - "-target ${LIBCXXABI_TARGET_TRIPLE}") + "--target=${LIBCXXABI_TARGET_TRIPLE}") add_target_flags_if(LIBCXXABI_GCC_TOOLCHAIN - "-gcc-toolchain ${LIBCXXABI_GCC_TOOLCHAIN}") + "--gcc-toolchain=${LIBCXXABI_GCC_TOOLCHAIN}") add_target_flags_if(LIBCXXABI_SYSROOT "--sysroot=${LIBCXXABI_SYSROOT}") +if (LIBCXXABI_TARGET_TRIPLE) + set(TARGET_TRIPLE "${LIBCXXABI_TARGET_TRIPLE}") +endif() + # Configure compiler. Must happen after setting the target flags. include(config-ix) @@ -247,53 +232,63 @@ if (LIBCXXABI_USE_COMPILER_RT) list(APPEND LIBCXXABI_LINK_FLAGS "-rtlib=compiler-rt") endif() -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror=return-type) +# Let the library headers know they are currently being used to build the +# library. +add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) + +# Disable DLL annotations on Windows for static builds. +if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) + add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) +endif() + +add_compile_flags_if_supported(-Werror=return-type) # Get warning flags -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_W_FLAG -W) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WALL_FLAG -Wall) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG -Wchar-subscripts) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCONVERSION_FLAG -Wconversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG -Wmismatched-tags) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISSING_BRACES_FLAG -Wmissing-braces) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNEWLINE_EOF_FLAG -Wnewline-eof) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_UNUSED_FUNCTION_FLAG -Wno-unused-function) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHADOW_FLAG -Wshadow) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG -Wshorten-64-to-32) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_COMPARE_FLAG -Wsign-compare) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG -Wsign-conversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG -Wstrict-aliasing=2) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG -Wstrict-overflow=4) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG -Wunused-parameter) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG -Wunused-variable) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WWRITE_STRINGS_FLAG -Wwrite-strings) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNDEF_FLAG -Wundef) +add_compile_flags_if_supported(-W) +add_compile_flags_if_supported(-Wall) +add_compile_flags_if_supported(-Wchar-subscripts) +add_compile_flags_if_supported(-Wconversion) +add_compile_flags_if_supported(-Wmismatched-tags) +add_compile_flags_if_supported(-Wmissing-braces) +add_compile_flags_if_supported(-Wnewline-eof) +add_compile_flags_if_supported(-Wunused-function) +add_compile_flags_if_supported(-Wshadow) +add_compile_flags_if_supported(-Wshorten-64-to-32) +add_compile_flags_if_supported(-Wsign-compare) +add_compile_flags_if_supported(-Wsign-conversion) +add_compile_flags_if_supported(-Wstrict-aliasing=2) +add_compile_flags_if_supported(-Wstrict-overflow=4) +add_compile_flags_if_supported(-Wunused-parameter) +add_compile_flags_if_supported(-Wunused-variable) +add_compile_flags_if_supported(-Wwrite-strings) +add_compile_flags_if_supported(-Wundef) if (LIBCXXABI_ENABLE_WERROR) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WX_FLAG -WX) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) else() - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_ERROR_FLAG -Wno-error) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_NO_WX_FLAG -WX-) + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) endif() if (LIBCXXABI_ENABLE_PEDANTIC) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_PEDANTIC_FLAG -pedantic) + add_compile_flags_if_supported(-pedantic) endif() # Get feature flags. -append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG -fstrict-aliasing) +add_compile_flags_if_supported(-fstrict-aliasing) # Exceptions if (LIBCXXABI_ENABLE_EXCEPTIONS) # Catches C++ exceptions only and tells the compiler to assume that extern C # functions never throw a C++ exception. - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_EHSC_FLAG -EHsc) - append_if(LIBCXXABI_C_FLAGS LIBCXXABI_HAS_FUNWIND_TABLES -funwind-tables) + add_compile_flags_if_supported(-EHsc) + # Do we really need to be run through the C compiler ? + add_c_compile_flags_if_supported(-funwind-tables) else() add_definitions(-D_LIBCXXABI_NO_EXCEPTIONS) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG -fno-exceptions) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHS_FLAG -EHs-) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHA_FLAG -EHa-) + add_compile_flags_if_supported(-fno-exceptions) + add_compile_flags_if_supported(-EHs-) + add_compile_flags_if_supported(-EHa-) endif() # Assert @@ -318,27 +313,92 @@ if (NOT LIBCXXABI_ENABLE_SHARED) list(APPEND LIBCXXABI_COMPILE_FLAGS -D_LIBCPP_BUILD_STATIC) endif() +# Threading if (NOT LIBCXXABI_ENABLE_THREADS) if (LIBCXXABI_HAS_PTHREAD_API) message(FATAL_ERROR "LIBCXXABI_HAS_PTHREAD_API can only" " be set to ON when LIBCXXABI_ENABLE_THREADS" " is also set to ON.") endif() - add_definitions(-DLIBCXXABI_HAS_NO_THREADS=1) + if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + message(FATAL_ERROR "LIBCXXABI_HAS_EXTERNAL_THREAD_API can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() + if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) + message(FATAL_ERROR "LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() + add_definitions(-D_LIBCXXABI_HAS_NO_THREADS) +endif() + +if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + if (LIBCXXABI_HAS_PTHREAD_API) + message(FATAL_ERROR "The options LIBCXXABI_HAS_EXTERNAL_THREAD_API" + " and LIBCXXABI_HAS_PTHREAD_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" + " 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) + add_compile_flags(-fno-modules) +endif() + +set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS OFF) +if ((NOT LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) + OR (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXXABI_ENABLE_SHARED) + OR MINGW) + set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS ON) +endif() + +if (LIBCXXABI_HAS_UNDEFINED_SYMBOLS) + # Need to allow unresolved symbols if this is to work with shared library builds + if (APPLE) + list(APPEND LIBCXXABI_LINK_FLAGS "-undefined dynamic_lookup") + else() + # Relax this restriction from HandleLLVMOptions + string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + endif() endif() if (LIBCXXABI_HAS_PTHREAD_API) add_definitions(-D_LIBCPP_HAS_THREAD_API_PTHREAD) endif() -# This is the _ONLY_ place where add_definitions is called. +if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + add_definitions(-D_LIBCPP_HAS_THREAD_API_EXTERNAL) +endif() + +if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) + add_definitions(-D_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) +endif() + +# Prevent libc++abi from having library dependencies on libc++ +add_definitions(-D_LIBCPP_DISABLE_EXTERN_TEMPLATE) + if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() # Define LIBCXXABI_USE_LLVM_UNWINDER for conditional compilation. -if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) - add_definitions(-DLIBCXXABI_USE_LLVM_UNWINDER=1) +if (LIBCXXABI_USE_LLVM_UNWINDER) + add_definitions(-DLIBCXXABI_USE_LLVM_UNWINDER) +endif() + +if (LIBCXXABI_SILENT_TERMINATE) + add_definitions(-DLIBCXXABI_SILENT_TERMINATE) +endif() + +if (LIBCXXABI_BAREMETAL) + add_definitions(-DLIBCXXABI_BAREMETAL) endif() string(REPLACE ";" " " LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}") @@ -363,32 +423,24 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) ${LIBCXXABI_LIBUNWIND_PATH}/include ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBUNWIND_INCLUDES} ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include + ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/include NO_DEFAULT_PATH ) - find_path( - LIBCXXABI_LIBUNWIND_SOURCES - libunwind_ext.h - PATHS ${LIBCXXABI_LIBUNWIND_PATH}/src/ - ${LIBCXXABI_LIBUNWIND_INCLUDES}/../src/ - ${LLVM_MAIN_SRC_DIR}/projects/libunwind/src/ - NO_DEFAULT_PATH - ) - - if (LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "LIBCXXABI_LIBUNWIND_SOURCES-NOTFOUND") - message(WARNING "LIBCXXABI_LIBUNWIND_SOURCES was not specified and couldn't be infered.") - set(LIBCXXABI_LIBUNWIND_SOURCES "") + if (LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL-NOTFOUND") + set(LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL "") endif() - include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}") - include_directories("${LIBCXXABI_LIBUNWIND_SOURCES}") + if (NOT LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "") + include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}") + endif() endif() # Add source code. This also contains all of the logic for deciding linker flags # soname, etc... add_subdirectory(src) -if (LIBCXXABI_BUILT_STANDALONE AND NOT LIBCXXABI_ENABLE_SHARED) +if (NOT LIBCXXABI_INCLUDE_TESTS OR (LIBCXXABI_STANDALONE_BUILD AND NOT LIBCXXABI_ENABLE_SHARED)) # We can't reasonably test the system C++ library with a static libc++abi. # We either need to be able to replace libc++abi at run time (with a shared # libc++abi), or we need to be able to replace the C++ runtime (with a non- @@ -401,4 +453,5 @@ if (LIBCXXABI_BUILT_STANDALONE AND NOT LIBCXXABI_ENABLE_SHARED) "available!") else() add_subdirectory(test) + add_subdirectory(fuzz) endif() diff --git a/lib/libcxxabi/CREDITS.TXT b/lib/libcxxabi/CREDITS.TXT index 9c910fcfd0c..fbb6cbf38ba 100644 --- a/lib/libcxxabi/CREDITS.TXT +++ b/lib/libcxxabi/CREDITS.TXT @@ -58,7 +58,7 @@ E: erik@olofsson.info D: Minor patches and fixes N: Jon Roelofs -E: jonathan@codesourcery.com +E: jroelofs@jroelofs.com D: ARM EHABI Unwind & Exception Handling, Bare-metal N: Nico Weber diff --git a/lib/libcxxabi/LICENSE.TXT b/lib/libcxxabi/LICENSE.TXT index 14fd39a9c4c..f333f1fe48d 100644 --- a/lib/libcxxabi/LICENSE.TXT +++ b/lib/libcxxabi/LICENSE.TXT @@ -14,7 +14,7 @@ Full text of the relevant licenses is included below. University of Illinois/NCSA Open Source License -Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2017 by the contributors listed in CREDITS.TXT All rights reserved. diff --git a/lib/libcxxabi/cmake/Modules/HandleCompilerRT.cmake b/lib/libcxxabi/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 00000000000..395c21ace66 --- /dev/null +++ b/lib/libcxxabi/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,58 @@ +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() + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${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) + 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) + 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/lib/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake b/lib/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake new file mode 100644 index 00000000000..3eddd7bdc62 --- /dev/null +++ b/lib/libcxxabi/cmake/Modules/HandleLibcxxabiFlags.cmake @@ -0,0 +1,208 @@ +# HandleLibcxxFlags - A set of macros used to setup the flags used to compile +# and link libc++abi. These macros add flags to the following CMake variables. +# - LIBCXXABI_COMPILE_FLAGS: flags used to compile libc++abi +# - LIBCXXABI_LINK_FLAGS: flags used to link libc++abi +# - LIBCXXABI_LIBRARIES: libraries to link libc++abi to. + +include(CheckCXXCompilerFlag) + +unset(add_flag_if_supported) + +# Mangle the name of a compiler flag into a valid CMake identifier. +# Ex: --std=c++11 -> STD_EQ_CXX11 +macro(mangle_name str output) + string(STRIP "${str}" strippedStr) + string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") + string(REPLACE "-" "_" strippedStr "${strippedStr}") + string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") + string(REPLACE "+" "X" strippedStr "${strippedStr}") + string(TOUPPER "${strippedStr}" ${output}) +endmacro() + +# Remove a list of flags from all CMake variables that affect compile flags. +# This can be used to remove unwanted flags specified on the command line +# or added in other parts of LLVM's cmake configuration. +macro(remove_flags) + foreach(var ${ARGN}) + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") + remove_definitions(${var}) + endforeach() +endmacro(remove_flags) + +macro(check_flag_supported flag) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") +endmacro() + +# Add a macro definition if condition is true. +macro(define_if condition def) + if (${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition if condition is not true. +macro(define_if_not condition def) + if (NOT ${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition to the __config_site file if the specified condition +# is 'true'. Note that '-D${def}' is not added. Instead it is expected that +# the build include the '__config_site' header. +macro(config_define_if condition def) + if (${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define_if_not condition def) + if (NOT ${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define value def) + set(${def} ${value}) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) +endmacro() + +# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags) + foreach(value ${ARGN}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to +# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXXABI_COMPILE_FLAGS' +# and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags_if condition) + if (${condition}) + add_target_flags(${ARGN}) + endif() +endmacro() + +# Add a specified list of flags to both 'LIBCXXABI_COMPILE_FLAGS' and +# 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags) + foreach(value ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to both +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags_if condition) + if (${condition}) + add_flags(${ARGN}) + endif() +endmacro() + +# Add each flag in the list to LIBCXXABI_COMPILE_FLAGS and LIBCXXABI_LINK_FLAGS +# if that flag is supported by the current compiler. +macro(add_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_COMPILE_FLAGS'. +macro(add_compile_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_COMPILE_FLAGS' +macro(add_compile_flags_if condition) + if (${condition}) + add_compile_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C compiler. +macro(add_c_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_c_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_LINK_FLAGS'. +macro(add_link_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_LINK_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_LINK_FLAGS' +macro(add_link_flags_if condition) + if (${condition}) + add_link_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_LINK_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_link_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of libraries or link flags to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags) + foreach(lib ${ARGN}) + list(APPEND LIBCXXABI_LIBRARIES ${lib}) + endforeach() +endmacro() + +# if 'condition' is true then add the specified list of libraries and flags +# to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags_if condition) + if(${condition}) + add_library_flags(${ARGN}) + endif() +endmacro() + +# Turn a comma separated CMake list into a space separated string. +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/lib/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake b/lib/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake new file mode 100644 index 00000000000..8e742088978 --- /dev/null +++ b/lib/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake @@ -0,0 +1,131 @@ +macro(find_llvm_parts) +# Rely on llvm-config. + set(CONFIG_OUTPUT) + if(NOT LLVM_CONFIG_PATH) + find_program(LLVM_CONFIG_PATH "llvm-config") + endif() + if(DEFINED LLVM_PATH) + set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") + set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) + set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") + elseif(LLVM_CONFIG_PATH) + message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") + set(LIBCXXABI_USING_INSTALLED_LLVM 1) + set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} + "--includedir" + "--prefix" + "--src-root") + execute_process( + COMMAND ${CONFIG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ) + if(NOT HAD_ERROR) + string(REGEX REPLACE + "[ \t]*[\r\n]+[ \t]*" ";" + CONFIG_OUTPUT ${CONFIG_OUTPUT}) + else() + string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") + message(STATUS "${CONFIG_COMMAND_STR}") + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + + list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) + list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) + list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) + + set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + + # --cmakedir is supported since llvm r291218 (4.0 release) + execute_process( + COMMAND ${LLVM_CONFIG_PATH} --cmakedir + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ERROR_QUIET) + if(NOT HAD_ERROR) + string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) + else() + set(LLVM_CMAKE_PATH + "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") + endif() + else() + set(LLVM_FOUND OFF) + message(WARNING "UNSUPPORTED LIBCXXABI CONFIGURATION DETECTED: " + "llvm-config not found and LLVM_PATH not defined.\n" + "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config " + "or -DLLVM_PATH=path/to/llvm-source-root.") + return() + endif() + + if (EXISTS "${LLVM_CMAKE_PATH}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + elseif (EXISTS "${LLVM_MAIN_SRC_DIR}/cmake/modules") + list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules") + else() + set(LLVM_FOUND OFF) + message(WARNING "Neither ${LLVM_CMAKE_PATH} nor ${LLVM_MAIN_SRC_DIR}/cmake/modules found") + return() + endif() + + set(LLVM_FOUND ON) +endmacro(find_llvm_parts) + +macro(configure_out_of_tree_llvm) + message(STATUS "Configuring for standalone build.") + set(LIBCXXABI_STANDALONE_BUILD 1) + + find_llvm_parts() + + # Add LLVM Functions -------------------------------------------------------- + if (LLVM_FOUND AND LIBCXXABI_USING_INSTALLED_LLVM) + include(LLVMConfig) # For TARGET_TRIPLE + else() + if (WIN32) + set(LLVM_ON_UNIX 0) + set(LLVM_ON_WIN32 1) + else() + set(LLVM_ON_UNIX 1) + set(LLVM_ON_WIN32 0) + endif() + endif() + if (LLVM_FOUND) + include(AddLLVM OPTIONAL) + include(HandleLLVMOptions OPTIONAL) + endif() + + # LLVM Options -------------------------------------------------------------- + if (NOT DEFINED LLVM_INCLUDE_TESTS) + set(LLVM_INCLUDE_TESTS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_INCLUDE_DOCS) + set(LLVM_INCLUDE_DOCS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_ENABLE_SPHINX) + set(LLVM_ENABLE_SPHINX OFF) + endif() + + # Required LIT Configuration ------------------------------------------------ + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + # Required doc configuration + if (LLVM_ENABLE_SPHINX) + find_package(Sphinx REQUIRED) + endif() + + if (LLVM_ON_UNIX AND NOT APPLE) + set(LLVM_HAVE_LINK_VERSION_SCRIPT 1) + else() + set(LLVM_HAVE_LINK_VERSION_SCRIPT 0) + endif() +endmacro(configure_out_of_tree_llvm) + +configure_out_of_tree_llvm() diff --git a/lib/libcxxabi/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/lib/libcxxabi/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 00000000000..e75002bd8b7 --- /dev/null +++ b/lib/libcxxabi/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,18 @@ +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD() + +macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) + +string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) +if( _insource ) + message( SEND_ERROR "${_errorMessage}" ) + message( FATAL_ERROR + "In-source builds are not allowed. + CMake would overwrite the makefiles distributed with libcxxabi. + Please create a directory and run cmake from there, passing the path + to this source directory as the last argument. + This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. + Please delete them." + ) +endif( _insource ) + +endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) diff --git a/lib/libcxxabi/cmake/config-ix.cmake b/lib/libcxxabi/cmake/config-ix.cmake index baed2db8e41..379b5547749 100644 --- a/lib/libcxxabi/cmake/config-ix.cmake +++ b/lib/libcxxabi/cmake/config-ix.cmake @@ -2,17 +2,61 @@ include(CheckLibraryExists) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) +check_library_exists(c fopen "" LIBCXXABI_HAS_C_LIB) +if (NOT LIBCXXABI_USE_COMPILER_RT) + check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXXABI_HAS_GCC_S_LIB) +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 +# 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") + if (LIBCXXABI_HAS_C_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (LIBCXXABI_USE_COMPILER_RT) + list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") + elseif (LIBCXXABI_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () + if (MINGW) + # Mingw64 requires quite a few "C" runtime libraries in order for basic + # programs to link successfully with -nodefaultlibs. + if (LIBCXXABI_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBCXXABI_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) + endif() + if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") + endif () + 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") + endif () +endif () + # Check compiler flags check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES) -check_cxx_compiler_flag(-fPIC LIBCXXABI_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fno-exceptions LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fno-rtti LIBCXXABI_HAS_NO_RTTI_FLAG) check_cxx_compiler_flag(-fstrict-aliasing LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG) -check_cxx_compiler_flag(-nodefaultlibs LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) check_cxx_compiler_flag(-nostdinc++ LIBCXXABI_HAS_NOSTDINCXX_FLAG) check_cxx_compiler_flag(-Wall LIBCXXABI_HAS_WALL_FLAG) check_cxx_compiler_flag(-W LIBCXXABI_HAS_W_FLAG) -check_cxx_compiler_flag(-Wno-unused-function LIBCXXABI_HAS_WNO_UNUSED_FUNCTION_FLAG) +check_cxx_compiler_flag(-Wunused-function LIBCXXABI_HAS_WUNUSED_FUNCTION_FLAG) check_cxx_compiler_flag(-Wunused-variable LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG) check_cxx_compiler_flag(-Wunused-parameter LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG) check_cxx_compiler_flag(-Wstrict-aliasing LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG) @@ -39,11 +83,7 @@ check_cxx_compiler_flag(/EHa- LIBCXXABI_HAS_NO_EHA_FLAG) check_cxx_compiler_flag(/GR- LIBCXXABI_HAS_NO_GR_FLAG) # Check libraries -check_library_exists(c fopen "" LIBCXXABI_HAS_C_LIB) check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB) check_library_exists(pthread pthread_once "" LIBCXXABI_HAS_PTHREAD_LIB) -if (NOT LIBCXXABI_USE_COMPILER_RT) - check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXXABI_HAS_GCC_S_LIB) -endif () check_library_exists(c __cxa_thread_atexit_impl "" LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) diff --git a/lib/libcxxabi/include/__cxxabi_config.h b/lib/libcxxabi/include/__cxxabi_config.h index 61555f1a927..65b1961e68a 100644 --- a/lib/libcxxabi/include/__cxxabi_config.h +++ b/lib/libcxxabi/include/__cxxabi_config.h @@ -12,17 +12,20 @@ #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) -#define LIBCXXABI_ARM_EHABI 1 -#else -#define LIBCXXABI_ARM_EHABI 0 +#define _LIBCXXABI_ARM_EHABI #endif #if !defined(__has_attribute) #define __has_attribute(_attribute_) 0 #endif -#if defined(_LIBCXXABI_DLL) - #if defined(cxxabi_EXPORTS) +#if defined(_WIN32) + #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS + #define _LIBCXXABI_FUNC_VIS + #define _LIBCXXABI_TYPE_VIS + #elif defined(_LIBCXXABI_BUILDING_LIBRARY) #define _LIBCXXABI_HIDDEN #define _LIBCXXABI_DATA_VIS __declspec(dllexport) #define _LIBCXXABI_FUNC_VIS __declspec(dllexport) @@ -34,14 +37,27 @@ #define _LIBCXXABI_TYPE_VIS __declspec(dllimport) #endif #else - #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden"))) - #define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default"))) - #define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default"))) - #if __has_attribute(__type_visibility__) - #define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default"))) + #if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden"))) + #define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default"))) + #define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default"))) + #if __has_attribute(__type_visibility__) + #define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default"))) + #else + #define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default"))) + #endif #else - #define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default"))) + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS + #define _LIBCXXABI_FUNC_VIS + #define _LIBCXXABI_TYPE_VIS #endif #endif +#if defined(_WIN32) +#define _LIBCXXABI_WEAK +#else +#define _LIBCXXABI_WEAK __attribute__((__weak__)) +#endif + #endif // ____CXXABI_CONFIG_H diff --git a/lib/libcxxabi/include/cxxabi.h b/lib/libcxxabi/include/cxxabi.h index e4a6797a815..2596560d6e9 100644 --- a/lib/libcxxabi/include/cxxabi.h +++ b/lib/libcxxabi/include/cxxabi.h @@ -21,7 +21,7 @@ #include <__cxxabi_config.h> #define _LIBCPPABI_VERSION 1002 -#define LIBCXXABI_NORETURN __attribute__((noreturn)) +#define _LIBCXXABI_NORETURN __attribute__((noreturn)) #ifdef __cplusplus @@ -45,7 +45,7 @@ extern _LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_exception) throw(); // 2.4.3 Throwing the Exception Object -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void *)); @@ -55,7 +55,7 @@ __cxa_get_exception_ptr(void *exceptionObject) throw(); extern _LIBCXXABI_FUNC_VIS void * __cxa_begin_catch(void *exceptionObject) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) extern _LIBCXXABI_FUNC_VIS bool __cxa_begin_cleanup(void *exceptionObject) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup(); @@ -63,19 +63,19 @@ extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup(); extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type(); // 2.5.4 Rethrowing Exceptions -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_rethrow(); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow(); // 2.6 Auxiliary Runtime APIs -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_cast(void); -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_typeid(void); -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw_bad_array_new_length(void); // 3.2.6 Pure Virtual Function API -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_pure_virtual(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void); // 3.2.7 Deleted Virtual Function API -extern _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_deleted_virtual(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void); // 3.3.2 One-time Construction API #ifdef __arm__ diff --git a/lib/libcxxabi/src/CMakeLists.txt b/lib/libcxxabi/src/CMakeLists.txt index b851b4ac777..240f6d0d103 100644 --- a/lib/libcxxabi/src/CMakeLists.txt +++ b/lib/libcxxabi/src/CMakeLists.txt @@ -1,22 +1,29 @@ # Get sources set(LIBCXXABI_SOURCES - abort_message.cpp + # C++ABI files cxa_aux_runtime.cpp cxa_default_handlers.cpp cxa_demangle.cpp cxa_exception_storage.cpp cxa_guard.cpp cxa_handlers.cpp - cxa_new_delete.cpp cxa_unexpected.cpp cxa_vector.cpp cxa_virtual.cpp - exception.cpp + # C++ STL files + stdlib_exception.cpp + stdlib_stdexcept.cpp + stdlib_typeinfo.cpp + # Internal files + abort_message.cpp + fallback_malloc.cpp private_typeinfo.cpp - stdexcept.cpp - typeinfo.cpp ) +if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) + list(APPEND LIBCXXABI_SOURCES stdlib_new_delete.cpp) +endif() + if (LIBCXXABI_ENABLE_EXCEPTIONS) list(APPEND LIBCXXABI_SOURCES cxa_exception.cpp) list(APPEND LIBCXXABI_SOURCES cxa_personality.cpp) @@ -24,7 +31,7 @@ else() list(APPEND LIBCXXABI_SOURCES cxa_noexception.cpp) endif() -if (UNIX AND NOT (APPLE OR CYGWIN)) +if (LIBCXXABI_ENABLE_THREADS AND UNIX AND NOT (APPLE OR CYGWIN)) list(APPEND LIBCXXABI_SOURCES cxa_thread_atexit.cpp) endif() @@ -45,24 +52,32 @@ if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) endif() -# Generate library list -set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES}) - if (LIBCXXABI_ENABLE_THREADS) - append_if(libraries LIBCXXABI_HAS_PTHREAD_LIB pthread) + add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) endif() -append_if(libraries LIBCXXABI_HAS_C_LIB c) - +add_library_flags_if(LIBCXXABI_HAS_C_LIB c) if (LIBCXXABI_USE_LLVM_UNWINDER) - list(APPEND libraries unwind) + # Prefer using the in-tree version of libunwind, either shared or static. If + # none are found fall back to using -lunwind. + # FIXME: Is it correct to prefer the static version of libunwind? + if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) + list(APPEND LIBCXXABI_LIBRARIES unwind_shared) + elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND)) + list(APPEND LIBCXXABI_LIBRARIES unwind_static) + else() + list(APPEND LIBCXXABI_LIBRARIES unwind) + endif() else() - append_if(libraries LIBCXXABI_HAS_GCC_S_LIB gcc_s) + add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) +endif() +if (MINGW) + # MINGW_LIBRARIES is defined in config-ix.cmake + list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) endif() # Setup flags. -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_FPIC_FLAG -fPIC) -append_if(LIBCXXABI_LINK_FLAGS LIBCXXABI_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs) +add_link_flags_if_supported(-nodefaultlibs) set(LIBCXXABI_SHARED_LINK_FLAGS) @@ -82,58 +97,108 @@ if ( APPLE ) endif() endif() -string(REPLACE ";" " " LIBCXXABI_COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_SHARED_LINK_FLAGS "${LIBCXXABI_SHARED_LINK_FLAGS}") +split_list(LIBCXXABI_COMPILE_FLAGS) +split_list(LIBCXXABI_LINK_FLAGS) +split_list(LIBCXXABI_SHARED_LINK_FLAGS) + +# FIXME: libc++abi.so will not link when modules are enabled because it depends +# on symbols defined in libc++.so which has not yet been built. +if (LLVM_ENABLE_MODULES) + string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") +endif() # Add a object library that contains the compiled source files. add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - set_target_properties(cxxabi_objects - PROPERTIES - COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + COMPILE_FLAGS + "${LIBCXXABI_COMPILE_FLAGS}" + POSITION_INDEPENDENT_CODE + ON) set(LIBCXXABI_TARGETS) # Build the shared library. if (LIBCXXABI_ENABLE_SHARED) add_library(cxxabi_shared SHARED $) - target_link_libraries(cxxabi_shared ${libraries}) + target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_shared - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - VERSION "1.0" - SOVERSION "1" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON + SOVERSION + "1" + VERSION + "1.0") list(APPEND LIBCXXABI_TARGETS "cxxabi_shared") endif() # Build the static library. if (LIBCXXABI_ENABLE_STATIC) - add_library(cxxabi_static STATIC $) - target_link_libraries(cxxabi_static ${libraries}) + set(cxxabi_static_sources $) + if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_ENABLE_STATIC_UNWINDER) + if (TARGET unwind_static OR HAVE_LIBUNWIND) + list(APPEND cxxabi_static_sources $) + endif() + endif() + add_library(cxxabi_static STATIC ${cxxabi_static_sources}) + target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_static - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON) list(APPEND LIBCXXABI_TARGETS "cxxabi_static") endif() # Add a meta-target for both libraries. add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS}) -install(TARGETS ${LIBCXXABI_TARGETS} - LIBRARY DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT libcxxabi - ARCHIVE DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT libcxxabi - ) +if (LIBCXXABI_INSTALL_LIBRARY) + install(TARGETS ${LIBCXXABI_TARGETS} + LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ) +endif() -if (NOT CMAKE_CONFIGURATION_TYPES) - add_custom_target(install-libcxxabi +if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY) + add_custom_target(install-cxxabi DEPENDS cxxabi COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=libcxxabi + -DCMAKE_INSTALL_COMPONENT=cxxabi -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") + add_custom_target(install-cxxabi-stripped + DEPENDS cxxabi + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=cxxabi + -DCMAKE_INSTALL_DO_STRIP=1 + -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") + + # TODO: This is a legacy target name and should be removed at some point. + add_custom_target(install-libcxxabi DEPENDS install-cxxabi) endif() diff --git a/lib/libcxxabi/src/abort_message.cpp b/lib/libcxxabi/src/abort_message.cpp index 5e25c0f3472..7a2a9f835bd 100644 --- a/lib/libcxxabi/src/abort_message.cpp +++ b/lib/libcxxabi/src/abort_message.cpp @@ -22,8 +22,6 @@ extern "C" void android_set_abort_message(const char* msg); #endif // __ANDROID_API__ >= 21 #endif // __BIONIC__ -#pragma GCC visibility push(hidden) - #ifdef __APPLE__ # if defined(__has_include) && __has_include() # define HAVE_CRASHREPORTERCLIENT_H @@ -31,10 +29,10 @@ extern "C" void android_set_abort_message(const char* msg); # endif #endif -__attribute__((visibility("hidden"), noreturn)) void abort_message(const char* format, ...) { // write message to stderr +#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) #ifdef __APPLE__ fprintf(stderr, "libc++abi.dylib: "); #endif @@ -43,6 +41,7 @@ void abort_message(const char* format, ...) vfprintf(stderr, format, list); va_end(list); fprintf(stderr, "\n"); +#endif #if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H) // record message in crash report @@ -77,5 +76,3 @@ void abort_message(const char* format, ...) abort(); } - -#pragma GCC visibility pop diff --git a/lib/libcxxabi/src/abort_message.h b/lib/libcxxabi/src/abort_message.h index 2c5cb204664..e8f9571cb56 100644 --- a/lib/libcxxabi/src/abort_message.h +++ b/lib/libcxxabi/src/abort_message.h @@ -10,24 +10,18 @@ #ifndef __ABORT_MESSAGE_H_ #define __ABORT_MESSAGE_H_ -#include - -#pragma GCC visibility push(hidden) +#include "cxxabi.h" #ifdef __cplusplus extern "C" { #endif -__attribute__((visibility("hidden"), noreturn)) - void abort_message(const char* format, ...) - __attribute__((format(printf, 1, 2))); - +_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void +abort_message(const char *format, ...) __attribute__((format(printf, 1, 2))); #ifdef __cplusplus } #endif -#pragma GCC visibility pop - #endif diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp index bb7c9f1255c..878d3bd034d 100644 --- a/lib/libcxxabi/src/cxa_aux_runtime.cpp +++ b/lib/libcxxabi/src/cxa_aux_runtime.cpp @@ -16,7 +16,7 @@ namespace __cxxabiv1 { extern "C" { -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_cast(void) { +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) { #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_cast(); #else @@ -24,7 +24,7 @@ _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_cast(void) { #endif } -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_typeid(); #else @@ -32,7 +32,7 @@ _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { #endif } -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw_bad_array_new_length(void) { #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_array_new_length(); diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp index 09350e7721a..f2e36b4bc83 100644 --- a/lib/libcxxabi/src/cxa_default_handlers.cpp +++ b/lib/libcxxabi/src/cxa_default_handlers.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include "abort_message.h" -#include "config.h" // For __sync_swap #include "cxxabi.h" #include "cxa_handlers.hpp" #include "cxa_exception.hpp" @@ -22,7 +22,7 @@ static const char* cause = "uncaught"; __attribute__((noreturn)) -static void default_terminate_handler() +static void demangling_terminate_handler() { // If there might be an uncaught exception using namespace __cxxabiv1; @@ -78,12 +78,19 @@ static void default_terminate_handler() } __attribute__((noreturn)) -static void default_unexpected_handler() +static void demangling_unexpected_handler() { cause = "unexpected"; std::terminate(); } +#if !defined(LIBCXXABI_SILENT_TERMINATE) +static std::terminate_handler default_terminate_handler = demangling_terminate_handler; +static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler; +#else +static std::terminate_handler default_terminate_handler = std::abort; +static std::terminate_handler default_unexpected_handler = std::terminate; +#endif // // Global variables that hold the pointers to the current handler diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp index 25aa741299a..9cfd99607bf 100644 --- a/lib/libcxxabi/src/cxa_demangle.cpp +++ b/lib/libcxxabi/src/cxa_demangle.cpp @@ -7,15 +7,20 @@ // //===----------------------------------------------------------------------===// -#define _LIBCPP_EXTERN_TEMPLATE(...) +// FIXME: (possibly) incomplete list of features that clang mangles that this +// file does not yet support: +// - enable_if attribute +// - decomposition declarations +// - C++ modules TS + #define _LIBCPP_NO_EXCEPTIONS #include "__cxxabi_config.h" #include #include -#include #include +#include #include #include #include @@ -42,75 +47,1685 @@ enum success }; -template - const char* parse_type(const char* first, const char* last, C& db); -template - const char* parse_encoding(const char* first, const char* last, C& db); -template - const char* parse_name(const char* first, const char* last, C& db, - bool* ends_with_template_args = 0); -template - const char* parse_expression(const char* first, const char* last, C& db); -template - const char* parse_template_args(const char* first, const char* last, C& db); -template - const char* parse_operator_name(const char* first, const char* last, C& db); -template - const char* parse_unqualified_name(const char* first, const char* last, C& db); -template - const char* parse_decltype(const char* first, const char* last, C& db); - -template -void -print_stack(const C& db) +class StringView { + const char *First; + const char *Last; + +public: + template + StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} + StringView(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + StringView() : First(nullptr), Last(nullptr) {} + + StringView substr(size_t From, size_t To) { + if (To >= size()) + To = size() - 1; + if (From >= size()) + From = size() - 1; + return StringView(First + From, First + To); + } + + StringView dropFront(size_t N) const { + if (N >= size()) + N = size() - 1; + return StringView(First + N, Last); + } + + bool startsWith(StringView Str) const { + if (Str.size() > size()) + return false; + return std::equal(Str.begin(), Str.end(), begin()); + } + + const char &operator[](size_t Idx) const { return *(begin() + Idx); } + + const char *begin() const { return First; } + const char *end() const { return Last; } + size_t size() const { return static_cast(Last - First); } +}; + +bool operator==(const StringView &LHS, const StringView &RHS) { + return LHS.size() == RHS.size() && + std::equal(LHS.begin(), LHS.end(), RHS.begin()); +} + +// Stream that AST nodes write their string representation into after the AST +// has been parsed. +class OutputStream { + char *Buffer; + size_t CurrentPosition; + size_t BufferCapacity; + + // Ensure there is at least n more positions in buffer. + void grow(size_t N) { + if (N + CurrentPosition >= BufferCapacity) { + BufferCapacity *= 2; + if (BufferCapacity < N + CurrentPosition) + BufferCapacity = N + CurrentPosition; + Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); + } + } + +public: + OutputStream(char *StartBuf, size_t Size) + : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} + + OutputStream &operator+=(StringView R) { + size_t Size = R.size(); + if (Size == 0) + return *this; + grow(Size); + memmove(Buffer + CurrentPosition, R.begin(), Size); + CurrentPosition += Size; + return *this; + } + + OutputStream &operator+=(char C) { + grow(1); + Buffer[CurrentPosition++] = C; + return *this; + } + + // Offset of position in buffer, used for building stream_string_view. + typedef unsigned StreamPosition; + + // StringView into a stream, used for caching the ast nodes. + class StreamStringView { + StreamPosition First, Last; + + friend class OutputStream; + + public: + StreamStringView() : First(0), Last(0) {} + + StreamStringView(StreamPosition First_, StreamPosition Last_) + : First(First_), Last(Last_) {} + + bool empty() const { return First == Last; } + }; + + OutputStream &operator+=(StreamStringView &s) { + size_t Sz = static_cast(s.Last - s.First); + if (Sz == 0) + return *this; + grow(Sz); + memmove(Buffer + CurrentPosition, Buffer + s.First, Sz); + CurrentPosition += Sz; + return *this; + } + + StreamPosition getCurrentPosition() const { + return static_cast(CurrentPosition); + } + + StreamStringView makeStringViewFromPastPosition(StreamPosition Pos) { + return StreamStringView(Pos, getCurrentPosition()); + } + + char back() const { + return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + } + + bool empty() const { return CurrentPosition == 0; } + + char *getBuffer() { return Buffer; } + char *getBufferEnd() { return Buffer + CurrentPosition - 1; } + size_t getBufferCapacity() { return BufferCapacity; } +}; + +// Base class of all AST nodes. The AST is built by the parser, then is +// traversed by the printLeft/Right functions to produce a demangled string. +class Node { +public: + enum Kind : unsigned char { + KDotSuffix, + KVendorExtQualType, + KQualType, + KConversionOperatorType, + KPostfixQualifiedType, + KNameType, + KAbiTagAttr, + KObjCProtoName, + KPointerType, + KLValueReferenceType, + KRValueReferenceType, + KPointerToMemberType, + KArrayType, + KFunctionType, + KTopLevelFunctionDecl, + KFunctionQualType, + KFunctionRefQualType, + KLiteralOperator, + KSpecialName, + KCtorVtableSpecialName, + KQualifiedName, + KEmptyName, + KVectorType, + KTemplateParams, + KNameWithTemplateArgs, + KGlobalQualifiedName, + KStdQualifiedName, + KExpandedSpecialSubstitution, + KSpecialSubstitution, + KCtorDtorName, + KDtorName, + KUnnamedTypeName, + KLambdaTypeName, + KExpr, + }; + + const Kind K; + +private: + // If this Node has any RHS part, potentally many Nodes further down. + const unsigned HasRHSComponent : 1; + const unsigned HasFunction : 1; + const unsigned HasArray : 1; + +public: + Node(Kind K_, bool HasRHS_ = false, bool HasFunction_ = false, + bool HasArray_ = false) + : K(K_), HasRHSComponent(HasRHS_), HasFunction(HasFunction_), + HasArray(HasArray_) {} + + bool hasRHSComponent() const { return HasRHSComponent; } + bool hasArray() const { return HasArray; } + bool hasFunction() const { return HasFunction; } + + void print(OutputStream &s) const { + printLeft(s); + if (hasRHSComponent()) + printRight(s); + } + + // Print the "left" side of this Node into OutputStream. + virtual void printLeft(OutputStream &) const = 0; + + // Print the "right". This distinction is necessary to represent C++ types + // that appear on the RHS of their subtype, such as arrays or functions. + // Since most types don't have such a component, provide a default + // implemenation. + virtual void printRight(OutputStream &) const {} + + virtual StringView getBaseName() const { return StringView(); } + + // Silence compiler warnings, this dtor will never be called. + virtual ~Node() = default; +}; + +class NodeArray { + Node **Elements; + size_t NumElements; + +public: + NodeArray() : NumElements(0) {} + NodeArray(Node **Elements_, size_t NumElements_) + : Elements(Elements_), NumElements(NumElements_) {} + + bool empty() const { return NumElements == 0; } + size_t size() const { return NumElements; } + + void printWithSeperator(OutputStream &S, StringView Seperator) const { + for (size_t Idx = 0; Idx != NumElements; ++Idx) { + if (Idx) + S += Seperator; + Elements[Idx]->print(S); + } + } +}; + +class DotSuffix final : public Node { + const Node *Prefix; + const StringView Suffix; + +public: + DotSuffix(Node *Prefix_, StringView Suffix_) + : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} + + void printLeft(OutputStream &s) const override { + Prefix->print(s); + s += " ("; + s += Suffix; + s += ")"; + } +}; + +class VendorExtQualType final : public Node { + const Node *Ext; + const Node *Ty; + +public: + VendorExtQualType(Node *Ext_, Node *Ty_) + : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + Ext->print(S); + S += " "; + Ty->printLeft(S); + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +enum Qualifiers { + QualNone = 0, + QualConst = 0x1, + QualVolatile = 0x2, + QualRestrict = 0x4, +}; + +void addQualifiers(Qualifiers &Q1, Qualifiers Q2) { + Q1 = static_cast(Q1 | Q2); +} + +class QualType : public Node { +protected: + const Qualifiers Quals; + const Node *Child; + + void printQuals(OutputStream &S) const { + if (Quals & QualConst) + S += " const"; + if (Quals & QualVolatile) + S += " volatile"; + if (Quals & QualRestrict) + S += " restrict"; + } + +public: + QualType(Node *Child_, Qualifiers Quals_) + : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + QualType(Node::Kind ChildKind_, Node *Child_, Qualifiers Quals_) + : Node(ChildKind_, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + Child->printLeft(S); + printQuals(S); + } + + void printRight(OutputStream &S) const override { Child->printRight(S); } +}; + +class ConversionOperatorType final : public Node { + const Node *Ty; + +public: + ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + S += "operator "; + Ty->print(S); + } +}; + +class PostfixQualifiedType final : public Node { + const Node *Ty; + const StringView Postfix; + +public: + PostfixQualifiedType(Node *Ty_, StringView Postfix_) + : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} + + void printLeft(OutputStream &s) const override { + Ty->printLeft(s); + s += Postfix; + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +class NameType final : public Node { + const StringView Name; + +public: + NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + + StringView getName() const { return Name; } + StringView getBaseName() const override { return Name; } + + void printLeft(OutputStream &s) const override { s += Name; } +}; + +class AbiTagAttr final : public Node { + const Node* Base; + StringView Tag; +public: + AbiTagAttr(const Node* Base_, StringView Tag_) + : Node(KAbiTagAttr), Base(Base_), Tag(Tag_) {} + + void printLeft(OutputStream &S) const override { + Base->printLeft(S); + S += "[abi:"; + S += Tag; + S += "]"; + } +}; + +class ObjCProtoName : public Node { + Node *Ty; + Node *Protocol; + + friend class PointerType; + +public: + ObjCProtoName(Node *Ty_, Node *Protocol_) + : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + + bool isObjCObject() const { + return Ty->K == KNameType && + static_cast(Ty)->getName() == "objc_object"; + } + + void printLeft(OutputStream &S) const override { + Ty->printLeft(S); + S += "<"; + Protocol->printLeft(S); + S += ">"; + } +}; + +class PointerType final : public Node { + const Node *Pointee; + +public: + PointerType(Node *Pointee_) + : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + // We rewrite objc_object* into id. + if (Pointee->K != KObjCProtoName || + !static_cast(Pointee)->isObjCObject()) { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "("; + s += "*"; + } else { + const auto *objcProto = static_cast(Pointee); + s += "id<"; + objcProto->Protocol->print(s); + s += ">"; + } + } + + void printRight(OutputStream &s) const override { + if (Pointee->K != KObjCProtoName || + !static_cast(Pointee)->isObjCObject()) { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } + } +}; + +class LValueReferenceType final : public Node { + const Node *Pointee; + +public: + LValueReferenceType(Node *Pointee_) + : Node(KLValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&"; + else + s += "&"; + } + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class RValueReferenceType final : public Node { + const Node *Pointee; + +public: + RValueReferenceType(Node *Pointee_) + : Node(KRValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&&"; + else + s += "&&"; + } + + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class PointerToMemberType final : public Node { + const Node *ClassType; + const Node *MemberType; + +public: + PointerToMemberType(Node *ClassType_, Node *MemberType_) + : Node(KPointerToMemberType, MemberType_->hasRHSComponent()), + ClassType(ClassType_), MemberType(MemberType_) {} + + void printLeft(OutputStream &s) const override { + MemberType->printLeft(s); + if (MemberType->hasArray() || MemberType->hasFunction()) + s += "("; + else + s += " "; + ClassType->print(s); + s += "::*"; + } + + void printRight(OutputStream &s) const override { + if (MemberType->hasArray() || MemberType->hasFunction()) + s += ")"; + MemberType->printRight(s); + } +}; + +class NodeOrString { + const void *First; + const void *Second; + +public: + /* implicit */ NodeOrString(StringView Str) { + const char *FirstChar = Str.begin(); + const char *SecondChar = Str.end(); + if (SecondChar == nullptr) { + assert(FirstChar == SecondChar); + ++FirstChar, ++SecondChar; + } + First = static_cast(FirstChar); + Second = static_cast(SecondChar); + } + + /* implicit */ NodeOrString(Node *N) + : First(static_cast(N)), Second(nullptr) {} + NodeOrString() : First(nullptr), Second(nullptr) {} + + bool isString() const { return Second && First; } + bool isNode() const { return First && !Second; } + bool isEmpty() const { return !First && !Second; } + + StringView asString() const { + assert(isString()); + return StringView(static_cast(First), + static_cast(Second)); + } + + const Node *asNode() const { + assert(isNode()); + return static_cast(First); + } +}; + +class ArrayType final : public Node { + Node *Base; + NodeOrString Dimension; + +public: + ArrayType(Node *Base_, NodeOrString Dimension_) + : Node(KArrayType, true, false, true), Base(Base_), Dimension(Dimension_) {} + + // Incomplete array type. + ArrayType(Node *Base_) : Node(KArrayType, true, false, true), Base(Base_) {} + + void printLeft(OutputStream &S) const override { Base->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (S.back() != ']') + S += " "; + S += "["; + if (Dimension.isString()) + S += Dimension.asString(); + else if (Dimension.isNode()) + Dimension.asNode()->print(S); + S += "]"; + Base->printRight(S); + } +}; + +class FunctionType final : public Node { + Node *Ret; + NodeArray Params; + +public: + FunctionType(Node *Ret_, NodeArray Params_) + : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {} + + // Handle C++'s ... quirky decl grammer by using the left & right + // distinction. Consider: + // int (*f(float))(char) {} + // f is a function that takes a float and returns a pointer to a function + // that takes a char and returns an int. If we're trying to print f, start + // by printing out the return types's left, then print our parameters, then + // finally print right of the return type. + void printLeft(OutputStream &S) const override { + Ret->printLeft(S); + S += " "; + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + Ret->printRight(S); + } +}; + +class TopLevelFunctionDecl final : public Node { + const Node *Ret; + const Node *Name; + NodeArray Params; + +public: + TopLevelFunctionDecl(Node *Ret_, Node *Name_, NodeArray Params_) + : Node(KTopLevelFunctionDecl, true, true), Ret(Ret_), Name(Name_), + Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (Ret) { + Ret->printLeft(S); + if (!Ret->hasRHSComponent()) + S += " "; + } + Name->print(S); + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + if (Ret) + Ret->printRight(S); + } +}; + +enum FunctionRefQual : unsigned char { + FrefQualNone, + FrefQualLValue, + FrefQualRValue, +}; + +class FunctionRefQualType : public Node { + Node *Fn; + FunctionRefQual Quals; + + friend class FunctionQualType; + +public: + FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_) + : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {} + + void printQuals(OutputStream &S) const { + if (Quals == FrefQualLValue) + S += " &"; + else + S += " &&"; + } + + void printLeft(OutputStream &S) const override { Fn->printLeft(S); } + + void printRight(OutputStream &S) const override { + Fn->printRight(S); + printQuals(S); + } +}; + +class FunctionQualType final : public QualType { +public: + FunctionQualType(Node *Child_, Qualifiers Quals_) + : QualType(KFunctionQualType, Child_, Quals_) {} + + void printLeft(OutputStream &S) const override { Child->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (Child->K == KFunctionRefQualType) { + auto *RefQuals = static_cast(Child); + RefQuals->Fn->printRight(S); + printQuals(S); + RefQuals->printQuals(S); + } else { + Child->printRight(S); + printQuals(S); + } + } +}; + +class LiteralOperator : public Node { + const Node *OpName; + +public: + LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {} + + void printLeft(OutputStream &S) const override { + S += "operator\"\" "; + OpName->print(S); + } +}; + +class SpecialName final : public Node { + const StringView Special; + const Node *Child; + +public: + SpecialName(StringView Special_, Node *Child_) + : Node(KSpecialName), Special(Special_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Special; + Child->print(S); + } +}; + +class CtorVtableSpecialName final : public Node { + const Node *FirstType; + const Node *SecondType; + +public: + CtorVtableSpecialName(Node *FirstType_, Node *SecondType_) + : Node(KCtorVtableSpecialName), FirstType(FirstType_), + SecondType(SecondType_) {} + + void printLeft(OutputStream &S) const override { + S += "construction vtable for "; + FirstType->print(S); + S += "-in-"; + SecondType->print(S); + } +}; + +class QualifiedName final : public Node { + // qualifier::name + const Node *Qualifier; + const Node *Name; + + mutable OutputStream::StreamStringView Cache; + +public: + QualifiedName(Node *Qualifier_, Node *Name_) + : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + if (Qualifier->K != KEmptyName) { + Qualifier->print(S); + S += "::"; + } + Name->print(S); + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class EmptyName : public Node { +public: + EmptyName() : Node(KEmptyName) {} + void printLeft(OutputStream &) const override {} +}; + +class VectorType final : public Node { + const Node *BaseType; + const NodeOrString Dimension; + const bool IsPixel; + +public: + VectorType(NodeOrString Dimension_) + : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_), + IsPixel(true) {} + VectorType(Node *BaseType_, NodeOrString Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_), + IsPixel(false) {} + + void printLeft(OutputStream &S) const override { + if (IsPixel) { + S += "pixel vector["; + S += Dimension.asString(); + S += "]"; + } else { + BaseType->print(S); + S += " vector["; + if (Dimension.isNode()) + Dimension.asNode()->print(S); + else if (Dimension.isString()) + S += Dimension.asString(); + S += "]"; + } + } +}; + +class TemplateParams final : public Node { + NodeArray Params; + + mutable OutputStream::StreamStringView Cache; + +public: + TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + + S += "<"; + Params.printWithSeperator(S, ", "); + if (S.back() == '>') + S += " "; + S += ">"; + + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class NameWithTemplateArgs final : public Node { + // name + Node *Name; + Node *TemplateArgs; + +public: + NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) + : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Name->print(S); + TemplateArgs->print(S); + } +}; + +class GlobalQualifiedName final : public Node { + Node *Child; + +public: + GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "::"; + Child->print(S); + } +}; + +class StdQualifiedName final : public Node { + Node *Child; + +public: + StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "std::"; + Child->print(S); + } +}; + +enum class SpecialSubKind { + allocator, + basic_string, + string, + istream, + ostream, + iostream, +}; + +class ExpandedSpecialSubstitution final : public Node { + SpecialSubKind SSK; + +public: + ExpandedSpecialSubstitution(SpecialSubKind SSK_) + : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("basic_string"); + case SpecialSubKind::istream: + return StringView("basic_istream"); + case SpecialSubKind::ostream: + return StringView("basic_ostream"); + case SpecialSubKind::iostream: + return StringView("basic_iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::basic_string, " + "std::allocator >"; + break; + case SpecialSubKind::basic_string: + case SpecialSubKind::string: + S += "std::basic_string, " + "std::allocator >"; + break; + case SpecialSubKind::istream: + S += "std::basic_istream >"; + break; + case SpecialSubKind::ostream: + S += "std::basic_ostream >"; + break; + case SpecialSubKind::iostream: + S += "std::basic_iostream >"; + break; + } + } +}; + +class SpecialSubstitution final : public Node { +public: + SpecialSubKind SSK; + + SpecialSubstitution(SpecialSubKind SSK_) + : Node(KSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("string"); + case SpecialSubKind::istream: + return StringView("istream"); + case SpecialSubKind::ostream: + return StringView("ostream"); + case SpecialSubKind::iostream: + return StringView("iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + case SpecialSubKind::string: + S += "std::string"; + break; + case SpecialSubKind::istream: + S += "std::istream"; + break; + case SpecialSubKind::ostream: + S += "std::ostream"; + break; + case SpecialSubKind::iostream: + S += "std::iostream"; + break; + } + } +}; + +class CtorDtorName final : public Node { + const Node *Basename; + const bool IsDtor; + +public: + CtorDtorName(Node *Basename_, bool IsDtor_) + : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {} + + void printLeft(OutputStream &S) const override { + if (IsDtor) + S += "~"; + S += Basename->getBaseName(); + } +}; + +class DtorName : public Node { + const Node *Base; + +public: + DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {} + + void printLeft(OutputStream &S) const override { + S += "~"; + Base->printLeft(S); + } +}; + +class UnnamedTypeName : public Node { + const StringView Count; + +public: + UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "'unnamed"; + S += Count; + S += "\'"; + } +}; + +class LambdaTypeName : public Node { + NodeArray Params; + StringView Count; + +public: + LambdaTypeName(NodeArray Params_, StringView Count_) + : Node(KLambdaTypeName), Params(Params_), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "\'lambda"; + S += Count; + S += "\'("; + Params.printWithSeperator(S, ", "); + S += ")"; + } +}; + +// -- Expression Nodes -- + +struct Expr : public Node { + Expr() : Node(KExpr) {} +}; + +class BinaryExpr : public Expr { + const Node *LHS; + const StringView InfixOperator; + const Node *RHS; + +public: + BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_) + : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + // might be a template argument expression, then we need to disambiguate + // with parens. + if (InfixOperator == ">") + S += "("; + + S += "("; + LHS->print(S); + S += ") "; + S += InfixOperator; + S += " ("; + RHS->print(S); + S += ")"; + + if (InfixOperator == ">") + S += ")"; + } +}; + +class ArraySubscriptExpr : public Expr { + const Node *Op1; + const Node *Op2; + +public: + ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Op1->print(S); + S += ")["; + Op2->print(S); + S += "]"; + } +}; + +class PostfixExpr : public Expr { + const Node *Child; + const StringView Operand; + +public: + PostfixExpr(Node *Child_, StringView Operand_) + : Child(Child_), Operand(Operand_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Child->print(S); + S += ")"; + S += Operand; + } +}; + +class ConditionalExpr : public Expr { + const Node *Cond; + const Node *Then; + const Node *Else; + +public: + ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_) + : Cond(Cond_), Then(Then_), Else(Else_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Cond->print(S); + S += ") ? ("; + Then->print(S); + S += ") : ("; + Else->print(S); + S += ")"; + } +}; + +class MemberExpr : public Expr { + const Node *LHS; + const StringView Kind; + const Node *RHS; + +public: + MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_) + : LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + LHS->print(S); + S += Kind; + RHS->print(S); + } +}; + +class EnclosingExpr : public Expr { + const StringView Prefix; + const Node *Infix; + const StringView Postfix; + +public: + EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) + : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + Infix->print(S); + S += Postfix; + } +}; + +class CastExpr : public Expr { + // cast_kind(from) + const StringView CastKind; + const Node *To; + const Node *From; + +public: + CastExpr(StringView CastKind_, Node *To_, Node *From_) + : CastKind(CastKind_), To(To_), From(From_) {} + + void printLeft(OutputStream &S) const override { + S += CastKind; + S += "<"; + To->printLeft(S); + S += ">("; + From->printLeft(S); + S += ")"; + } +}; + +class SizeofParamPackExpr : public Expr { + NodeArray Args; + +public: + SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {} + + void printLeft(OutputStream &S) const override { + S += "sizeof...("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class CallExpr : public Expr { + const Node *Callee; + NodeArray Args; + +public: + CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {} + + void printLeft(OutputStream &S) const override { + Callee->print(S); + S += "("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class NewExpr : public Expr { + // new (expr_list) type(init_list) + NodeArray ExprList; + Node *Type; + NodeArray InitList; + bool IsGlobal; // ::operator new ? + bool IsArray; // new[] ? +public: + NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, + bool IsArray_) + : ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::operator "; + S += "new"; + if (IsArray) + S += "[]"; + if (!ExprList.empty()) { + S += "("; + ExprList.printWithSeperator(S, ", "); + S += ")"; + } + Type->print(S); + if (!InitList.empty()) { + S += "("; + InitList.printWithSeperator(S, ", "); + S += ")"; + } + } +}; + +class DeleteExpr : public Expr { + Node *Op; + bool IsGlobal; + bool IsArray; + +public: + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) + : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::"; + S += "delete"; + if (IsArray) + S += "[] "; + Op->print(S); + } +}; + +class PrefixExpr : public Expr { + StringView Prefix; + Node *Child; + +public: + PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + S += "("; + Child->print(S); + S += ")"; + } +}; + +class FunctionParam : public Expr { + StringView Number; + +public: + FunctionParam(StringView Number_) : Number(Number_) {} + + void printLeft(OutputStream &S) const override { + S += "fp"; + S += Number; + } +}; + +class ExprList : public Expr { + NodeArray SubExprs; + +public: + ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + SubExprs.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ConversionExpr : public Expr { + NodeArray Expressions; + NodeArray Types; + +public: + ConversionExpr(NodeArray Expressions_, NodeArray Types_) + : Expressions(Expressions_), Types(Types_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Expressions.printWithSeperator(S, ", "); + S += ")("; + Types.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ThrowExpr : public Expr { + const Node *Op; + +public: + ThrowExpr(Node *Op_) : Op(Op_) {} + + void printLeft(OutputStream &S) const override { + S += "throw "; + Op->print(S); + } +}; + +class BoolExpr : public Expr { + bool Value; + +public: + BoolExpr(bool Value_) : Value(Value_) {} + + void printLeft(OutputStream &S) const override { + S += Value ? StringView("true") : StringView("false"); + } +}; + +class IntegerCastExpr : public Expr { + // ty(integer) + Node *Ty; + StringView Integer; + +public: + IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Ty->print(S); + S += ")"; + S += Integer; + } +}; + +class IntegerExpr : public Expr { + StringView Type; + StringView Value; + +public: + IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {} + + void printLeft(OutputStream &S) const override { + if (Type.size() > 3) { + S += "("; + S += Type; + S += ")"; + } + + if (Value[0] == 'n') { + S += "-"; + S += Value.dropFront(1); + } else + S += Value; + + if (Type.size() <= 3) + S += Type; + } +}; + +template struct FloatData; + +template class FloatExpr : public Expr { + const StringView Contents; + +public: + FloatExpr(StringView Contents_) : Contents(Contents_) {} + + void printLeft(OutputStream &s) const override { + const char *first = Contents.begin(); + const char *last = Contents.end() + 1; + + const size_t N = FloatData::mangled_size; + if (static_cast(last - first) > N) { + last = first + N; + union { + Float value; + char buf[sizeof(Float)]; + }; + const char *t = first; + char *e = buf; + for (; t != last; ++t, ++e) { + unsigned d1 = isdigit(*t) ? static_cast(*t - '0') + : static_cast(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast(*t - '0') + : static_cast(*t - 'a' + 10); + *e = static_cast((d1 << 4) + d0); + } +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[FloatData::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), FloatData::spec, value); + s += StringView(num, num + n); + } + } +}; + +class BumpPointerAllocator { + struct BlockMeta { + BlockMeta* Next; + size_t Current; + }; + + static constexpr size_t AllocSize = 4096; + static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); + + alignas(16) char InitialBuffer[AllocSize]; + BlockMeta* BlockList = nullptr; + + void grow() { + char* NewMeta = new char[AllocSize]; + BlockList = new (NewMeta) BlockMeta{BlockList, 0}; + } + + void* allocateMassive(size_t NBytes) { + NBytes += sizeof(BlockMeta); + BlockMeta* NewMeta = reinterpret_cast(new char[NBytes]); + BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; + return static_cast(NewMeta + 1); + } + +public: + BumpPointerAllocator() + : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} + + void* allocate(size_t N) { + N = (N + 15u) & ~15u; + if (N + BlockList->Current >= UsableAllocSize) { + if (N > UsableAllocSize) + return allocateMassive(N); + grow(); + } + BlockList->Current += N; + return static_cast(reinterpret_cast(BlockList + 1) + + BlockList->Current - N); + } + + ~BumpPointerAllocator() { + while (BlockList) { + BlockMeta* Tmp = BlockList; + BlockList = BlockList->Next; + if (reinterpret_cast(Tmp) != InitialBuffer) + delete[] reinterpret_cast(Tmp); + } + } +}; + +template +class PODSmallVector { + static_assert(std::is_pod::value, + "T is required to be a plain old data type"); + + T* First; + T* Last; + T* Cap; + T Inline[N]; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); + std::copy(First, Last, Tmp); + First = Tmp; + } else + First = static_cast(std::realloc(First, NewCap * sizeof(T))); + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector&) = delete; + PODSmallVector& operator=(const PODSmallVector&) = delete; + + PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector& operator=(PODSmallVector&& Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + void push_back(const T& Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T* begin() { return First; } + T* end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast(Last - First); } + T& back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T& operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + +// Substitution table. This type is used to track the substitutions that are +// known by the parser. +template +class SubstitutionTable { + // Substitutions hold the actual entries in the table, and PackIndices tells + // us which entries are members of which pack. For example, if the + // substitutions we're tracking are: {int, {float, FooBar}, char}, with + // {float, FooBar} being a parameter pack, we represent the substitutions as: + // Substitutions: int, float, FooBar, char + // PackIndices: 0, 1, 3 + // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and + // PackIndices[I + 1] holds the offset of the end. + PODSmallVector Substitutions; + PODSmallVector PackIndices; + +public: + // Add a substitution that represents a single name to the table. This is + // modeled as a parameter pack with just one element. + void pushSubstitution(Node* Entry) { + pushPack(); + pushSubstitutionIntoPack(Entry); + } + + // Add a new empty pack to the table. Subsequent calls to + // pushSubstitutionIntoPack() will add to this pack. + void pushPack() { + PackIndices.push_back(static_cast(Substitutions.size())); + } + void pushSubstitutionIntoPack(Node* Entry) { + assert(!PackIndices.empty() && "No pack to push substitution into!"); + Substitutions.push_back(Entry); + } + + // Remove the last pack from the table. + void popPack() { + unsigned Last = PackIndices.back(); + PackIndices.pop_back(); + Substitutions.dropBack(Last); + } + + // For use in a range-for loop. + struct NodeRange { + Node** First; + Node** Last; + Node** begin() { return First; } + Node** end() { return Last; } + }; + + // Retrieve the Nth substitution. This is represented as a range, as the + // substitution could be referring to a parameter pack. + NodeRange nthSubstitution(size_t N) { + assert(PackIndices[N] <= Substitutions.size()); + // The Nth parameter pack starts at offset PackIndices[N], and ends at + // PackIndices[N + 1]. + Node** Begin = Substitutions.begin() + PackIndices[N]; + Node** End; + if (N + 1 != PackIndices.size()) { + assert(PackIndices[N + 1] <= Substitutions.size()); + End = Substitutions.begin() + PackIndices[N + 1]; + } else + End = Substitutions.end(); + assert(Begin <= End); + return NodeRange{Begin, End}; + } + + size_t size() const { return PackIndices.size(); } + bool empty() const { return PackIndices.empty(); } + void clear() { + Substitutions.clear(); + PackIndices.clear(); + } +}; + +struct Db { - fprintf(stderr, "---------\n"); - fprintf(stderr, "names:\n"); - for (auto& s : db.names) - fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - fprintf(stderr, "subs:\n"); - for (auto& v : db.subs) + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser colapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 42nd entry in this table. + SubstitutionTable<32> Subs; + + // Template parameter table. Like the above, but referenced like "T42_". + // This has a smaller size compared to Subs and Names because it can be + // stored on the stack. + SubstitutionTable<4> TemplateParams; + + Qualifiers CV = QualNone; + FunctionRefQual RefQuals = FrefQualNone; + unsigned EncodingDepth = 0; + bool ParsedCtorDtorCV = false; + bool TagTemplates = true; + bool FixForwardReferences = false; + bool TryToParseTemplateArgs = true; + + BumpPointerAllocator ASTAllocator; + + template T* make(Args&& ...args) { - if (i >= 0) - fprintf(stderr, "S%i_ = {", i); - else - fprintf(stderr, "S_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward(args)...); } - fprintf(stderr, "template_param:\n"); - for (auto& t : db.template_param) + + template NodeArray makeNodeArray(It begin, It end) { - fprintf(stderr, "--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - fprintf(stderr, "T%i_ = {", i); - else - fprintf(stderr, "T_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } + size_t sz = static_cast(end - begin); + void* mem = ASTAllocator.allocate(sizeof(Node*) * sz); + Node** data = new (mem) Node*[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); } - fprintf(stderr, "---------\n\n"); -} -template -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - fprintf(stderr, "%s: ", msg); - for (; first != last; ++first) - fprintf(stderr, "%c", *first); - fprintf(stderr, "\n"); - print_stack(db); -} + NodeArray popTrailingNodeArray(size_t FromPosition) + { + assert(FromPosition <= Names.size()); + NodeArray res = makeNodeArray( + Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } +}; + +const char* parse_type(const char* first, const char* last, Db& db); +const char* parse_encoding(const char* first, const char* last, Db& db); +const char* parse_name(const char* first, const char* last, Db& db, + bool* ends_with_template_args = 0); +const char* parse_expression(const char* first, const char* last, Db& db); +const char* parse_template_args(const char* first, const char* last, Db& db); +const char* parse_operator_name(const char* first, const char* last, Db& db); +const char* parse_unqualified_name(const char* first, const char* last, Db& db); +const char* parse_decltype(const char* first, const char* last, Db& db); // ::= [n] @@ -140,30 +1755,30 @@ parse_number(const char* first, const char* last) } template -struct float_data; +struct FloatData; template <> -struct float_data +struct FloatData { static const size_t mangled_size = 8; static const size_t max_demangled_size = 24; static constexpr const char* spec = "%af"; }; -constexpr const char* float_data::spec; +constexpr const char* FloatData::spec; template <> -struct float_data +struct FloatData { static const size_t mangled_size = 16; static const size_t max_demangled_size = 32; static constexpr const char* spec = "%a"; }; -constexpr const char* float_data::spec; +constexpr const char* FloatData::spec; template <> -struct float_data +struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ defined(__wasm__) @@ -177,55 +1792,34 @@ struct float_data static constexpr const char* spec = "%LaL"; }; -constexpr const char* float_data::spec; +constexpr const char* FloatData::spec; -template +template const char* -parse_floating_number(const char* first, const char* last, C& db) +parse_floating_number(const char* first, const char* last, Db& db) { - const size_t N = float_data::mangled_size; - if (static_cast(last - first) > N) + const size_t N = FloatData::mangled_size; + if (static_cast(last - first) <= N) + return first; + last = first + N; + const char* t = first; + for (; t != last; ++t) { - last = first + N; - union - { - Float value; - char buf[sizeof(Float)]; - }; - const char* t = first; - char* e = buf; - for (; t != last; ++t, ++e) - { - if (!isxdigit(*t)) - return first; - unsigned d1 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - *e = static_cast((d1 << 4) + d0); - } - if (*t == 'E') - { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[float_data::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), float_data::spec, value); - if (static_cast(n) >= sizeof(num)) - return first; - db.names.push_back(typename C::String(num, static_cast(n))); - first = t+1; - } + if (!isxdigit(*t)) + return first; + } + if (*t == 'E') + { + db.Names.push_back( + db.make>(StringView(first, t))); + first = t + 1; } return first; } -// ::= - -template +// ::= [0-9]* const char* -parse_source_name(const char* first, const char* last, C& db) +parse_positive_integer(const char* first, const char* last, size_t* out) { if (first != last) { @@ -240,15 +1834,53 @@ parse_source_name(const char* first, const char* last, C& db) if (++t == last) return first; } - if (static_cast(last - t) >= n) - { - typename C::String r(t, n); - if (r.substr(0, 10) == "_GLOBAL__N") - db.names.push_back("(anonymous namespace)"); - else - db.names.push_back(std::move(r)); - first = t + n; - } + *out = n; + first = t; + } + } + return first; +} + +// extension +// ::= * +// ::= B +const char* +parse_abi_tag_seq(const char* first, const char* last, Db& db) +{ + while (first != last && *first == 'B' && first+1 != last) + { + size_t length; + const char* t = parse_positive_integer(first+1, last, &length); + if (t == first+1) + return first; + if (static_cast(last - t) < length || db.Names.empty()) + return first; + db.Names.back() = db.make( + db.Names.back(), StringView(t, t + length)); + first = t + length; + } + return first; +} + +// ::= [] +const char* +parse_source_name(const char* first, const char* last, Db& db) +{ + if (first != last) + { + size_t length; + const char* t = parse_positive_integer(first, last, &length); + if (t == first) + return first; + if (static_cast(last - t) >= length) + { + StringView r(t, t + length); + if (r.substr(0, 10) == "_GLOBAL__N") + db.Names.push_back(db.make("(anonymous namespace)")); + else + db.Names.push_back(db.make(r)); + first = t + length; + first = parse_abi_tag_seq(first, last, db); } } return first; @@ -265,9 +1897,8 @@ parse_source_name(const char* first, const char* last, C& db) // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > -template const char* -parse_substitution(const char* first, const char* last, C& db) +parse_substitution(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -276,34 +1907,39 @@ parse_substitution(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("std::allocator"); + db.Names.push_back( + db.make( + SpecialSubKind::allocator)); first += 2; break; case 'b': - db.names.push_back("std::basic_string"); + db.Names.push_back( + db.make(SpecialSubKind::basic_string)); first += 2; break; case 's': - db.names.push_back("std::string"); + db.Names.push_back( + db.make( + SpecialSubKind::string)); first += 2; break; case 'i': - db.names.push_back("std::istream"); + db.Names.push_back(db.make(SpecialSubKind::istream)); first += 2; break; case 'o': - db.names.push_back("std::ostream"); + db.Names.push_back(db.make(SpecialSubKind::ostream)); first += 2; break; case 'd': - db.names.push_back("std::iostream"); + db.Names.push_back(db.make(SpecialSubKind::iostream)); first += 2; break; case '_': - if (!db.subs.empty()) + if (!db.Subs.empty()) { - for (const auto& n : db.subs.front()) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(0)) + db.Names.push_back(n); first += 2; } break; @@ -327,10 +1963,10 @@ parse_substitution(const char* first, const char* last, C& db) if (t == last || *t != '_') return first; ++sub; - if (sub < db.subs.size()) + if (sub < db.Subs.size()) { - for (const auto& n : db.subs[sub]) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(sub)) + db.Names.push_back(n); first = t+1; } } @@ -373,96 +2009,95 @@ parse_substitution(const char* first, const char* last, C& db) // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) // ::= u # vendor extended type -template const char* -parse_builtin_type(const char* first, const char* last, C& db) +parse_builtin_type(const char* first, const char* last, Db& db) { if (first != last) { switch (*first) { case 'v': - db.names.push_back("void"); + db.Names.push_back(db.make("void")); ++first; break; case 'w': - db.names.push_back("wchar_t"); + db.Names.push_back(db.make("wchar_t")); ++first; break; case 'b': - db.names.push_back("bool"); + db.Names.push_back(db.make("bool")); ++first; break; case 'c': - db.names.push_back("char"); + db.Names.push_back(db.make("char")); ++first; break; case 'a': - db.names.push_back("signed char"); + db.Names.push_back(db.make("signed char")); ++first; break; case 'h': - db.names.push_back("unsigned char"); + db.Names.push_back(db.make("unsigned char")); ++first; break; case 's': - db.names.push_back("short"); + db.Names.push_back(db.make("short")); ++first; break; case 't': - db.names.push_back("unsigned short"); + db.Names.push_back(db.make("unsigned short")); ++first; break; case 'i': - db.names.push_back("int"); + db.Names.push_back(db.make("int")); ++first; break; case 'j': - db.names.push_back("unsigned int"); + db.Names.push_back(db.make("unsigned int")); ++first; break; case 'l': - db.names.push_back("long"); + db.Names.push_back(db.make("long")); ++first; break; case 'm': - db.names.push_back("unsigned long"); + db.Names.push_back(db.make("unsigned long")); ++first; break; case 'x': - db.names.push_back("long long"); + db.Names.push_back(db.make("long long")); ++first; break; case 'y': - db.names.push_back("unsigned long long"); + db.Names.push_back(db.make("unsigned long long")); ++first; break; case 'n': - db.names.push_back("__int128"); + db.Names.push_back(db.make("__int128")); ++first; break; case 'o': - db.names.push_back("unsigned __int128"); + db.Names.push_back(db.make("unsigned __int128")); ++first; break; case 'f': - db.names.push_back("float"); + db.Names.push_back(db.make("float")); ++first; break; case 'd': - db.names.push_back("double"); + db.Names.push_back(db.make("double")); ++first; break; case 'e': - db.names.push_back("long double"); + db.Names.push_back(db.make("long double")); ++first; break; case 'g': - db.names.push_back("__float128"); + db.Names.push_back(db.make("__float128")); ++first; break; case 'z': - db.names.push_back("..."); + db.Names.push_back(db.make("...")); ++first; break; case 'u': @@ -478,39 +2113,39 @@ parse_builtin_type(const char* first, const char* last, C& db) switch (first[1]) { case 'd': - db.names.push_back("decimal64"); + db.Names.push_back(db.make("decimal64")); first += 2; break; case 'e': - db.names.push_back("decimal128"); + db.Names.push_back(db.make("decimal128")); first += 2; break; case 'f': - db.names.push_back("decimal32"); + db.Names.push_back(db.make("decimal32")); first += 2; break; case 'h': - db.names.push_back("decimal16"); + db.Names.push_back(db.make("decimal16")); first += 2; break; case 'i': - db.names.push_back("char32_t"); + db.Names.push_back(db.make("char32_t")); first += 2; break; case 's': - db.names.push_back("char16_t"); + db.Names.push_back(db.make("char16_t")); first += 2; break; case 'a': - db.names.push_back("auto"); + db.Names.push_back(db.make("auto")); first += 2; break; case 'c': - db.names.push_back("decltype(auto)"); + db.Names.push_back(db.make("decltype(auto)")); first += 2; break; case 'n': - db.names.push_back("std::nullptr_t"); + db.Names.push_back(db.make("std::nullptr_t")); first += 2; break; } @@ -521,27 +2156,27 @@ parse_builtin_type(const char* first, const char* last, C& db) return first; } -// ::= [r] [V] [K] +// ::= [r] [V] [K] const char* -parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) +parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv) { - cv = 0; + cv = QualNone; if (first != last) { if (*first == 'r') { - cv |= 4; + addQualifiers(cv, QualRestrict); ++first; } if (*first == 'V') { - cv |= 2; + addQualifiers(cv, QualVolatile); ++first; } if (*first == 'K') { - cv |= 1; + addQualifiers(cv, QualConst); ++first; } } @@ -551,9 +2186,8 @@ parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) // ::= T_ # first template parameter // ::= T _ -template const char* -parse_template_param(const char* first, const char* last, C& db) +parse_template_param(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -561,19 +2195,17 @@ parse_template_param(const char* first, const char* last, C& db) { if (first[1] == '_') { - if (db.template_param.empty()) - return first; - if (!db.template_param.back().empty()) + if (!db.TemplateParams.empty()) { - for (auto& t : db.template_param.back().front()) - db.names.push_back(t); + for (Node *t : db.TemplateParams.nthSubstitution(0)) + db.Names.push_back(t); first += 2; } else { - db.names.push_back("T_"); + db.Names.push_back(db.make("T_")); first += 2; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } else if (isdigit(first[1])) @@ -585,20 +2217,21 @@ parse_template_param(const char* first, const char* last, C& db) sub *= 10; sub += static_cast(*t - '0'); } - if (t == last || *t != '_' || db.template_param.empty()) + if (t == last || *t != '_') return first; ++sub; - if (sub < db.template_param.back().size()) + if (sub < db.TemplateParams.size()) { - for (auto& temp : db.template_param.back()[sub]) - db.names.push_back(temp); + for (Node *temp : db.TemplateParams.nthSubstitution(sub)) + db.Names.push_back(temp); first = t+1; } else { - db.names.push_back(typename C::String(first, t+1)); + db.Names.push_back( + db.make(StringView(first, t + 1))); first = t+1; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } } @@ -608,9 +2241,8 @@ parse_template_param(const char* first, const char* last, C& db) // cc # const_cast (expression) -template const char* -parse_const_cast_expr(const char* first, const char* last, C& db) +parse_const_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') { @@ -620,13 +2252,14 @@ parse_const_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make( + "const_cast", db.Names.back(), from_expr); first = t1; } } @@ -636,9 +2269,8 @@ parse_const_cast_expr(const char* first, const char* last, C& db) // dc # dynamic_cast (expression) -template const char* -parse_dynamic_cast_expr(const char* first, const char* last, C& db) +parse_dynamic_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') { @@ -648,13 +2280,14 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make( + "dynamic_cast", db.Names.back(), from_expr); first = t1; } } @@ -664,9 +2297,8 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) // rc # reinterpret_cast (expression) -template const char* -parse_reinterpret_cast_expr(const char* first, const char* last, C& db) +parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') { @@ -676,13 +2308,14 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make( + "reinterpret_cast", db.Names.back(), from_expr); first = t1; } } @@ -692,9 +2325,8 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) // sc # static_cast (expression) -template const char* -parse_static_cast_expr(const char* first, const char* last, C& db) +parse_static_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'c') { @@ -704,11 +2336,12 @@ parse_static_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + auto from_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + "static_cast", db.Names.back(), from_expr); first = t1; } } @@ -718,9 +2351,8 @@ parse_static_cast_expr(const char* first, const char* last, C& db) // sp # pack expansion -template const char* -parse_pack_expansion(const char* first, const char* last, C& db) +parse_pack_expansion(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { @@ -733,18 +2365,18 @@ parse_pack_expansion(const char* first, const char* last, C& db) // st # sizeof (a type) -template const char* -parse_sizeof_type_expr(const char* first, const char* last, C& db) +parse_sizeof_type_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -753,18 +2385,18 @@ parse_sizeof_type_expr(const char* first, const char* last, C& db) // sz # sizeof (a expression) -template const char* -parse_sizeof_expr_expr(const char* first, const char* last, C& db) +parse_sizeof_expr_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -773,60 +2405,50 @@ parse_sizeof_expr_expr(const char* first, const char* last, C& db) // sZ # size of a parameter pack -template const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) + size_t k1 = db.Names.size(); + if (t != first+2 && k0 <= k1) { - typename C::String tmp("sizeof...("); - size_t k = k0; - if (k != k1) - { - tmp += db.names[k].move_full(); - for (++k; k != k1; ++k) - tmp += ", " + db.names[k].move_full(); - } - tmp += ")"; - for (; k1 != k0; --k1) - db.names.pop_back(); - db.names.push_back(std::move(tmp)); + Node* sizeof_expr = db.make( + db.popTrailingNodeArray(k0)); + db.Names.push_back(sizeof_expr); first = t; } } return first; } -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p _ # L > 0, second and later parameters +// ::= fp _ # L == 0, first parameter +// ::= fp _ # L == 0, second and later parameters +// ::= fL p _ # L > 0, first parameter +// ::= fL p _ # L > 0, second and later parameters -template const char* -parse_function_param(const char* first, const char* last, C& db) +parse_function_param(const char* first, const char* last, Db& db) { if (last - first >= 3 && *first == 'f') { if (first[1] == 'p') { - unsigned cv; + Qualifiers cv; const char* t = parse_cv_qualifiers(first+2, last, cv); const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make(StringView(t, t1))); first = t1+1; } } else if (first[1] == 'L') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_number(first+2, last); if (t0 != last && *t0 == 'p') { @@ -835,7 +2457,8 @@ parse_function_param(const char* first, const char* last, C& db) const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make(StringView(t, t1))); first = t1+1; } } @@ -846,18 +2469,18 @@ parse_function_param(const char* first, const char* last, C& db) // sZ # size of a function parameter pack -template const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') { const char* t = parse_function_param(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make( + "sizeof...(", db.Names.back(), ")"); first = t; } } @@ -867,9 +2490,8 @@ parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db // te # typeid (expression) // ti # typeid (type) -template const char* -parse_typeid_expr(const char* first, const char* last, C& db) +parse_typeid_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) { @@ -880,9 +2502,10 @@ parse_typeid_expr(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make( + "typeid(", db.Names.back(), ")"); first = t; } } @@ -891,18 +2514,17 @@ parse_typeid_expr(const char* first, const char* last, C& db) // tw # throw expression -template const char* -parse_throw_expr(const char* first, const char* last, C& db) +parse_throw_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && first[1] == 'w') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "throw " + db.names.back().move_full(); + db.Names.back() = db.make(db.Names.back()); first = t; } } @@ -911,9 +2533,8 @@ parse_throw_expr(const char* first, const char* last, C& db) // ds # expr.*expr -template const char* -parse_dot_star_expr(const char* first, const char* last, C& db) +parse_dot_star_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 's') { @@ -923,11 +2544,12 @@ parse_dot_star_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += ".*" + expr; + auto rhs_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), ".*", rhs_expr); first = t1; } } @@ -937,9 +2559,8 @@ parse_dot_star_expr(const char* first, const char* last, C& db) // ::= [ ] -template const char* -parse_simple_id(const char* first, const char* last, C& db) +parse_simple_id(const char* first, const char* last, Db& db) { if (first != last) { @@ -949,11 +2570,12 @@ parse_simple_id(const char* first, const char* last, C& db) const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), args); } first = t1; } @@ -967,9 +2589,8 @@ parse_simple_id(const char* first, const char* last, C& db) // ::= // ::= -template const char* -parse_unresolved_type(const char* first, const char* last, C& db) +parse_unresolved_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -978,18 +2599,18 @@ parse_unresolved_type(const char* first, const char* last, C& db) { case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first && k1 == k0 + 1) { - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } else { for (; k1 != k0; --k1) - db.names.pop_back(); + db.Names.pop_back(); } break; } @@ -997,9 +2618,9 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } break; @@ -1014,10 +2635,11 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_unqualified_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = + db.make(db.Names.back()); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -1031,9 +2653,8 @@ parse_unresolved_type(const char* first, const char* last, C& db) // ::= # e.g., ~T or ~decltype(f()) // ::= # e.g., ~A<2*N> -template const char* -parse_destructor_name(const char* first, const char* last, C& db) +parse_destructor_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -1042,9 +2663,9 @@ parse_destructor_name(const char* first, const char* last, C& db) t = parse_simple_id(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "~"); + db.Names.back() = db.make(db.Names.back()); first = t; } } @@ -1059,9 +2680,8 @@ parse_destructor_name(const char* first, const char* last, C& db) // ::= dn # destructor or pseudo-destructor; // # e.g. ~X or ~X -template const char* -parse_base_unresolved_name(const char* first, const char* last, C& db) +parse_base_unresolved_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -1075,11 +2695,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make( + db.Names.back(), args); } } } @@ -1101,11 +2723,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make( + db.Names.back(), args); } } } @@ -1118,9 +2742,8 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) // ::= -template const char* -parse_unresolved_qualifier_level(const char* first, const char* last, C& db) +parse_unresolved_qualifier_level(const char* first, const char* last, Db& db) { return parse_simple_id(first, last, db); } @@ -1135,9 +2758,8 @@ parse_unresolved_qualifier_level(const char* first, const char* last, C& db) // # T::N::x /decltype(p)::N::x // (ignored) ::= srN + E -template const char* -parse_unresolved_name(const char* first, const char* last, C& db) +parse_unresolved_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -1153,9 +2775,10 @@ parse_unresolved_name(const char* first, const char* last, C& db) { if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make(db.Names.back()); } first = t2; } @@ -1171,41 +2794,44 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), args); t = t1; if (t == last) { - db.names.pop_back(); + db.Names.pop_back(); return first; } } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); first = t1; } else @@ -1218,25 +2844,28 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make( + db.Names.back(), args); t = t1; } t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); first = t1; } else @@ -1247,33 +2876,37 @@ parse_unresolved_name(const char* first, const char* last, C& db) t = t1; if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make( + db.Names.back()); } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make(db.Names.back(), s); first = t1; } } @@ -1284,9 +2917,8 @@ parse_unresolved_name(const char* first, const char* last, C& db) // dt # expr.name -template const char* -parse_dot_expr(const char* first, const char* last, C& db) +parse_dot_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 't') { @@ -1296,13 +2928,13 @@ parse_dot_expr(const char* first, const char* last, C& db) const char* t1 = parse_unresolved_name(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += "." + name; + db.Names.back() = db.make(db.Names.back(), ".", name); first = t1; } } @@ -1312,51 +2944,31 @@ parse_dot_expr(const char* first, const char* last, C& db) // cl + E # call -template -const char* -parse_call_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (t == last) - return first; - if (db.names.empty()) - return first; - db.names.back().first += db.names.back().second; - db.names.back().second = typename C::String(); - db.names.back().first.append("("); - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_expr) - { - db.names.back().first.append(", "); - first_expr = false; - } - db.names.back().first.append(tmp); - } - t = t1; - } - ++t; - if (db.names.empty()) +const char* +parse_call_expr(const char* first, const char* last, Db& db) +{ + if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') + { + const char* t = parse_expression(first+2, last, db); + if (t == last || t == first + 2 || db.Names.empty()) + return first; + Node* callee = db.Names.back(); + db.Names.pop_back(); + size_t args_begin = db.Names.size(); + while (*t != 'E') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == last || t1 == t) return first; - db.names.back().first.append(")"); - first = t; + t = t1; } + if (db.Names.size() < args_begin) + return first; + ++t; + CallExpr* the_call = db.make( + callee, db.popTrailingNodeArray(args_begin)); + db.Names.push_back(the_call); + first = t; } return first; } @@ -1367,9 +2979,8 @@ parse_call_expr(const char* first, const char* last, C& db) // [gs] na * _ # new[] (expr-list) type (init) // ::= pi * E # parenthesized initialization -template const char* -parse_new_expr(const char* first, const char* last, C& db) +parse_new_expr(const char* first, const char* last, Db& db) { if (last - first >= 4) { @@ -1386,31 +2997,18 @@ parse_new_expr(const char* first, const char* last, C& db) t += 2; if (t == last) return first; - bool has_expr_list = false; - bool first_expr = true; + size_t first_expr_in_list = db.Names.size(); + NodeArray ExprList, init_list; while (*t != '_') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - has_expr_list = true; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } + if (first_expr_in_list > db.Names.size()) + return first; + ExprList = db.popTrailingNodeArray(first_expr_in_list); ++t; const char* t1 = parse_type(t, last, db); if (t1 == t || t1 == last) @@ -1421,65 +3019,25 @@ parse_new_expr(const char* first, const char* last, C& db) { t += 2; has_init = true; - first_expr = true; + size_t init_list_begin = db.Names.size(); while (*t != 'E') { t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } - } - if (*t != 'E') - return first; - typename C::String init_list; - if (has_init) - { - if (db.names.empty()) + if (init_list_begin > db.Names.size()) return first; - init_list = db.names.back().move_full(); - db.names.pop_back(); + init_list = db.popTrailingNodeArray(init_list_begin); } - if (db.names.empty()) + if (*t != 'E' || db.Names.empty()) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - typename C::String expr_list; - if (has_expr_list) - { - if (db.names.empty()) - return first; - expr_list = db.names.back().move_full(); - db.names.pop_back(); - } - typename C::String r; - if (parsed_gs) - r = "::"; - if (is_array) - r += "[] "; - else - r += " "; - if (has_expr_list) - r += "(" + expr_list + ") "; - r += type; - if (has_init) - r += " (" + init_list + ")"; - db.names.push_back(std::move(r)); + auto type = db.Names.back(); + db.Names.pop_back(); + db.Names.push_back( + db.make(ExprList, type, init_list, + parsed_gs, is_array)); first = t+1; } } @@ -1489,18 +3047,19 @@ parse_new_expr(const char* first, const char* last, C& db) // cv # conversion with one argument // cv _ * E # conversion with a different number of arguments -template const char* -parse_conversion_expr(const char* first, const char* last, C& db) +parse_conversion_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; + size_t type_begin = db.Names.size(); const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2 && t != last) { + size_t expr_list_begin = db.Names.size(); if (*t != '_') { const char* t1 = parse_expression(t, last, db); @@ -1513,41 +3072,30 @@ parse_conversion_expr(const char* first, const char* last, C& db) ++t; if (t == last) return first; - if (*t == 'E') - db.names.emplace_back(); - else + if (*t != 'E') { - bool first_expr = true; while (*t != 'E') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } } ++t; } - if (db.names.size() < 2) + if (db.Names.size() < expr_list_begin || + type_begin > expr_list_begin) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; + NodeArray expressions = db.makeNodeArray( + db.Names.begin() + (long)expr_list_begin, db.Names.end()); + NodeArray types = db.makeNodeArray( + db.Names.begin() + (long)type_begin, + db.Names.begin() + (long)expr_list_begin); + auto* conv_expr = db.make( + types, expressions); + db.Names.dropBack(type_begin); + db.Names.push_back(conv_expr); first = t; } } @@ -1556,9 +3104,8 @@ parse_conversion_expr(const char* first, const char* last, C& db) // pt # expr->name -template const char* -parse_arrow_expr(const char* first, const char* last, C& db) +parse_arrow_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'p' && first[1] == 't') { @@ -1568,12 +3115,12 @@ parse_arrow_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "->"; - db.names.back().first += tmp; + auto tmp = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), "->", tmp); first = t1; } } @@ -1586,9 +3133,8 @@ parse_arrow_expr(const char* first, const char* last, C& db) // ::= F [Y] [] E -template const char* -parse_function_type(const char* first, const char* last, C& db) +parse_function_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'F') { @@ -1602,16 +3148,19 @@ parse_function_type(const char* first, const char* last, C& db) return first; } const char* t1 = parse_type(t, last, db); - if (t1 != t) + if (t1 != t && !db.Names.empty()) { + Node* ret_type = db.Names.back(); + db.Names.pop_back(); + size_t params_begin = db.Names.size(); t = t1; - typename C::String sig("("); - int ref_qual = 0; + FunctionRefQual RefQuals = FrefQualNone; while (true) { if (t == last) { - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } if (*t == 'E') @@ -1626,45 +3175,30 @@ parse_function_type(const char* first, const char* last, C& db) } if (*t == 'R' && t+1 != last && t[1] == 'E') { - ref_qual = 1; + RefQuals = FrefQualLValue; ++t; continue; } if (*t == 'O' && t+1 != last && t[1] == 'E') { - ref_qual = 2; + RefQuals = FrefQualRValue; ++t; continue; } - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 == t || t1 == last) + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k1 < k0) return first; - for (size_t k = k0; k < k1; ++k) - { - if (sig.size() > 1) - sig += ", "; - sig += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) - db.names.pop_back(); t = t1; } - sig += ")"; - switch (ref_qual) - { - case 1: - sig += " &"; - break; - case 2: - sig += " &&"; - break; - } - if (db.names.empty()) + if (db.Names.empty() || params_begin > db.Names.size()) return first; - db.names.back().first += " "; - db.names.back().second.insert(0, sig); + Node* fty = db.make( + ret_type, db.popTrailingNodeArray(params_begin)); + if (RefQuals) + fty = db.make(fty, RefQuals); + db.Names.push_back(fty); first = t; } } @@ -1674,9 +3208,8 @@ parse_function_type(const char* first, const char* last, C& db) // ::= M -template const char* -parse_pointer_to_member_type(const char* first, const char* last, C& db) +parse_pointer_to_member_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'M') { @@ -1686,21 +3219,13 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto func = std::move(db.names.back()); - db.names.pop_back(); - auto class_type = std::move(db.names.back()); - if (!func.second.empty() && func.second.front() == '(') - { - db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; - db.names.back().second = ")" + std::move(func.second); - } - else - { - db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; - db.names.back().second = std::move(func.second); - } + auto func = std::move(db.Names.back()); + db.Names.pop_back(); + auto ClassType = std::move(db.Names.back()); + db.Names.back() = + db.make(ClassType, func); first = t2; } } @@ -1711,9 +3236,8 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) // ::= A _ // ::= A [] _ -template const char* -parse_array_type(const char* first, const char* last, C& db) +parse_array_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'A' && first+1 != last) { @@ -1722,11 +3246,9 @@ parse_array_type(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " []"); + db.Names.back() = db.make(db.Names.back()); first = t; } } @@ -1738,11 +3260,11 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t+1, last, db); if (t2 != t+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); + db.Names.back() = + db.make(db.Names.back(), + StringView(first + 1, t)); first = t2; } } @@ -1755,15 +3277,13 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(++t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = std::move(db.names.back()); - db.names.pop_back(); - auto expr = std::move(db.names.back()); - db.names.back().first = std::move(type.first); - if (type.second.substr(0, 2) == " [") - type.second.erase(0, 1); - db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); + auto base_type = std::move(db.Names.back()); + db.Names.pop_back(); + auto dimension_expr = std::move(db.Names.back()); + db.Names.back() = + db.make(base_type, dimension_expr); first = t2; } } @@ -1775,9 +3295,8 @@ parse_array_type(const char* first, const char* last, C& db) // ::= Dt E # decltype of an id-expression or class member access (C++0x) // ::= DT E # decltype of an expression (C++0x) -template const char* -parse_decltype(const char* first, const char* last, C& db) +parse_decltype(const char* first, const char* last, Db& db) { if (last - first >= 4 && first[0] == 'D') { @@ -1789,9 +3308,10 @@ parse_decltype(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2 && t != last && *t == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make( + "decltype(", db.Names.back(), ")"); first = t+1; } } @@ -1808,9 +3328,8 @@ parse_decltype(const char* first, const char* last, C& db) // ::= // ::= p # AltiVec vector pixel -template const char* -parse_vector_type(const char* first, const char* last, C& db) +parse_vector_type(const char* first, const char* last, Db& db) { if (last - first > 3 && first[0] == 'D' && first[1] == 'v') { @@ -1828,33 +3347,36 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t1 = parse_type(t, last, db); if (t1 != t) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + db.Names.back() = + db.make(db.Names.back(), + StringView(num, num + sz)); first = t1; } } else { ++t; - db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + db.Names.push_back( + db.make(StringView(num, num + sz))); first = t; } } } else { - typename C::String num; + Node* num = nullptr; const char* t1 = first+2; if (*t1 != '_') { const char* t = parse_expression(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - num = db.names.back().move_full(); - db.names.pop_back(); + num = db.Names.back(); + db.Names.pop_back(); t1 = t; } } @@ -1863,11 +3385,17 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t = parse_type(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + num + "]"; + if (num) + db.Names.back() = + db.make(db.Names.back(), num); + else + db.Names.back() = + db.make(db.Names.back(), StringView()); first = t; - } + } else if (num) + db.Names.push_back(num); } } } @@ -1883,7 +3411,7 @@ parse_vector_type(const char* first, const char* last, C& db) // ::= // ::= // ::= -// ::= +// ::= // ::= P # pointer-to // ::= R # reference-to // ::= O # rvalue reference-to (C++0x) @@ -1897,9 +3425,8 @@ parse_vector_type(const char* first, const char* last, C& db) // ::= objcproto # k0 = 9 + + k1 // := # PU<11+>objcproto 11objc_object 11objc_object -> id -template const char* -parse_type(const char* first, const char* last, C& db) +parse_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -1909,51 +3436,30 @@ parse_type(const char* first, const char* last, C& db) case 'V': case 'K': { - unsigned cv = 0; + Qualifiers cv = QualNone; const char* t = parse_cv_qualifiers(first, last, cv); if (t != first) { bool is_function = *t == 'F'; - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t1 != t) { if (is_function) - db.subs.pop_back(); - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.popPack(); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (is_function) - { - size_t p = db.names[k].second.size(); - if (db.names[k].second[p-2] == '&') - p -= 3; - else if (db.names[k].second.back() == '&') - p -= 2; - if (cv & 1) - { - db.names[k].second.insert(p, " const"); - p += 6; - } - if (cv & 2) - { - db.names[k].second.insert(p, " volatile"); - p += 9; - } - if (cv & 4) - db.names[k].second.insert(p, " restrict"); - } - else - { - if (cv & 1) - db.names[k].first.append(" const"); - if (cv & 2) - db.names[k].first.append(" volatile"); - if (cv & 4) - db.names[k].first.append(" restrict"); + if (cv) { + if (is_function) + db.Names[k] = db.make( + db.Names[k], cv); + else + db.Names[k] = + db.make(db.Names[k], cv); } - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t1; } @@ -1975,77 +3481,69 @@ parse_type(const char* first, const char* last, C& db) t = parse_array_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'C': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" complex"); + db.Names.back() = db.make( + db.Names.back(), " complex"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'F': t = parse_function_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'G': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" imaginary"); + db.Names.back() = db.make( + db.Names.back(), " imaginary"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'M': t = parse_pointer_to_member_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'O': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2053,34 +3551,16 @@ parse_type(const char* first, const char* last, C& db) } case 'P': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") - { - db.names[k].first.append("*"); - } - else - { - db.names[k].first.replace(0, 11, "id"); - } - db.subs.back().push_back(db.names[k]); + db.Names[k] = db.make(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2088,27 +3568,17 @@ parse_type(const char* first, const char* last, C& db) } case 'R': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2116,23 +3586,25 @@ parse_type(const char* first, const char* last, C& db) } case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - if (db.try_to_parse_template_args && k1 == k0+1) + db.Subs.pushSubstitutionIntoPack(db.Names[k]); + if (db.TryToParseTemplateArgs && k1 == k0+1) { const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), args); + db.Subs.pushSubstitution(db.Names.back()); t = t1; } } @@ -2149,29 +3621,30 @@ parse_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.back().first.substr(0, 9) != "objcproto") + auto type = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KNameType || + !static_cast(db.Names.back())->getName().startsWith("objcproto")) { - db.names.back() = type + " " + db.names.back().move_full(); + db.Names.back() = db.make(type, db.Names.back()); } else { - auto proto = db.names.back().move_full(); - db.names.pop_back(); - t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); - if (t != proto.data() + 9) + auto* proto = static_cast(db.Names.back()); + db.Names.pop_back(); + t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db); + if (t != proto->getName().begin() + 9) { - db.names.back() = type + "<" + db.names.back().move_full() + ">"; + db.Names.back() = db.make(type, db.Names.back()); } else { - db.names.push_back(type + " " + proto); + db.Names.push_back(db.make(type, proto)); } } - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t2; } } @@ -2183,9 +3656,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2197,17 +3670,22 @@ parse_type(const char* first, const char* last, C& db) first = t; // Parsed a substitution. If the substitution is a // it might be followed by . - t = parse_template_args(first, last, db); - if (t != first) + if (db.TryToParseTemplateArgs) { - if (db.names.size() < 2) - return first; - auto template_args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += template_args; - // Need to create substitution for - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; + t = parse_template_args(first, last, db); + if (t != first) + { + if (db.Names.size() < 2) + return first; + auto template_args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), template_args); + // Need to create substitution for + db.Subs.pushSubstitution(db.Names.back()); + first = t; + } } } } @@ -2219,14 +3697,14 @@ parse_type(const char* first, const char* last, C& db) { case 'p': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+2, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+2) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); first = t; return first; } @@ -2237,9 +3715,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } @@ -2248,16 +3726,16 @@ parse_type(const char* first, const char* last, C& db) t = parse_vector_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } break; } } - // drop through + _LIBCPP_FALLTHROUGH(); default: // must check for builtin-types before class-enum-types to avoid // ambiguities with operator-names @@ -2271,9 +3749,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2338,11 +3816,11 @@ parse_type(const char* first, const char* last, C& db) // ::= rs # >> // ::= rS # >>= // ::= v # vendor extended operator - -template +// extension ::= const char* -parse_operator_name(const char* first, const char* last, C& db) +parse_operator_name(const char* first, const char* last, Db& db) { + const char* original_first = first; if (last - first >= 2) { switch (first[0]) @@ -2351,20 +3829,20 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator&&"); + db.Names.push_back(db.make("operator&&")); first += 2; break; case 'd': case 'n': - db.names.push_back("operator&"); + db.Names.push_back(db.make("operator&")); first += 2; break; case 'N': - db.names.push_back("operator&="); + db.Names.push_back(db.make("operator&=")); first += 2; break; case 'S': - db.names.push_back("operator="); + db.Names.push_back(db.make("operator=")); first += 2; break; } @@ -2373,29 +3851,30 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'l': - db.names.push_back("operator()"); + db.Names.push_back(db.make("operator()")); first += 2; break; case 'm': - db.names.push_back("operator,"); + db.Names.push_back(db.make("operator,")); first += 2; break; case 'o': - db.names.push_back("operator~"); + db.Names.push_back(db.make("operator~")); first += 2; break; case 'v': { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); - db.parsed_ctor_dtor_cv = true; + db.Names.back() = + db.make(db.Names.back()); + db.ParsedCtorDtorCV = true; first = t; } } @@ -2406,23 +3885,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator delete[]"); + db.Names.push_back(db.make("operator delete[]")); first += 2; break; case 'e': - db.names.push_back("operator*"); + db.Names.push_back(db.make("operator*")); first += 2; break; case 'l': - db.names.push_back("operator delete"); + db.Names.push_back(db.make("operator delete")); first += 2; break; case 'v': - db.names.push_back("operator/"); + db.Names.push_back(db.make("operator/")); first += 2; break; case 'V': - db.names.push_back("operator/="); + db.Names.push_back(db.make("operator/=")); first += 2; break; } @@ -2431,15 +3910,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator^"); + db.Names.push_back(db.make("operator^")); first += 2; break; case 'O': - db.names.push_back("operator^="); + db.Names.push_back(db.make("operator^=")); first += 2; break; case 'q': - db.names.push_back("operator=="); + db.Names.push_back(db.make("operator==")); first += 2; break; } @@ -2448,11 +3927,11 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator>="); + db.Names.push_back(db.make("operator>=")); first += 2; break; case 't': - db.names.push_back("operator>"); + db.Names.push_back(db.make("operator>")); first += 2; break; } @@ -2460,7 +3939,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'i': if (first[1] == 'x') { - db.names.push_back("operator[]"); + db.Names.push_back(db.make("operator[]")); first += 2; } break; @@ -2468,7 +3947,7 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator<="); + db.Names.push_back(db.make("operator<=")); first += 2; break; case 'i': @@ -2476,23 +3955,24 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator\"\" "); + db.Names.back() = + db.make(db.Names.back()); first = t; } } break; case 's': - db.names.push_back("operator<<"); + db.Names.push_back(db.make("operator<<")); first += 2; break; case 'S': - db.names.push_back("operator<<="); + db.Names.push_back(db.make("operator<<=")); first += 2; break; case 't': - db.names.push_back("operator<"); + db.Names.push_back(db.make("operator<")); first += 2; break; } @@ -2501,23 +3981,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'i': - db.names.push_back("operator-"); + db.Names.push_back(db.make("operator-")); first += 2; break; case 'I': - db.names.push_back("operator-="); + db.Names.push_back(db.make("operator-=")); first += 2; break; case 'l': - db.names.push_back("operator*"); + db.Names.push_back(db.make("operator*")); first += 2; break; case 'L': - db.names.push_back("operator*="); + db.Names.push_back(db.make("operator*=")); first += 2; break; case 'm': - db.names.push_back("operator--"); + db.Names.push_back(db.make("operator--")); first += 2; break; } @@ -2526,23 +4006,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator new[]"); + db.Names.push_back(db.make("operator new[]")); first += 2; break; case 'e': - db.names.push_back("operator!="); + db.Names.push_back(db.make("operator!=")); first += 2; break; case 'g': - db.names.push_back("operator-"); + db.Names.push_back(db.make("operator-")); first += 2; break; case 't': - db.names.push_back("operator!"); + db.Names.push_back(db.make("operator!")); first += 2; break; case 'w': - db.names.push_back("operator new"); + db.Names.push_back(db.make("operator new")); first += 2; break; } @@ -2551,15 +4031,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator||"); + db.Names.push_back(db.make("operator||")); first += 2; break; case 'r': - db.names.push_back("operator|"); + db.Names.push_back(db.make("operator|")); first += 2; break; case 'R': - db.names.push_back("operator|="); + db.Names.push_back(db.make("operator|=")); first += 2; break; } @@ -2568,27 +4048,27 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator->*"); + db.Names.push_back(db.make("operator->*")); first += 2; break; case 'l': - db.names.push_back("operator+"); + db.Names.push_back(db.make("operator+")); first += 2; break; case 'L': - db.names.push_back("operator+="); + db.Names.push_back(db.make("operator+=")); first += 2; break; case 'p': - db.names.push_back("operator++"); + db.Names.push_back(db.make("operator++")); first += 2; break; case 's': - db.names.push_back("operator+"); + db.Names.push_back(db.make("operator+")); first += 2; break; case 't': - db.names.push_back("operator->"); + db.Names.push_back(db.make("operator->")); first += 2; break; } @@ -2596,7 +4076,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'q': if (first[1] == 'u') { - db.names.push_back("operator?"); + db.Names.push_back(db.make("operator?")); first += 2; } break; @@ -2604,19 +4084,19 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator%"); + db.Names.push_back(db.make("operator%")); first += 2; break; case 'M': - db.names.push_back("operator%="); + db.Names.push_back(db.make("operator%=")); first += 2; break; case 's': - db.names.push_back("operator>>"); + db.Names.push_back(db.make("operator>>")); first += 2; break; case 'S': - db.names.push_back("operator>>="); + db.Names.push_back(db.make("operator>>=")); first += 2; break; } @@ -2627,37 +4107,31 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); + db.Names.back() = + db.make(db.Names.back()); first = t; } } break; } } + + if (original_first != first) + first = parse_abi_tag_seq(first, last, db); + return first; } -template const char* -parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) +parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) { const char* t = parse_number(first, last); if (t != first && t != last && *t == 'E') { - if (lit.size() > 3) - db.names.push_back("(" + lit + ")"); - else - db.names.emplace_back(); - if (*first == 'n') - { - db.names.back().first += '-'; - ++first; - } - db.names.back().first.append(first, t); - if (lit.size() <= 3) - db.names.back().first += lit; + db.Names.push_back( + db.make(lit, StringView(first, t))); first = t+1; } return first; @@ -2670,9 +4144,8 @@ parse_integer_literal(const char* first, const char* last, const typename C::Str // ::= L _ E # complex floating point literal (C 2000) // ::= L E # external name -template const char* -parse_expr_primary(const char* first, const char* last, C& db) +parse_expr_primary(const char* first, const char* last, Db& db) { if (last - first >= 4 && *first == 'L') { @@ -2691,11 +4164,11 @@ parse_expr_primary(const char* first, const char* last, C& db) switch (first[2]) { case '0': - db.names.push_back("false"); + db.Names.push_back(db.make(0)); first += 4; break; case '1': - db.names.push_back("true"); + db.Names.push_back(db.make(1)); first += 4; break; } @@ -2838,9 +4311,10 @@ parse_expr_primary(const char* first, const char* last, C& db) ; if (n != t && n != last && *n == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + db.Names.back() = db.make( + db.Names.back(), StringView(t, n)); first = n+1; break; } @@ -2857,65 +4331,22 @@ parse_expr_primary(const char* first, const char* last, C& db) return first; } -template -String -base_name(String& s) +Node* maybe_change_special_sub_name(Node* inp, Db& db) { - if (s.empty()) - return s; - if (s == "std::string") - { - s = "std::basic_string, std::allocator >"; - return "basic_string"; - } - if (s == "std::istream") - { - s = "std::basic_istream >"; - return "basic_istream"; - } - if (s == "std::ostream") + if (inp->K != Node::KSpecialSubstitution) + return inp; + auto Kind = static_cast(inp)->SSK; + switch (Kind) { - s = "std::basic_ostream >"; - return "basic_ostream"; + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + return db.make(Kind); + default: + break; } - if (s == "std::iostream") - { - s = "std::basic_iostream >"; - return "basic_iostream"; - } - const char* const pf = s.data(); - const char* pe = pf + s.size(); - if (pe[-1] == '>') - { - unsigned c = 1; - while (true) - { - if (--pe == pf) - return String(); - if (pe[-1] == '<') - { - if (--c == 0) - { - --pe; - break; - } - } - else if (pe[-1] == '>') - ++c; - } - } - if (pe - pf <= 1) - return String(); - const char* p0 = pe - 1; - for (; p0 != pf; --p0) - { - if (*p0 == ':') - { - ++p0; - break; - } - } - return String(p0, pe); + return inp; } // ::= C1 # complete object constructor @@ -2926,12 +4357,11 @@ base_name(String& s) // ::= D1 # complete object destructor // ::= D2 # base object destructor // extension ::= D5 # ? - -template +// extension ::= const char* -parse_ctor_dtor_name(const char* first, const char* last, C& db) +parse_ctor_dtor_name(const char* first, const char* last, Db& db) { - if (last-first >= 2 && !db.names.empty()) + if (last-first >= 2 && !db.Names.empty()) { switch (first[0]) { @@ -2942,11 +4372,15 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '2': case '3': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back(base_name(db.names.back().first)); + db.Names.back() = + maybe_change_special_sub_name(db.Names.back(), db); + db.Names.push_back( + db.make(db.Names.back(), false)); first += 2; - db.parsed_ctor_dtor_cv = true; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; break; } break; @@ -2957,11 +4391,13 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '1': case '2': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back("~" + base_name(db.names.back().first)); + db.Names.push_back( + db.make(db.Names.back(), true)); first += 2; - db.parsed_ctor_dtor_cv = true; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; break; } break; @@ -2970,16 +4406,14 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) return first; } -// ::= Ut [ ] _ +// ::= Ut [] _ [] // ::= // // ::= Ul E [ ] _ // // ::= + # Parameter types or "v" if the lambda has no parameters - -template const char* -parse_unnamed_type_name(const char* first, const char* last, C& db) +parse_unnamed_type_name(const char* first, const char* last, Db& db) { if (last - first > 2 && first[0] == 'U') { @@ -2988,101 +4422,64 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) { case 't': { - db.names.push_back(typename C::String("'unnamed")); const char* t0 = first+2; if (t0 == last) - { - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.append(t0, t1); + count = StringView(t0, t1); t0 = t1; } - db.names.back().first.push_back('\''); if (t0 == last || *t0 != '_') - { - db.names.pop_back(); return first; - } + db.Names.push_back(db.make(count)); first = t0 + 1; + first = parse_abi_tag_seq(first, last, db); } break; case 'l': { - db.names.push_back(typename C::String("'lambda'(")); + size_t begin_pos = db.Names.size(); const char* t0 = first+2; + NodeArray lambda_params; if (first[2] == 'v') { - db.names.back().first += ')'; ++t0; } else { - const char* t1 = parse_type(t0, last, db); - if (t1 == t0) - { - if(!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first.append(tmp); - t0 = t1; while (true) { - t1 = parse_type(t0, last, db); + const char* t1 = parse_type(t0, last, db); if (t1 == t0) break; - if (db.names.size() < 2) - return first; - tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - } t0 = t1; } - if(db.names.empty()) - return first; - db.names.back().first.append(")"); + if (db.Names.size() < begin_pos) + return first; + lambda_params = db.popTrailingNodeArray(begin_pos); } if (t0 == last || *t0 != 'E') - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } ++t0; if (t0 == last) - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); + count = StringView(t0, t1); t0 = t1; } if (t0 == last || *t0 != '_') - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + db.Names.push_back(db.make(lambda_params, count)); first = t0 + 1; } break; @@ -3096,9 +4493,8 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) // ::= // ::= -template const char* -parse_unqualified_name(const char* first, const char* last, C& db) +parse_unqualified_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -3143,9 +4539,8 @@ parse_unqualified_name(const char* first, const char* last, C& db) // ::= St # ::std:: // extension ::= StL -template const char* -parse_unscoped_name(const char* first, const char* last, C& db) +parse_unscoped_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3163,9 +4558,10 @@ parse_unscoped_name(const char* first, const char* last, C& db) { if (St) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); + db.Names.back() = + db.make(db.Names.back()); } first = t1; } @@ -3175,18 +4571,18 @@ parse_unscoped_name(const char* first, const char* last, C& db) // at # alignof (a type) -template const char* -parse_alignof_type(const char* first, const char* last, C& db) +parse_alignof_type(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make("alignof (", db.Names.back(), ")"); first = t; } } @@ -3195,57 +4591,55 @@ parse_alignof_type(const char* first, const char* last, C& db) // az # alignof (a expression) -template const char* -parse_alignof_expr(const char* first, const char* last, C& db) +parse_alignof_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make("alignof (", db.Names.back(), ")"); first = t; } } return first; } -template const char* -parse_noexcept_expression(const char* first, const char* last, C& db) +parse_noexcept_expression(const char* first, const char* last, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make("noexcept (", db.Names.back(), ")"); first = t1; } return first; } -template const char* -parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_prefix_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = op + "(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make(op, db.Names.back()); first = t1; } return first; } -template const char* -parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_binary_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) @@ -3253,22 +4647,14 @@ parse_binary_expression(const char* first, const char* last, const typename C::S const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - auto& nm = db.names.back().first; - nm.clear(); - if (op == ">") - nm += '('; - nm += "(" + op1 + ") " + op + " (" + op2 + ")"; - if (op == ">") - nm += ')'; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = db.make(op1, op, op2); first = t2; } - else if(!db.names.empty()) - db.names.pop_back(); } return first; } @@ -3313,9 +4699,8 @@ parse_binary_expression(const char* first, const char* last, const typename C::S // # objectless nonstatic member reference // ::= -template const char* -parse_expression(const char* first, const char* last, C& db) +parse_expression(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3405,10 +4790,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete[] " + db.names.back().move_full(); + db.Names.back() = db.make( + db.Names.back(), parsed_gs, /*is_array=*/true); first = t1; } } @@ -3426,10 +4811,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete " + db.names.back().move_full(); + db.Names.back() = db.make( + db.Names.back(), parsed_gs, /*is_array=*/false); first = t1; } } @@ -3498,16 +4883,17 @@ parse_expression(const char* first, const char* last, C& db) const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ")[" + op2 + "]"; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make(op1, op2); first = t2; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3571,9 +4957,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")--"; + db.Names.back() = + db.make(db.Names.back(), "--"); first = t1; } } @@ -3661,9 +5048,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")++"; + db.Names.back() = + db.make(db.Names.back(), "++"); first = t1; } } @@ -3690,26 +5078,27 @@ parse_expression(const char* first, const char* last, C& db) const char* t3 = parse_expression(t2, last, db); if (t3 != t2) { - if (db.names.size() < 3) + if (db.Names.size() < 3) return first; - auto op3 = db.names.back().move_full(); - db.names.pop_back(); - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; + auto op3 = db.Names.back(); + db.Names.pop_back(); + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make(op1, op2, op3); first = t3; } else { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - db.names.pop_back(); - db.names.pop_back(); + db.Names.pop_back(); + db.Names.pop_back(); } } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3782,7 +5171,7 @@ parse_expression(const char* first, const char* last, C& db) first = parse_typeid_expr(first, last, db); break; case 'r': - db.names.push_back("throw"); + db.Names.push_back(db.make("throw")); first += 2; break; case 'w': @@ -3811,9 +5200,8 @@ parse_expression(const char* first, const char* last, C& db) // ::= J * E # argument pack // ::= LZ E # extension -template const char* -parse_template_arg(const char* first, const char* last, C& db) +parse_template_arg(const char* first, const char* last, Db& db) { if (first != last) { @@ -3864,57 +5252,52 @@ parse_template_arg(const char* first, const char* last, C& db) // ::= I * E // extension, the abi says + -template const char* -parse_template_args(const char* first, const char* last, C& db) +parse_template_args(const char* first, const char* last, Db& db) { if (last - first >= 2 && *first == 'I') { - if (db.tag_templates) - db.template_param.back().clear(); + if (db.TagTemplates) + db.TemplateParams.clear(); const char* t = first+1; - typename C::String args("<"); + size_t begin_idx = db.Names.size(); while (*t != 'E') { - if (db.tag_templates) - db.template_param.emplace_back(db.names.get_allocator()); - size_t k0 = db.names.size(); - const char* t1 = parse_template_arg(t, last, db); - size_t k1 = db.names.size(); - if (db.tag_templates) - db.template_param.pop_back(); - if (t1 == t || t1 == last) - return first; - if (db.tag_templates) + if (db.TagTemplates) { - db.template_param.back().emplace_back(db.names.get_allocator()); + auto TmpParams = std::move(db.TemplateParams); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + db.TemplateParams = std::move(TmpParams); + + if (t1 == t || t1 == last || k0 > k1) + return first; + db.TemplateParams.pushPack(); for (size_t k = k0; k < k1; ++k) - db.template_param.back().back().push_back(db.names[k]); - } - for (size_t k = k0; k < k1; ++k) - { - if (args.size() > 1) - args += ", "; - args += db.names[k].move_full(); + db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]); + t = t1; + continue; } - for (; k1 > k0; --k1) - if (!db.names.empty()) - db.names.pop_back(); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k0 > k1) + return first; t = t1; } + if (begin_idx > db.Names.size()) + return first; first = t + 1; - if (args.back() != '>') - args += ">"; - else - args += " >"; - db.names.push_back(std::move(args)); - + TemplateParams* tp = db.make( + db.popTrailingNodeArray(begin_idx)); + db.Names.push_back(tp); } return first; } -// ::= N [] [] E -// ::= N [] [] E +// ::= N [] [] E +// ::= N [] [] E // // ::= // ::= @@ -3929,39 +5312,35 @@ parse_template_args(const char* first, const char* last, C& db) // ::= // ::= -template const char* -parse_nested_name(const char* first, const char* last, C& db, +parse_nested_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'N') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_cv_qualifiers(first+1, last, cv); if (t0 == last) return first; - db.ref = 0; + db.RefQuals = FrefQualNone; if (*t0 == 'R') { - db.ref = 1; + db.RefQuals = FrefQualLValue; ++t0; } else if (*t0 == 'O') { - db.ref = 2; + db.RefQuals = FrefQualRValue; ++t0; } - db.names.emplace_back(); + db.Names.push_back(db.make()); if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') { t0 += 2; - db.names.back().first = "std"; + db.Names.back() = db.make("std"); } if (t0 == last) - { - db.names.pop_back(); return first; - } bool pop_subs = false; bool component_ends_with_template_args = false; while (*t0 != 'E') @@ -3976,17 +5355,18 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_substitution(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) { - db.names.back().first += "::" + name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = db.make( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); } else - db.names.back().first = name; + db.Names.back() = name; pop_subs = true; t0 = t1; } @@ -3997,15 +5377,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_param(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4018,15 +5399,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_decltype(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4037,12 +5419,13 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - db.names.back().first += name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto name = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; component_ends_with_template_args = true; } @@ -4058,15 +5441,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_unqualified_name(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4075,9 +5459,9 @@ parse_nested_name(const char* first, const char* last, C& db, } } first = t0 + 1; - db.cv = cv; - if (pop_subs && !db.subs.empty()) - db.subs.pop_back(); + db.CV = cv; + if (pop_subs && !db.Subs.empty()) + db.Subs.popPack(); if (ends_with_template_args) *ends_with_template_args = component_ends_with_template_args; } @@ -4126,9 +5510,8 @@ parse_discriminator(const char* first, const char* last) // := Z E s [] // := Z Ed [ ] _ -template const char* -parse_local_name(const char* first, const char* last, C& db, +parse_local_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'Z') @@ -4140,9 +5523,10 @@ parse_local_name(const char* first, const char* last, C& db, { case 's': first = parse_discriminator(t+1, last); - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append("::string literal"); + db.Names.back() = db.make( + db.Names.back(), db.make("string literal")); break; case 'd': if (++t != last) @@ -4155,18 +5539,18 @@ parse_local_name(const char* first, const char* last, C& db, ends_with_template_args); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make(db.Names.back(), name); first = t1; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -4178,17 +5562,17 @@ parse_local_name(const char* first, const char* last, C& db, { // parse but ignore discriminator first = parse_discriminator(t1, last); - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make(db.Names.back(), name); } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } break; } @@ -4205,9 +5589,8 @@ parse_local_name(const char* first, const char* last, C& db, // ::= // ::= -template const char* -parse_name(const char* first, const char* last, C& db, +parse_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (last - first >= 2) @@ -4241,20 +5624,22 @@ parse_name(const char* first, const char* last, C& db, { if (t1 != last && *t1 == 'I') // { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4272,13 +5657,15 @@ parse_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4343,12 +5730,13 @@ parse_call_offset(const char* first, const char* last) // # base is the nominal target function of thunk // ::= GV # Guard variable for one-time initialization // # No +// ::= TW # Thread-local wrapper +// ::= TH # Thread-local initialization // extension ::= TC _ # construction vtable for second-in-first // extension ::= GR # reference temporary for object -template const char* -parse_special_name(const char* first, const char* last, C& db) +parse_special_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -4363,9 +5751,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "vtable for "); + db.Names.back() = + db.make("vtable for ", db.Names.back()); first = t; } break; @@ -4374,9 +5763,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "VTT for "); + db.Names.back() = + db.make("VTT for ", db.Names.back()); first = t; } break; @@ -4385,9 +5775,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo for "); + db.Names.back() = + db.make("typeinfo for ", db.Names.back()); first = t; } break; @@ -4396,9 +5787,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo name for "); + db.Names.back() = + db.make("typeinfo name for ", db.Names.back()); first = t; } break; @@ -4414,9 +5806,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "covariant return thunk to "); + db.Names.back() = + db.make("covariant return thunk to ", + db.Names.back()); first = t; } } @@ -4432,20 +5826,44 @@ parse_special_name(const char* first, const char* last, C& db) const char* t1 = parse_type(++t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto left = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto left = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first = "construction vtable for " + - std::move(left) + "-in-" + - db.names.back().move_full(); + db.Names.back() = db.make( + left, db.Names.back()); first = t1; } } } break; + case 'W': + // TW # Thread-local wrapper + t = parse_name(first + 2, last, db); + if (t != first + 2) + { + if (db.Names.empty()) + return first; + db.Names.back() = + db.make("thread-local wrapper routine for ", + db.Names.back()); + first = t; + } + break; + case 'H': + //TH # Thread-local initialization + t = parse_name(first + 2, last, db); + if (t != first + 2) + { + if (db.Names.empty()) + return first; + db.Names.back() = db.make( + "thread-local initialization routine for ", db.Names.back()); + first = t; + } + break; default: // T { @@ -4455,16 +5873,20 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t0, last, db); if (t != t0) { - if (db.names.empty()) + if (db.Names.empty()) return first; if (first[1] == 'v') { - db.names.back().first.insert(0, "virtual thunk to "); + db.Names.back() = + db.make("virtual thunk to ", + db.Names.back()); first = t; } else { - db.names.back().first.insert(0, "non-virtual thunk to "); + db.Names.back() = + db.make("non-virtual thunk to ", + db.Names.back()); first = t; } } @@ -4480,9 +5902,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "guard variable for "); + db.Names.back() = + db.make("guard variable for ", db.Names.back()); first = t; } break; @@ -4491,9 +5914,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "reference temporary for "); + db.Names.back() = + db.make("reference temporary for ", + db.Names.back()); first = t; } break; @@ -4528,17 +5953,18 @@ public: // ::= // ::= -template const char* -parse_encoding(const char* first, const char* last, C& db) +parse_encoding(const char* first, const char* last, Db& db) { if (first != last) { - save_value su(db.encoding_depth); - ++db.encoding_depth; - save_value sb(db.tag_templates); - if (db.encoding_depth > 1) - db.tag_templates = true; + save_value su(db.EncodingDepth); + ++db.EncodingDepth; + save_value sb(db.TagTemplates); + if (db.EncodingDepth > 1) + db.TagTemplates = true; + save_value sp(db.ParsedCtorDtorCV); + db.ParsedCtorDtorCV = false; switch (*first) { case 'G': @@ -4550,96 +5976,72 @@ parse_encoding(const char* first, const char* last, C& db) bool ends_with_template_args = false; const char* t = parse_name(first, last, db, &ends_with_template_args); - unsigned cv = db.cv; - unsigned ref = db.ref; + if (db.Names.empty()) + return first; + Qualifiers cv = db.CV; + FunctionRefQual ref = db.RefQuals; if (t != first) { if (t != last && *t != 'E' && *t != '.') { - save_value sb2(db.tag_templates); - db.tag_templates = false; + save_value sb2(db.TagTemplates); + db.TagTemplates = false; const char* t2; - typename C::String ret2; - if (db.names.empty()) + if (db.Names.empty()) return first; - const typename C::String& nm = db.names.back().first; - if (nm.empty()) + if (!db.Names.back()) return first; - if (!db.parsed_ctor_dtor_cv && ends_with_template_args) + Node* return_type = nullptr; + if (!db.ParsedCtorDtorCV && ends_with_template_args) { t2 = parse_type(t, last, db); if (t2 == t) return first; - if (db.names.size() < 2) - return first; - auto ret1 = std::move(db.names.back().first); - ret2 = std::move(db.names.back().second); - if (ret2.empty()) - ret1 += ' '; - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 1) return first; - - db.names.back().first.insert(0, ret1); + return_type = db.Names.back(); + db.Names.pop_back(); t = t2; } - db.names.back().first += '('; + + Node* result = nullptr; + if (t != last && *t == 'v') { ++t; + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make( + return_type, name, NodeArray()); } else { - bool first_arg = true; + size_t params_begin = db.Names.size(); while (true) { - size_t k0 = db.names.size(); t2 = parse_type(t, last, db); - size_t k1 = db.names.size(); if (t2 == t) break; - if (k1 > k0) - { - typename C::String tmp; - for (size_t k = k0; k < k1; ++k) - { - if (!tmp.empty()) - tmp += ", "; - tmp += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) { - if (db.names.empty()) - return first; - db.names.pop_back(); - } - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_arg) - db.names.back().first += ", "; - else - first_arg = false; - db.names.back().first += tmp; - } - } t = t2; } + if (db.Names.size() < params_begin) + return first; + NodeArray params = + db.popTrailingNodeArray(params_begin); + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make( + return_type, name, params); } - if (db.names.empty()) - return first; - db.names.back().first += ')'; - if (cv & 1) - db.names.back().first.append(" const"); - if (cv & 2) - db.names.back().first.append(" volatile"); - if (cv & 4) - db.names.back().first.append(" restrict"); - if (ref == 1) - db.names.back().first.append(" &"); - else if (ref == 2) - db.names.back().first.append(" &&"); - db.names.back().first += ret2; + if (ref != FrefQualNone) + result = db.make(result, ref); + if (cv != QualNone) + result = db.make(result, cv); + db.Names.push_back(result); first = t; } else @@ -4656,12 +6058,12 @@ parse_encoding(const char* first, const char* last, C& db) // _block_invoke+ // _block_invoke_+ -template const char* -parse_block_invoke(const char* first, const char* last, C& db) +parse_block_invoke(const char* first, const char* last, Db& db) { if (last - first >= 13) { + // FIXME: strcmp? const char test[] = "_block_invoke"; const char* t = first; for (int i = 0; i < 13; ++i, ++t) @@ -4682,9 +6084,11 @@ parse_block_invoke(const char* first, const char* last, C& db) while (t != last && isdigit(*t)) ++t; } - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "invocation function for block in "); + db.Names.back() = + db.make("invocation function for block in ", + db.Names.back()); first = t; } return first; @@ -4693,15 +6097,15 @@ parse_block_invoke(const char* first, const char* last, C& db) // extension // := . -template const char* -parse_dot_suffix(const char* first, const char* last, C& db) +parse_dot_suffix(const char* first, const char* last, Db& db) { if (first != last && *first == '.') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " (" + typename C::String(first, last) + ")"; + db.Names.back() = + db.make(db.Names.back(), StringView(first, last)); first = last; } return first; @@ -4713,9 +6117,8 @@ parse_dot_suffix(const char* first, const char* last, C& db) // ::= _Z // ::= -template void -demangle(const char* first, const char* last, C& db, int& status) +demangle(const char* first, const char* last, Db& db, int& status) { if (first >= last) { @@ -4758,216 +6161,10 @@ demangle(const char* first, const char* last, C& db, int& status) if (t != last) status = invalid_mangled_name; } - if (status == success && db.names.empty()) + if (status == success && db.Names.empty()) status = invalid_mangled_name; } -template -class arena -{ - static const std::size_t alignment = 16; - alignas(alignment) char buf_[N]; - char* ptr_; - - std::size_t - align_up(std::size_t n) noexcept - {return (n + (alignment-1)) & ~(alignment-1);} - - bool - pointer_in_buffer(char* p) noexcept - {return buf_ <= p && p <= buf_ + N;} - -public: - arena() noexcept : ptr_(buf_) {} - ~arena() {ptr_ = nullptr;} - arena(const arena&) = delete; - arena& operator=(const arena&) = delete; - - char* allocate(std::size_t n); - void deallocate(char* p, std::size_t n) noexcept; - - static constexpr std::size_t size() {return N;} - std::size_t used() const {return static_cast(ptr_ - buf_);} - void reset() {ptr_ = buf_;} -}; - -template -char* -arena::allocate(std::size_t n) -{ - n = align_up(n); - if (static_cast(buf_ + N - ptr_) >= n) - { - char* r = ptr_; - ptr_ += n; - return r; - } - return static_cast(std::malloc(n)); -} - -template -void -arena::deallocate(char* p, std::size_t n) noexcept -{ - if (pointer_in_buffer(p)) - { - n = align_up(n); - if (p + n == ptr_) - ptr_ = p; - } - else - std::free(p); -} - -template -class short_alloc -{ - arena& a_; -public: - typedef T value_type; - -public: - template struct rebind {typedef short_alloc<_Up, N> other;}; - - short_alloc(arena& a) noexcept : a_(a) {} - template - short_alloc(const short_alloc& a) noexcept - : a_(a.a_) {} - short_alloc(const short_alloc&) = default; - short_alloc& operator=(const short_alloc&) = delete; - - T* allocate(std::size_t n) - { - return reinterpret_cast(a_.allocate(n*sizeof(T))); - } - void deallocate(T* p, std::size_t n) noexcept - { - a_.deallocate(reinterpret_cast(p), n*sizeof(T)); - } - - template - friend - bool - operator==(const short_alloc& x, const short_alloc& y) noexcept; - - template friend class short_alloc; -}; - -template -inline -bool -operator==(const short_alloc& x, const short_alloc& y) noexcept -{ - return N == M && &x.a_ == &y.a_; -} - -template -inline -bool -operator!=(const short_alloc& x, const short_alloc& y) noexcept -{ - return !(x == y); -} - -template -class malloc_alloc -{ -public: - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - malloc_alloc() = default; - template malloc_alloc(const malloc_alloc&) noexcept {} - - T* allocate(std::size_t n) - { - return static_cast(std::malloc(n*sizeof(T))); - } - void deallocate(T* p, std::size_t) noexcept - { - std::free(p); - } - - template struct rebind { using other = malloc_alloc; }; - template - void construct(U* p, Args&&... args) - { - ::new ((void*)p) U(std::forward(args)...); - } - void destroy(T* p) - { - p->~T(); - } -}; - -template -inline -bool -operator==(const malloc_alloc&, const malloc_alloc&) noexcept -{ - return true; -} - -template -inline -bool -operator!=(const malloc_alloc& x, const malloc_alloc& y) noexcept -{ - return !(x == y); -} - -const size_t bs = 4 * 1024; -template using Alloc = short_alloc; -template using Vector = std::vector>; - -template -struct string_pair -{ - StrT first; - StrT second; - - string_pair() = default; - string_pair(StrT f) : first(std::move(f)) {} - string_pair(StrT f, StrT s) - : first(std::move(f)), second(std::move(s)) {} - template - string_pair(const char (&s)[N]) : first(s, N-1) {} - - size_t size() const {return first.size() + second.size();} - StrT full() const {return first + second;} - StrT move_full() {return std::move(first) + std::move(second);} -}; - -struct Db -{ - typedef std::basic_string, - malloc_alloc> String; - typedef Vector> sub_type; - typedef Vector template_param_type; - sub_type names; - template_param_type subs; - Vector template_param; - unsigned cv; - unsigned ref; - unsigned encoding_depth; - bool parsed_ctor_dtor_cv; - bool tag_templates; - bool fix_forward_references; - bool try_to_parse_template_args; - - template - Db(arena& ar) : - names(ar), - subs(0, names, ar), - template_param(0, subs, ar) - {} -}; - } // unnamed namespace extern "C" _LIBCXXABI_FUNC_VIS char * @@ -4978,56 +6175,44 @@ __cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) { *status = invalid_args; return nullptr; } + size_t internal_size = buf != nullptr ? *n : 0; - arena a; - Db db(a); - db.cv = 0; - db.ref = 0; - db.encoding_depth = 0; - db.parsed_ctor_dtor_cv = false; - db.tag_templates = true; - db.template_param.emplace_back(a); - db.fix_forward_references = false; - db.try_to_parse_template_args = true; + Db db; int internal_status = success; size_t len = std::strlen(mangled_name); demangle(mangled_name, mangled_name + len, db, internal_status); - if (internal_status == success && db.fix_forward_references && - !db.template_param.empty() && !db.template_param.front().empty()) + + if (internal_status == success && db.FixForwardReferences && + !db.TemplateParams.empty()) { - db.fix_forward_references = false; - db.tag_templates = false; - db.names.clear(); - db.subs.clear(); + db.FixForwardReferences = false; + db.TagTemplates = false; + db.Names.clear(); + db.Subs.clear(); demangle(mangled_name, mangled_name + len, db, internal_status); - if (db.fix_forward_references) + if (db.FixForwardReferences) internal_status = invalid_mangled_name; } + if (internal_status == success) { - size_t sz = db.names.back().size() + 1; - if (sz > internal_size) + if (!buf) { - char* newbuf = static_cast(std::realloc(buf, sz)); - if (newbuf == nullptr) - { - internal_status = memory_alloc_failure; - buf = nullptr; - } - else - { - buf = newbuf; - if (n != nullptr) - *n = sz; - } + internal_size = 1024; + buf = static_cast(std::malloc(internal_size)); } - if (buf != nullptr) + + if (buf) { - db.names.back().first += db.names.back().second; - std::memcpy(buf, db.names.back().first.data(), sz-1); - buf[sz-1] = char(0); + OutputStream s(buf, internal_size); + db.Names.back()->print(s); + s += '\0'; + if (n) *n = s.getCurrentPosition(); + buf = s.getBuffer(); } + else + internal_status = memory_alloc_failure; } else buf = nullptr; diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp index 50d1a468cea..d5230cdc7d9 100644 --- a/lib/libcxxabi/src/cxa_exception.cpp +++ b/lib/libcxxabi/src/cxa_exception.cpp @@ -11,17 +11,17 @@ // //===----------------------------------------------------------------------===// -#include "config.h" #include "cxxabi.h" #include // for std::terminate -#include // for malloc, free #include // for memset -#if !LIBCXXABI_HAS_NO_THREADS -# include // for fallback_malloc.ipp's mutexes -#endif #include "cxa_exception.hpp" #include "cxa_handlers.hpp" +#include "fallback_malloc.h" + +#if __has_feature(address_sanitizer) +extern "C" void __asan_handle_no_return(void); +#endif // +---------------------------+-----------------------------+---------------+ // | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | @@ -36,8 +36,6 @@ namespace __cxxabiv1 { -#pragma GCC visibility push(default) - // Utility routines static inline @@ -68,12 +66,16 @@ cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exceptio return cxa_exception_from_thrown_object(unwind_exception + 1 ); } -static -inline -size_t -cxa_exception_size_from_exception_thrown_size(size_t size) -{ - return size + sizeof (__cxa_exception); +// Round s up to next multiple of a. +static inline +size_t aligned_allocation_size(size_t s, size_t a) { + return (s + a - 1) & ~(a - 1); +} + +static inline +size_t cxa_exception_size_from_exception_thrown_size(size_t size) { + return aligned_allocation_size(size + sizeof (__cxa_exception), + alignof(__cxa_exception)); } static void setExceptionClass(_Unwind_Exception* unwind_exception) { @@ -104,20 +106,6 @@ static inline int decrementHandlerCount(__cxa_exception *exception) { return --exception->handlerCount; } -#include "fallback_malloc.ipp" - -// Allocate some memory from _somewhere_ -static void *do_malloc(size_t size) { - void *ptr = std::malloc(size); - if (NULL == ptr) // if malloc fails, fall back to emergency stash - ptr = fallback_malloc(size); - return ptr; -} - -static void do_free(void *ptr) { - is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr); -} - /* If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler stored in exc is called. Otherwise the exceptionDestructor stored in @@ -137,7 +125,7 @@ exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exc __cxa_decrement_exception_refcount(unwind_exception + 1); } -static LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { +static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { // Section 2.5.3 says: // * For purposes of this ABI, several things are considered exception handlers: // ** A terminate() call due to a throw. @@ -149,6 +137,28 @@ static LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { std::__terminate(exception_header->terminateHandler); } +// Return the offset of the __cxa_exception header from the start of the +// allocated buffer. If __cxa_exception's alignment is smaller than the maximum +// useful alignment for the target machine, padding has to be inserted before +// the header to ensure the thrown object that follows the header is +// sufficiently aligned. This happens if _Unwind_exception isn't double-word +// aligned (on Darwin, for example). +static size_t get_cxa_exception_offset() { + struct S { + } __attribute__((aligned)); + + // Compute the maximum alignment for the target machine. + constexpr size_t alignment = std::alignment_of::value; + constexpr size_t excp_size = sizeof(__cxa_exception); + constexpr size_t aligned_size = + (excp_size + alignment - 1) / alignment * alignment; + constexpr size_t offset = aligned_size - excp_size; + static_assert((offset == 0 || + std::alignment_of<_Unwind_Exception>::value < alignment), + "offset is non-zero only if _Unwind_Exception isn't aligned"); + return offset; +} + extern "C" { // Allocate a __cxa_exception object, and zero-fill it. @@ -156,19 +166,30 @@ extern "C" { // object. Zero-fill the object. If memory can't be allocated, call // std::terminate. Return a pointer to the memory to be used for the // user's exception object. -_LIBCXXABI_FUNC_VIS void *__cxa_allocate_exception(size_t thrown_size) throw() { +void *__cxa_allocate_exception(size_t thrown_size) throw() { size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); - __cxa_exception* exception_header = static_cast<__cxa_exception*>(do_malloc(actual_size)); - if (NULL == exception_header) + + // Allocate extra space before the __cxa_exception header to ensure the + // start of the thrown object is sufficiently aligned. + size_t header_offset = get_cxa_exception_offset(); + char *raw_buffer = + (char *)__aligned_malloc_with_fallback(header_offset + actual_size); + if (NULL == raw_buffer) std::terminate(); + __cxa_exception *exception_header = + static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); std::memset(exception_header, 0, actual_size); return thrown_object_from_cxa_exception(exception_header); } // Free a __cxa_exception object allocated with __cxa_allocate_exception. -_LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_object) throw() { - do_free(cxa_exception_from_thrown_object(thrown_object)); +void __cxa_free_exception(void *thrown_object) throw() { + // Compute the size of the padding before the header. + size_t header_offset = get_cxa_exception_offset(); + char *raw_buffer = + ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; + __aligned_free_with_fallback((void *)raw_buffer); } @@ -177,7 +198,7 @@ _LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_object) throw() { // Otherwise, it will work like __cxa_allocate_exception. void * __cxa_allocate_dependent_exception () { size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = do_malloc(actual_size); + void *ptr = __aligned_malloc_with_fallback(actual_size); if (NULL == ptr) std::terminate(); std::memset(ptr, 0, actual_size); @@ -188,7 +209,7 @@ void * __cxa_allocate_dependent_exception () { // This function shall free a dependent_exception. // It does not affect the reference count of the primary exception. void __cxa_free_dependent_exception (void * dependent_exception) { - do_free(dependent_exception); + __aligned_free_with_fallback(dependent_exception); } @@ -218,7 +239,7 @@ handler, _Unwind_RaiseException may return. In that case, __cxa_throw will call terminate, assuming that there was no handler for the exception. */ -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void +void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { __cxa_eh_globals *globals = __cxa_get_globals(); __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -232,6 +253,12 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + +#if __has_feature(address_sanitizer) + // Inform the ASan runtime that now might be a good time to clean stuff up. + __asan_handle_no_return(); +#endif + #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else @@ -251,9 +278,8 @@ The adjusted pointer is computed by the personality routine during phase 1 Requires: exception is native */ -_LIBCXXABI_FUNC_VIS void *__cxa_get_exception_ptr(void *unwind_exception) throw() { -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) return reinterpret_cast( static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); #else @@ -262,12 +288,11 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() { #endif } -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) /* The routine to be called before the cleanup. This will save __cxa_exception in __cxa_eh_globals, so that __cxa_end_cleanup() can recover later. */ -_LIBCXXABI_FUNC_VIS bool __cxa_begin_cleanup(void *unwind_arg) throw() { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); __cxa_eh_globals* globals = __cxa_get_globals(); @@ -345,7 +370,7 @@ asm ( " bl abort\n" " .popsection" ); -#endif // LIBCXXABI_ARM_EHABI +#endif // defined(_LIBCXXABI_ARM_EHABI) /* This routine can catch foreign or native exceptions. If native, the exception @@ -405,7 +430,7 @@ __cxa_begin_catch(void* unwind_arg) throw() globals->caughtExceptions = exception_header; } globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) return reinterpret_cast(exception_header->unwindHeader.barrier_cache.bitpattern[0]); #else return exception_header->adjustedPtr; @@ -439,7 +464,7 @@ For a foreign exception: * If it has been rethrown, there is nothing to do. * Otherwise delete the exception and pop the catch stack to empty. */ -_LIBCXXABI_FUNC_VIS void __cxa_end_catch() { +void __cxa_end_catch() { static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), "sizeof(__cxa_exception) must be equal to " "sizeof(__cxa_dependent_exception)"); @@ -516,7 +541,7 @@ _LIBCXXABI_FUNC_VIS void __cxa_end_catch() { // Note: exception_header may be masquerading as a __cxa_dependent_exception // and that's ok. exceptionType is there too. // However watch out for foreign exceptions. Return null for them. -_LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type() { +std::type_info *__cxa_current_exception_type() { // get the current exception __cxa_eh_globals *globals = __cxa_get_globals_fast(); if (NULL == globals) @@ -541,7 +566,7 @@ If the exception is native: Note: exception_header may be masquerading as a __cxa_dependent_exception and that's ok. */ -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_rethrow() { +void __cxa_rethrow() { __cxa_eh_globals* globals = __cxa_get_globals(); __cxa_exception* exception_header = globals->caughtExceptions; if (NULL == exception_header) @@ -586,7 +611,7 @@ _LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN void __cxa_rethrow() { Requires: If thrown_object is not NULL, it is a native exception. */ -_LIBCXXABI_FUNC_VIS void +void __cxa_increment_exception_refcount(void *thrown_object) throw() { if (thrown_object != NULL ) { @@ -603,7 +628,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ -_LIBCXXABI_FUNC_VIS void +void __cxa_decrement_exception_refcount(void *thrown_object) throw() { if (thrown_object != NULL ) { @@ -627,7 +652,7 @@ __cxa_decrement_exception_refcount(void *thrown_object) throw() { been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ -_LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw() { +void *__cxa_current_primary_exception() throw() { // get the current exception __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (NULL == globals) @@ -713,6 +738,4 @@ __cxa_uncaught_exceptions() throw() } // extern "C" -#pragma GCC visibility pop - } // abi diff --git a/lib/libcxxabi/src/cxa_exception.hpp b/lib/libcxxabi/src/cxa_exception.hpp index 6e68f985389..c8b0fb1678e 100644 --- a/lib/libcxxabi/src/cxa_exception.hpp +++ b/lib/libcxxabi/src/cxa_exception.hpp @@ -15,19 +15,17 @@ #define _CXA_EXCEPTION_H #include // for std::unexpected_handler and std::terminate_handler -#include +#include "cxxabi.h" #include "unwind.h" namespace __cxxabiv1 { -#pragma GCC visibility push(hidden) - static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ -struct __cxa_exception { -#if defined(__LP64__) || LIBCXXABI_ARM_EHABI +struct _LIBCXXABI_HIDDEN __cxa_exception { +#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) // This is a new field to support C++ 0x exception_ptr. // For binary compatibility it is at the start of this // struct which is prepended to the object thrown in @@ -45,7 +43,7 @@ struct __cxa_exception { int handlerCount; -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) __cxa_exception* nextPropagatingException; int propagationCount; #else @@ -56,21 +54,20 @@ struct __cxa_exception { void *adjustedPtr; #endif -#if !defined(__LP64__) && !LIBCXXABI_ARM_EHABI +#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) // This is a new field to support C++ 0x exception_ptr. // For binary compatibility it is placed where the compiler // previously adding padded to 64-bit align unwindHeader. size_t referenceCount; #endif - _Unwind_Exception unwindHeader; }; // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html // The layout of this structure MUST match the layout of __cxa_exception, with // primaryException instead of referenceCount. -struct __cxa_dependent_exception { -#if defined(__LP64__) || LIBCXXABI_ARM_EHABI +struct _LIBCXXABI_HIDDEN __cxa_dependent_exception { +#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) void* primaryException; #endif @@ -83,7 +80,7 @@ struct __cxa_dependent_exception { int handlerCount; -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) __cxa_exception* nextPropagatingException; int propagationCount; #else @@ -94,31 +91,25 @@ struct __cxa_dependent_exception { void *adjustedPtr; #endif -#if !defined(__LP64__) && !LIBCXXABI_ARM_EHABI +#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) void* primaryException; #endif - _Unwind_Exception unwindHeader; }; -struct __cxa_eh_globals { +struct _LIBCXXABI_HIDDEN __cxa_eh_globals { __cxa_exception * caughtExceptions; unsigned int uncaughtExceptions; -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) __cxa_exception* propagatingExceptions; #endif }; -#pragma GCC visibility pop -#pragma GCC visibility push(default) - -extern "C" __cxa_eh_globals * __cxa_get_globals (); -extern "C" __cxa_eh_globals * __cxa_get_globals_fast (); - -extern "C" void * __cxa_allocate_dependent_exception (); -extern "C" void __cxa_free_dependent_exception (void * dependent_exception); +extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals (); +extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast (); -#pragma GCC visibility pop +extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception (); +extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception); } // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_exception_storage.cpp b/lib/libcxxabi/src/cxa_exception_storage.cpp index a39b6db005f..c641e0225f8 100644 --- a/lib/libcxxabi/src/cxa_exception_storage.cpp +++ b/lib/libcxxabi/src/cxa_exception_storage.cpp @@ -13,9 +13,9 @@ #include "cxa_exception.hpp" -#include "config.h" +#include <__threading_support> -#if LIBCXXABI_HAS_NO_THREADS +#if defined(_LIBCXXABI_HAS_NO_THREADS) namespace __cxxabiv1 { extern "C" { @@ -44,28 +44,27 @@ extern "C" { #else -#include -#include // for calloc, free #include "abort_message.h" +#include "fallback_malloc.h" -// In general, we treat all pthread errors as fatal. +// In general, we treat all threading errors as fatal. // We cannot call std::terminate() because that will in turn // call __cxa_get_globals() and cause infinite recursion. namespace __cxxabiv1 { namespace { - pthread_key_t key_; - pthread_once_t flag_ = PTHREAD_ONCE_INIT; + std::__libcpp_tls_key key_; + std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - void destruct_ (void *p) { - std::free ( p ); - if ( 0 != ::pthread_setspecific ( 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 != pthread_key_create ( &key_, destruct_ ) ) - abort_message("cannot create pthread key for __cxa_get_globals()"); + if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) + abort_message("cannot create thread specific key for __cxa_get_globals()"); } } @@ -77,11 +76,11 @@ extern "C" { // If this is the first time we've been asked for these globals, create them if ( NULL == retVal ) { retVal = static_cast<__cxa_eh_globals*> - (std::calloc (1, sizeof (__cxa_eh_globals))); + (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); if ( NULL == retVal ) abort_message("cannot allocate __cxa_eh_globals"); - if ( 0 != pthread_setspecific ( key_, retVal ) ) - abort_message("pthread_setspecific failure in __cxa_get_globals()"); + if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) + abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); } return retVal; } @@ -92,10 +91,10 @@ extern "C" { // libc++abi. __cxa_eh_globals * __cxa_get_globals_fast () { // First time through, create the key. - if (0 != pthread_once(&flag_, construct_)) - abort_message("pthread_once failure in __cxa_get_globals_fast()"); + 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*>(::pthread_getspecific(key_)); + return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); } } diff --git a/lib/libcxxabi/src/cxa_guard.cpp b/lib/libcxxabi/src/cxa_guard.cpp index 72e868f787e..f4c2a184dc5 100644 --- a/lib/libcxxabi/src/cxa_guard.cpp +++ b/lib/libcxxabi/src/cxa_guard.cpp @@ -10,11 +10,8 @@ #include "__cxxabi_config.h" #include "abort_message.h" -#include "config.h" +#include <__threading_support> -#if !LIBCXXABI_HAS_NO_THREADS -# include -#endif #include /* @@ -22,9 +19,9 @@ which will turn around and try to call __cxa_guard_acquire reentrantly. For this reason, the headers of this file are as restricted as possible. Previous implementations of this code for __APPLE__ have used - pthread_mutex_lock and the abort_message utility without problem. This - implementation also uses pthread_cond_wait which has tested to not be a - problem. + std::__libcpp_mutex_lock and the abort_message utility without problem. This + implementation also uses std::__libcpp_condvar_wait which has tested + to not be a problem. */ namespace __cxxabiv1 @@ -34,39 +31,43 @@ namespace { #ifdef __arm__ - // A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must // be statically initialized to 0. typedef uint32_t guard_type; -// Test the lowest bit. -inline bool is_initialized(guard_type* guard_object) { - return (*guard_object) & 1; -} - inline void set_initialized(guard_type* guard_object) { *guard_object |= 1; } - #else - typedef uint64_t guard_type; -bool is_initialized(guard_type* guard_object) { +void set_initialized(guard_type* guard_object) { char* initialized = (char*)guard_object; - return *initialized; + *initialized = 1; } +#endif -void set_initialized(guard_type* guard_object) { +#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__)) +#ifdef __arm__ + +// Test the lowest bit. +inline bool is_initialized(guard_type* guard_object) { + return (*guard_object) & 1; +} + +#else + +bool is_initialized(guard_type* guard_object) { char* initialized = (char*)guard_object; - *initialized = 1; + return *initialized; } +#endif #endif -#if !LIBCXXABI_HAS_NO_THREADS -pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; +#ifndef _LIBCXXABI_HAS_NO_THREADS +std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER; +std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER; #endif #if defined(__APPLE__) && !defined(__arm__) @@ -111,9 +112,10 @@ set_lock(uint64_t& x, lock_type y) typedef bool lock_type; -inline -lock_type -get_lock(uint64_t x) +#if !defined(__arm__) +static_assert(std::is_same::value, ""); + +inline lock_type get_lock(uint64_t x) { union { @@ -123,9 +125,7 @@ get_lock(uint64_t x) return f.lock[1] != 0; } -inline -void -set_lock(uint64_t& x, lock_type y) +inline void set_lock(uint64_t& x, lock_type y) { union { @@ -135,10 +135,10 @@ set_lock(uint64_t& x, lock_type y) f.lock[1] = y; x = f.guard; } +#else // defined(__arm__) +static_assert(std::is_same::value, ""); -inline -lock_type -get_lock(uint32_t x) +inline lock_type get_lock(uint32_t x) { union { @@ -148,9 +148,7 @@ get_lock(uint32_t x) return f.lock[1] != 0; } -inline -void -set_lock(uint32_t& x, lock_type y) +inline void set_lock(uint32_t& x, lock_type y) { union { @@ -161,38 +159,37 @@ set_lock(uint32_t& x, lock_type y) x = f.guard; } -#endif // __APPLE__ +#endif // !defined(__arm__) + +#endif // __APPLE__ && !__arm__ } // unnamed namespace extern "C" { -#if LIBCXXABI_HAS_NO_THREADS -_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { - return !is_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - *guard_object = 0; - set_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - *guard_object = 0; -} - -#else // !LIBCXXABI_HAS_NO_THREADS - +#ifndef _LIBCXXABI_HAS_NO_THREADS _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { char* initialized = (char*)guard_object; - if (pthread_mutex_lock(&guard_mut)) + if (std::__libcpp_mutex_lock(&guard_mut)) abort_message("__cxa_guard_acquire failed to acquire mutex"); int result = *initialized == 0; if (result) { #if defined(__APPLE__) && !defined(__arm__) - const lock_type id = pthread_mach_thread_np(pthread_self()); + // This is a special-case pthread dependency for Mac. We can't pull this + // out into libcxx's threading API (__threading_support) because not all + // supported Mac environments provide this function (in pthread.h). To + // make it possible to build/use libcxx in those environments, we have to + // keep this pthread dependency local to libcxxabi. If there is some + // convenient way to detect precisely when pthread_mach_thread_np is + // available in a given Mac environment, it might still be possible to + // bury this dependency in __threading_support. + #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD + const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id()); + #else + #error "How do I pthread_mach_thread_np()?" + #endif lock_type lock = get_lock(*guard_object); if (lock) { @@ -201,7 +198,7 @@ _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { abort_message("__cxa_guard_acquire detected deadlock"); do { - if (pthread_cond_wait(&guard_cv, &guard_mut)) + if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) abort_message("__cxa_guard_acquire condition variable wait failed"); lock = get_lock(*guard_object); } while (lock); @@ -213,40 +210,55 @@ _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { set_lock(*guard_object, id); #else // !__APPLE__ || __arm__ while (get_lock(*guard_object)) - if (pthread_cond_wait(&guard_cv, &guard_mut)) + if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) abort_message("__cxa_guard_acquire condition variable wait failed"); result = *initialized == 0; if (result) set_lock(*guard_object, true); #endif // !__APPLE__ || __arm__ } - if (pthread_mutex_unlock(&guard_mut)) + if (std::__libcpp_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_acquire failed to release mutex"); return result; } _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - if (pthread_mutex_lock(&guard_mut)) + if (std::__libcpp_mutex_lock(&guard_mut)) abort_message("__cxa_guard_release failed to acquire mutex"); *guard_object = 0; set_initialized(guard_object); - if (pthread_mutex_unlock(&guard_mut)) + if (std::__libcpp_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_release failed to release mutex"); - if (pthread_cond_broadcast(&guard_cv)) + if (std::__libcpp_condvar_broadcast(&guard_cv)) abort_message("__cxa_guard_release failed to broadcast condition variable"); } _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - if (pthread_mutex_lock(&guard_mut)) + if (std::__libcpp_mutex_lock(&guard_mut)) abort_message("__cxa_guard_abort failed to acquire mutex"); *guard_object = 0; - if (pthread_mutex_unlock(&guard_mut)) + if (std::__libcpp_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_abort failed to release mutex"); - if (pthread_cond_broadcast(&guard_cv)) + if (std::__libcpp_condvar_broadcast(&guard_cv)) abort_message("__cxa_guard_abort failed to broadcast condition variable"); } -#endif // !LIBCXXABI_HAS_NO_THREADS +#else // _LIBCXXABI_HAS_NO_THREADS + +_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { + return !is_initialized(guard_object); +} + +_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { + *guard_object = 0; + set_initialized(guard_object); +} + +_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { + *guard_object = 0; +} + +#endif // !_LIBCXXABI_HAS_NO_THREADS } // extern "C" diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp index 3f781313df8..2881a2a65fe 100644 --- a/lib/libcxxabi/src/cxa_handlers.cpp +++ b/lib/libcxxabi/src/cxa_handlers.cpp @@ -14,7 +14,6 @@ #include #include #include "abort_message.h" -#include "config.h" #include "cxxabi.h" #include "cxa_handlers.hpp" #include "cxa_exception.hpp" @@ -32,7 +31,6 @@ get_unexpected() _NOEXCEPT // return __cxa_unexpected_handler.load(memory_order_acq); } -__attribute__((visibility("hidden"), noreturn)) void __unexpected(unexpected_handler func) { @@ -57,7 +55,6 @@ get_terminate() _NOEXCEPT // return __cxa_terminate_handler.load(memory_order_acq); } -__attribute__((visibility("hidden"), noreturn)) void __terminate(terminate_handler func) _NOEXCEPT { @@ -104,7 +101,9 @@ terminate() _NOEXCEPT // In the future this will become: // std::atomic __cxa_new_handler(0); -extern "C" _LIBCXXABI_DATA_VIS new_handler __cxa_new_handler = 0; +extern "C" { +new_handler __cxa_new_handler = 0; +} new_handler set_new_handler(new_handler handler) _NOEXCEPT diff --git a/lib/libcxxabi/src/cxa_handlers.hpp b/lib/libcxxabi/src/cxa_handlers.hpp index ce567ec1471..14c0e10119d 100644 --- a/lib/libcxxabi/src/cxa_handlers.hpp +++ b/lib/libcxxabi/src/cxa_handlers.hpp @@ -13,16 +13,18 @@ #ifndef _CXA_HANDLERS_H #define _CXA_HANDLERS_H +#include <__cxxabi_config.h> + #include namespace std { -__attribute__((visibility("hidden"), noreturn)) +_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void __unexpected(unexpected_handler func); -__attribute__((visibility("hidden"), noreturn)) +_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void __terminate(terminate_handler func) _NOEXCEPT; @@ -31,9 +33,9 @@ __terminate(terminate_handler func) _NOEXCEPT; extern "C" { -extern void (*__cxa_terminate_handler)(); -extern void (*__cxa_unexpected_handler)(); -extern void (*__cxa_new_handler)(); +_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)(); +_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)(); +_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)(); /* diff --git a/lib/libcxxabi/src/cxa_noexception.cpp b/lib/libcxxabi/src/cxa_noexception.cpp index e45ceff0165..adda552b89f 100644 --- a/lib/libcxxabi/src/cxa_noexception.cpp +++ b/lib/libcxxabi/src/cxa_noexception.cpp @@ -13,7 +13,6 @@ // Support functions for the no-exceptions libc++ library -#include "config.h" #include "cxxabi.h" #include // for std::terminate @@ -22,8 +21,6 @@ namespace __cxxabiv1 { -#pragma GCC visibility push(default) - extern "C" { void @@ -55,6 +52,4 @@ __cxa_uncaught_exceptions() throw() { return 0; } } // extern "C" -#pragma GCC visibility pop - } // abi diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp index 85b6df2393a..7f857faf78f 100644 --- a/lib/libcxxabi/src/cxa_personality.cpp +++ b/lib/libcxxabi/src/cxa_personality.cpp @@ -18,7 +18,6 @@ #include #include "__cxxabi_config.h" -#include "config.h" #include "cxa_exception.hpp" #include "cxa_handlers.hpp" #include "private_typeinfo.h" @@ -317,7 +316,7 @@ call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) std::terminate(); } -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) static const void* read_target2_value(const void* ptr) { uintptr_t offset = *reinterpret_cast(ptr); @@ -328,7 +327,7 @@ static const void* read_target2_value(const void* ptr) // deferred to the linker. For bare-metal they turn into absolute // relocations. For linux they turn into GOT-REL relocations." // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html -#if LIBCXXABI_BAREMETAL +#if defined(LIBCXXABI_BAREMETAL) return reinterpret_cast(reinterpret_cast(ptr) + offset); #else @@ -348,14 +347,17 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, call_terminate(native_exception, unwind_exception); } - assert(ttypeEncoding == DW_EH_PE_absptr && "Unexpected TTypeEncoding"); + assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 + (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal + (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux + "Unexpected TTypeEncoding"); (void)ttypeEncoding; const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); return reinterpret_cast( read_target2_value(ttypePtr)); } -#else // !LIBCXXABI_ARM_EHABI +#else // !defined(_LIBCXXABI_ARM_EHABI) static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, @@ -391,7 +393,7 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, classInfo -= ttypeIndex; return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); } -#endif // !LIBCXXABI_ARM_EHABI +#endif // !defined(_LIBCXXABI_ARM_EHABI) /* This is checking a thrown exception type, excpType, against a possibly empty @@ -402,7 +404,7 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, the list will catch a excpType. If any catchType in the list can catch an excpType, then this exception spec does not catch the excpType. */ -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) static bool exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, @@ -415,7 +417,10 @@ exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, call_terminate(false, unwind_exception); } - assert(ttypeEncoding == DW_EH_PE_absptr && "Unexpected TTypeEncoding"); + assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 + (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal + (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux + "Unexpected TTypeEncoding"); (void)ttypeEncoding; // specIndex is negative of 1-based byte offset into classInfo; @@ -928,7 +933,7 @@ _UA_CLEANUP_PHASE Else a cleanup is not found: return _URC_CONTINUE_UNWIND */ -#if !LIBCXXABI_ARM_EHABI +#if !defined(_LIBCXXABI_ARM_EHABI) _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code #ifdef __USING_SJLJ_EXCEPTIONS__ __gxx_personality_sj0 @@ -1035,7 +1040,7 @@ static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, } // ARM register names -#if !LIBCXXABI_USE_LLVM_UNWINDER +#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block #endif static const uint32_t REG_SP = 13; @@ -1071,7 +1076,7 @@ __gxx_personality_v0(_Unwind_State state, bool native_exception = (unwind_exception->exception_class & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); -#if !LIBCXXABI_USE_LLVM_UNWINDER +#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) // Copy the address of _Unwind_Control_Block to r12 so that // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can // return correct address. @@ -1188,7 +1193,7 @@ __cxa_call_unexpected(void* arg) u_handler = old_exception_header->unexpectedHandler; // If std::__unexpected(u_handler) rethrows the same exception, // these values get overwritten by the rethrow. So save them now: -#if LIBCXXABI_ARM_EHABI +#if defined(_LIBCXXABI_ARM_EHABI) ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; #else diff --git a/lib/libcxxabi/src/cxa_thread_atexit.cpp b/lib/libcxxabi/src/cxa_thread_atexit.cpp index 7962e28af70..49d15d6b145 100644 --- a/lib/libcxxabi/src/cxa_thread_atexit.cpp +++ b/lib/libcxxabi/src/cxa_thread_atexit.cpp @@ -7,20 +7,134 @@ // //===----------------------------------------------------------------------===// +#include "abort_message.h" #include "cxxabi.h" +#include <__threading_support> +#include 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 + // __cxa_thread_atexit_impl() for us. It has a number of limitations that are + // difficult to impossible to address without ..._impl(): + // + // - dso_symbol is ignored. This means that a shared library may be unloaded + // (via dlclose()) before its thread_local destructors have run. + // + // - thread_local destructors for the main thread are run by the destructor of + // a static object. This is later than expected; they should run before the + // destructors of any objects with static storage duration. + // + // - thread_local destructors on non-main threads run on the first iteration + // through the __libccpp_tls_key destructors. + // std::notify_all_at_thread_exit() and similar functions must be careful to + // wait until the second iteration to provide their intended ordering + // guarantees. + // + // Another limitation, though one shared with ..._impl(), is that any + // thread_locals that are first initialized after non-thread_local global + // destructors begin to run will not be destroyed. [basic.start.term] states + // that all thread_local destructors are sequenced before the destruction of + // objects with static storage duration, resulting in a contradiction if a + // thread_local is constructed after that point. Thus we consider such + // programs ill-formed, and don't bother to run those destructors. (If the + // program terminates abnormally after such a thread_local is constructed, + // the destructor is not expected to run and thus there is no contradiction. + // So construction still has to work.) + + struct DtorList { + Dtor dtor; + void* obj; + DtorList* next; + }; + + // The linked list of thread-local destructors to run + __thread DtorList* dtors = nullptr; + // True if the destructors are currently scheduled to run on this thread + __thread bool dtors_alive = false; + // Used to trigger destructors on thread exit; value is ignored + std::__libcpp_tls_key dtors_key; + + void run_dtors(void*) { + while (auto head = dtors) { + dtors = head->next; + head->dtor(head->obj); + std::free(head); + } + + dtors_alive = false; + } + + struct DtorsManager { + DtorsManager() { + // There is intentionally no matching std::__libcpp_tls_delete call, as + // __cxa_thread_atexit() may be called arbitrarily late (for example, from + // global destructors or atexit() handlers). + if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) { + abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()"); + } + } + + ~DtorsManager() { + // std::__libcpp_tls_key destructors do not run on threads that call exit() + // (including when the main thread returns from main()), so we explicitly + // call the destructor here. This runs at exit time (potentially earlier + // if libc++abi is dlclose()'d). Any thread_locals initialized after this + // point will not be destroyed. + run_dtors(nullptr); + } + }; +} // 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 { + // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for + // one-time initialization and __cxa_atexit() for destruction) + static DtorsManager manager; + + if (!dtors_alive) { + if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) { + return -1; + } + dtors_alive = true; + } + + auto head = static_cast(std::malloc(sizeof(DtorList))); + if (!head) { + return -1; + } -_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*dtor)(void *), void *obj, - void *dso_symbol) throw() { - extern int __cxa_thread_atexit_impl(void (*)(void *), void *, void *); - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); -} + head->dtor = dtor; + head->obj = obj; + head->next = dtors; + dtors = head; -#endif // HAVE__CXA_THREAD_ATEXIT_IMPL + return 0; + } +#endif // HAVE___CXA_THREAD_ATEXIT_IMPL + } } // extern "C" } // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_unexpected.cpp b/lib/libcxxabi/src/cxa_unexpected.cpp index f6e6b6ab97e..7d4ef80c39e 100644 --- a/lib/libcxxabi/src/cxa_unexpected.cpp +++ b/lib/libcxxabi/src/cxa_unexpected.cpp @@ -8,20 +8,16 @@ //===----------------------------------------------------------------------===// #include -#include +#include "cxxabi.h" #include "cxa_exception.hpp" namespace __cxxabiv1 { -#pragma GCC visibility push(default) - extern "C" { } -#pragma GCC visibility pop - } // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_virtual.cpp b/lib/libcxxabi/src/cxa_virtual.cpp index ac81ad39d07..f59fa7ee2c6 100644 --- a/lib/libcxxabi/src/cxa_virtual.cpp +++ b/lib/libcxxabi/src/cxa_virtual.cpp @@ -12,12 +12,12 @@ namespace __cxxabiv1 { extern "C" { -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void) { abort_message("Pure virtual function called!"); } -_LIBCXXABI_FUNC_VIS LIBCXXABI_NORETURN +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void) { abort_message("Deleted virtual function called!"); } diff --git a/lib/libcxxabi/src/fallback_malloc.cpp b/lib/libcxxabi/src/fallback_malloc.cpp new file mode 100644 index 00000000000..336ad31b017 --- /dev/null +++ b/lib/libcxxabi/src/fallback_malloc.cpp @@ -0,0 +1,252 @@ +//===------------------------ fallback_malloc.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "fallback_malloc.h" + +#include <__threading_support> + +#include // for malloc, calloc, free +#include // for memset + +// A small, simple heap manager based (loosely) on +// the startup heap manager from FreeBSD, optimized for space. +// +// Manages a fixed-size memory pool, supports malloc and free only. +// No support for realloc. +// +// Allocates chunks in multiples of four bytes, with a four byte header +// for each chunk. The overhead of each chunk is kept low by keeping pointers +// as two byte offsets within the heap, rather than (4 or 8 byte) pointers. + +namespace { + +// When POSIX threads are not available, make the mutex operations a nop +#ifndef _LIBCXXABI_HAS_NO_THREADS +_LIBCPP_SAFE_STATIC +static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER; +#else +static void* heap_mutex = 0; +#endif + +class mutexor { +public: +#ifndef _LIBCXXABI_HAS_NO_THREADS + mutexor(std::__libcpp_mutex_t* m) : mtx_(m) { + std::__libcpp_mutex_lock(mtx_); + } + ~mutexor() { std::__libcpp_mutex_unlock(mtx_); } +#else + mutexor(void*) {} + ~mutexor() {} +#endif +private: + mutexor(const mutexor& rhs); + mutexor& operator=(const mutexor& rhs); +#ifndef _LIBCXXABI_HAS_NO_THREADS + std::__libcpp_mutex_t* mtx_; +#endif +}; + +static const size_t HEAP_SIZE = 512; +char heap[HEAP_SIZE] __attribute__((aligned)); + +typedef unsigned short heap_offset; +typedef unsigned short heap_size; + +struct heap_node { + heap_offset next_node; // offset into heap + heap_size len; // size in units of "sizeof(heap_node)" +}; + +static const heap_node* list_end = + (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap +static heap_node* freelist = NULL; + +heap_node* node_from_offset(const heap_offset offset) { + return (heap_node*)(heap + (offset * sizeof(heap_node))); +} + +heap_offset offset_from_node(const heap_node* ptr) { + return static_cast( + static_cast(reinterpret_cast(ptr) - heap) / + sizeof(heap_node)); +} + +void init_heap() { + freelist = (heap_node*)heap; + freelist->next_node = offset_from_node(list_end); + freelist->len = HEAP_SIZE / sizeof(heap_node); +} + +// How big a chunk we allocate +size_t alloc_size(size_t len) { + return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; +} + +bool is_fallback_ptr(void* ptr) { + return ptr >= heap && ptr < (heap + HEAP_SIZE); +} + +void* fallback_malloc(size_t len) { + heap_node *p, *prev; + const size_t nelems = alloc_size(len); + mutexor mtx(&heap_mutex); + + if (NULL == freelist) + init_heap(); + + // Walk the free list, looking for a "big enough" chunk + for (p = freelist, prev = 0; p && p != list_end; + prev = p, p = node_from_offset(p->next_node)) { + + if (p->len > nelems) { // chunk is larger, shorten, and return the tail + heap_node* q; + + p->len = static_cast(p->len - nelems); + q = p + p->len; + q->next_node = 0; + q->len = static_cast(nelems); + return (void*)(q + 1); + } + + if (p->len == nelems) { // exact size match + if (prev == 0) + freelist = node_from_offset(p->next_node); + else + prev->next_node = p->next_node; + p->next_node = 0; + return (void*)(p + 1); + } + } + return NULL; // couldn't find a spot big enough +} + +// Return the start of the next block +heap_node* after(struct heap_node* p) { return p + p->len; } + +void fallback_free(void* ptr) { + struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk + struct heap_node *p, *prev; + + mutexor mtx(&heap_mutex); + +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << "Freeing item at " << offset_from_node(cp) << " of size " + << cp->len << std::endl; +#endif + + for (p = freelist, prev = 0; p && p != list_end; + prev = p, p = node_from_offset(p->next_node)) { +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " p, cp, after (p), after(cp) " << offset_from_node(p) << ' ' + << offset_from_node(cp) << ' ' << offset_from_node(after(p)) + << ' ' << offset_from_node(after(cp)) << std::endl; +#endif + if (after(p) == cp) { +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Appending onto chunk at " << offset_from_node(p) + << std::endl; +#endif + p->len = static_cast( + p->len + cp->len); // make the free heap_node larger + return; + } else if (after(cp) == p) { // there's a free heap_node right after +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Appending free chunk at " << offset_from_node(p) + << std::endl; +#endif + cp->len = static_cast(cp->len + p->len); + if (prev == 0) { + freelist = cp; + cp->next_node = p->next_node; + } else + prev->next_node = offset_from_node(cp); + return; + } + } +// Nothing to merge with, add it to the start of the free list +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Making new free list entry " << offset_from_node(cp) + << std::endl; +#endif + cp->next_node = offset_from_node(freelist); + freelist = cp; +} + +#ifdef INSTRUMENT_FALLBACK_MALLOC +size_t print_free_list() { + struct heap_node *p, *prev; + heap_size total_free = 0; + if (NULL == freelist) + init_heap(); + + for (p = freelist, prev = 0; p && p != list_end; + prev = p, p = node_from_offset(p->next_node)) { + std::cout << (prev == 0 ? "" : " ") << "Offset: " << offset_from_node(p) + << "\tsize: " << p->len << " Next: " << p->next_node << std::endl; + total_free += p->len; + } + std::cout << "Total Free space: " << total_free << std::endl; + return total_free; +} +#endif +} // end unnamed namespace + +namespace __cxxabiv1 { + +struct __attribute__((aligned)) __aligned_type {}; + +void* __aligned_malloc_with_fallback(size_t size) { +#if defined(_WIN32) + if (void* dest = _aligned_malloc(size, alignof(__aligned_type))) + return dest; +#elif defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + if (void* dest = std::malloc(size)) + return dest; +#else + if (size == 0) + size = 1; + void* dest; + if (::posix_memalign(&dest, alignof(__aligned_type), size) == 0) + return dest; +#endif + return fallback_malloc(size); +} + +void* __calloc_with_fallback(size_t count, size_t size) { + void* ptr = std::calloc(count, size); + if (NULL != ptr) + return ptr; + // if calloc fails, fall back to emergency stash + ptr = fallback_malloc(size * count); + if (NULL != ptr) + std::memset(ptr, 0, size * count); + return ptr; +} + +void __aligned_free_with_fallback(void* ptr) { + if (is_fallback_ptr(ptr)) + fallback_free(ptr); + else { +#if defined(_WIN32) + ::_aligned_free(ptr); +#else + std::free(ptr); +#endif + } +} + +void __free_with_fallback(void* ptr) { + if (is_fallback_ptr(ptr)) + fallback_free(ptr); + else + std::free(ptr); +} + +} // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/fallback_malloc.h b/lib/libcxxabi/src/fallback_malloc.h new file mode 100644 index 00000000000..d6f471483a2 --- /dev/null +++ b/lib/libcxxabi/src/fallback_malloc.h @@ -0,0 +1,29 @@ +//===------------------------- fallback_malloc.h --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _FALLBACK_MALLOC_H +#define _FALLBACK_MALLOC_H + +#include "__cxxabi_config.h" +#include // for size_t + +namespace __cxxabiv1 { + +// Allocate some memory from _somewhere_ +_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size); + +// Allocate and zero-initialize memory from _somewhere_ +_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size); + +_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr); +_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr); + +} // namespace __cxxabiv1 + +#endif diff --git a/lib/libcxxabi/src/include/refstring.h b/lib/libcxxabi/src/include/refstring.h new file mode 100644 index 00000000000..bc131aeb5ae --- /dev/null +++ b/lib/libcxxabi/src/include/refstring.h @@ -0,0 +1,131 @@ +//===------------------------ __refstring ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of +// duplicating the file in libc++abi we should require that the libc++ sources +// are available when building libc++abi. + +#ifndef _LIBCPPABI_REFSTRING_H +#define _LIBCPPABI_REFSTRING_H + +#include <__config> +#include +#include +#include +#ifdef __APPLE__ +#include +#include +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __refstring_imp { namespace { +typedef int count_t; + +struct _Rep_base { + std::size_t len; + std::size_t cap; + count_t count; +}; + +inline _Rep_base* rep_from_data(const char *data_) noexcept { + char *data = const_cast(data_); + return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); +} + +inline char * data_from_rep(_Rep_base *rep) noexcept { + char *data = reinterpret_cast(rep); + return data + sizeof(*rep); +} + +#if defined(__APPLE__) +inline +const char* compute_gcc_empty_string_storage() _NOEXCEPT +{ + void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); + if (handle == nullptr) + return nullptr; + void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); + if (sym == nullptr) + return nullptr; + return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); +} + +inline +const char* +get_gcc_empty_string_storage() _NOEXCEPT +{ + static const char* p = compute_gcc_empty_string_storage(); + return p; +} +#endif + +}} // namespace __refstring_imp + +using namespace __refstring_imp; + +inline +__libcpp_refstring::__libcpp_refstring(const char* msg) { + std::size_t len = strlen(msg); + _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); + rep->len = len; + rep->cap = len; + rep->count = 0; + char *data = data_from_rep(rep); + std::memcpy(data, msg, len + 1); + __imp_ = data; +} + +inline +__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT + : __imp_(s.__imp_) +{ + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); +} + +inline +__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { + bool adjust_old_count = __uses_refcount(); + struct _Rep_base *old_rep = rep_from_data(__imp_); + __imp_ = s.__imp_; + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); + if (adjust_old_count) + { + if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0) + { + ::operator delete(old_rep); + } + } + return *this; +} + +inline +__libcpp_refstring::~__libcpp_refstring() { + if (__uses_refcount()) { + _Rep_base* rep = rep_from_data(__imp_); + if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0) { + ::operator delete(rep); + } + } +} + +inline +bool __libcpp_refstring::__uses_refcount() const { +#ifdef __APPLE__ + return __imp_ != get_gcc_empty_string_storage(); +#else + return true; +#endif +} + +_LIBCPP_END_NAMESPACE_STD + +#endif //_LIBCPPABI_REFSTRING_H diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp index df03596e8b6..ef9466ef610 100644 --- a/lib/libcxxabi/src/private_typeinfo.cpp +++ b/lib/libcxxabi/src/private_typeinfo.cpp @@ -55,12 +55,7 @@ #include #endif -namespace __cxxabiv1 -{ - -#pragma GCC visibility push(hidden) - -inline +static inline bool is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) { @@ -73,6 +68,8 @@ is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) #endif } +namespace __cxxabiv1 +{ // __shim_type_info @@ -171,8 +168,12 @@ __pointer_to_member_type_info::~__pointer_to_member_type_info() // catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object) // catch (D2* d2) : adjustedPtr == d2 // catch (D2*& d2) : adjustedPtr == d2 -// +// // catch (...) : adjustedPtr == & of the exception +// +// If the thrown type is nullptr_t and the caught type is a pointer to +// member type, adjustedPtr points to a statically-allocated null pointer +// representation of that type. // Handles bullet 1 bool @@ -228,7 +229,7 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type, if (thrown_class_type == 0) return false; // bullet 2 - __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -337,12 +338,11 @@ __vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, } } -// Handles bullets 1 and 4 for both pointers and member pointers +// Handles bullet 1 for both pointers and member pointers bool __pbase_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { - if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) return true; bool use_strcmp = this->__flags & (__incomplete_class_mask | __incomplete_mask); if (!use_strcmp) { @@ -367,7 +367,13 @@ bool __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // bullets 1 and 4 + // bullet 4 + if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { + adjustedPtr = nullptr; + return true; + } + + // bullet 1 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) { if (adjustedPtr != NULL) adjustedPtr = *static_cast(adjustedPtr); @@ -381,8 +387,10 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, // Do the dereference adjustment if (adjustedPtr != NULL) adjustedPtr = *static_cast(adjustedPtr); - // bullet 3B - if (thrown_pointer_type->__flags & ~__flags) + // bullet 3B and 3C + if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) + return false; + if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) return false; if (is_equal(__pointee, thrown_pointer_type->__pointee, false)) return true; @@ -419,7 +427,7 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, dynamic_cast(thrown_pointer_type->__pointee); if (thrown_class_type == 0) return false; - __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -468,7 +476,22 @@ bool __pointer_type_info::can_catch_nested( bool __pointer_to_member_type_info::can_catch( const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // bullets 1 and 4 + // bullet 4 + if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { + // We assume that the pointer to member representation is the same for + // all pointers to data members and for all pointers to member functions. + struct X {}; + if (dynamic_cast(__pointee)) { + static int (X::*const null_ptr_rep)() = nullptr; + adjustedPtr = const_cast(&null_ptr_rep); + } else { + static int X::*const null_ptr_rep = nullptr; + adjustedPtr = const_cast(&null_ptr_rep); + } + return true; + } + + // bullet 1 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) return true; @@ -476,7 +499,9 @@ bool __pointer_to_member_type_info::can_catch( dynamic_cast(thrown_type); if (thrown_pointer_type == 0) return false; - if (thrown_pointer_type->__flags & ~__flags) + if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) + return false; + if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) return false; if (!is_equal(__pointee, thrown_pointer_type->__pointee, false)) return false; @@ -510,9 +535,6 @@ bool __pointer_to_member_type_info::can_catch_nested( #pragma clang diagnostic pop #endif -#pragma GCC visibility pop -#pragma GCC visibility push(default) - #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" @@ -592,13 +614,11 @@ bool __pointer_to_member_type_info::can_catch_nested( // If there is a public path from (dynamic_ptr, dynamic_type) to // (static_ptr, static_type), then return dynamic_ptr. // Else return nullptr. -extern "C" -void* -__dynamic_cast(const void* static_ptr, - const __class_type_info* static_type, - const __class_type_info* dst_type, - std::ptrdiff_t src2dst_offset) -{ + +extern "C" _LIBCXXABI_FUNC_VIS void * +__dynamic_cast(const void *static_ptr, const __class_type_info *static_type, + const __class_type_info *dst_type, + std::ptrdiff_t src2dst_offset) { // Possible future optimization: Take advantage of src2dst_offset // Currently clang always sets src2dst_offset to -1 (no hint). @@ -613,7 +633,7 @@ __dynamic_cast(const void* static_ptr, // be returned. const void* dst_ptr = 0; // Initialize info struct for this search. - __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; + __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; // Find out if we can use a giant short cut in the search if (is_equal(dynamic_type, dst_type, false)) @@ -653,8 +673,8 @@ __dynamic_cast(const void* static_ptr, info.path_dynamic_ptr_to_static_ptr == unknown) { syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " - " has hidden visibility. They should all have public visibility. " - " %s, %s, %s.\n", static_type->name(), dynamic_type->name(), + "has hidden visibility. They should all have public visibility. " + "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), dst_type->name()); // Redo the search comparing type_info's using strcmp info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; @@ -689,9 +709,6 @@ __dynamic_cast(const void* static_ptr, #pragma clang diagnostic pop #endif -#pragma GCC visibility pop -#pragma GCC visibility push(hidden) - // Call this function when you hit a static_type which is a base (above) a dst_type. // Let caller know you hit a static_type. But only start recording details if // this is (static_ptr, static_type) -- the node we are casting from. @@ -1274,6 +1291,4 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, use_strcmp); } -#pragma GCC visibility pop - } // __cxxabiv1 diff --git a/lib/libcxxabi/src/private_typeinfo.h b/lib/libcxxabi/src/private_typeinfo.h index ef98c3ae60b..3922ae6ef56 100644 --- a/lib/libcxxabi/src/private_typeinfo.h +++ b/lib/libcxxabi/src/private_typeinfo.h @@ -16,7 +16,6 @@ #include namespace __cxxabiv1 { -#pragma GCC visibility push(hidden) class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info { public: @@ -67,7 +66,7 @@ enum class _LIBCXXABI_TYPE_VIS __class_type_info; -struct __dynamic_cast_info +struct _LIBCXXABI_HIDDEN __dynamic_cast_info { // const data supplied to the search: @@ -153,7 +152,7 @@ public: has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const; }; -struct __base_class_type_info +struct _LIBCXXABI_HIDDEN __base_class_type_info { public: const __class_type_info* __base_type; @@ -206,7 +205,22 @@ public: __volatile_mask = 0x2, __restrict_mask = 0x4, __incomplete_mask = 0x8, - __incomplete_class_mask = 0x10 + __incomplete_class_mask = 0x10, + __transaction_safe_mask = 0x20, + // This implements the following proposal from cxx-abi-dev (not yet part of + // the ABI document): + // + // http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html + // + // This is necessary for support of http://wg21.link/p0012, which permits + // throwing noexcept function and member function pointers and catching + // them as non-noexcept pointers. + __noexcept_mask = 0x40, + + // Flags that cannot be removed by a standard conversion. + __no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask, + // Flags that cannot be added by a standard conversion. + __no_add_flags_mask = __transaction_safe_mask | __noexcept_mask }; _LIBCXXABI_HIDDEN virtual ~__pbase_type_info(); @@ -233,8 +247,6 @@ public: _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const; }; -#pragma GCC visibility pop - } // __cxxabiv1 #endif // __PRIVATE_TYPEINFO_H_ diff --git a/lib/libcxxabi/src/stdlib_exception.cpp b/lib/libcxxabi/src/stdlib_exception.cpp new file mode 100644 index 00000000000..a8f71ab0ecc --- /dev/null +++ b/lib/libcxxabi/src/stdlib_exception.cpp @@ -0,0 +1,103 @@ +//===---------------------------- exception.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define _LIBCPP_BUILDING_LIBRARY +#define _LIBCPP_BUILDING_NEW +#include +#include + +namespace std +{ + +// exception + +exception::~exception() _NOEXCEPT +{ +} + +const char* exception::what() const _NOEXCEPT +{ + return "std::exception"; +} + +// bad_exception + +bad_exception::~bad_exception() _NOEXCEPT +{ +} + +const char* bad_exception::what() const _NOEXCEPT +{ + return "std::bad_exception"; +} + + +// bad_alloc + +bad_alloc::bad_alloc() _NOEXCEPT +{ +} + +bad_alloc::~bad_alloc() _NOEXCEPT +{ +} + +const char* +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 +{ +} + +const char* +bad_array_new_length::what() const _NOEXCEPT +{ + return "bad_array_new_length"; +} + +// bad_array_length + +#ifndef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED + +class _LIBCPP_EXCEPTION_ABI bad_array_length + : public bad_alloc +{ +public: + bad_array_length() _NOEXCEPT; + virtual ~bad_array_length() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +#endif // _LIBCPP_BAD_ARRAY_LENGTH_DEFINED + +bad_array_length::bad_array_length() _NOEXCEPT +{ +} + +bad_array_length::~bad_array_length() _NOEXCEPT +{ +} + +const char* +bad_array_length::what() const _NOEXCEPT +{ + return "bad_array_length"; +} + + +} // std diff --git a/lib/libcxxabi/src/stdlib_new_delete.cpp b/lib/libcxxabi/src/stdlib_new_delete.cpp new file mode 100644 index 00000000000..0e85f6ad299 --- /dev/null +++ b/lib/libcxxabi/src/stdlib_new_delete.cpp @@ -0,0 +1,264 @@ +//===--------------------- stdlib_new_delete.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the new and delete operators. +//===----------------------------------------------------------------------===// + +#define _LIBCPP_BUILDING_NEW +#define _LIBCPP_BUILDING_LIBRARY +#include "__cxxabi_config.h" +#include +#include + +#if !defined(_THROW_BAD_ALLOC) || !defined(_NOEXCEPT) || !defined(_LIBCXXABI_WEAK) +#error The _THROW_BAD_ALLOC, _NOEXCEPT, and _LIBCXXABI_WEAK libc++ macros must \ + already be defined by libc++. +#endif +// Implement all new and delete operators as weak definitions +// in this shared library, so that they can be overridden by programs +// that define non-weak copies of the functions. + +_LIBCXXABI_WEAK +void * +operator new(std::size_t size) _THROW_BAD_ALLOC +{ + if (size == 0) + size = 1; + void* p; + while ((p = ::malloc(size)) == 0) + { + // If malloc fails and there is a new_handler, + // call it to try free up memory. + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else +#ifndef _LIBCXXABI_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + break; +#endif + } + return p; +} + +_LIBCXXABI_WEAK +void* +operator new(size_t size, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCXXABI_NO_EXCEPTIONS + try + { +#endif // _LIBCXXABI_NO_EXCEPTIONS + p = ::operator new(size); +#ifndef _LIBCXXABI_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCXXABI_NO_EXCEPTIONS + return p; +} + +_LIBCXXABI_WEAK +void* +operator new[](size_t size) _THROW_BAD_ALLOC +{ + return ::operator new(size); +} + +_LIBCXXABI_WEAK +void* +operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCXXABI_NO_EXCEPTIONS + try + { +#endif // _LIBCXXABI_NO_EXCEPTIONS + p = ::operator new[](size); +#ifndef _LIBCXXABI_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCXXABI_NO_EXCEPTIONS + return p; +} + +_LIBCXXABI_WEAK +void +operator delete(void* ptr) _NOEXCEPT +{ + if (ptr) + ::free(ptr); +} + +_LIBCXXABI_WEAK +void +operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT +{ + ::operator delete(ptr); +} + +_LIBCXXABI_WEAK +void +operator delete(void* ptr, size_t) _NOEXCEPT +{ + ::operator delete(ptr); +} + +_LIBCXXABI_WEAK +void +operator delete[] (void* ptr) _NOEXCEPT +{ + ::operator delete(ptr); +} + +_LIBCXXABI_WEAK +void +operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT +{ + ::operator delete[](ptr); +} + +_LIBCXXABI_WEAK +void +operator delete[] (void* ptr, size_t) _NOEXCEPT +{ + ::operator delete[](ptr); +} + +#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + +_LIBCXXABI_WEAK +void * +operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC +{ + if (size == 0) + size = 1; + if (static_cast(alignment) < sizeof(void*)) + alignment = std::align_val_t(sizeof(void*)); + void* p; +#if defined(_LIBCPP_WIN32API) + while ((p = _aligned_malloc(size, static_cast(alignment))) == nullptr) +#else + while (::posix_memalign(&p, static_cast(alignment), size) != 0) +#endif + { + // If posix_memalign fails and there is a new_handler, + // call it to try free up memory. + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else { +#ifndef _LIBCXXABI_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + p = nullptr; // posix_memalign doesn't initialize 'p' on failure + break; +#endif + } + } + return p; +} + +_LIBCXXABI_WEAK +void* +operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCXXABI_NO_EXCEPTIONS + try + { +#endif // _LIBCXXABI_NO_EXCEPTIONS + p = ::operator new(size, alignment); +#ifndef _LIBCXXABI_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCXXABI_NO_EXCEPTIONS + return p; +} + +_LIBCXXABI_WEAK +void* +operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC +{ + return ::operator new(size, alignment); +} + +_LIBCXXABI_WEAK +void* +operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCXXABI_NO_EXCEPTIONS + try + { +#endif // _LIBCXXABI_NO_EXCEPTIONS + p = ::operator new[](size, alignment); +#ifndef _LIBCXXABI_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCXXABI_NO_EXCEPTIONS + return p; +} + +_LIBCXXABI_WEAK +void +operator delete(void* ptr, std::align_val_t) _NOEXCEPT +{ + if (ptr) +#if defined(_LIBCPP_WIN32API) + ::_aligned_free(ptr); +#else + ::free(ptr); +#endif +} + +_LIBCXXABI_WEAK +void +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(ptr, alignment); +} + +_LIBCXXABI_WEAK +void +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[](ptr, alignment); +} + +_LIBCXXABI_WEAK +void +operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT +{ + ::operator delete[](ptr, alignment); +} + +#endif // !_LIBCPP_HAS_NO_ALIGNED_ALLOCATION diff --git a/lib/libcxxabi/src/stdlib_stdexcept.cpp b/lib/libcxxabi/src/stdlib_stdexcept.cpp new file mode 100644 index 00000000000..e3b7cd40658 --- /dev/null +++ b/lib/libcxxabi/src/stdlib_stdexcept.cpp @@ -0,0 +1,48 @@ +//===------------------------ stdexcept.cpp -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "include/refstring.h" +#include "stdexcept" +#include "new" +#include +#include +#include +#include + +static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); + +namespace std // purposefully not using versioning namespace +{ + +logic_error::~logic_error() _NOEXCEPT {} + +const char* +logic_error::what() const _NOEXCEPT +{ + return __imp_.c_str(); +} + +runtime_error::~runtime_error() _NOEXCEPT {} + +const char* +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 {} + +range_error::~range_error() _NOEXCEPT {} +overflow_error::~overflow_error() _NOEXCEPT {} +underflow_error::~underflow_error() _NOEXCEPT {} + +} // std diff --git a/lib/libcxxabi/src/stdlib_typeinfo.cpp b/lib/libcxxabi/src/stdlib_typeinfo.cpp new file mode 100644 index 00000000000..9313be04a39 --- /dev/null +++ b/lib/libcxxabi/src/stdlib_typeinfo.cpp @@ -0,0 +1,53 @@ +//===----------------------------- typeinfo.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +namespace std +{ + +// type_info + +type_info::~type_info() +{ +} + +// bad_cast + +bad_cast::bad_cast() _NOEXCEPT +{ +} + +bad_cast::~bad_cast() _NOEXCEPT +{ +} + +const char* +bad_cast::what() const _NOEXCEPT +{ + return "std::bad_cast"; +} + +// bad_typeid + +bad_typeid::bad_typeid() _NOEXCEPT +{ +} + +bad_typeid::~bad_typeid() _NOEXCEPT +{ +} + +const char* +bad_typeid::what() const _NOEXCEPT +{ + return "std::bad_typeid"; +} + +} // std