diff options
Diffstat (limited to 'chromium/buildtools/third_party/libc++abi')
14 files changed, 3192 insertions, 1674 deletions
diff --git a/chromium/buildtools/third_party/libc++abi/BUILD.gn b/chromium/buildtools/third_party/libc++abi/BUILD.gn index cf33e624bee..ef5e2f6047b 100644 --- a/chromium/buildtools/third_party/libc++abi/BUILD.gn +++ b/chromium/buildtools/third_party/libc++abi/BUILD.gn @@ -4,10 +4,11 @@ source_set("libc++abi") { visibility = [ "//buildtools/third_party/libc++" ] + deps = [] # This condition should match the one in build/config/c++. - if ((is_linux && current_cpu == "arm") || is_fuchsia) { - deps = [ + if (current_cpu == "arm" || is_fuchsia) { + deps += [ "//buildtools/third_party/libunwind", ] } @@ -15,7 +16,6 @@ source_set("libc++abi") { "trunk/src/abort_message.cpp", "trunk/src/cxa_aux_runtime.cpp", "trunk/src/cxa_default_handlers.cpp", - "trunk/src/cxa_demangle.cpp", "trunk/src/cxa_exception.cpp", "trunk/src/cxa_exception_storage.cpp", "trunk/src/cxa_guard.cpp", @@ -34,6 +34,14 @@ source_set("libc++abi") { "trunk/src/stdlib_stdexcept.cpp", "trunk/src/stdlib_typeinfo.cpp", ] + + # On Android, android_crazy_linker provides __cxa_demangle. + if (is_android) { + deps += [ "//third_party/android_crazy_linker" ] + } else { + sources += [ "trunk/src/cxa_demangle.cpp" ] + } + # This file should really be included on linux as well, but that # would introduce an unwanted glibc 2.18 dependency. if (is_posix && !is_mac && !is_linux) { @@ -41,11 +49,13 @@ source_set("libc++abi") { } configs -= [ "//build/config/compiler:chromium_code", + "//build/config/compiler:no_exceptions", "//build/config/compiler:no_rtti", - "//build/config/gcc:no_exceptions", + "//build/config/coverage:default_coverage", ] configs += [ "//build/config/compiler:no_chromium_code", + "//build/config/compiler:exceptions", "//build/config/compiler:rtti", "//buildtools/third_party/libc++:config", ] diff --git a/chromium/buildtools/third_party/libc++abi/README.chromium b/chromium/buildtools/third_party/libc++abi/README.chromium index c676b3befb0..a57429eeaa3 100644 --- a/chromium/buildtools/third_party/libc++abi/README.chromium +++ b/chromium/buildtools/third_party/libc++abi/README.chromium @@ -4,10 +4,8 @@ URL: http://libcxxabi.llvm.org/ Version: 1.0 License: MIT, University of Illinois/NCSA Open Source License License File: trunk/LICENSE.TXT -Security Critical: no +Security Critical: yes Description: libc++abi for Chromium. -This is intended for instrumented builds, not for release. -There was no security review for this library. diff --git a/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt b/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt index 2a0b4da1621..456250e6d89 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt +++ b/chromium/buildtools/third_party/libc++abi/trunk/CMakeLists.txt @@ -1,3 +1,5 @@ +# See www/CMake.html for instructions on how to build libcxxabi with CMake. + #=============================================================================== # Setup Project #=============================================================================== @@ -16,121 +18,28 @@ set(CMAKE_MODULE_PATH ) if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - project(libcxxabi) - - # Rely on llvm-config. - set(CONFIG_OUTPUT) - if (NOT LLVM_CONFIG_PATH) - find_program(LLVM_CONFIG_PATH "llvm-config") - endif() - if(DEFINED LLVM_PATH) - set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") - set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) - set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") - elseif(LLVM_CONFIG_PATH) - message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") - set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} - "--includedir" - "--prefix" - "--src-root") - execute_process( - COMMAND ${CONFIG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE CONFIG_OUTPUT - ) - if(NOT HAD_ERROR) - string(REGEX REPLACE - "[ \t]*[\r\n]+[ \t]*" ";" - CONFIG_OUTPUT ${CONFIG_OUTPUT}) - else() - string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") - message(STATUS "${CONFIG_COMMAND_STR}") - message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") - endif() - - list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) - list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) - list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) - - set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") - set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") - set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") - set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py") - - # --cmakedir is supported since llvm r291218 (4.0 release) - execute_process( - COMMAND ${LLVM_CONFIG_PATH} --cmakedir - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE CONFIG_OUTPUT - ERROR_QUIET) - if(NOT HAD_ERROR) - string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) - else() - set(LLVM_CMAKE_PATH - "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") - endif() - else() - message(FATAL_ERROR "llvm-config not found and LLVM_MAIN_SRC_DIR not defined. " - "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config " - "or -DLLVM_PATH=path/to/llvm-source-root.") - endif() - - if(EXISTS ${LLVM_CMAKE_PATH}) - list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") - include("${LLVM_CMAKE_PATH}/AddLLVM.cmake") - include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake") - else() - message(FATAL_ERROR "Not found: ${LLVM_CMAKE_PATH}") - endif() + project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 5.0.0svn) + set(PACKAGE_VERSION 6.0.0svn) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") - if (NOT DEFINED LLVM_INCLUDE_TESTS) - set(LLVM_INCLUDE_TESTS ON) - endif() - - if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - else() - # Seek installed Lit. - find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit - DOC "Path to lit.py") - endif() - - if(LLVM_LIT) - # Define the default arguments to use with 'lit', and an option for the user - # to override. - set(LIT_ARGS_DEFAULT "-sv") - if (MSVC OR XCODE) - set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") - endif() - set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") - - # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. - if( WIN32 AND NOT CYGWIN ) - set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") - endif() - else() - set(LLVM_INCLUDE_TESTS OFF) - endif() - - set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING - "Define suffix of library directory name (32/64)") - - set(LIBCXXABI_STANDALONE_BUILD 1) -else() - set(LLVM_MAIN_SRC_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "Path to LLVM source tree") - set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py") - set(LIBCXXABI_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX}) + # Find the LLVM sources and simulate LLVM CMake options. + include(HandleOutOfTreeLLVM) endif() +# Require out of source build. +include(MacroEnsureOutOfSourceBuild) +MACRO_ENSURE_OUT_OF_SOURCE_BUILD( + "${PROJECT_NAME} requires an out of source build. Please create a separate + build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there." + ) + #=============================================================================== # Setup CMake Options #=============================================================================== +include(CMakeDependentOption) include(HandleCompilerRT) # Define options. @@ -158,6 +67,8 @@ option(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS provides these definitions" ON) option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS}) option(LIBCXXABI_INCLUDE_TESTS "Generate build targets for the libc++abi unit tests." ${LLVM_INCLUDE_TESTS}) +set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") @@ -245,8 +156,16 @@ else() set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) endif() +set(LIBCXXABI_INSTALL_PREFIX "" CACHE STRING + "Define libc++abi destination prefix.") + +if (NOT LIBCXXABI_INSTALL_PREFIX MATCHES "^$|.*/") + message(FATAL_ERROR "LIBCXXABI_INSTALL_PREFIX has to end with \"/\".") +endif() + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) # By default, for non-standalone builds, libcxx and libcxxabi share a library # directory. @@ -264,30 +183,26 @@ elseif(LIBCXXABI_BUILD_32_BITS) message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.") endif() -#=============================================================================== -# Setup Compiler Flags -#=============================================================================== - -# Get required flags. -macro(append_if list condition var) - if (${condition}) - list(APPEND ${list} ${var}) - endif() -endmacro() - -macro(add_target_flags_if condition var) - if (${condition}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${var}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${var}") - list(APPEND LIBCXXABI_COMPILE_FLAGS ${var}) - list(APPEND LIBCXXABI_LINK_FLAGS ${var}) - endif() -endmacro() +# Declare libc++abi configuration variables. +# They are intended for use as follows: +# LIBCXXABI_C_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_CXX_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_COMPILE_FLAGS: Compile only flags. +# LIBCXXABI_LINK_FLAGS: Linker only flags. +# LIBCXXABI_LIBRARIES: libraries libc++abi is linked to. set(LIBCXXABI_C_FLAGS "") set(LIBCXXABI_CXX_FLAGS "") set(LIBCXXABI_COMPILE_FLAGS "") set(LIBCXXABI_LINK_FLAGS "") +set(LIBCXXABI_LIBRARIES "") + +# Include macros for adding and removing libc++abi flags. +include(HandleLibcxxabiFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== # Configure target flags add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") @@ -322,56 +237,57 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) # Disable DLL annotations on Windows for static builds. if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) - add_definitions(-D_LIBCXXABI_DISABLE_DLL_IMPORT_EXPORT) + add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) endif() -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror=return-type) +add_compile_flags_if_supported(-Werror=return-type) # Get warning flags -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_W_FLAG -W) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WALL_FLAG -Wall) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG -Wchar-subscripts) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WCONVERSION_FLAG -Wconversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG -Wmismatched-tags) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WMISSING_BRACES_FLAG -Wmissing-braces) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNEWLINE_EOF_FLAG -Wnewline-eof) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_FUNCTION_FLAG -Wunused-function) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHADOW_FLAG -Wshadow) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG -Wshorten-64-to-32) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_COMPARE_FLAG -Wsign-compare) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG -Wsign-conversion) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG -Wstrict-aliasing=2) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG -Wstrict-overflow=4) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG -Wunused-parameter) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG -Wunused-variable) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WWRITE_STRINGS_FLAG -Wwrite-strings) -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WUNDEF_FLAG -Wundef) +add_compile_flags_if_supported(-W) +add_compile_flags_if_supported(-Wall) +add_compile_flags_if_supported(-Wchar-subscripts) +add_compile_flags_if_supported(-Wconversion) +add_compile_flags_if_supported(-Wmismatched-tags) +add_compile_flags_if_supported(-Wmissing-braces) +add_compile_flags_if_supported(-Wnewline-eof) +add_compile_flags_if_supported(-Wunused-function) +add_compile_flags_if_supported(-Wshadow) +add_compile_flags_if_supported(-Wshorten-64-to-32) +add_compile_flags_if_supported(-Wsign-compare) +add_compile_flags_if_supported(-Wsign-conversion) +add_compile_flags_if_supported(-Wstrict-aliasing=2) +add_compile_flags_if_supported(-Wstrict-overflow=4) +add_compile_flags_if_supported(-Wunused-parameter) +add_compile_flags_if_supported(-Wunused-variable) +add_compile_flags_if_supported(-Wwrite-strings) +add_compile_flags_if_supported(-Wundef) if (LIBCXXABI_ENABLE_WERROR) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WERROR_FLAG -Werror) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WX_FLAG -WX) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) else() - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_WNO_ERROR_FLAG -Wno-error) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_NO_WX_FLAG -WX-) + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) endif() if (LIBCXXABI_ENABLE_PEDANTIC) - append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_PEDANTIC_FLAG -pedantic) + add_compile_flags_if_supported(-pedantic) endif() # Get feature flags. -append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG -fstrict-aliasing) +add_compile_flags_if_supported(-fstrict-aliasing) # Exceptions if (LIBCXXABI_ENABLE_EXCEPTIONS) # Catches C++ exceptions only and tells the compiler to assume that extern C # functions never throw a C++ exception. - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_EHSC_FLAG -EHsc) - append_if(LIBCXXABI_C_FLAGS LIBCXXABI_HAS_FUNWIND_TABLES -funwind-tables) + add_compile_flags_if_supported(-EHsc) + # Do we really need to be run through the C compiler ? + add_c_compile_flags_if_supported(-funwind-tables) else() add_definitions(-D_LIBCXXABI_NO_EXCEPTIONS) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG -fno-exceptions) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHS_FLAG -EHs-) - append_if(LIBCXXABI_CXX_FLAGS LIBCXXABI_HAS_NO_EHA_FLAG -EHa-) + add_compile_flags_if_supported(-fno-exceptions) + add_compile_flags_if_supported(-EHs-) + add_compile_flags_if_supported(-EHa-) endif() # Assert @@ -429,6 +345,12 @@ if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) endif() endif() +if (LLVM_ENABLE_MODULES) + # Ignore that the rest of the modules flags are now unused. + add_compile_flags_if_supported(-Wno-unused-command-line-argument) + add_compile_flags(-fno-modules) +endif() + set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS OFF) if ((NOT LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) OR (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXXABI_ENABLE_SHARED) @@ -504,21 +426,6 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) NO_DEFAULT_PATH ) - find_path( - LIBCXXABI_LIBUNWIND_SOURCES - libunwind_ext.h - PATHS ${LIBCXXABI_LIBUNWIND_PATH}/src/ - ${LIBCXXABI_LIBUNWIND_INCLUDES}/../src/ - ${LLVM_MAIN_SRC_DIR}/projects/libunwind/src/ - ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/src/ - NO_DEFAULT_PATH - ) - - if (LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "LIBCXXABI_LIBUNWIND_SOURCES-NOTFOUND") - message(WARNING "LIBCXXABI_LIBUNWIND_SOURCES was not specified and couldn't be infered.") - set(LIBCXXABI_LIBUNWIND_SOURCES "") - endif() - if (LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL-NOTFOUND") set(LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL "") endif() @@ -526,10 +433,6 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) if (NOT LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "") include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}") endif() - - if (NOT LIBCXXABI_LIBUNWIND_SOURCES STREQUAL "") - include_directories("${LIBCXXABI_LIBUNWIND_SOURCES}") - endif() endif() # Add source code. This also contains all of the logic for deciding linker flags diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake new file mode 100644 index 00000000000..3eddd7bdc62 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleLibcxxabiFlags.cmake @@ -0,0 +1,208 @@ +# HandleLibcxxFlags - A set of macros used to setup the flags used to compile +# and link libc++abi. These macros add flags to the following CMake variables. +# - LIBCXXABI_COMPILE_FLAGS: flags used to compile libc++abi +# - LIBCXXABI_LINK_FLAGS: flags used to link libc++abi +# - LIBCXXABI_LIBRARIES: libraries to link libc++abi to. + +include(CheckCXXCompilerFlag) + +unset(add_flag_if_supported) + +# Mangle the name of a compiler flag into a valid CMake identifier. +# Ex: --std=c++11 -> STD_EQ_CXX11 +macro(mangle_name str output) + string(STRIP "${str}" strippedStr) + string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") + string(REPLACE "-" "_" strippedStr "${strippedStr}") + string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") + string(REPLACE "+" "X" strippedStr "${strippedStr}") + string(TOUPPER "${strippedStr}" ${output}) +endmacro() + +# Remove a list of flags from all CMake variables that affect compile flags. +# This can be used to remove unwanted flags specified on the command line +# or added in other parts of LLVM's cmake configuration. +macro(remove_flags) + foreach(var ${ARGN}) + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") + remove_definitions(${var}) + endforeach() +endmacro(remove_flags) + +macro(check_flag_supported flag) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") +endmacro() + +# Add a macro definition if condition is true. +macro(define_if condition def) + if (${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition if condition is not true. +macro(define_if_not condition def) + if (NOT ${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition to the __config_site file if the specified condition +# is 'true'. Note that '-D${def}' is not added. Instead it is expected that +# the build include the '__config_site' header. +macro(config_define_if condition def) + if (${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define_if_not condition def) + if (NOT ${condition}) + set(${def} ON) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define value def) + set(${def} ${value}) + set(LIBCXXABI_NEEDS_SITE_CONFIG ON) +endmacro() + +# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags) + foreach(value ${ARGN}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to +# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXXABI_COMPILE_FLAGS' +# and 'LIBCXXABI_LINK_FLAGS'. +macro(add_target_flags_if condition) + if (${condition}) + add_target_flags(${ARGN}) + endif() +endmacro() + +# Add a specified list of flags to both 'LIBCXXABI_COMPILE_FLAGS' and +# 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags) + foreach(value ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${value}) + list(APPEND LIBCXXABI_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to both +# 'LIBCXXABI_COMPILE_FLAGS' and 'LIBCXXABI_LINK_FLAGS'. +macro(add_flags_if condition) + if (${condition}) + add_flags(${ARGN}) + endif() +endmacro() + +# Add each flag in the list to LIBCXXABI_COMPILE_FLAGS and LIBCXXABI_LINK_FLAGS +# if that flag is supported by the current compiler. +macro(add_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_COMPILE_FLAGS'. +macro(add_compile_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_COMPILE_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_COMPILE_FLAGS' +macro(add_compile_flags_if condition) + if (${condition}) + add_compile_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_COMPILE_FLAGS' if the +# flag is supported by the C compiler. +macro(add_c_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_c_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBCXXABI_LINK_FLAGS'. +macro(add_link_flags) + foreach(f ${ARGN}) + list(APPEND LIBCXXABI_LINK_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBCXXABI_LINK_FLAGS' +macro(add_link_flags_if condition) + if (${condition}) + add_link_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBCXXABI_LINK_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_link_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBCXXABI_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(LIBCXXABI_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of libraries or link flags to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags) + foreach(lib ${ARGN}) + list(APPEND LIBCXXABI_LIBRARIES ${lib}) + endforeach() +endmacro() + +# if 'condition' is true then add the specified list of libraries and flags +# to 'LIBCXXABI_LIBRARIES'. +macro(add_library_flags_if condition) + if(${condition}) + add_library_flags(${ARGN}) + endif() +endmacro() + +# Turn a comma separated CMake list into a space separated string. +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake new file mode 100644 index 00000000000..8e742088978 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/HandleOutOfTreeLLVM.cmake @@ -0,0 +1,131 @@ +macro(find_llvm_parts) +# Rely on llvm-config. + set(CONFIG_OUTPUT) + if(NOT LLVM_CONFIG_PATH) + find_program(LLVM_CONFIG_PATH "llvm-config") + endif() + if(DEFINED LLVM_PATH) + set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") + set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) + set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") + elseif(LLVM_CONFIG_PATH) + message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") + set(LIBCXXABI_USING_INSTALLED_LLVM 1) + set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} + "--includedir" + "--prefix" + "--src-root") + execute_process( + COMMAND ${CONFIG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ) + if(NOT HAD_ERROR) + string(REGEX REPLACE + "[ \t]*[\r\n]+[ \t]*" ";" + CONFIG_OUTPUT ${CONFIG_OUTPUT}) + else() + string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") + message(STATUS "${CONFIG_COMMAND_STR}") + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + + list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) + list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) + list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) + + set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + + # --cmakedir is supported since llvm r291218 (4.0 release) + execute_process( + COMMAND ${LLVM_CONFIG_PATH} --cmakedir + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ERROR_QUIET) + if(NOT HAD_ERROR) + string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) + else() + set(LLVM_CMAKE_PATH + "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") + endif() + else() + set(LLVM_FOUND OFF) + message(WARNING "UNSUPPORTED LIBCXXABI CONFIGURATION DETECTED: " + "llvm-config not found and LLVM_PATH not defined.\n" + "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config " + "or -DLLVM_PATH=path/to/llvm-source-root.") + return() + endif() + + if (EXISTS "${LLVM_CMAKE_PATH}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + elseif (EXISTS "${LLVM_MAIN_SRC_DIR}/cmake/modules") + list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules") + else() + set(LLVM_FOUND OFF) + message(WARNING "Neither ${LLVM_CMAKE_PATH} nor ${LLVM_MAIN_SRC_DIR}/cmake/modules found") + return() + endif() + + set(LLVM_FOUND ON) +endmacro(find_llvm_parts) + +macro(configure_out_of_tree_llvm) + message(STATUS "Configuring for standalone build.") + set(LIBCXXABI_STANDALONE_BUILD 1) + + find_llvm_parts() + + # Add LLVM Functions -------------------------------------------------------- + if (LLVM_FOUND AND LIBCXXABI_USING_INSTALLED_LLVM) + include(LLVMConfig) # For TARGET_TRIPLE + else() + if (WIN32) + set(LLVM_ON_UNIX 0) + set(LLVM_ON_WIN32 1) + else() + set(LLVM_ON_UNIX 1) + set(LLVM_ON_WIN32 0) + endif() + endif() + if (LLVM_FOUND) + include(AddLLVM OPTIONAL) + include(HandleLLVMOptions OPTIONAL) + endif() + + # LLVM Options -------------------------------------------------------------- + if (NOT DEFINED LLVM_INCLUDE_TESTS) + set(LLVM_INCLUDE_TESTS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_INCLUDE_DOCS) + set(LLVM_INCLUDE_DOCS ${LLVM_FOUND}) + endif() + if (NOT DEFINED LLVM_ENABLE_SPHINX) + set(LLVM_ENABLE_SPHINX OFF) + endif() + + # Required LIT Configuration ------------------------------------------------ + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + # Required doc configuration + if (LLVM_ENABLE_SPHINX) + find_package(Sphinx REQUIRED) + endif() + + if (LLVM_ON_UNIX AND NOT APPLE) + set(LLVM_HAVE_LINK_VERSION_SCRIPT 1) + else() + set(LLVM_HAVE_LINK_VERSION_SCRIPT 0) + endif() +endmacro(configure_out_of_tree_llvm) + +configure_out_of_tree_llvm() diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 00000000000..e75002bd8b7 --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,18 @@ +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>) + +macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) + +string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) +if( _insource ) + message( SEND_ERROR "${_errorMessage}" ) + message( FATAL_ERROR + "In-source builds are not allowed. + CMake would overwrite the makefiles distributed with libcxxabi. + Please create a directory and run cmake from there, passing the path + to this source directory as the last argument. + This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. + Please delete them." + ) +endif( _insource ) + +endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake b/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake index 5541ed41a0f..379b5547749 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake +++ b/chromium/buildtools/third_party/libc++abi/trunk/cmake/config-ix.cmake @@ -36,7 +36,7 @@ if (LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) set(MINGW_RUNTIME gcc_s gcc) endif() set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 - shell32 user32 kernel32 iconv mingw32 ${MINGW_RUNTIME} + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) endif() @@ -50,7 +50,6 @@ endif () # Check compiler flags check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES) -check_cxx_compiler_flag(-fPIC LIBCXXABI_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fno-exceptions LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fno-rtti LIBCXXABI_HAS_NO_RTTI_FLAG) check_cxx_compiler_flag(-fstrict-aliasing LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG) @@ -82,11 +81,6 @@ check_cxx_compiler_flag(/EHsc LIBCXXABI_HAS_EHSC_FLAG) check_cxx_compiler_flag(/EHs- LIBCXXABI_HAS_NO_EHS_FLAG) check_cxx_compiler_flag(/EHa- LIBCXXABI_HAS_NO_EHA_FLAG) check_cxx_compiler_flag(/GR- LIBCXXABI_HAS_NO_GR_FLAG) -check_cxx_compiler_flag(-std=c++11 LIBCXXABI_HAS_STD_CXX11) - -if(LIBCXXABI_HAS_STD_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -endif() # Check libraries check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt b/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt index d844b7fb718..adcc412880c 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/CMakeLists.txt @@ -52,36 +52,32 @@ if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) endif() -# Generate library list -set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES}) - if (LIBCXXABI_ENABLE_THREADS) - append_if(libraries LIBCXXABI_HAS_PTHREAD_LIB pthread) + add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) endif() -append_if(libraries LIBCXXABI_HAS_C_LIB c) +add_library_flags_if(LIBCXXABI_HAS_C_LIB c) if (LIBCXXABI_USE_LLVM_UNWINDER) # Prefer using the in-tree version of libunwind, either shared or static. If # none are found fall back to using -lunwind. # FIXME: Is it correct to prefer the static version of libunwind? if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND libraries unwind_shared) + list(APPEND LIBCXXABI_LIBRARIES unwind_shared) elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND libraries unwind_static) + list(APPEND LIBCXXABI_LIBRARIES unwind_static) else() - list(APPEND libraries unwind) + list(APPEND LIBCXXABI_LIBRARIES unwind) endif() else() - append_if(libraries LIBCXXABI_HAS_GCC_S_LIB gcc_s) + add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) endif() if (MINGW) # MINGW_LIBRARIES is defined in config-ix.cmake - list(APPEND libraries ${MINGW_LIBRARIES}) + list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) endif() # Setup flags. -append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_FPIC_FLAG -fPIC) -append_if(LIBCXXABI_LINK_FLAGS LIBCXXABI_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs) +add_link_flags_if_supported(-nodefaultlibs) set(LIBCXXABI_SHARED_LINK_FLAGS) @@ -101,9 +97,9 @@ if ( APPLE ) endif() endif() -string(REPLACE ";" " " LIBCXXABI_COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}") -string(REPLACE ";" " " LIBCXXABI_SHARED_LINK_FLAGS "${LIBCXXABI_SHARED_LINK_FLAGS}") +split_list(LIBCXXABI_COMPILE_FLAGS) +split_list(LIBCXXABI_LINK_FLAGS) +split_list(LIBCXXABI_SHARED_LINK_FLAGS) # FIXME: libc++abi.so will not link when modules are enabled because it depends # on symbols defined in libc++.so which has not yet been built. @@ -113,37 +109,64 @@ endif() # Add a object library that contains the compiled source files. add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) - set_target_properties(cxxabi_objects - PROPERTIES - COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + COMPILE_FLAGS + "${LIBCXXABI_COMPILE_FLAGS}" + POSITION_INDEPENDENT_CODE + ON) set(LIBCXXABI_TARGETS) # Build the shared library. if (LIBCXXABI_ENABLE_SHARED) add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>) - target_link_libraries(cxxabi_shared ${libraries}) + target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_shared - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - VERSION "1.0" - SOVERSION "1" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON + SOVERSION + "1" + VERSION + "1.0") list(APPEND LIBCXXABI_TARGETS "cxxabi_shared") endif() # Build the static library. if (LIBCXXABI_ENABLE_STATIC) add_library(cxxabi_static STATIC $<TARGET_OBJECTS:cxxabi_objects>) - target_link_libraries(cxxabi_static ${libraries}) + target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES}) set_target_properties(cxxabi_static - PROPERTIES - LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME "c++abi" - ) + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + LINK_FLAGS + "${LIBCXXABI_LINK_FLAGS}" + OUTPUT_NAME + "c++abi" + POSITION_INDEPENDENT_CODE + ON) list(APPEND LIBCXXABI_TARGETS "cxxabi_static") endif() @@ -151,8 +174,8 @@ endif() add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS}) install(TARGETS ${LIBCXXABI_TARGETS} - LIBRARY DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ARCHIVE DESTINATION lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi ) if (NOT CMAKE_CONFIGURATION_TYPES) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp index d8734fbbf9d..7d173189835 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp @@ -13,8 +13,8 @@ #include <vector> #include <algorithm> -#include <string> #include <numeric> +#include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> @@ -41,75 +41,1669 @@ enum success }; -template <class C> - const char* parse_type(const char* first, const char* last, C& db); -template <class C> - const char* parse_encoding(const char* first, const char* last, C& db); -template <class C> - const char* parse_name(const char* first, const char* last, C& db, - bool* ends_with_template_args = 0); -template <class C> - const char* parse_expression(const char* first, const char* last, C& db); -template <class C> - const char* parse_template_args(const char* first, const char* last, C& db); -template <class C> - const char* parse_operator_name(const char* first, const char* last, C& db); -template <class C> - const char* parse_unqualified_name(const char* first, const char* last, C& db); -template <class C> - const char* parse_decltype(const char* first, const char* last, C& db); - -template <class C> -void -print_stack(const C& db) +class StringView { + const char *First; + const char *Last; + +public: + template <size_t N> + StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} + StringView(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + StringView() : First(nullptr), Last(nullptr) {} + + StringView substr(size_t From, size_t To) { + if (To >= size()) + To = size() - 1; + if (From >= size()) + From = size() - 1; + return StringView(First + From, First + To); + } + + StringView dropFront(size_t N) const { + if (N >= size()) + N = size() - 1; + return StringView(First + N, Last); + } + + bool startsWith(StringView Str) const { + if (Str.size() > size()) + return false; + return std::equal(Str.begin(), Str.end(), begin()); + } + + const char &operator[](size_t Idx) const { return *(begin() + Idx); } + + const char *begin() const { return First; } + const char *end() const { return Last; } + size_t size() const { return static_cast<size_t>(Last - First); } +}; + +bool operator==(const StringView &LHS, const StringView &RHS) { + return LHS.size() == RHS.size() && + std::equal(LHS.begin(), LHS.end(), RHS.begin()); +} + +// Stream that AST nodes write their string representation into after the AST +// has been parsed. +class OutputStream { + char *Buffer; + size_t CurrentPosition; + size_t BufferCapacity; + + // Ensure there is at least n more positions in buffer. + void grow(size_t N) { + if (N + CurrentPosition >= BufferCapacity) { + BufferCapacity *= 2; + if (BufferCapacity < N + CurrentPosition) + BufferCapacity = N + CurrentPosition; + Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); + } + } + +public: + OutputStream(char *StartBuf, size_t Size) + : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} + + OutputStream &operator+=(StringView R) { + size_t Size = R.size(); + if (Size == 0) + return *this; + grow(Size); + memmove(Buffer + CurrentPosition, R.begin(), Size); + CurrentPosition += Size; + return *this; + } + + OutputStream &operator+=(char C) { + grow(1); + Buffer[CurrentPosition++] = C; + return *this; + } + + // Offset of position in buffer, used for building stream_string_view. + typedef unsigned StreamPosition; + + // StringView into a stream, used for caching the ast nodes. + class StreamStringView { + StreamPosition First, Last; + + friend class OutputStream; + + public: + StreamStringView() : First(0), Last(0) {} + + StreamStringView(StreamPosition First_, StreamPosition Last_) + : First(First_), Last(Last_) {} + + bool empty() const { return First == Last; } + }; + + OutputStream &operator+=(StreamStringView &s) { + size_t Sz = static_cast<size_t>(s.Last - s.First); + if (Sz == 0) + return *this; + grow(Sz); + memmove(Buffer + CurrentPosition, Buffer + s.First, Sz); + CurrentPosition += Sz; + return *this; + } + + StreamPosition getCurrentPosition() const { + return static_cast<StreamPosition>(CurrentPosition); + } + + StreamStringView makeStringViewFromPastPosition(StreamPosition Pos) { + return StreamStringView(Pos, getCurrentPosition()); + } + + char back() const { + return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + } + + bool empty() const { return CurrentPosition == 0; } + + char *getBuffer() { return Buffer; } + char *getBufferEnd() { return Buffer + CurrentPosition - 1; } + size_t getBufferCapacity() { return BufferCapacity; } +}; + +// Base class of all AST nodes. The AST is built by the parser, then is +// traversed by the printLeft/Right functions to produce a demangled string. +class Node { +public: + enum Kind : unsigned char { + KDotSuffix, + KVendorExtQualType, + KQualType, + KConversionOperatorType, + KPostfixQualifiedType, + KNameType, + KObjCProtoName, + KPointerType, + KLValueReferenceType, + KRValueReferenceType, + KPointerToMemberType, + KArrayType, + KFunctionType, + KTopLevelFunctionDecl, + KFunctionQualType, + KFunctionRefQualType, + KLiteralOperator, + KSpecialName, + KCtorVtableSpecialName, + KQualifiedName, + KEmptyName, + KVectorType, + KTemplateParams, + KNameWithTemplateArgs, + KGlobalQualifiedName, + KStdQualifiedName, + KExpandedSpecialSubstitution, + KSpecialSubstitution, + KCtorDtorName, + KDtorName, + KUnnamedTypeName, + KLambdaTypeName, + KExpr, + }; + + const Kind K; + +private: + // If this Node has any RHS part, potentally many Nodes further down. + const unsigned HasRHSComponent : 1; + const unsigned HasFunction : 1; + const unsigned HasArray : 1; + +public: + Node(Kind K_, bool HasRHS_ = false, bool HasFunction_ = false, + bool HasArray_ = false) + : K(K_), HasRHSComponent(HasRHS_), HasFunction(HasFunction_), + HasArray(HasArray_) {} + + bool hasRHSComponent() const { return HasRHSComponent; } + bool hasArray() const { return HasArray; } + bool hasFunction() const { return HasFunction; } + + void print(OutputStream &s) const { + printLeft(s); + if (hasRHSComponent()) + printRight(s); + } + + // Print the "left" side of this Node into OutputStream. + virtual void printLeft(OutputStream &) const = 0; + + // Print the "right". This distinction is necessary to represent C++ types + // that appear on the RHS of their subtype, such as arrays or functions. + // Since most types don't have such a component, provide a default + // implemenation. + virtual void printRight(OutputStream &) const {} + + virtual StringView getBaseName() const { return StringView(); } + + // Silence compiler warnings, this dtor will never be called. + virtual ~Node() = default; +}; + +class NodeArray { + Node **Elements; + size_t NumElements; + +public: + NodeArray() : NumElements(0) {} + NodeArray(Node **Elements_, size_t NumElements_) + : Elements(Elements_), NumElements(NumElements_) {} + + bool empty() const { return NumElements == 0; } + size_t size() const { return NumElements; } + + void printWithSeperator(OutputStream &S, StringView Seperator) const { + for (size_t Idx = 0; Idx != NumElements; ++Idx) { + if (Idx) + S += Seperator; + Elements[Idx]->print(S); + } + } +}; + +class DotSuffix final : public Node { + const Node *Prefix; + const StringView Suffix; + +public: + DotSuffix(Node *Prefix_, StringView Suffix_) + : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} + + void printLeft(OutputStream &s) const override { + Prefix->print(s); + s += " ("; + s += Suffix; + s += ")"; + } +}; + +class VendorExtQualType final : public Node { + const Node *Ext; + const Node *Ty; + +public: + VendorExtQualType(Node *Ext_, Node *Ty_) + : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + Ext->print(S); + S += " "; + Ty->printLeft(S); + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +enum Qualifiers { + QualNone = 0, + QualConst = 0x1, + QualVolatile = 0x2, + QualRestrict = 0x4, +}; + +void addQualifiers(Qualifiers &Q1, Qualifiers Q2) { + Q1 = static_cast<Qualifiers>(Q1 | Q2); +} + +class QualType : public Node { +protected: + const Qualifiers Quals; + const Node *Child; + + void printQuals(OutputStream &S) const { + if (Quals & QualConst) + S += " const"; + if (Quals & QualVolatile) + S += " volatile"; + if (Quals & QualRestrict) + S += " restrict"; + } + +public: + QualType(Node *Child_, Qualifiers Quals_) + : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + QualType(Node::Kind ChildKind_, Node *Child_, Qualifiers Quals_) + : Node(ChildKind_, Child_->hasRHSComponent(), Child_->hasFunction(), + Child_->hasArray()), + Quals(Quals_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + Child->printLeft(S); + printQuals(S); + } + + void printRight(OutputStream &S) const override { Child->printRight(S); } +}; + +class ConversionOperatorType final : public Node { + const Node *Ty; + +public: + ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {} + + void printLeft(OutputStream &S) const override { + S += "operator "; + Ty->print(S); + } +}; + +class PostfixQualifiedType final : public Node { + const Node *Ty; + const StringView Postfix; + +public: + PostfixQualifiedType(Node *Ty_, StringView Postfix_) + : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} + + void printLeft(OutputStream &s) const override { + Ty->printLeft(s); + s += Postfix; + } + + void printRight(OutputStream &S) const override { Ty->printRight(S); } +}; + +class NameType final : public Node { + const StringView Name; + +public: + NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + + StringView getName() const { return Name; } + StringView getBaseName() const override { return Name; } + + void printLeft(OutputStream &s) const override { s += Name; } +}; + +class ObjCProtoName : public Node { + Node *Ty; + Node *Protocol; + + friend class PointerType; + +public: + ObjCProtoName(Node *Ty_, Node *Protocol_) + : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + + bool isObjCObject() const { + return Ty->K == KNameType && + static_cast<NameType *>(Ty)->getName() == "objc_object"; + } + + void printLeft(OutputStream &S) const override { + Ty->printLeft(S); + S += "<"; + Protocol->printLeft(S); + S += ">"; + } +}; + +class PointerType final : public Node { + const Node *Pointee; + +public: + PointerType(Node *Pointee_) + : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. + if (Pointee->K != KObjCProtoName || + !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "("; + s += "*"; + } else { + const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); + s += "id<"; + objcProto->Protocol->print(s); + s += ">"; + } + } + + void printRight(OutputStream &s) const override { + if (Pointee->K != KObjCProtoName || + !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } + } +}; + +class LValueReferenceType final : public Node { + const Node *Pointee; + +public: + LValueReferenceType(Node *Pointee_) + : Node(KLValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&"; + else + s += "&"; + } + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class RValueReferenceType final : public Node { + const Node *Pointee; + +public: + RValueReferenceType(Node *Pointee_) + : Node(KRValueReferenceType, Pointee_->hasRHSComponent()), + Pointee(Pointee_) {} + + void printLeft(OutputStream &s) const override { + Pointee->printLeft(s); + if (Pointee->hasArray()) + s += " "; + if (Pointee->hasArray() || Pointee->hasFunction()) + s += "(&&"; + else + s += "&&"; + } + + void printRight(OutputStream &s) const override { + if (Pointee->hasArray() || Pointee->hasFunction()) + s += ")"; + Pointee->printRight(s); + } +}; + +class PointerToMemberType final : public Node { + const Node *ClassType; + const Node *MemberType; + +public: + PointerToMemberType(Node *ClassType_, Node *MemberType_) + : Node(KPointerToMemberType, MemberType_->hasRHSComponent()), + ClassType(ClassType_), MemberType(MemberType_) {} + + void printLeft(OutputStream &s) const override { + MemberType->printLeft(s); + if (MemberType->hasArray() || MemberType->hasFunction()) + s += "("; + else + s += " "; + ClassType->print(s); + s += "::*"; + } + + void printRight(OutputStream &s) const override { + if (MemberType->hasArray() || MemberType->hasFunction()) + s += ")"; + MemberType->printRight(s); + } +}; + +class NodeOrString { + const void *First; + const void *Second; + +public: + /* implicit */ NodeOrString(StringView Str) { + const char *FirstChar = Str.begin(); + const char *SecondChar = Str.end(); + if (SecondChar == nullptr) { + assert(FirstChar == SecondChar); + ++FirstChar, ++SecondChar; + } + First = static_cast<const void *>(FirstChar); + Second = static_cast<const void *>(SecondChar); + } + + /* implicit */ NodeOrString(Node *N) + : First(static_cast<const void *>(N)), Second(nullptr) {} + NodeOrString() : First(nullptr), Second(nullptr) {} + + bool isString() const { return Second && First; } + bool isNode() const { return First && !Second; } + bool isEmpty() const { return !First && !Second; } + + StringView asString() const { + assert(isString()); + return StringView(static_cast<const char *>(First), + static_cast<const char *>(Second)); + } + + const Node *asNode() const { + assert(isNode()); + return static_cast<const Node *>(First); + } +}; + +class ArrayType final : public Node { + Node *Base; + NodeOrString Dimension; + +public: + ArrayType(Node *Base_, NodeOrString Dimension_) + : Node(KArrayType, true, false, true), Base(Base_), Dimension(Dimension_) {} + + // Incomplete array type. + ArrayType(Node *Base_) : Node(KArrayType, true, false, true), Base(Base_) {} + + void printLeft(OutputStream &S) const override { Base->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (S.back() != ']') + S += " "; + S += "["; + if (Dimension.isString()) + S += Dimension.asString(); + else if (Dimension.isNode()) + Dimension.asNode()->print(S); + S += "]"; + Base->printRight(S); + } +}; + +class FunctionType final : public Node { + Node *Ret; + NodeArray Params; + +public: + FunctionType(Node *Ret_, NodeArray Params_) + : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {} + + // Handle C++'s ... quirky decl grammer by using the left & right + // distinction. Consider: + // int (*f(float))(char) {} + // f is a function that takes a float and returns a pointer to a function + // that takes a char and returns an int. If we're trying to print f, start + // by printing out the return types's left, then print our parameters, then + // finally print right of the return type. + void printLeft(OutputStream &S) const override { + Ret->printLeft(S); + S += " "; + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + Ret->printRight(S); + } +}; + +class TopLevelFunctionDecl final : public Node { + const Node *Ret; + const Node *Name; + NodeArray Params; + +public: + TopLevelFunctionDecl(Node *Ret_, Node *Name_, NodeArray Params_) + : Node(KTopLevelFunctionDecl, true, true), Ret(Ret_), Name(Name_), + Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (Ret) { + Ret->printLeft(S); + if (!Ret->hasRHSComponent()) + S += " "; + } + Name->print(S); + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithSeperator(S, ", "); + S += ")"; + if (Ret) + Ret->printRight(S); + } +}; + +enum FunctionRefQual : unsigned char { + FrefQualNone, + FrefQualLValue, + FrefQualRValue, +}; + +class FunctionRefQualType : public Node { + Node *Fn; + FunctionRefQual Quals; + + friend class FunctionQualType; + +public: + FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_) + : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {} + + void printQuals(OutputStream &S) const { + if (Quals == FrefQualLValue) + S += " &"; + else + S += " &&"; + } + + void printLeft(OutputStream &S) const override { Fn->printLeft(S); } + + void printRight(OutputStream &S) const override { + Fn->printRight(S); + printQuals(S); + } +}; + +class FunctionQualType final : public QualType { +public: + FunctionQualType(Node *Child_, Qualifiers Quals_) + : QualType(KFunctionQualType, Child_, Quals_) {} + + void printLeft(OutputStream &S) const override { Child->printLeft(S); } + + void printRight(OutputStream &S) const override { + if (Child->K == KFunctionRefQualType) { + auto *RefQuals = static_cast<const FunctionRefQualType *>(Child); + RefQuals->Fn->printRight(S); + printQuals(S); + RefQuals->printQuals(S); + } else { + Child->printRight(S); + printQuals(S); + } + } +}; + +class LiteralOperator : public Node { + const Node *OpName; + +public: + LiteralOperator(Node *OpName_) : Node(KLiteralOperator), OpName(OpName_) {} + + void printLeft(OutputStream &S) const override { + S += "operator\"\" "; + OpName->print(S); + } +}; + +class SpecialName final : public Node { + const StringView Special; + const Node *Child; + +public: + SpecialName(StringView Special_, Node *Child_) + : Node(KSpecialName), Special(Special_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Special; + Child->print(S); + } +}; + +class CtorVtableSpecialName final : public Node { + const Node *FirstType; + const Node *SecondType; + +public: + CtorVtableSpecialName(Node *FirstType_, Node *SecondType_) + : Node(KCtorVtableSpecialName), FirstType(FirstType_), + SecondType(SecondType_) {} + + void printLeft(OutputStream &S) const override { + S += "construction vtable for "; + FirstType->print(S); + S += "-in-"; + SecondType->print(S); + } +}; + +class QualifiedName final : public Node { + // qualifier::name + const Node *Qualifier; + const Node *Name; + + mutable OutputStream::StreamStringView Cache; + +public: + QualifiedName(Node *Qualifier_, Node *Name_) + : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + if (Qualifier->K != KEmptyName) { + Qualifier->print(S); + S += "::"; + } + Name->print(S); + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class EmptyName : public Node { +public: + EmptyName() : Node(KEmptyName) {} + void printLeft(OutputStream &) const override {} +}; + +class VectorType final : public Node { + const Node *BaseType; + const NodeOrString Dimension; + const bool IsPixel; + +public: + VectorType(NodeOrString Dimension_) + : Node(KVectorType), BaseType(nullptr), Dimension(Dimension_), + IsPixel(true) {} + VectorType(Node *BaseType_, NodeOrString Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_), + IsPixel(false) {} + + void printLeft(OutputStream &S) const override { + if (IsPixel) { + S += "pixel vector["; + S += Dimension.asString(); + S += "]"; + } else { + BaseType->print(S); + S += " vector["; + if (Dimension.isNode()) + Dimension.asNode()->print(S); + else if (Dimension.isString()) + S += Dimension.asString(); + S += "]"; + } + } +}; + +class TemplateParams final : public Node { + NodeArray Params; + + mutable OutputStream::StreamStringView Cache; + +public: + TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {} + + void printLeft(OutputStream &S) const override { + if (!Cache.empty()) { + S += Cache; + return; + } + + OutputStream::StreamPosition Start = S.getCurrentPosition(); + + S += "<"; + Params.printWithSeperator(S, ", "); + if (S.back() == '>') + S += " "; + S += ">"; + + Cache = S.makeStringViewFromPastPosition(Start); + } +}; + +class NameWithTemplateArgs final : public Node { + // name<template_args> + Node *Name; + Node *TemplateArgs; + +public: + NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) + : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Name->print(S); + TemplateArgs->print(S); + } +}; + +class GlobalQualifiedName final : public Node { + Node *Child; + +public: + GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "::"; + Child->print(S); + } +}; + +class StdQualifiedName final : public Node { + Node *Child; + +public: + StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "std::"; + Child->print(S); + } +}; + +enum class SpecialSubKind { + allocator, + basic_string, + string, + istream, + ostream, + iostream, +}; + +class ExpandedSpecialSubstitution final : public Node { + SpecialSubKind SSK; + +public: + ExpandedSpecialSubstitution(SpecialSubKind SSK_) + : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("basic_string"); + case SpecialSubKind::istream: + return StringView("basic_istream"); + case SpecialSubKind::ostream: + return StringView("basic_ostream"); + case SpecialSubKind::iostream: + return StringView("basic_iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::basic_string<char, std::char_traits<char>, " + "std::allocator<char> >"; + break; + case SpecialSubKind::basic_string: + case SpecialSubKind::string: + S += "std::basic_string<char, std::char_traits<char>, " + "std::allocator<char> >"; + break; + case SpecialSubKind::istream: + S += "std::basic_istream<char, std::char_traits<char> >"; + break; + case SpecialSubKind::ostream: + S += "std::basic_ostream<char, std::char_traits<char> >"; + break; + case SpecialSubKind::iostream: + S += "std::basic_iostream<char, std::char_traits<char> >"; + break; + } + } +}; + +class SpecialSubstitution final : public Node { +public: + SpecialSubKind SSK; + + SpecialSubstitution(SpecialSubKind SSK_) + : Node(KSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("string"); + case SpecialSubKind::istream: + return StringView("istream"); + case SpecialSubKind::ostream: + return StringView("ostream"); + case SpecialSubKind::iostream: + return StringView("iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + case SpecialSubKind::string: + S += "std::string"; + break; + case SpecialSubKind::istream: + S += "std::istream"; + break; + case SpecialSubKind::ostream: + S += "std::ostream"; + break; + case SpecialSubKind::iostream: + S += "std::iostream"; + break; + } + } +}; + +class CtorDtorName final : public Node { + const Node *Basename; + const bool IsDtor; + +public: + CtorDtorName(Node *Basename_, bool IsDtor_) + : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {} + + void printLeft(OutputStream &S) const override { + if (IsDtor) + S += "~"; + S += Basename->getBaseName(); + } +}; + +class DtorName : public Node { + const Node *Base; + +public: + DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {} + + void printLeft(OutputStream &S) const override { + S += "~"; + Base->printLeft(S); + } +}; + +class UnnamedTypeName : public Node { + const StringView Count; + +public: + UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "'unnamed"; + S += Count; + S += "\'"; + } +}; + +class LambdaTypeName : public Node { + NodeArray Params; + StringView Count; + +public: + LambdaTypeName(NodeArray Params_, StringView Count_) + : Node(KLambdaTypeName), Params(Params_), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "\'lambda"; + S += Count; + S += "\'("; + Params.printWithSeperator(S, ", "); + S += ")"; + } +}; + +// -- Expression Nodes -- + +struct Expr : public Node { + Expr() : Node(KExpr) {} +}; + +class BinaryExpr : public Expr { + const Node *LHS; + const StringView InfixOperator; + const Node *RHS; + +public: + BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_) + : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + // might be a template argument expression, then we need to disambiguate + // with parens. + if (InfixOperator == ">") + S += "("; + + S += "("; + LHS->print(S); + S += ") "; + S += InfixOperator; + S += " ("; + RHS->print(S); + S += ")"; + + if (InfixOperator == ">") + S += ")"; + } +}; + +class ArraySubscriptExpr : public Expr { + const Node *Op1; + const Node *Op2; + +public: + ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Op1->print(S); + S += ")["; + Op2->print(S); + S += "]"; + } +}; + +class PostfixExpr : public Expr { + const Node *Child; + const StringView Operand; + +public: + PostfixExpr(Node *Child_, StringView Operand_) + : Child(Child_), Operand(Operand_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Child->print(S); + S += ")"; + S += Operand; + } +}; + +class ConditionalExpr : public Expr { + const Node *Cond; + const Node *Then; + const Node *Else; + +public: + ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_) + : Cond(Cond_), Then(Then_), Else(Else_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Cond->print(S); + S += ") ? ("; + Then->print(S); + S += ") : ("; + Else->print(S); + S += ")"; + } +}; + +class MemberExpr : public Expr { + const Node *LHS; + const StringView Kind; + const Node *RHS; + +public: + MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_) + : LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + LHS->print(S); + S += Kind; + RHS->print(S); + } +}; + +class EnclosingExpr : public Expr { + const StringView Prefix; + const Node *Infix; + const StringView Postfix; + +public: + EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) + : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + Infix->print(S); + S += Postfix; + } +}; + +class CastExpr : public Expr { + // cast_kind<to>(from) + const StringView CastKind; + const Node *To; + const Node *From; + +public: + CastExpr(StringView CastKind_, Node *To_, Node *From_) + : CastKind(CastKind_), To(To_), From(From_) {} + + void printLeft(OutputStream &S) const override { + S += CastKind; + S += "<"; + To->printLeft(S); + S += ">("; + From->printLeft(S); + S += ")"; + } +}; + +class SizeofParamPackExpr : public Expr { + NodeArray Args; + +public: + SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {} + + void printLeft(OutputStream &S) const override { + S += "sizeof...("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class CallExpr : public Expr { + const Node *Callee; + NodeArray Args; + +public: + CallExpr(Node *Callee_, NodeArray Args_) : Callee(Callee_), Args(Args_) {} + + void printLeft(OutputStream &S) const override { + Callee->print(S); + S += "("; + Args.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class NewExpr : public Expr { + // new (expr_list) type(init_list) + NodeArray ExprList; + Node *Type; + NodeArray InitList; + bool IsGlobal; // ::operator new ? + bool IsArray; // new[] ? +public: + NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, + bool IsArray_) + : ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::operator "; + S += "new"; + if (IsArray) + S += "[]"; + if (!ExprList.empty()) { + S += "("; + ExprList.printWithSeperator(S, ", "); + S += ")"; + } + Type->print(S); + if (!InitList.empty()) { + S += "("; + InitList.printWithSeperator(S, ", "); + S += ")"; + } + } +}; + +class DeleteExpr : public Expr { + Node *Op; + bool IsGlobal; + bool IsArray; + +public: + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) + : Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsGlobal) + S += "::"; + S += "delete"; + if (IsArray) + S += "[] "; + Op->print(S); + } +}; + +class PrefixExpr : public Expr { + StringView Prefix; + Node *Child; + +public: + PrefixExpr(StringView Prefix_, Node *Child_) : Prefix(Prefix_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + S += "("; + Child->print(S); + S += ")"; + } +}; + +class FunctionParam : public Expr { + StringView Number; + +public: + FunctionParam(StringView Number_) : Number(Number_) {} + + void printLeft(OutputStream &S) const override { + S += "fp"; + S += Number; + } +}; + +class ExprList : public Expr { + NodeArray SubExprs; + +public: + ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + SubExprs.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ConversionExpr : public Expr { + NodeArray Expressions; + NodeArray Types; + +public: + ConversionExpr(NodeArray Expressions_, NodeArray Types_) + : Expressions(Expressions_), Types(Types_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Expressions.printWithSeperator(S, ", "); + S += ")("; + Types.printWithSeperator(S, ", "); + S += ")"; + } +}; + +class ThrowExpr : public Expr { + const Node *Op; + +public: + ThrowExpr(Node *Op_) : Op(Op_) {} + + void printLeft(OutputStream &S) const override { + S += "throw "; + Op->print(S); + } +}; + +class BoolExpr : public Expr { + bool Value; + +public: + BoolExpr(bool Value_) : Value(Value_) {} + + void printLeft(OutputStream &S) const override { + S += Value ? StringView("true") : StringView("false"); + } +}; + +class IntegerCastExpr : public Expr { + // ty(integer) + Node *Ty; + StringView Integer; + +public: + IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Ty->print(S); + S += ")"; + S += Integer; + } +}; + +class IntegerExpr : public Expr { + StringView Type; + StringView Value; + +public: + IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {} + + void printLeft(OutputStream &S) const override { + if (Type.size() > 3) { + S += "("; + S += Type; + S += ")"; + } + + if (Value[0] == 'n') { + S += "-"; + S += Value.dropFront(1); + } else + S += Value; + + if (Type.size() <= 3) + S += Type; + } +}; + +template <class Float> struct FloatData; + +template <class Float> class FloatExpr : public Expr { + const StringView Contents; + +public: + FloatExpr(StringView Contents_) : Contents(Contents_) {} + + void printLeft(OutputStream &s) const override { + const char *first = Contents.begin(); + const char *last = Contents.end() + 1; + + const size_t N = FloatData<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) > N) { + last = first + N; + union { + Float value; + char buf[sizeof(Float)]; + }; + const char *t = first; + char *e = buf; + for (; t != last; ++t, ++e) { + unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') + : static_cast<unsigned>(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') + : static_cast<unsigned>(*t - 'a' + 10); + *e = static_cast<char>((d1 << 4) + d0); + } +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[FloatData<Float>::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); + s += StringView(num, num + n); + } + } +}; + +class BumpPointerAllocator { + struct BlockMeta { + BlockMeta* Next; + size_t Current; + }; + + static constexpr size_t AllocSize = 4096; + static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); + + alignas(16) char InitialBuffer[AllocSize]; + BlockMeta* BlockList = nullptr; + + void grow() { + char* NewMeta = new char[AllocSize]; + BlockList = new (NewMeta) BlockMeta{BlockList, 0}; + } + + void* allocateMassive(size_t NBytes) { + NBytes += sizeof(BlockMeta); + BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(new char[NBytes]); + BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; + return static_cast<void*>(NewMeta + 1); + } + +public: + BumpPointerAllocator() + : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} + + void* allocate(size_t N) { + N = (N + 15u) & ~15u; + if (N + BlockList->Current >= UsableAllocSize) { + if (N > UsableAllocSize) + return allocateMassive(N); + grow(); + } + BlockList->Current += N; + return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + + BlockList->Current - N); + } + + ~BumpPointerAllocator() { + while (BlockList) { + BlockMeta* Tmp = BlockList; + BlockList = BlockList->Next; + if (reinterpret_cast<char*>(Tmp) != InitialBuffer) + delete[] reinterpret_cast<char*>(Tmp); + } + } +}; + +template <class T, size_t N> +class PODSmallVector { + static_assert(std::is_pod<T>::value, + "T is required to be a plain old data type"); + + T* First; + T* Last; + T* Cap; + T Inline[N]; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T))); + std::copy(First, Last, Tmp); + First = Tmp; + } else + First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector&) = delete; + PODSmallVector& operator=(const PODSmallVector&) = delete; + + PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector& operator=(PODSmallVector&& Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + void push_back(const T& Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T* begin() { return First; } + T* end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast<size_t>(Last - First); } + T& back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T& operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + +// Substitution table. This type is used to track the substitutions that are +// known by the parser. +template <size_t Size> +class SubstitutionTable { + // Substitutions hold the actual entries in the table, and PackIndices tells + // us which entries are members of which pack. For example, if the + // substitutions we're tracking are: {int, {float, FooBar}, char}, with + // {float, FooBar} being a parameter pack, we represent the substitutions as: + // Substitutions: int, float, FooBar, char + // PackIndices: 0, 1, 3 + // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and + // PackIndices[I + 1] holds the offset of the end. + PODSmallVector<Node*, Size> Substitutions; + PODSmallVector<unsigned, Size> PackIndices; + +public: + // Add a substitution that represents a single name to the table. This is + // modeled as a parameter pack with just one element. + void pushSubstitution(Node* Entry) { + pushPack(); + pushSubstitutionIntoPack(Entry); + } + + // Add a new empty pack to the table. Subsequent calls to + // pushSubstitutionIntoPack() will add to this pack. + void pushPack() { + PackIndices.push_back(static_cast<unsigned>(Substitutions.size())); + } + void pushSubstitutionIntoPack(Node* Entry) { + assert(!PackIndices.empty() && "No pack to push substitution into!"); + Substitutions.push_back(Entry); + } + + // Remove the last pack from the table. + void popPack() { + unsigned Last = PackIndices.back(); + PackIndices.pop_back(); + Substitutions.dropBack(Last); + } + + // For use in a range-for loop. + struct NodeRange { + Node** First; + Node** Last; + Node** begin() { return First; } + Node** end() { return Last; } + }; + + // Retrieve the Nth substitution. This is represented as a range, as the + // substitution could be referring to a parameter pack. + NodeRange nthSubstitution(size_t N) { + assert(PackIndices[N] <= Substitutions.size()); + // The Nth parameter pack starts at offset PackIndices[N], and ends at + // PackIndices[N + 1]. + Node** Begin = Substitutions.begin() + PackIndices[N]; + Node** End; + if (N + 1 != PackIndices.size()) { + assert(PackIndices[N + 1] <= Substitutions.size()); + End = Substitutions.begin() + PackIndices[N + 1]; + } else + End = Substitutions.end(); + assert(Begin <= End); + return NodeRange{Begin, End}; + } + + size_t size() const { return PackIndices.size(); } + bool empty() const { return PackIndices.empty(); } + void clear() { + Substitutions.clear(); + PackIndices.clear(); + } +}; + +struct Db { - fprintf(stderr, "---------\n"); - fprintf(stderr, "names:\n"); - for (auto& s : db.names) - fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - fprintf(stderr, "subs:\n"); - for (auto& v : db.subs) + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser colapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector<Node*, 32> Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 42nd entry in this table. + SubstitutionTable<32> Subs; + + // Template parameter table. Like the above, but referenced like "T42_". + // This has a smaller size compared to Subs and Names because it can be + // stored on the stack. + SubstitutionTable<4> TemplateParams; + + Qualifiers CV = QualNone; + FunctionRefQual RefQuals = FrefQualNone; + unsigned EncodingDepth = 0; + bool ParsedCtorDtorCV = false; + bool TagTemplates = true; + bool FixForwardReferences = false; + bool TryToParseTemplateArgs = true; + + BumpPointerAllocator ASTAllocator; + + template <class T, class... Args> T* make(Args&& ...args) { - if (i >= 0) - fprintf(stderr, "S%i_ = {", i); - else - fprintf(stderr, "S_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward<Args>(args)...); } - fprintf(stderr, "template_param:\n"); - for (auto& t : db.template_param) + + template <class It> NodeArray makeNodeArray(It begin, It end) { - fprintf(stderr, "--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - fprintf(stderr, "T%i_ = {", i); - else - fprintf(stderr, "T_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } + size_t sz = static_cast<size_t>(end - begin); + void* mem = ASTAllocator.allocate(sizeof(Node*) * sz); + Node** data = new (mem) Node*[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); } - fprintf(stderr, "---------\n\n"); -} -template <class C> -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - fprintf(stderr, "%s: ", msg); - for (; first != last; ++first) - fprintf(stderr, "%c", *first); - fprintf(stderr, "\n"); - print_stack(db); -} + NodeArray popTrailingNodeArray(size_t FromPosition) + { + assert(FromPosition <= Names.size()); + NodeArray res = makeNodeArray( + Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } +}; + +const char* parse_type(const char* first, const char* last, Db& db); +const char* parse_encoding(const char* first, const char* last, Db& db); +const char* parse_name(const char* first, const char* last, Db& db, + bool* ends_with_template_args = 0); +const char* parse_expression(const char* first, const char* last, Db& db); +const char* parse_template_args(const char* first, const char* last, Db& db); +const char* parse_operator_name(const char* first, const char* last, Db& db); +const char* parse_unqualified_name(const char* first, const char* last, Db& db); +const char* parse_decltype(const char* first, const char* last, Db& db); // <number> ::= [n] <non-negative decimal integer> @@ -139,30 +1733,30 @@ parse_number(const char* first, const char* last) } template <class Float> -struct float_data; +struct FloatData; template <> -struct float_data<float> +struct FloatData<float> { static const size_t mangled_size = 8; static const size_t max_demangled_size = 24; static constexpr const char* spec = "%af"; }; -constexpr const char* float_data<float>::spec; +constexpr const char* FloatData<float>::spec; template <> -struct float_data<double> +struct FloatData<double> { static const size_t mangled_size = 16; static const size_t max_demangled_size = 32; static constexpr const char* spec = "%a"; }; -constexpr const char* float_data<double>::spec; +constexpr const char* FloatData<double>::spec; template <> -struct float_data<long double> +struct FloatData<long double> { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ defined(__wasm__) @@ -176,55 +1770,35 @@ struct float_data<long double> static constexpr const char* spec = "%LaL"; }; -constexpr const char* float_data<long double>::spec; +constexpr const char* FloatData<long double>::spec; -template <class Float, class C> +template <class Float> const char* -parse_floating_number(const char* first, const char* last, C& db) +parse_floating_number(const char* first, const char* last, Db& db) { - const size_t N = float_data<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) + const size_t N = FloatData<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) <= N) + return first; + last = first + N; + const char* t = first; + for (; t != last; ++t) { - last = first + N; - union - { - Float value; - char buf[sizeof(Float)]; - }; - const char* t = first; - char* e = buf; - for (; t != last; ++t, ++e) - { - if (!isxdigit(*t)) - return first; - unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : - static_cast<unsigned>(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : - static_cast<unsigned>(*t - 'a' + 10); - *e = static_cast<char>((d1 << 4) + d0); - } - if (*t == 'E') - { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[float_data<Float>::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), float_data<Float>::spec, value); - if (static_cast<std::size_t>(n) >= sizeof(num)) - return first; - db.names.push_back(typename C::String(num, static_cast<std::size_t>(n))); - first = t+1; - } + if (!isxdigit(*t)) + return first; + } + if (*t == 'E') + { + db.Names.push_back( + db.make<FloatExpr<Float>>(StringView(first, t))); + first = t + 1; } return first; } // <source-name> ::= <positive length number> <identifier> -template <class C> const char* -parse_source_name(const char* first, const char* last, C& db) +parse_source_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -241,11 +1815,11 @@ parse_source_name(const char* first, const char* last, C& db) } if (static_cast<size_t>(last - t) >= n) { - typename C::String r(t, n); + StringView r(t, t + n); if (r.substr(0, 10) == "_GLOBAL__N") - db.names.push_back("(anonymous namespace)"); + db.Names.push_back(db.make<NameType>("(anonymous namespace)")); else - db.names.push_back(std::move(r)); + db.Names.push_back(db.make<NameType>(r)); first = t + n; } } @@ -264,9 +1838,8 @@ parse_source_name(const char* first, const char* last, C& db) // <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > -template <class C> const char* -parse_substitution(const char* first, const char* last, C& db) +parse_substitution(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -275,34 +1848,39 @@ parse_substitution(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("std::allocator"); + db.Names.push_back( + db.make<SpecialSubstitution>( + SpecialSubKind::allocator)); first += 2; break; case 'b': - db.names.push_back("std::basic_string"); + db.Names.push_back( + db.make<SpecialSubstitution>(SpecialSubKind::basic_string)); first += 2; break; case 's': - db.names.push_back("std::string"); + db.Names.push_back( + db.make<SpecialSubstitution>( + SpecialSubKind::string)); first += 2; break; case 'i': - db.names.push_back("std::istream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream)); first += 2; break; case 'o': - db.names.push_back("std::ostream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream)); first += 2; break; case 'd': - db.names.push_back("std::iostream"); + db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream)); first += 2; break; case '_': - if (!db.subs.empty()) + if (!db.Subs.empty()) { - for (const auto& n : db.subs.front()) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(0)) + db.Names.push_back(n); first += 2; } break; @@ -326,10 +1904,10 @@ parse_substitution(const char* first, const char* last, C& db) if (t == last || *t != '_') return first; ++sub; - if (sub < db.subs.size()) + if (sub < db.Subs.size()) { - for (const auto& n : db.subs[sub]) - db.names.push_back(n); + for (Node* n : db.Subs.nthSubstitution(sub)) + db.Names.push_back(n); first = t+1; } } @@ -372,96 +1950,95 @@ parse_substitution(const char* first, const char* last, C& db) // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) // ::= u <source-name> # vendor extended type -template <class C> const char* -parse_builtin_type(const char* first, const char* last, C& db) +parse_builtin_type(const char* first, const char* last, Db& db) { if (first != last) { switch (*first) { case 'v': - db.names.push_back("void"); + db.Names.push_back(db.make<NameType>("void")); ++first; break; case 'w': - db.names.push_back("wchar_t"); + db.Names.push_back(db.make<NameType>("wchar_t")); ++first; break; case 'b': - db.names.push_back("bool"); + db.Names.push_back(db.make<NameType>("bool")); ++first; break; case 'c': - db.names.push_back("char"); + db.Names.push_back(db.make<NameType>("char")); ++first; break; case 'a': - db.names.push_back("signed char"); + db.Names.push_back(db.make<NameType>("signed char")); ++first; break; case 'h': - db.names.push_back("unsigned char"); + db.Names.push_back(db.make<NameType>("unsigned char")); ++first; break; case 's': - db.names.push_back("short"); + db.Names.push_back(db.make<NameType>("short")); ++first; break; case 't': - db.names.push_back("unsigned short"); + db.Names.push_back(db.make<NameType>("unsigned short")); ++first; break; case 'i': - db.names.push_back("int"); + db.Names.push_back(db.make<NameType>("int")); ++first; break; case 'j': - db.names.push_back("unsigned int"); + db.Names.push_back(db.make<NameType>("unsigned int")); ++first; break; case 'l': - db.names.push_back("long"); + db.Names.push_back(db.make<NameType>("long")); ++first; break; case 'm': - db.names.push_back("unsigned long"); + db.Names.push_back(db.make<NameType>("unsigned long")); ++first; break; case 'x': - db.names.push_back("long long"); + db.Names.push_back(db.make<NameType>("long long")); ++first; break; case 'y': - db.names.push_back("unsigned long long"); + db.Names.push_back(db.make<NameType>("unsigned long long")); ++first; break; case 'n': - db.names.push_back("__int128"); + db.Names.push_back(db.make<NameType>("__int128")); ++first; break; case 'o': - db.names.push_back("unsigned __int128"); + db.Names.push_back(db.make<NameType>("unsigned __int128")); ++first; break; case 'f': - db.names.push_back("float"); + db.Names.push_back(db.make<NameType>("float")); ++first; break; case 'd': - db.names.push_back("double"); + db.Names.push_back(db.make<NameType>("double")); ++first; break; case 'e': - db.names.push_back("long double"); + db.Names.push_back(db.make<NameType>("long double")); ++first; break; case 'g': - db.names.push_back("__float128"); + db.Names.push_back(db.make<NameType>("__float128")); ++first; break; case 'z': - db.names.push_back("..."); + db.Names.push_back(db.make<NameType>("...")); ++first; break; case 'u': @@ -477,39 +2054,39 @@ parse_builtin_type(const char* first, const char* last, C& db) switch (first[1]) { case 'd': - db.names.push_back("decimal64"); + db.Names.push_back(db.make<NameType>("decimal64")); first += 2; break; case 'e': - db.names.push_back("decimal128"); + db.Names.push_back(db.make<NameType>("decimal128")); first += 2; break; case 'f': - db.names.push_back("decimal32"); + db.Names.push_back(db.make<NameType>("decimal32")); first += 2; break; case 'h': - db.names.push_back("decimal16"); + db.Names.push_back(db.make<NameType>("decimal16")); first += 2; break; case 'i': - db.names.push_back("char32_t"); + db.Names.push_back(db.make<NameType>("char32_t")); first += 2; break; case 's': - db.names.push_back("char16_t"); + db.Names.push_back(db.make<NameType>("char16_t")); first += 2; break; case 'a': - db.names.push_back("auto"); + db.Names.push_back(db.make<NameType>("auto")); first += 2; break; case 'c': - db.names.push_back("decltype(auto)"); + db.Names.push_back(db.make<NameType>("decltype(auto)")); first += 2; break; case 'n': - db.names.push_back("std::nullptr_t"); + db.Names.push_back(db.make<NameType>("std::nullptr_t")); first += 2; break; } @@ -520,27 +2097,27 @@ parse_builtin_type(const char* first, const char* last, C& db) return first; } -// <CV-qualifiers> ::= [r] [V] [K] +// <CV-Qualifiers> ::= [r] [V] [K] const char* -parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) +parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv) { - cv = 0; + cv = QualNone; if (first != last) { if (*first == 'r') { - cv |= 4; + addQualifiers(cv, QualRestrict); ++first; } if (*first == 'V') { - cv |= 2; + addQualifiers(cv, QualVolatile); ++first; } if (*first == 'K') { - cv |= 1; + addQualifiers(cv, QualConst); ++first; } } @@ -550,9 +2127,8 @@ parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) // <template-param> ::= T_ # first template parameter // ::= T <parameter-2 non-negative number> _ -template <class C> const char* -parse_template_param(const char* first, const char* last, C& db) +parse_template_param(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -560,19 +2136,17 @@ parse_template_param(const char* first, const char* last, C& db) { if (first[1] == '_') { - if (db.template_param.empty()) - return first; - if (!db.template_param.back().empty()) + if (!db.TemplateParams.empty()) { - for (auto& t : db.template_param.back().front()) - db.names.push_back(t); + for (Node *t : db.TemplateParams.nthSubstitution(0)) + db.Names.push_back(t); first += 2; } else { - db.names.push_back("T_"); + db.Names.push_back(db.make<NameType>("T_")); first += 2; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } else if (isdigit(first[1])) @@ -584,20 +2158,21 @@ parse_template_param(const char* first, const char* last, C& db) sub *= 10; sub += static_cast<size_t>(*t - '0'); } - if (t == last || *t != '_' || db.template_param.empty()) + if (t == last || *t != '_') return first; ++sub; - if (sub < db.template_param.back().size()) + if (sub < db.TemplateParams.size()) { - for (auto& temp : db.template_param.back()[sub]) - db.names.push_back(temp); + for (Node *temp : db.TemplateParams.nthSubstitution(sub)) + db.Names.push_back(temp); first = t+1; } else { - db.names.push_back(typename C::String(first, t+1)); + db.Names.push_back( + db.make<NameType>(StringView(first, t + 1))); first = t+1; - db.fix_forward_references = true; + db.FixForwardReferences = true; } } } @@ -607,9 +2182,8 @@ parse_template_param(const char* first, const char* last, C& db) // cc <type> <expression> # const_cast<type> (expression) -template <class C> const char* -parse_const_cast_expr(const char* first, const char* last, C& db) +parse_const_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') { @@ -619,13 +2193,14 @@ parse_const_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "const_cast", db.Names.back(), from_expr); first = t1; } } @@ -635,9 +2210,8 @@ parse_const_cast_expr(const char* first, const char* last, C& db) // dc <type> <expression> # dynamic_cast<type> (expression) -template <class C> const char* -parse_dynamic_cast_expr(const char* first, const char* last, C& db) +parse_dynamic_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') { @@ -647,13 +2221,14 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "dynamic_cast", db.Names.back(), from_expr); first = t1; } } @@ -663,9 +2238,8 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) // rc <type> <expression> # reinterpret_cast<type> (expression) -template <class C> const char* -parse_reinterpret_cast_expr(const char* first, const char* last, C& db) +parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') { @@ -675,13 +2249,14 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto from_expr = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + db.Names.back() = db.make<CastExpr>( + "reinterpret_cast", db.Names.back(), from_expr); first = t1; } } @@ -691,9 +2266,8 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) // sc <type> <expression> # static_cast<type> (expression) -template <class C> const char* -parse_static_cast_expr(const char* first, const char* last, C& db) +parse_static_cast_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'c') { @@ -703,11 +2277,12 @@ parse_static_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + auto from_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<CastExpr>( + "static_cast", db.Names.back(), from_expr); first = t1; } } @@ -717,9 +2292,8 @@ parse_static_cast_expr(const char* first, const char* last, C& db) // sp <expression> # pack expansion -template <class C> const char* -parse_pack_expansion(const char* first, const char* last, C& db) +parse_pack_expansion(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { @@ -732,18 +2306,18 @@ parse_pack_expansion(const char* first, const char* last, C& db) // st <type> # sizeof (a type) -template <class C> const char* -parse_sizeof_type_expr(const char* first, const char* last, C& db) +parse_sizeof_type_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -752,18 +2326,18 @@ parse_sizeof_type_expr(const char* first, const char* last, C& db) // sz <expr> # sizeof (a expression) -template <class C> const char* -parse_sizeof_expr_expr(const char* first, const char* last, C& db) +parse_sizeof_expr_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof (", db.Names.back(), ")"); first = t; } } @@ -772,60 +2346,50 @@ parse_sizeof_expr_expr(const char* first, const char* last, C& db) // sZ <template-param> # size of a parameter pack -template <class C> const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) + size_t k1 = db.Names.size(); + if (t != first+2 && k0 <= k1) { - typename C::String tmp("sizeof...("); - size_t k = k0; - if (k != k1) - { - tmp += db.names[k].move_full(); - for (++k; k != k1; ++k) - tmp += ", " + db.names[k].move_full(); - } - tmp += ")"; - for (; k1 != k0; --k1) - db.names.pop_back(); - db.names.push_back(std::move(tmp)); + Node* sizeof_expr = db.make<SizeofParamPackExpr>( + db.popTrailingNodeArray(k0)); + db.Names.push_back(sizeof_expr); first = t; } } return first; } -// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters -template <class C> const char* -parse_function_param(const char* first, const char* last, C& db) +parse_function_param(const char* first, const char* last, Db& db) { if (last - first >= 3 && *first == 'f') { if (first[1] == 'p') { - unsigned cv; + Qualifiers cv; const char* t = parse_cv_qualifiers(first+2, last, cv); const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make<FunctionParam>(StringView(t, t1))); first = t1+1; } } else if (first[1] == 'L') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_number(first+2, last); if (t0 != last && *t0 == 'p') { @@ -834,7 +2398,8 @@ parse_function_param(const char* first, const char* last, C& db) const char* t1 = parse_number(t, last); if (t1 != last && *t1 == '_') { - db.names.push_back("fp" + typename C::String(t, t1)); + db.Names.push_back( + db.make<FunctionParam>(StringView(t, t1))); first = t1+1; } } @@ -845,18 +2410,18 @@ parse_function_param(const char* first, const char* last, C& db) // sZ <function-param> # size of a function parameter pack -template <class C> const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) +parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') { const char* t = parse_function_param(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "sizeof...(", db.Names.back(), ")"); first = t; } } @@ -866,9 +2431,8 @@ parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db // te <expression> # typeid (expression) // ti <type> # typeid (type) -template <class C> const char* -parse_typeid_expr(const char* first, const char* last, C& db) +parse_typeid_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) { @@ -879,9 +2443,10 @@ parse_typeid_expr(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "typeid(", db.Names.back(), ")"); first = t; } } @@ -890,18 +2455,17 @@ parse_typeid_expr(const char* first, const char* last, C& db) // tw <expression> # throw expression -template <class C> const char* -parse_throw_expr(const char* first, const char* last, C& db) +parse_throw_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 't' && first[1] == 'w') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "throw " + db.names.back().move_full(); + db.Names.back() = db.make<ThrowExpr>(db.Names.back()); first = t; } } @@ -910,9 +2474,8 @@ parse_throw_expr(const char* first, const char* last, C& db) // ds <expression> <expression> # expr.*expr -template <class C> const char* -parse_dot_star_expr(const char* first, const char* last, C& db) +parse_dot_star_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 's') { @@ -922,11 +2485,12 @@ parse_dot_star_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += ".*" + expr; + auto rhs_expr = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<MemberExpr>( + db.Names.back(), ".*", rhs_expr); first = t1; } } @@ -936,9 +2500,8 @@ parse_dot_star_expr(const char* first, const char* last, C& db) // <simple-id> ::= <source-name> [ <template-args> ] -template <class C> const char* -parse_simple_id(const char* first, const char* last, C& db) +parse_simple_id(const char* first, const char* last, Db& db) { if (first != last) { @@ -948,11 +2511,12 @@ parse_simple_id(const char* first, const char* last, C& db) const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>(db.Names.back(), args); } first = t1; } @@ -966,9 +2530,8 @@ parse_simple_id(const char* first, const char* last, C& db) // ::= <decltype> // ::= <substitution> -template <class C> const char* -parse_unresolved_type(const char* first, const char* last, C& db) +parse_unresolved_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -977,18 +2540,18 @@ parse_unresolved_type(const char* first, const char* last, C& db) { case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first && k1 == k0 + 1) { - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } else { for (; k1 != k0; --k1) - db.names.pop_back(); + db.Names.pop_back(); } break; } @@ -996,9 +2559,9 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } break; @@ -1013,10 +2576,11 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_unqualified_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = + db.make<StdQualifiedName>(db.Names.back()); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -1030,9 +2594,8 @@ parse_unresolved_type(const char* first, const char* last, C& db) // <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) // ::= <simple-id> # e.g., ~A<2*N> -template <class C> const char* -parse_destructor_name(const char* first, const char* last, C& db) +parse_destructor_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -1041,9 +2604,9 @@ parse_destructor_name(const char* first, const char* last, C& db) t = parse_simple_id(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "~"); + db.Names.back() = db.make<DtorName>(db.Names.back()); first = t; } } @@ -1058,9 +2621,8 @@ parse_destructor_name(const char* first, const char* last, C& db) // ::= dn <destructor-name> # destructor or pseudo-destructor; // # e.g. ~X or ~X<N-1> -template <class C> const char* -parse_base_unresolved_name(const char* first, const char* last, C& db) +parse_base_unresolved_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -1074,11 +2636,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); } } } @@ -1100,11 +2664,13 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); } } } @@ -1117,9 +2683,8 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) // <unresolved-qualifier-level> ::= <simple-id> -template <class C> const char* -parse_unresolved_qualifier_level(const char* first, const char* last, C& db) +parse_unresolved_qualifier_level(const char* first, const char* last, Db& db) { return parse_simple_id(first, last, db); } @@ -1134,9 +2699,8 @@ parse_unresolved_qualifier_level(const char* first, const char* last, C& db) // # T::N::x /decltype(p)::N::x // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -template <class C> const char* -parse_unresolved_name(const char* first, const char* last, C& db) +parse_unresolved_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -1152,9 +2716,10 @@ parse_unresolved_name(const char* first, const char* last, C& db) { if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make<GlobalQualifiedName>(db.Names.back()); } first = t2; } @@ -1170,41 +2735,44 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<NameWithTemplateArgs>( + db.Names.back(), args); t = t1; if (t == last) { - db.names.pop_back(); + db.Names.pop_back(); return first; } } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } else @@ -1217,25 +2785,28 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); t = t1; } t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } else @@ -1246,33 +2817,37 @@ parse_unresolved_name(const char* first, const char* last, C& db) t = t1; if (global) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "::"); + db.Names.back() = + db.make<GlobalQualifiedName>( + db.Names.back()); } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) + if (t1 == t || t1 == last || db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), s); t = t1; } ++t; t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); first = t1; } } @@ -1283,9 +2858,8 @@ parse_unresolved_name(const char* first, const char* last, C& db) // dt <expression> <unresolved-name> # expr.name -template <class C> const char* -parse_dot_expr(const char* first, const char* last, C& db) +parse_dot_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 't') { @@ -1295,13 +2869,13 @@ parse_dot_expr(const char* first, const char* last, C& db) const char* t1 = parse_unresolved_name(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += "." + name; + db.Names.back() = db.make<MemberExpr>(db.Names.back(), ".", name); first = t1; } } @@ -1311,51 +2885,31 @@ parse_dot_expr(const char* first, const char* last, C& db) // cl <expression>+ E # call -template <class C> const char* -parse_call_expr(const char* first, const char* last, C& db) +parse_call_expr(const char* first, const char* last, Db& db) { if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') { const char* t = parse_expression(first+2, last, db); - if (t != first+2) + if (t == last || t == first + 2 || db.Names.empty()) + return first; + Node* callee = db.Names.back(); + db.Names.pop_back(); + size_t args_begin = db.Names.size(); + while (*t != 'E') { - if (t == last) - return first; - if (db.names.empty()) - return first; - db.names.back().first += db.names.back().second; - db.names.back().second = typename C::String(); - db.names.back().first.append("("); - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_expr) - { - db.names.back().first.append(", "); - first_expr = false; - } - db.names.back().first.append(tmp); - } - t = t1; - } - ++t; - if (db.names.empty()) + const char* t1 = parse_expression(t, last, db); + if (t1 == last || t1 == t) return first; - db.names.back().first.append(")"); - first = t; + t = t1; } + if (db.Names.size() < args_begin) + return first; + ++t; + CallExpr* the_call = db.make<CallExpr>( + callee, db.popTrailingNodeArray(args_begin)); + db.Names.push_back(the_call); + first = t; } return first; } @@ -1366,9 +2920,8 @@ parse_call_expr(const char* first, const char* last, C& db) // [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) // <initializer> ::= pi <expression>* E # parenthesized initialization -template <class C> const char* -parse_new_expr(const char* first, const char* last, C& db) +parse_new_expr(const char* first, const char* last, Db& db) { if (last - first >= 4) { @@ -1385,31 +2938,18 @@ parse_new_expr(const char* first, const char* last, C& db) t += 2; if (t == last) return first; - bool has_expr_list = false; - bool first_expr = true; + size_t first_expr_in_list = db.Names.size(); + NodeArray ExprList, init_list; while (*t != '_') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - has_expr_list = true; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } + if (first_expr_in_list > db.Names.size()) + return first; + ExprList = db.popTrailingNodeArray(first_expr_in_list); ++t; const char* t1 = parse_type(t, last, db); if (t1 == t || t1 == last) @@ -1420,65 +2960,25 @@ parse_new_expr(const char* first, const char* last, C& db) { t += 2; has_init = true; - first_expr = true; + size_t init_list_begin = db.Names.size(); while (*t != 'E') { t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } - } - if (*t != 'E') - return first; - typename C::String init_list; - if (has_init) - { - if (db.names.empty()) + if (init_list_begin > db.Names.size()) return first; - init_list = db.names.back().move_full(); - db.names.pop_back(); + init_list = db.popTrailingNodeArray(init_list_begin); } - if (db.names.empty()) + if (*t != 'E' || db.Names.empty()) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - typename C::String expr_list; - if (has_expr_list) - { - if (db.names.empty()) - return first; - expr_list = db.names.back().move_full(); - db.names.pop_back(); - } - typename C::String r; - if (parsed_gs) - r = "::"; - if (is_array) - r += "[] "; - else - r += " "; - if (has_expr_list) - r += "(" + expr_list + ") "; - r += type; - if (has_init) - r += " (" + init_list + ")"; - db.names.push_back(std::move(r)); + auto type = db.Names.back(); + db.Names.pop_back(); + db.Names.push_back( + db.make<NewExpr>(ExprList, type, init_list, + parsed_gs, is_array)); first = t+1; } } @@ -1488,18 +2988,19 @@ parse_new_expr(const char* first, const char* last, C& db) // cv <type> <expression> # conversion with one argument // cv <type> _ <expression>* E # conversion with a different number of arguments -template <class C> const char* -parse_conversion_expr(const char* first, const char* last, C& db) +parse_conversion_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; + size_t type_begin = db.Names.size(); const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2 && t != last) { + size_t expr_list_begin = db.Names.size(); if (*t != '_') { const char* t1 = parse_expression(t, last, db); @@ -1512,41 +3013,30 @@ parse_conversion_expr(const char* first, const char* last, C& db) ++t; if (t == last) return first; - if (*t == 'E') - db.names.emplace_back(); - else + if (*t != 'E') { - bool first_expr = true; while (*t != 'E') { const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } t = t1; } } ++t; } - if (db.names.size() < 2) + if (db.Names.size() < expr_list_begin || + type_begin > expr_list_begin) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; + NodeArray expressions = db.makeNodeArray( + db.Names.begin() + (long)expr_list_begin, db.Names.end()); + NodeArray types = db.makeNodeArray( + db.Names.begin() + (long)type_begin, + db.Names.begin() + (long)expr_list_begin); + auto* conv_expr = db.make<ConversionExpr>( + types, expressions); + db.Names.dropBack(type_begin); + db.Names.push_back(conv_expr); first = t; } } @@ -1555,9 +3045,8 @@ parse_conversion_expr(const char* first, const char* last, C& db) // pt <expression> <expression> # expr->name -template <class C> const char* -parse_arrow_expr(const char* first, const char* last, C& db) +parse_arrow_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'p' && first[1] == 't') { @@ -1567,12 +3056,12 @@ parse_arrow_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "->"; - db.names.back().first += tmp; + auto tmp = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<MemberExpr>( + db.Names.back(), "->", tmp); first = t1; } } @@ -1585,9 +3074,8 @@ parse_arrow_expr(const char* first, const char* last, C& db) // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E -template <class C> const char* -parse_function_type(const char* first, const char* last, C& db) +parse_function_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'F') { @@ -1601,17 +3089,19 @@ parse_function_type(const char* first, const char* last, C& db) return first; } const char* t1 = parse_type(t, last, db); - if (t1 != t) + if (t1 != t && !db.Names.empty()) { + Node* ret_type = db.Names.back(); + db.Names.pop_back(); + size_t params_begin = db.Names.size(); t = t1; - typename C::String sig("("); - int ref_qual = 0; + FunctionRefQual RefQuals = FrefQualNone; while (true) { if (t == last) { - if (!db.names.empty()) - db.names.pop_back(); + if (!db.Names.empty()) + db.Names.pop_back(); return first; } if (*t == 'E') @@ -1626,45 +3116,30 @@ parse_function_type(const char* first, const char* last, C& db) } if (*t == 'R' && t+1 != last && t[1] == 'E') { - ref_qual = 1; + RefQuals = FrefQualLValue; ++t; continue; } if (*t == 'O' && t+1 != last && t[1] == 'E') { - ref_qual = 2; + RefQuals = FrefQualRValue; ++t; continue; } - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 == t || t1 == last) + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k1 < k0) return first; - for (size_t k = k0; k < k1; ++k) - { - if (sig.size() > 1) - sig += ", "; - sig += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) - db.names.pop_back(); t = t1; } - sig += ")"; - switch (ref_qual) - { - case 1: - sig += " &"; - break; - case 2: - sig += " &&"; - break; - } - if (db.names.empty()) + if (db.Names.empty() || params_begin > db.Names.size()) return first; - db.names.back().first += " "; - db.names.back().second.insert(0, sig); + Node* fty = db.make<FunctionType>( + ret_type, db.popTrailingNodeArray(params_begin)); + if (RefQuals) + fty = db.make<FunctionRefQualType>(fty, RefQuals); + db.Names.push_back(fty); first = t; } } @@ -1674,9 +3149,8 @@ parse_function_type(const char* first, const char* last, C& db) // <pointer-to-member-type> ::= M <class type> <member type> -template <class C> const char* -parse_pointer_to_member_type(const char* first, const char* last, C& db) +parse_pointer_to_member_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'M') { @@ -1686,21 +3160,13 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto func = std::move(db.names.back()); - db.names.pop_back(); - auto class_type = std::move(db.names.back()); - if (!func.second.empty() && func.second.front() == '(') - { - db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; - db.names.back().second = ")" + std::move(func.second); - } - else - { - db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; - db.names.back().second = std::move(func.second); - } + auto func = std::move(db.Names.back()); + db.Names.pop_back(); + auto ClassType = std::move(db.Names.back()); + db.Names.back() = + db.make<PointerToMemberType>(ClassType, func); first = t2; } } @@ -1711,9 +3177,8 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) // <array-type> ::= A <positive dimension number> _ <element type> // ::= A [<dimension expression>] _ <element type> -template <class C> const char* -parse_array_type(const char* first, const char* last, C& db) +parse_array_type(const char* first, const char* last, Db& db) { if (first != last && *first == 'A' && first+1 != last) { @@ -1722,11 +3187,9 @@ parse_array_type(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " []"); + db.Names.back() = db.make<ArrayType>(db.Names.back()); first = t; } } @@ -1738,11 +3201,11 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t+1, last, db); if (t2 != t+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); + db.Names.back() = + db.make<ArrayType>(db.Names.back(), + StringView(first + 1, t)); first = t2; } } @@ -1755,15 +3218,13 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(++t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = std::move(db.names.back()); - db.names.pop_back(); - auto expr = std::move(db.names.back()); - db.names.back().first = std::move(type.first); - if (type.second.substr(0, 2) == " [") - type.second.erase(0, 1); - db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); + auto base_type = std::move(db.Names.back()); + db.Names.pop_back(); + auto dimension_expr = std::move(db.Names.back()); + db.Names.back() = + db.make<ArrayType>(base_type, dimension_expr); first = t2; } } @@ -1775,9 +3236,8 @@ parse_array_type(const char* first, const char* last, C& db) // <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) // ::= DT <expression> E # decltype of an expression (C++0x) -template <class C> const char* -parse_decltype(const char* first, const char* last, C& db) +parse_decltype(const char* first, const char* last, Db& db) { if (last - first >= 4 && first[0] == 'D') { @@ -1789,9 +3249,10 @@ parse_decltype(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2 && t != last && *t == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<EnclosingExpr>( + "decltype(", db.Names.back(), ")"); first = t+1; } } @@ -1808,9 +3269,8 @@ parse_decltype(const char* first, const char* last, C& db) // <extended element type> ::= <element type> // ::= p # AltiVec vector pixel -template <class C> const char* -parse_vector_type(const char* first, const char* last, C& db) +parse_vector_type(const char* first, const char* last, Db& db) { if (last - first > 3 && first[0] == 'D' && first[1] == 'v') { @@ -1828,33 +3288,36 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t1 = parse_type(t, last, db); if (t1 != t) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + db.Names.back() = + db.make<VectorType>(db.Names.back(), + StringView(num, num + sz)); first = t1; } } else { ++t; - db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + db.Names.push_back( + db.make<VectorType>(StringView(num, num + sz))); first = t; } } } else { - typename C::String num; + Node* num = nullptr; const char* t1 = first+2; if (*t1 != '_') { const char* t = parse_expression(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - num = db.names.back().move_full(); - db.names.pop_back(); + num = db.Names.back(); + db.Names.pop_back(); t1 = t; } } @@ -1863,11 +3326,17 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t = parse_type(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " vector[" + num + "]"; + if (num) + db.Names.back() = + db.make<VectorType>(db.Names.back(), num); + else + db.Names.back() = + db.make<VectorType>(db.Names.back(), StringView()); first = t; - } + } else if (num) + db.Names.push_back(num); } } } @@ -1883,7 +3352,7 @@ parse_vector_type(const char* first, const char* last, C& db) // ::= <template-template-param> <template-args> // ::= <decltype> // ::= <substitution> -// ::= <CV-qualifiers> <type> +// ::= <CV-Qualifiers> <type> // ::= P <type> # pointer-to // ::= R <type> # reference-to // ::= O <type> # rvalue reference-to (C++0x) @@ -1897,9 +3366,8 @@ parse_vector_type(const char* first, const char* last, C& db) // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 // <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> -template <class C> const char* -parse_type(const char* first, const char* last, C& db) +parse_type(const char* first, const char* last, Db& db) { if (first != last) { @@ -1909,52 +3377,30 @@ parse_type(const char* first, const char* last, C& db) case 'V': case 'K': { - unsigned cv = 0; + Qualifiers cv = QualNone; const char* t = parse_cv_qualifiers(first, last, cv); if (t != first) { bool is_function = *t == 'F'; - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); const char* t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t1 != t) { if (is_function) - db.subs.pop_back(); - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.popPack(); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (is_function) - { - size_t p = db.names[k].second.size(); - if (db.names[k].second[p - 2] == '&' && - db.names[k].second[p - 1] == '&') - p -= 2; - else if (db.names[k].second.back() == '&') - p -= 1; - if (cv & 1) - { - db.names[k].second.insert(p, " const"); - p += 6; - } - if (cv & 2) - { - db.names[k].second.insert(p, " volatile"); - p += 9; - } - if (cv & 4) - db.names[k].second.insert(p, " restrict"); - } - else - { - if (cv & 1) - db.names[k].first.append(" const"); - if (cv & 2) - db.names[k].first.append(" volatile"); - if (cv & 4) - db.names[k].first.append(" restrict"); + if (cv) { + if (is_function) + db.Names[k] = db.make<FunctionQualType>( + db.Names[k], cv); + else + db.Names[k] = + db.make<QualType>(db.Names[k], cv); } - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t1; } @@ -1976,77 +3422,69 @@ parse_type(const char* first, const char* last, C& db) t = parse_array_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'C': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" complex"); + db.Names.back() = db.make<PostfixQualifiedType>( + db.Names.back(), " complex"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'F': t = parse_function_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'G': t = parse_type(first+1, last, db); if (t != first+1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append(" imaginary"); + db.Names.back() = db.make<PostfixQualifiedType>( + db.Names.back(), " imaginary"); first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'M': t = parse_pointer_to_member_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); } break; case 'O': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make<RValueReferenceType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2054,34 +3492,16 @@ parse_type(const char* first, const char* last, C& db) } case 'P': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") - { - db.names[k].first.append("*"); - } - else - { - db.names[k].first.replace(0, 11, "id"); - } - db.subs.back().push_back(db.names[k]); + db.Names[k] = db.make<PointerType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2089,27 +3509,17 @@ parse_type(const char* first, const char* last, C& db) } case 'R': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+1) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&"); - db.subs.back().push_back(db.names[k]); + db.Names[k] = + db.make<LValueReferenceType>(db.Names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); } first = t; } @@ -2117,23 +3527,25 @@ parse_type(const char* first, const char* last, C& db) } case 'T': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - if (db.try_to_parse_template_args && k1 == k0+1) + db.Subs.pushSubstitutionIntoPack(db.Names[k]); + if (db.TryToParseTemplateArgs && k1 == k0+1) { const char* t1 = parse_template_args(t, last, db); if (t1 != t) { - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), args); + db.Subs.pushSubstitution(db.Names.back()); t = t1; } } @@ -2150,29 +3562,30 @@ parse_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.back().first.substr(0, 9) != "objcproto") + auto type = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KNameType || + !static_cast<NameType*>(db.Names.back())->getName().startsWith("objcproto")) { - db.names.back() = type + " " + db.names.back().move_full(); + db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back()); } else { - auto proto = db.names.back().move_full(); - db.names.pop_back(); - t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); - if (t != proto.data() + 9) + auto* proto = static_cast<NameType*>(db.Names.back()); + db.Names.pop_back(); + t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db); + if (t != proto->getName().begin() + 9) { - db.names.back() = type + "<" + db.names.back().move_full() + ">"; + db.Names.back() = db.make<ObjCProtoName>(type, db.Names.back()); } else { - db.names.push_back(type + " " + proto); + db.Names.push_back(db.make<VendorExtQualType>(type, proto)); } } - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t2; } } @@ -2184,9 +3597,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2198,17 +3611,22 @@ parse_type(const char* first, const char* last, C& db) first = t; // Parsed a substitution. If the substitution is a // <template-param> it might be followed by <template-args>. - t = parse_template_args(first, last, db); - if (t != first) + if (db.TryToParseTemplateArgs) { - if (db.names.size() < 2) - return first; - auto template_args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += template_args; - // Need to create substitution for <template-template-param> <template-args> - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; + t = parse_template_args(first, last, db); + if (t != first) + { + if (db.Names.size() < 2) + return first; + auto template_args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make< + NameWithTemplateArgs>( + db.Names.back(), template_args); + // Need to create substitution for <template-template-param> <template-args> + db.Subs.pushSubstitution(db.Names.back()); + first = t; + } } } } @@ -2220,14 +3638,14 @@ parse_type(const char* first, const char* last, C& db) { case 'p': { - size_t k0 = db.names.size(); + size_t k0 = db.Names.size(); t = parse_type(first+2, last, db); - size_t k1 = db.names.size(); + size_t k1 = db.Names.size(); if (t != first+2) { - db.subs.emplace_back(db.names.get_allocator()); + db.Subs.pushPack(); for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); + db.Subs.pushSubstitutionIntoPack(db.Names[k]); first = t; return first; } @@ -2238,9 +3656,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } @@ -2249,16 +3667,16 @@ parse_type(const char* first, const char* last, C& db) t = parse_vector_type(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; return first; } break; } } - // drop through + _LIBCPP_FALLTHROUGH(); default: // must check for builtin-types before class-enum-types to avoid // ambiguities with operator-names @@ -2272,9 +3690,9 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); first = t; } } @@ -2340,9 +3758,8 @@ parse_type(const char* first, const char* last, C& db) // ::= rS # >>= // ::= v <digit> <source-name> # vendor extended operator -template <class C> const char* -parse_operator_name(const char* first, const char* last, C& db) +parse_operator_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -2352,20 +3769,20 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator&&"); + db.Names.push_back(db.make<NameType>("operator&&")); first += 2; break; case 'd': case 'n': - db.names.push_back("operator&"); + db.Names.push_back(db.make<NameType>("operator&")); first += 2; break; case 'N': - db.names.push_back("operator&="); + db.Names.push_back(db.make<NameType>("operator&=")); first += 2; break; case 'S': - db.names.push_back("operator="); + db.Names.push_back(db.make<NameType>("operator=")); first += 2; break; } @@ -2374,29 +3791,30 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'l': - db.names.push_back("operator()"); + db.Names.push_back(db.make<NameType>("operator()")); first += 2; break; case 'm': - db.names.push_back("operator,"); + db.Names.push_back(db.make<NameType>("operator,")); first += 2; break; case 'o': - db.names.push_back("operator~"); + db.Names.push_back(db.make<NameType>("operator~")); first += 2; break; case 'v': { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; + bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; + db.TryToParseTemplateArgs = false; const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; + db.TryToParseTemplateArgs = TryToParseTemplateArgs; if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); - db.parsed_ctor_dtor_cv = true; + db.Names.back() = + db.make<ConversionOperatorType>(db.Names.back()); + db.ParsedCtorDtorCV = true; first = t; } } @@ -2407,23 +3825,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator delete[]"); + db.Names.push_back(db.make<NameType>("operator delete[]")); first += 2; break; case 'e': - db.names.push_back("operator*"); + db.Names.push_back(db.make<NameType>("operator*")); first += 2; break; case 'l': - db.names.push_back("operator delete"); + db.Names.push_back(db.make<NameType>("operator delete")); first += 2; break; case 'v': - db.names.push_back("operator/"); + db.Names.push_back(db.make<NameType>("operator/")); first += 2; break; case 'V': - db.names.push_back("operator/="); + db.Names.push_back(db.make<NameType>("operator/=")); first += 2; break; } @@ -2432,15 +3850,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator^"); + db.Names.push_back(db.make<NameType>("operator^")); first += 2; break; case 'O': - db.names.push_back("operator^="); + db.Names.push_back(db.make<NameType>("operator^=")); first += 2; break; case 'q': - db.names.push_back("operator=="); + db.Names.push_back(db.make<NameType>("operator==")); first += 2; break; } @@ -2449,11 +3867,11 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator>="); + db.Names.push_back(db.make<NameType>("operator>=")); first += 2; break; case 't': - db.names.push_back("operator>"); + db.Names.push_back(db.make<NameType>("operator>")); first += 2; break; } @@ -2461,7 +3879,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'i': if (first[1] == 'x') { - db.names.push_back("operator[]"); + db.Names.push_back(db.make<NameType>("operator[]")); first += 2; } break; @@ -2469,7 +3887,7 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'e': - db.names.push_back("operator<="); + db.Names.push_back(db.make<NameType>("operator<=")); first += 2; break; case 'i': @@ -2477,23 +3895,24 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator\"\" "); + db.Names.back() = + db.make<LiteralOperator>(db.Names.back()); first = t; } } break; case 's': - db.names.push_back("operator<<"); + db.Names.push_back(db.make<NameType>("operator<<")); first += 2; break; case 'S': - db.names.push_back("operator<<="); + db.Names.push_back(db.make<NameType>("operator<<=")); first += 2; break; case 't': - db.names.push_back("operator<"); + db.Names.push_back(db.make<NameType>("operator<")); first += 2; break; } @@ -2502,23 +3921,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'i': - db.names.push_back("operator-"); + db.Names.push_back(db.make<NameType>("operator-")); first += 2; break; case 'I': - db.names.push_back("operator-="); + db.Names.push_back(db.make<NameType>("operator-=")); first += 2; break; case 'l': - db.names.push_back("operator*"); + db.Names.push_back(db.make<NameType>("operator*")); first += 2; break; case 'L': - db.names.push_back("operator*="); + db.Names.push_back(db.make<NameType>("operator*=")); first += 2; break; case 'm': - db.names.push_back("operator--"); + db.Names.push_back(db.make<NameType>("operator--")); first += 2; break; } @@ -2527,23 +3946,23 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'a': - db.names.push_back("operator new[]"); + db.Names.push_back(db.make<NameType>("operator new[]")); first += 2; break; case 'e': - db.names.push_back("operator!="); + db.Names.push_back(db.make<NameType>("operator!=")); first += 2; break; case 'g': - db.names.push_back("operator-"); + db.Names.push_back(db.make<NameType>("operator-")); first += 2; break; case 't': - db.names.push_back("operator!"); + db.Names.push_back(db.make<NameType>("operator!")); first += 2; break; case 'w': - db.names.push_back("operator new"); + db.Names.push_back(db.make<NameType>("operator new")); first += 2; break; } @@ -2552,15 +3971,15 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'o': - db.names.push_back("operator||"); + db.Names.push_back(db.make<NameType>("operator||")); first += 2; break; case 'r': - db.names.push_back("operator|"); + db.Names.push_back(db.make<NameType>("operator|")); first += 2; break; case 'R': - db.names.push_back("operator|="); + db.Names.push_back(db.make<NameType>("operator|=")); first += 2; break; } @@ -2569,27 +3988,27 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator->*"); + db.Names.push_back(db.make<NameType>("operator->*")); first += 2; break; case 'l': - db.names.push_back("operator+"); + db.Names.push_back(db.make<NameType>("operator+")); first += 2; break; case 'L': - db.names.push_back("operator+="); + db.Names.push_back(db.make<NameType>("operator+=")); first += 2; break; case 'p': - db.names.push_back("operator++"); + db.Names.push_back(db.make<NameType>("operator++")); first += 2; break; case 's': - db.names.push_back("operator+"); + db.Names.push_back(db.make<NameType>("operator+")); first += 2; break; case 't': - db.names.push_back("operator->"); + db.Names.push_back(db.make<NameType>("operator->")); first += 2; break; } @@ -2597,7 +4016,7 @@ parse_operator_name(const char* first, const char* last, C& db) case 'q': if (first[1] == 'u') { - db.names.push_back("operator?"); + db.Names.push_back(db.make<NameType>("operator?")); first += 2; } break; @@ -2605,19 +4024,19 @@ parse_operator_name(const char* first, const char* last, C& db) switch (first[1]) { case 'm': - db.names.push_back("operator%"); + db.Names.push_back(db.make<NameType>("operator%")); first += 2; break; case 'M': - db.names.push_back("operator%="); + db.Names.push_back(db.make<NameType>("operator%=")); first += 2; break; case 's': - db.names.push_back("operator>>"); + db.Names.push_back(db.make<NameType>("operator>>")); first += 2; break; case 'S': - db.names.push_back("operator>>="); + db.Names.push_back(db.make<NameType>("operator>>=")); first += 2; break; } @@ -2628,9 +4047,10 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "operator "); + db.Names.back() = + db.make<ConversionOperatorType>(db.Names.back()); first = t; } } @@ -2640,25 +4060,14 @@ parse_operator_name(const char* first, const char* last, C& db) return first; } -template <class C> const char* -parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) +parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) { const char* t = parse_number(first, last); if (t != first && t != last && *t == 'E') { - if (lit.size() > 3) - db.names.push_back("(" + lit + ")"); - else - db.names.emplace_back(); - if (*first == 'n') - { - db.names.back().first += '-'; - ++first; - } - db.names.back().first.append(first, t); - if (lit.size() <= 3) - db.names.back().first += lit; + db.Names.push_back( + db.make<IntegerExpr>(lit, StringView(first, t))); first = t+1; } return first; @@ -2671,9 +4080,8 @@ parse_integer_literal(const char* first, const char* last, const typename C::Str // ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) // ::= L <mangled-name> E # external name -template <class C> const char* -parse_expr_primary(const char* first, const char* last, C& db) +parse_expr_primary(const char* first, const char* last, Db& db) { if (last - first >= 4 && *first == 'L') { @@ -2692,11 +4100,11 @@ parse_expr_primary(const char* first, const char* last, C& db) switch (first[2]) { case '0': - db.names.push_back("false"); + db.Names.push_back(db.make<BoolExpr>(0)); first += 4; break; case '1': - db.names.push_back("true"); + db.Names.push_back(db.make<BoolExpr>(1)); first += 4; break; } @@ -2839,9 +4247,10 @@ parse_expr_primary(const char* first, const char* last, C& db) ; if (n != t && n != last && *n == 'E') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + db.Names.back() = db.make<IntegerCastExpr>( + db.Names.back(), StringView(t, n)); first = n+1; break; } @@ -2858,65 +4267,22 @@ parse_expr_primary(const char* first, const char* last, C& db) return first; } -template <class String> -String -base_name(String& s) +Node* maybe_change_special_sub_name(Node* inp, Db& db) { - if (s.empty()) - return s; - if (s == "std::string") - { - s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"; - return "basic_string"; - } - if (s == "std::istream") - { - s = "std::basic_istream<char, std::char_traits<char> >"; - return "basic_istream"; - } - if (s == "std::ostream") - { - s = "std::basic_ostream<char, std::char_traits<char> >"; - return "basic_ostream"; - } - if (s == "std::iostream") - { - s = "std::basic_iostream<char, std::char_traits<char> >"; - return "basic_iostream"; - } - const char* const pf = s.data(); - const char* pe = pf + s.size(); - if (pe[-1] == '>') + if (inp->K != Node::KSpecialSubstitution) + return inp; + auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK; + switch (Kind) { - unsigned c = 1; - while (true) - { - if (--pe == pf) - return String(); - if (pe[-1] == '<') - { - if (--c == 0) - { - --pe; - break; - } - } - else if (pe[-1] == '>') - ++c; - } + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + return db.make<ExpandedSpecialSubstitution>(Kind); + default: + break; } - if (pe - pf <= 1) - return String(); - const char* p0 = pe - 1; - for (; p0 != pf; --p0) - { - if (*p0 == ':') - { - ++p0; - break; - } - } - return String(p0, pe); + return inp; } // <ctor-dtor-name> ::= C1 # complete object constructor @@ -2928,11 +4294,10 @@ base_name(String& s) // ::= D2 # base object destructor // extension ::= D5 # ? -template <class C> const char* -parse_ctor_dtor_name(const char* first, const char* last, C& db) +parse_ctor_dtor_name(const char* first, const char* last, Db& db) { - if (last-first >= 2 && !db.names.empty()) + if (last-first >= 2 && !db.Names.empty()) { switch (first[0]) { @@ -2943,11 +4308,14 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '2': case '3': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back(base_name(db.names.back().first)); + db.Names.back() = + maybe_change_special_sub_name(db.Names.back(), db); + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), false)); first += 2; - db.parsed_ctor_dtor_cv = true; + db.ParsedCtorDtorCV = true; break; } break; @@ -2958,11 +4326,12 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '1': case '2': case '5': - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.push_back("~" + base_name(db.names.back().first)); + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), true)); first += 2; - db.parsed_ctor_dtor_cv = true; + db.ParsedCtorDtorCV = true; break; } break; @@ -2978,9 +4347,8 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) // // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -template <class C> const char* -parse_unnamed_type_name(const char* first, const char* last, C& db) +parse_unnamed_type_name(const char* first, const char* last, Db& db) { if (last - first > 2 && first[0] == 'U') { @@ -2989,106 +4357,63 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) { case 't': { - db.names.push_back(typename C::String("'unnamed")); const char* t0 = first+2; if (t0 == last) - { - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.append(t0, t1); + count = StringView(t0, t1); t0 = t1; } - db.names.back().first.push_back('\''); if (t0 == last || *t0 != '_') - { - db.names.pop_back(); return first; - } + db.Names.push_back(db.make<UnnamedTypeName>(count)); first = t0 + 1; } break; case 'l': { - size_t lambda_pos = db.names.size(); - db.names.push_back(typename C::String("'lambda'(")); + size_t begin_pos = db.Names.size(); const char* t0 = first+2; + NodeArray lambda_params; if (first[2] == 'v') { - db.names.back().first += ')'; ++t0; } else { - bool is_first_it = true; while (true) { - long k0 = static_cast<long>(db.names.size()); const char* t1 = parse_type(t0, last, db); - long k1 = static_cast<long>(db.names.size()); if (t1 == t0) break; - if (k0 >= k1) - return first; - // If the call to parse_type above found a pack expansion - // substitution, then multiple names could have been - // inserted into the name table. Walk through the names, - // appending each onto the lambda's parameter list. - std::for_each(db.names.begin() + k0, db.names.begin() + k1, - [&](typename C::sub_type::value_type &pair) { - if (pair.empty()) - return; - auto &lambda = db.names[lambda_pos].first; - if (!is_first_it) - lambda.append(", "); - is_first_it = false; - lambda.append(pair.move_full()); - }); - db.names.erase(db.names.begin() + k0, db.names.end()); t0 = t1; } - if (is_first_it) - { - if (!db.names.empty()) - db.names.pop_back(); + if (db.Names.size() < begin_pos) return first; - } - if (db.names.empty() || db.names.size() - 1 != lambda_pos) - return first; - db.names.back().first.append(")"); + lambda_params = db.popTrailingNodeArray(begin_pos); } if (t0 == last || *t0 != 'E') - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } + return first; ++t0; if (t0 == last) - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + StringView count; if (std::isdigit(*t0)) { const char* t1 = t0 + 1; while (t1 != last && std::isdigit(*t1)) ++t1; - db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); + count = StringView(t0, t1); t0 = t1; } if (t0 == last || *t0 != '_') - { - if(!db.names.empty()) - db.names.pop_back(); return first; - } + db.Names.push_back(db.make<LambdaTypeName>(lambda_params, count)); first = t0 + 1; } break; @@ -3102,9 +4427,8 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) // ::= <source-name> // ::= <unnamed-type-name> -template <class C> const char* -parse_unqualified_name(const char* first, const char* last, C& db) +parse_unqualified_name(const char* first, const char* last, Db& db) { if (first != last) { @@ -3149,9 +4473,8 @@ parse_unqualified_name(const char* first, const char* last, C& db) // ::= St <unqualified-name> # ::std:: // extension ::= StL<unqualified-name> -template <class C> const char* -parse_unscoped_name(const char* first, const char* last, C& db) +parse_unscoped_name(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3169,9 +4492,10 @@ parse_unscoped_name(const char* first, const char* last, C& db) { if (St) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "std::"); + db.Names.back() = + db.make<StdQualifiedName>(db.Names.back()); } first = t1; } @@ -3181,18 +4505,18 @@ parse_unscoped_name(const char* first, const char* last, C& db) // at <type> # alignof (a type) -template <class C> const char* -parse_alignof_type(const char* first, const char* last, C& db) +parse_alignof_type(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 't') { const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("alignof (", db.Names.back(), ")"); first = t; } } @@ -3201,57 +4525,55 @@ parse_alignof_type(const char* first, const char* last, C& db) // az <expression> # alignof (a expression) -template <class C> const char* -parse_alignof_expr(const char* first, const char* last, C& db) +parse_alignof_expr(const char* first, const char* last, Db& db) { if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') { const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("alignof (", db.Names.back(), ")"); first = t; } } return first; } -template <class C> const char* -parse_noexcept_expression(const char* first, const char* last, C& db) +parse_noexcept_expression(const char* first, const char* last, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; + db.Names.back() = + db.make<EnclosingExpr>("noexcept (", db.Names.back(), ")"); first = t1; } return first; } -template <class C> const char* -parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_prefix_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = op + "(" + db.names.back().move_full() + ")"; + db.Names.back() = db.make<PrefixExpr>(op, db.Names.back()); first = t1; } return first; } -template <class C> const char* -parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) +parse_binary_expression(const char* first, const char* last, StringView op, Db& db) { const char* t1 = parse_expression(first, last, db); if (t1 != first) @@ -3259,22 +4581,14 @@ parse_binary_expression(const char* first, const char* last, const typename C::S const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - auto& nm = db.names.back().first; - nm.clear(); - if (op == ">") - nm += '('; - nm += "(" + op1 + ") " + op + " (" + op2 + ")"; - if (op == ">") - nm += ')'; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = db.make<BinaryExpr>(op1, op, op2); first = t2; } - else if(!db.names.empty()) - db.names.pop_back(); } return first; } @@ -3319,9 +4633,8 @@ parse_binary_expression(const char* first, const char* last, const typename C::S // # objectless nonstatic member reference // ::= <expr-primary> -template <class C> const char* -parse_expression(const char* first, const char* last, C& db) +parse_expression(const char* first, const char* last, Db& db) { if (last - first >= 2) { @@ -3411,10 +4724,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete[] " + db.names.back().move_full(); + db.Names.back() = db.make<DeleteExpr>( + db.Names.back(), parsed_gs, /*is_array=*/true); first = t1; } } @@ -3432,10 +4745,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete " + db.names.back().move_full(); + db.Names.back() = db.make<DeleteExpr>( + db.Names.back(), parsed_gs, /*is_array=*/false); first = t1; } } @@ -3504,16 +4817,17 @@ parse_expression(const char* first, const char* last, C& db) const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ")[" + op2 + "]"; + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make<ArraySubscriptExpr>(op1, op2); first = t2; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3577,9 +4891,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")--"; + db.Names.back() = + db.make<PostfixExpr>(db.Names.back(), "--"); first = t1; } } @@ -3667,9 +4982,10 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back() = "(" + db.names.back().move_full() + ")++"; + db.Names.back() = + db.make<PostfixExpr>(db.Names.back(), "++"); first = t1; } } @@ -3696,26 +5012,27 @@ parse_expression(const char* first, const char* last, C& db) const char* t3 = parse_expression(t2, last, db); if (t3 != t2) { - if (db.names.size() < 3) + if (db.Names.size() < 3) return first; - auto op3 = db.names.back().move_full(); - db.names.pop_back(); - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; + auto op3 = db.Names.back(); + db.Names.pop_back(); + auto op2 = db.Names.back(); + db.Names.pop_back(); + auto op1 = db.Names.back(); + db.Names.back() = + db.make<ConditionalExpr>(op1, op2, op3); first = t3; } else { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - db.names.pop_back(); - db.names.pop_back(); + db.Names.pop_back(); + db.Names.pop_back(); } } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -3788,7 +5105,7 @@ parse_expression(const char* first, const char* last, C& db) first = parse_typeid_expr(first, last, db); break; case 'r': - db.names.push_back("throw"); + db.Names.push_back(db.make<NameType>("throw")); first += 2; break; case 'w': @@ -3817,9 +5134,8 @@ parse_expression(const char* first, const char* last, C& db) // ::= J <template-arg>* E # argument pack // ::= LZ <encoding> E # extension -template <class C> const char* -parse_template_arg(const char* first, const char* last, C& db) +parse_template_arg(const char* first, const char* last, Db& db) { if (first != last) { @@ -3870,57 +5186,52 @@ parse_template_arg(const char* first, const char* last, C& db) // <template-args> ::= I <template-arg>* E // extension, the abi says <template-arg>+ -template <class C> const char* -parse_template_args(const char* first, const char* last, C& db) +parse_template_args(const char* first, const char* last, Db& db) { if (last - first >= 2 && *first == 'I') { - if (db.tag_templates) - db.template_param.back().clear(); + if (db.TagTemplates) + db.TemplateParams.clear(); const char* t = first+1; - typename C::String args("<"); + size_t begin_idx = db.Names.size(); while (*t != 'E') { - if (db.tag_templates) - db.template_param.emplace_back(db.names.get_allocator()); - size_t k0 = db.names.size(); - const char* t1 = parse_template_arg(t, last, db); - size_t k1 = db.names.size(); - if (db.tag_templates) - db.template_param.pop_back(); - if (t1 == t || t1 == last) - return first; - if (db.tag_templates) + if (db.TagTemplates) { - db.template_param.back().emplace_back(db.names.get_allocator()); + auto TmpParams = std::move(db.TemplateParams); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + db.TemplateParams = std::move(TmpParams); + + if (t1 == t || t1 == last || k0 > k1) + return first; + db.TemplateParams.pushPack(); for (size_t k = k0; k < k1; ++k) - db.template_param.back().back().push_back(db.names[k]); - } - for (size_t k = k0; k < k1; ++k) - { - if (args.size() > 1) - args += ", "; - args += db.names[k].move_full(); + db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]); + t = t1; + continue; } - for (; k1 > k0; --k1) - if (!db.names.empty()) - db.names.pop_back(); + size_t k0 = db.Names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.Names.size(); + if (t1 == t || t1 == last || k0 > k1) + return first; t = t1; } + if (begin_idx > db.Names.size()) + return first; first = t + 1; - if (args.back() != '>') - args += ">"; - else - args += " >"; - db.names.push_back(std::move(args)); - + TemplateParams* tp = db.make<TemplateParams>( + db.popTrailingNodeArray(begin_idx)); + db.Names.push_back(tp); } return first; } -// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E -// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E +// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E +// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E // // <prefix> ::= <prefix> <unqualified-name> // ::= <template-prefix> <template-args> @@ -3935,39 +5246,35 @@ parse_template_args(const char* first, const char* last, C& db) // ::= <template-param> // ::= <substitution> -template <class C> const char* -parse_nested_name(const char* first, const char* last, C& db, +parse_nested_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'N') { - unsigned cv; + Qualifiers cv; const char* t0 = parse_cv_qualifiers(first+1, last, cv); if (t0 == last) return first; - db.ref = 0; + db.RefQuals = FrefQualNone; if (*t0 == 'R') { - db.ref = 1; + db.RefQuals = FrefQualLValue; ++t0; } else if (*t0 == 'O') { - db.ref = 2; + db.RefQuals = FrefQualRValue; ++t0; } - db.names.emplace_back(); + db.Names.push_back(db.make<EmptyName>()); if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') { t0 += 2; - db.names.back().first = "std"; + db.Names.back() = db.make<NameType>("std"); } if (t0 == last) - { - db.names.pop_back(); return first; - } bool pop_subs = false; bool component_ends_with_template_args = false; while (*t0 != 'E') @@ -3982,17 +5289,18 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_substitution(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) { - db.names.back().first += "::" + name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); } else - db.names.back().first = name; + db.Names.back() = name; pop_subs = true; t0 = t1; } @@ -4003,15 +5311,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_param(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4024,15 +5333,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_decltype(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4043,12 +5353,13 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - db.names.back().first += name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + auto name = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<NameWithTemplateArgs>( + db.Names.back(), name); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; component_ends_with_template_args = true; } @@ -4064,15 +5375,16 @@ parse_nested_name(const char* first, const char* last, C& db, t1 = parse_unqualified_name(t0, last, db); if (t1 != t0 && t1 != last) { - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + if (db.Names.size() < 2) return first; - if (!db.names.back().first.empty()) - db.names.back().first += "::" + name; + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.back()->K != Node::KEmptyName) + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); else - db.names.back().first = name; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Names.back() = name; + db.Subs.pushSubstitution(db.Names.back()); pop_subs = true; t0 = t1; } @@ -4081,9 +5393,9 @@ parse_nested_name(const char* first, const char* last, C& db, } } first = t0 + 1; - db.cv = cv; - if (pop_subs && !db.subs.empty()) - db.subs.pop_back(); + db.CV = cv; + if (pop_subs && !db.Subs.empty()) + db.Subs.popPack(); if (ends_with_template_args) *ends_with_template_args = component_ends_with_template_args; } @@ -4132,9 +5444,8 @@ parse_discriminator(const char* first, const char* last) // := Z <function encoding> E s [<discriminator>] // := Z <function encoding> Ed [ <parameter number> ] _ <entity name> -template <class C> const char* -parse_local_name(const char* first, const char* last, C& db, +parse_local_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (first != last && *first == 'Z') @@ -4146,9 +5457,10 @@ parse_local_name(const char* first, const char* last, C& db, { case 's': first = parse_discriminator(t+1, last); - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.append("::string literal"); + db.Names.back() = db.make<QualifiedName>( + db.Names.back(), db.make<NameType>("string literal")); break; case 'd': if (++t != last) @@ -4161,18 +5473,18 @@ parse_local_name(const char* first, const char* last, C& db, ends_with_template_args); if (t1 != t) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); first = t1; } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } } break; @@ -4184,17 +5496,17 @@ parse_local_name(const char* first, const char* last, C& db, { // parse but ignore discriminator first = parse_discriminator(t1, last); - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto name = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first.append("::"); - db.names.back().first.append(name); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), name); } - else if (!db.names.empty()) - db.names.pop_back(); + else if (!db.Names.empty()) + db.Names.pop_back(); } break; } @@ -4211,9 +5523,8 @@ parse_local_name(const char* first, const char* last, C& db, // <unscoped-template-name> ::= <unscoped-name> // ::= <substitution> -template <class C> const char* -parse_name(const char* first, const char* last, C& db, +parse_name(const char* first, const char* last, Db& db, bool* ends_with_template_args) { if (last - first >= 2) @@ -4247,20 +5558,22 @@ parse_name(const char* first, const char* last, C& db, { if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args> { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + db.Subs.pushSubstitution(db.Names.back()); t0 = t1; t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4278,13 +5591,15 @@ parse_name(const char* first, const char* last, C& db, t1 = parse_template_args(t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto tmp = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first += tmp; + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), tmp); first = t1; if (ends_with_template_args) *ends_with_template_args = true; @@ -4354,9 +5669,8 @@ parse_call_offset(const char* first, const char* last) // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first // extension ::= GR <object name> # reference temporary for object -template <class C> const char* -parse_special_name(const char* first, const char* last, C& db) +parse_special_name(const char* first, const char* last, Db& db) { if (last - first > 2) { @@ -4371,9 +5685,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "vtable for "); + db.Names.back() = + db.make<SpecialName>("vtable for ", db.Names.back()); first = t; } break; @@ -4382,9 +5697,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "VTT for "); + db.Names.back() = + db.make<SpecialName>("VTT for ", db.Names.back()); first = t; } break; @@ -4393,9 +5709,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo for "); + db.Names.back() = + db.make<SpecialName>("typeinfo for ", db.Names.back()); first = t; } break; @@ -4404,9 +5721,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "typeinfo name for "); + db.Names.back() = + db.make<SpecialName>("typeinfo name for ", db.Names.back()); first = t; } break; @@ -4422,9 +5740,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t1, last, db); if (t != t1) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "covariant return thunk to "); + db.Names.back() = + db.make<SpecialName>("covariant return thunk to ", + db.Names.back()); first = t; } } @@ -4440,15 +5760,14 @@ parse_special_name(const char* first, const char* last, C& db) const char* t1 = parse_type(++t0, last, db); if (t1 != t0) { - if (db.names.size() < 2) + if (db.Names.size() < 2) return first; - auto left = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.empty()) + auto left = db.Names.back(); + db.Names.pop_back(); + if (db.Names.empty()) return first; - db.names.back().first = "construction vtable for " + - std::move(left) + "-in-" + - db.names.back().move_full(); + db.Names.back() = db.make<CtorVtableSpecialName>( + left, db.Names.back()); first = t1; } } @@ -4459,9 +5778,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first + 2, last, db); if (t != first + 2) { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "thread-local wrapper routine for "); + if (db.Names.empty()) + return first; + db.Names.back() = + db.make<SpecialName>("thread-local wrapper routine for ", + db.Names.back()); first = t; } break; @@ -4470,9 +5791,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first + 2, last, db); if (t != first + 2) { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "thread-local initialization routine for "); + if (db.Names.empty()) + return first; + db.Names.back() = db.make<SpecialName>( + "thread-local initialization routine for ", db.Names.back()); first = t; } break; @@ -4485,16 +5807,20 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t0, last, db); if (t != t0) { - if (db.names.empty()) + if (db.Names.empty()) return first; if (first[1] == 'v') { - db.names.back().first.insert(0, "virtual thunk to "); + db.Names.back() = + db.make<SpecialName>("virtual thunk to ", + db.Names.back()); first = t; } else { - db.names.back().first.insert(0, "non-virtual thunk to "); + db.Names.back() = + db.make<SpecialName>("non-virtual thunk to ", + db.Names.back()); first = t; } } @@ -4510,9 +5836,10 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "guard variable for "); + db.Names.back() = + db.make<SpecialName>("guard variable for ", db.Names.back()); first = t; } break; @@ -4521,9 +5848,11 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "reference temporary for "); + db.Names.back() = + db.make<SpecialName>("reference temporary for ", + db.Names.back()); first = t; } break; @@ -4558,19 +5887,18 @@ public: // ::= <data name> // ::= <special-name> -template <class C> const char* -parse_encoding(const char* first, const char* last, C& db) +parse_encoding(const char* first, const char* last, Db& db) { if (first != last) { - save_value<decltype(db.encoding_depth)> su(db.encoding_depth); - ++db.encoding_depth; - save_value<decltype(db.tag_templates)> sb(db.tag_templates); - if (db.encoding_depth > 1) - db.tag_templates = true; - save_value<decltype(db.parsed_ctor_dtor_cv)> sp(db.parsed_ctor_dtor_cv); - db.parsed_ctor_dtor_cv = false; + save_value<decltype(db.EncodingDepth)> su(db.EncodingDepth); + ++db.EncodingDepth; + save_value<decltype(db.TagTemplates)> sb(db.TagTemplates); + if (db.EncodingDepth > 1) + db.TagTemplates = true; + save_value<decltype(db.ParsedCtorDtorCV)> sp(db.ParsedCtorDtorCV); + db.ParsedCtorDtorCV = false; switch (*first) { case 'G': @@ -4582,96 +5910,72 @@ parse_encoding(const char* first, const char* last, C& db) bool ends_with_template_args = false; const char* t = parse_name(first, last, db, &ends_with_template_args); - unsigned cv = db.cv; - unsigned ref = db.ref; + if (db.Names.empty()) + return first; + Qualifiers cv = db.CV; + FunctionRefQual ref = db.RefQuals; if (t != first) { if (t != last && *t != 'E' && *t != '.') { - save_value<bool> sb2(db.tag_templates); - db.tag_templates = false; + save_value<bool> sb2(db.TagTemplates); + db.TagTemplates = false; const char* t2; - typename C::String ret2; - if (db.names.empty()) + if (db.Names.empty()) return first; - const typename C::String& nm = db.names.back().first; - if (nm.empty()) + if (!db.Names.back()) return first; - if (!db.parsed_ctor_dtor_cv && ends_with_template_args) + Node* return_type = nullptr; + if (!db.ParsedCtorDtorCV && ends_with_template_args) { t2 = parse_type(t, last, db); if (t2 == t) return first; - if (db.names.size() < 2) + if (db.Names.size() < 1) return first; - auto ret1 = std::move(db.names.back().first); - ret2 = std::move(db.names.back().second); - if (ret2.empty()) - ret1 += ' '; - db.names.pop_back(); - if (db.names.empty()) - return first; - - db.names.back().first.insert(0, ret1); + return_type = db.Names.back(); + db.Names.pop_back(); t = t2; } - db.names.back().first += '('; + + Node* result = nullptr; + if (t != last && *t == 'v') { ++t; + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make<TopLevelFunctionDecl>( + return_type, name, NodeArray()); } else { - bool first_arg = true; + size_t params_begin = db.Names.size(); while (true) { - size_t k0 = db.names.size(); t2 = parse_type(t, last, db); - size_t k1 = db.names.size(); if (t2 == t) break; - if (k1 > k0) - { - typename C::String tmp; - for (size_t k = k0; k < k1; ++k) - { - if (!tmp.empty()) - tmp += ", "; - tmp += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) { - if (db.names.empty()) - return first; - db.names.pop_back(); - } - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_arg) - db.names.back().first += ", "; - else - first_arg = false; - db.names.back().first += tmp; - } - } t = t2; } + if (db.Names.size() < params_begin) + return first; + NodeArray params = + db.popTrailingNodeArray(params_begin); + if (db.Names.empty()) + return first; + Node* name = db.Names.back(); + db.Names.pop_back(); + result = db.make<TopLevelFunctionDecl>( + return_type, name, params); } - if (db.names.empty()) - return first; - db.names.back().first += ')'; - if (cv & 1) - db.names.back().first.append(" const"); - if (cv & 2) - db.names.back().first.append(" volatile"); - if (cv & 4) - db.names.back().first.append(" restrict"); - if (ref == 1) - db.names.back().first.append(" &"); - else if (ref == 2) - db.names.back().first.append(" &&"); - db.names.back().first += ret2; + if (ref != FrefQualNone) + result = db.make<FunctionRefQualType>(result, ref); + if (cv != QualNone) + result = db.make<FunctionQualType>(result, cv); + db.Names.push_back(result); first = t; } else @@ -4688,12 +5992,12 @@ parse_encoding(const char* first, const char* last, C& db) // _block_invoke<decimal-digit>+ // _block_invoke_<decimal-digit>+ -template <class C> const char* -parse_block_invoke(const char* first, const char* last, C& db) +parse_block_invoke(const char* first, const char* last, Db& db) { if (last - first >= 13) { + // FIXME: strcmp? const char test[] = "_block_invoke"; const char* t = first; for (int i = 0; i < 13; ++i, ++t) @@ -4714,9 +6018,11 @@ parse_block_invoke(const char* first, const char* last, C& db) while (t != last && isdigit(*t)) ++t; } - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first.insert(0, "invocation function for block in "); + db.Names.back() = + db.make<SpecialName>("invocation function for block in ", + db.Names.back()); first = t; } return first; @@ -4725,15 +6031,15 @@ parse_block_invoke(const char* first, const char* last, C& db) // extension // <dot-suffix> := .<anything and everything> -template <class C> const char* -parse_dot_suffix(const char* first, const char* last, C& db) +parse_dot_suffix(const char* first, const char* last, Db& db) { if (first != last && *first == '.') { - if (db.names.empty()) + if (db.Names.empty()) return first; - db.names.back().first += " (" + typename C::String(first, last) + ")"; + db.Names.back() = + db.make<DotSuffix>(db.Names.back(), StringView(first, last)); first = last; } return first; @@ -4745,9 +6051,8 @@ parse_dot_suffix(const char* first, const char* last, C& db) // <mangled-name> ::= _Z<encoding> // ::= <type> -template <class C> void -demangle(const char* first, const char* last, C& db, int& status) +demangle(const char* first, const char* last, Db& db, int& status) { if (first >= last) { @@ -4790,217 +6095,10 @@ demangle(const char* first, const char* last, C& db, int& status) if (t != last) status = invalid_mangled_name; } - if (status == success && db.names.empty()) + if (status == success && db.Names.empty()) status = invalid_mangled_name; } -template <std::size_t N> -class arena -{ - static const std::size_t alignment = 16; - alignas(alignment) char buf_[N]; - char* ptr_; - - std::size_t - align_up(std::size_t n) noexcept - {return (n + (alignment-1)) & ~(alignment-1);} - - bool - pointer_in_buffer(char* p) noexcept - {return buf_ <= p && p <= buf_ + N;} - -public: - arena() noexcept : ptr_(buf_) {} - ~arena() {ptr_ = nullptr;} - arena(const arena&) = delete; - arena& operator=(const arena&) = delete; - - char* allocate(std::size_t n); - void deallocate(char* p, std::size_t n) noexcept; - - static constexpr std::size_t size() {return N;} - std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);} - void reset() {ptr_ = buf_;} -}; - -template <std::size_t N> -char* -arena<N>::allocate(std::size_t n) -{ - n = align_up(n); - if (static_cast<std::size_t>(buf_ + N - ptr_) >= n) - { - char* r = ptr_; - ptr_ += n; - return r; - } - return static_cast<char*>(std::malloc(n)); -} - -template <std::size_t N> -void -arena<N>::deallocate(char* p, std::size_t n) noexcept -{ - if (pointer_in_buffer(p)) - { - n = align_up(n); - if (p + n == ptr_) - ptr_ = p; - } - else - std::free(p); -} - -template <class T, std::size_t N> -class short_alloc -{ - arena<N>& a_; -public: - typedef T value_type; - -public: - template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;}; - - short_alloc(arena<N>& a) noexcept : a_(a) {} - template <class U> - short_alloc(const short_alloc<U, N>& a) noexcept - : a_(a.a_) {} - short_alloc(const short_alloc&) = default; - short_alloc& operator=(const short_alloc&) = delete; - - T* allocate(std::size_t n) - { - return reinterpret_cast<T*>(a_.allocate(n*sizeof(T))); - } - void deallocate(T* p, std::size_t n) noexcept - { - a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T)); - } - - template <class T1, std::size_t N1, class U, std::size_t M> - friend - bool - operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept; - - template <class U, std::size_t M> friend class short_alloc; -}; - -template <class T, std::size_t N, class U, std::size_t M> -inline -bool -operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept -{ - return N == M && &x.a_ == &y.a_; -} - -template <class T, std::size_t N, class U, std::size_t M> -inline -bool -operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept -{ - return !(x == y); -} - -template <class T> -class malloc_alloc -{ -public: - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - malloc_alloc() = default; - template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {} - - T* allocate(std::size_t n) - { - return static_cast<T*>(std::malloc(n*sizeof(T))); - } - void deallocate(T* p, std::size_t) noexcept - { - std::free(p); - } - - template <class U> struct rebind { using other = malloc_alloc<U>; }; - template <class U, class... Args> - void construct(U* p, Args&&... args) - { - ::new ((void*)p) U(std::forward<Args>(args)...); - } - void destroy(T* p) - { - p->~T(); - } -}; - -template <class T, class U> -inline -bool -operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept -{ - return true; -} - -template <class T, class U> -inline -bool -operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept -{ - return !(x == y); -} - -const size_t bs = 4 * 1024; -template <class T> using Alloc = short_alloc<T, bs>; -template <class T> using Vector = std::vector<T, Alloc<T>>; - -template <class StrT> -struct string_pair -{ - StrT first; - StrT second; - - string_pair() = default; - string_pair(StrT f) : first(std::move(f)) {} - string_pair(StrT f, StrT s) - : first(std::move(f)), second(std::move(s)) {} - template <size_t N> - string_pair(const char (&s)[N]) : first(s, N-1) {} - - size_t size() const {return first.size() + second.size();} - bool empty() const { return first.empty() && second.empty(); } - StrT full() const {return first + second;} - StrT move_full() {return std::move(first) + std::move(second);} -}; - -struct Db -{ - typedef std::basic_string<char, std::char_traits<char>, - malloc_alloc<char>> String; - typedef Vector<string_pair<String>> sub_type; - typedef Vector<sub_type> template_param_type; - sub_type names; - template_param_type subs; - Vector<template_param_type> template_param; - unsigned cv = 0; - unsigned ref = 0; - unsigned encoding_depth = 0; - bool parsed_ctor_dtor_cv = false; - bool tag_templates = true; - bool fix_forward_references = false; - bool try_to_parse_template_args = true; - - template <size_t N> - Db(arena<N>& ar) : - names(ar), - subs(0, names, ar), - template_param(0, subs, ar) - {} -}; - } // unnamed namespace extern "C" _LIBCXXABI_FUNC_VIS char * @@ -5013,48 +6111,42 @@ __cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) { } size_t internal_size = buf != nullptr ? *n : 0; - arena<bs> a; - Db db(a); - db.template_param.emplace_back(a); + Db db; int internal_status = success; size_t len = std::strlen(mangled_name); demangle(mangled_name, mangled_name + len, db, internal_status); - if (internal_status == success && db.fix_forward_references && - !db.template_param.empty() && !db.template_param.front().empty()) + + if (internal_status == success && db.FixForwardReferences && + !db.TemplateParams.empty()) { - db.fix_forward_references = false; - db.tag_templates = false; - db.names.clear(); - db.subs.clear(); + db.FixForwardReferences = false; + db.TagTemplates = false; + db.Names.clear(); + db.Subs.clear(); demangle(mangled_name, mangled_name + len, db, internal_status); - if (db.fix_forward_references) + if (db.FixForwardReferences) internal_status = invalid_mangled_name; } + if (internal_status == success) { - size_t sz = db.names.back().size() + 1; - if (sz > internal_size) + if (!buf) { - char* newbuf = static_cast<char*>(std::realloc(buf, sz)); - if (newbuf == nullptr) - { - internal_status = memory_alloc_failure; - buf = nullptr; - } - else - { - buf = newbuf; - if (n != nullptr) - *n = sz; - } + internal_size = 1024; + buf = static_cast<char*>(std::malloc(internal_size)); } - if (buf != nullptr) + + if (buf) { - db.names.back().first += db.names.back().second; - std::memcpy(buf, db.names.back().first.data(), sz-1); - buf[sz-1] = char(0); + OutputStream s(buf, internal_size); + db.Names.back()->print(s); + s += '\0'; + if (n) *n = s.getCurrentPosition(); + buf = s.getBuffer(); } + else + internal_status = memory_alloc_failure; } else buf = nullptr; diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp index 0794444bcc5..e6ed0931ceb 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp @@ -19,6 +19,10 @@ #include "cxa_handlers.hpp" #include "fallback_malloc.h" +#if __has_feature(address_sanitizer) +extern "C" void __asan_handle_no_return(void); +#endif + // +---------------------------+-----------------------------+---------------+ // | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | // +---------------------------+-----------------------------+---------------+ @@ -217,6 +221,12 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + +#if __has_feature(address_sanitizer) + // Inform the ASan runtime that now might be a good time to clean stuff up. + __asan_handle_no_return(); +#endif + #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp index eaac21734f9..c641e0225f8 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp @@ -56,7 +56,7 @@ namespace { std::__libcpp_tls_key key_; std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - void destruct_ (void *p) { + void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { __free_with_fallback ( p ); if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) abort_message("cannot zero out thread value for __cxa_get_globals()"); diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h b/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h new file mode 100644 index 00000000000..bc131aeb5ae --- /dev/null +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/include/refstring.h @@ -0,0 +1,131 @@ +//===------------------------ __refstring ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of +// duplicating the file in libc++abi we should require that the libc++ sources +// are available when building libc++abi. + +#ifndef _LIBCPPABI_REFSTRING_H +#define _LIBCPPABI_REFSTRING_H + +#include <__config> +#include <stdexcept> +#include <cstddef> +#include <cstring> +#ifdef __APPLE__ +#include <dlfcn.h> +#include <mach-o/dyld.h> +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __refstring_imp { namespace { +typedef int count_t; + +struct _Rep_base { + std::size_t len; + std::size_t cap; + count_t count; +}; + +inline _Rep_base* rep_from_data(const char *data_) noexcept { + char *data = const_cast<char *>(data_); + return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); +} + +inline char * data_from_rep(_Rep_base *rep) noexcept { + char *data = reinterpret_cast<char *>(rep); + return data + sizeof(*rep); +} + +#if defined(__APPLE__) +inline +const char* compute_gcc_empty_string_storage() _NOEXCEPT +{ + void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); + if (handle == nullptr) + return nullptr; + void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); + if (sym == nullptr) + return nullptr; + return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); +} + +inline +const char* +get_gcc_empty_string_storage() _NOEXCEPT +{ + static const char* p = compute_gcc_empty_string_storage(); + return p; +} +#endif + +}} // namespace __refstring_imp + +using namespace __refstring_imp; + +inline +__libcpp_refstring::__libcpp_refstring(const char* msg) { + std::size_t len = strlen(msg); + _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); + rep->len = len; + rep->cap = len; + rep->count = 0; + char *data = data_from_rep(rep); + std::memcpy(data, msg, len + 1); + __imp_ = data; +} + +inline +__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT + : __imp_(s.__imp_) +{ + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); +} + +inline +__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { + bool adjust_old_count = __uses_refcount(); + struct _Rep_base *old_rep = rep_from_data(__imp_); + __imp_ = s.__imp_; + if (__uses_refcount()) + __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); + if (adjust_old_count) + { + if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0) + { + ::operator delete(old_rep); + } + } + return *this; +} + +inline +__libcpp_refstring::~__libcpp_refstring() { + if (__uses_refcount()) { + _Rep_base* rep = rep_from_data(__imp_); + if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0) { + ::operator delete(rep); + } + } +} + +inline +bool __libcpp_refstring::__uses_refcount() const { +#ifdef __APPLE__ + return __imp_ != get_gcc_empty_string_storage(); +#else + return true; +#endif +} + +_LIBCPP_END_NAMESPACE_STD + +#endif //_LIBCPPABI_REFSTRING_H diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp index 58a2b0df6c0..08e2b45fa86 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp @@ -229,7 +229,7 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type, if (thrown_class_type == 0) return false; // bullet 2 - __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -427,7 +427,7 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); if (thrown_class_type == 0) return false; - __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0}; + __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; info.number_of_dst_type = 1; thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); if (info.path_dst_ptr_to_static_ptr == public_path) @@ -633,7 +633,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, // be returned. const void* dst_ptr = 0; // Initialize info struct for this search. - __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; + __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; // Find out if we can use a giant short cut in the search if (is_equal(dynamic_type, dst_type, false)) diff --git a/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp b/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp index bd6789ef227..e3b7cd40658 100644 --- a/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp +++ b/chromium/buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "__refstring" +#include "include/refstring.h" #include "stdexcept" #include "new" #include <cstdlib> |